From 3d8cc28acd6d6b7239b46cd07044800c828a1ae5 Mon Sep 17 00:00:00 2001 From: DH Date: Tue, 15 Aug 2023 03:04:25 +0300 Subject: [PATCH] [orbis-kernel] AudioOut: refactoring --- orbis-kernel/include/orbis/AudioOut.hpp | 406 ++++++++----------- orbis-kernel/include/orbis/KernelContext.hpp | 2 + orbis-kernel/src/sys/sys_sce.cpp | 105 +++-- rpcsx-os/main.cpp | 12 +- 4 files changed, 249 insertions(+), 276 deletions(-) diff --git a/orbis-kernel/include/orbis/AudioOut.hpp b/orbis-kernel/include/orbis/AudioOut.hpp index 3839bcc69..e813a9c73 100644 --- a/orbis-kernel/include/orbis/AudioOut.hpp +++ b/orbis-kernel/include/orbis/AudioOut.hpp @@ -1,280 +1,234 @@ #pragma once -#include -#include -#include -#include +#include "evf.hpp" +#include "utils/Logs.hpp" +#include +#include +#include #include -#include -#include -#include -#include -#include -#include "sys/sysproto.hpp" -#include #include +#include +#include +#include +#include -struct args { - int32_t audioPort; - int32_t idControl; - int32_t idAudio; - orbis::Thread *thread; - int32_t evfId; +namespace orbis { +struct AudioOutChannelInfo { + std::int32_t port{}; + std::int32_t idControl{}; + std::int32_t channel{}; + Ref evf; }; -int msleep(long msec) -{ - struct timespec ts; - int res; +struct AudioOut { + std::mutex thrMtx; + std::vector threads; + AudioOutChannelInfo channelInfo; + std::atomic exit{false}; - if (msec < 0) - { - errno = EINVAL; - return -1; + AudioOut() { + if (sox_init() != SOX_SUCCESS) { + ORBIS_LOG_FATAL("Failed to initialize sox"); + std::abort(); } + } - ts.tv_sec = msec / 1000; - ts.tv_nsec = (msec % 1000) * 1000000; + ~AudioOut() { + exit = true; + for (auto &thread : threads) { + thread.join(); + } + sox_quit(); + } - do { - res = nanosleep(&ts, &ts); - } while (res && errno == EINTR); - - return res; -} - -void DumpHex(const void* data, size_t size) { - char ascii[17]; - size_t i, j; - ascii[16] = '\0'; - for (i = 0; i < size; ++i) { - printf("%02X ", ((unsigned char*)data)[i]); - if (((unsigned char*)data)[i] >= ' ' && ((unsigned char*)data)[i] <= '~') { - ascii[i % 16] = ((unsigned char*)data)[i]; - } else { - ascii[i % 16] = '.'; - } - if ((i+1) % 8 == 0 || i+1 == size) { - printf(" "); - if ((i+1) % 16 == 0) { - printf("| %s \n", ascii); - } else if (i+1 == size) { - ascii[(i+1) % 16] = '\0'; - if ((i+1) % 16 <= 8) { - printf(" "); - } - for (j = (i+1) % 16; j < 16; ++j) { - printf(" "); - } - printf("| %s \n", ascii); - } - } - } -} - -void * loop(void *vargp) -{ - size_t control_shm_size = 0x10000; - size_t audio_shm_size = 65536; + void start() { + std::lock_guard lock(thrMtx); + threads.push_back(std::thread( + [this, channelInfo = channelInfo] { channelEntry(channelInfo); })); + } +private: + void channelEntry(AudioOutChannelInfo info) { char control_shm_name[32]; char audio_shm_name[32]; - sprintf(control_shm_name, "/rpcsx-shm_%d_C", ((struct args*)vargp)->idControl); - sprintf(audio_shm_name, "/rpcsx-shm_%d_%d_A", ((struct args*)vargp)->idAudio, ((struct args*)vargp)->audioPort); + std::snprintf(control_shm_name, sizeof(control_shm_name), "/rpcsx-shm_%d_C", + info.idControl); + std::snprintf(audio_shm_name, sizeof(audio_shm_name), "/rpcsx-shm_%d_%d_A", + info.channel, info.port); - int controlFd = shm_open(control_shm_name, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); + int controlFd = + ::shm_open(control_shm_name, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); if (controlFd == -1) { - perror("shm_open"); - exit(EXIT_FAILURE); + perror("shm_open"); + std::abort(); } - void *controlPtr = mmap(NULL, control_shm_size, PROT_READ | PROT_WRITE, MAP_SHARED, controlFd, 0); + + struct stat controlStat; + if (::fstat(controlFd, &controlStat)) { + perror("shm_open"); + std::abort(); + } + + auto controlPtr = reinterpret_cast( + ::mmap(NULL, controlStat.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, + controlFd, 0)); if (controlPtr == MAP_FAILED) { - perror("mmap"); - exit(EXIT_FAILURE); + perror("mmap"); + std::abort(); } - int audioFd = shm_open(audio_shm_name, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); - if (audioFd == -1) { + int bufferFd = + ::shm_open(audio_shm_name, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); + if (bufferFd == -1) { perror("open"); - exit(EXIT_FAILURE); - } - void *audioPtr = mmap(NULL, audio_shm_size, PROT_READ | PROT_WRITE, MAP_SHARED, audioFd, 0); - - int64_t controlPtrWithOffset = (int64_t)(controlPtr + 8); - - int32_t bitPattern = 1 << ((struct args*)vargp)->audioPort; - - int firstNonEmptyByteIndex; - - for (size_t i = 24; i < control_shm_size; ++i) { - if (*((char *)controlPtr + i) > 0) { - firstNonEmptyByteIndex = i - 8; - break; - } + std::abort(); } - int outParamFirstByte = *((char *)controlPtr + firstNonEmptyByteIndex + 8); - int isFloatByte = *((char *)controlPtr + firstNonEmptyByteIndex + 44); - // int outParamThirdByte = *((char *)controlPtr + firstNonEmptyByteIndex + 44); // need to find the third index - int in_channels = 2, in_samples = 256, sample_rate = 48000; // probably there is no point to parse frequency, because it's always 48000 - if (outParamFirstByte == 2 && isFloatByte == 0) { - in_channels = 1; - printf("outputParam is ORBIS_AUDIO_OUT_PARAM_FORMAT_S16_MONO\n"); + struct stat bufferStat; + if (::fstat(bufferFd, &bufferStat)) { + perror("shm_open"); + std::abort(); } - if (outParamFirstByte == 4 && isFloatByte == 0) { - in_channels = 2; - printf("outputParam is ORBIS_AUDIO_OUT_PARAM_FORMAT_S16_STEREO\n"); + + auto audioBuffer = ::mmap(NULL, bufferStat.st_size, PROT_READ | PROT_WRITE, + MAP_SHARED, bufferFd, 0); + auto bitPattern = 1u << info.port; + + int firstNonEmptyByteIndex = -1; + + for (std::size_t i = 24; i < controlStat.st_size; ++i) { + if (controlPtr[i] != 0) { + firstNonEmptyByteIndex = i - 8; + break; + } + + // FIXME: following line triggers error, investigate _C shm layout + // std::this_thread::sleep_for(std::chrono::milliseconds(1)); + + if (exit.load(std::memory_order::relaxed)) { + break; + } } - if (outParamFirstByte == 16 && isFloatByte == 0) { - in_channels = 8; - printf("outputParam is ORBIS_AUDIO_OUT_PARAM_FORMAT_S16_8CH\n"); + + if (firstNonEmptyByteIndex < 0) { + ORBIS_LOG_ERROR("AudioOut: Failed to find first non zero byte index"); + std::abort(); } - if (outParamFirstByte == 4 && isFloatByte == 1) { - in_channels = 1; - printf("outputParam is ORBIS_AUDIO_OUT_PARAM_FORMAT_FLOAT_MONO\n"); + + int outParamFirstByte = controlPtr[firstNonEmptyByteIndex + 8]; + int isFloat = controlPtr[firstNonEmptyByteIndex + 44]; + + // int outParamThirdByte = *((char *)controlPtr + firstNonEmptyByteIndex + + // 44); // need to find the third index + + unsigned inChannels = 2; + unsigned inSamples = 256; + sox_rate_t sampleRate = 48000; // probably there is no point to parse + // frequency, because it's always 48000 + if (outParamFirstByte == 2 && isFloat == 0) { + inChannels = 1; + ORBIS_LOG_NOTICE( + "AudioOut: outputParam is ORBIS_AUDIO_OUT_PARAM_FORMAT_S16_MONO"); + } else if (outParamFirstByte == 4 && isFloat == 0) { + inChannels = 2; + ORBIS_LOG_NOTICE( + "AudioOut: outputParam is ORBIS_AUDIO_OUT_PARAM_FORMAT_S16_STEREO"); + } else if (outParamFirstByte == 16 && isFloat == 0) { + inChannels = 8; + ORBIS_LOG_NOTICE( + "AudioOut: outputParam is ORBIS_AUDIO_OUT_PARAM_FORMAT_S16_8CH"); + } else if (outParamFirstByte == 4 && isFloat == 1) { + inChannels = 1; + ORBIS_LOG_NOTICE( + "AudioOut: outputParam is ORBIS_AUDIO_OUT_PARAM_FORMAT_FLOAT_MONO"); + } else if (outParamFirstByte == 8 && isFloat == 1) { + inChannels = 2; + ORBIS_LOG_NOTICE( + "AudioOut: outputParam is ORBIS_AUDIO_OUT_PARAM_FORMAT_FLOAT_STEREO"); + } else if (outParamFirstByte == 32 && isFloat == 1) { + inChannels = 8; + ORBIS_LOG_NOTICE( + "AudioOut: outputParam is ORBIS_AUDIO_OUT_PARAM_FORMAT_FLOAT_8CH"); + } else { + ORBIS_LOG_ERROR("AudioOut: unknown output type"); } - if (outParamFirstByte == 8 && isFloatByte == 1) { - in_channels = 2; - printf("outputParam is ORBIS_AUDIO_OUT_PARAM_FORMAT_FLOAT_STEREO\n"); - } - if (outParamFirstByte == 32 && isFloatByte == 1) { - in_channels = 8; - printf("outputParam is ORBIS_AUDIO_OUT_PARAM_FORMAT_FLOAT_8CH\n"); - } - // // it's need third byte - // if (outParamFirstByte == 16 && outParamSecondByte == 0 && outParamThirdByte == 1) { + + // it's need third byte + // if (outParamFirstByte == 16 && outParamSecondByte == 0 && + // outParamThirdByte + // == 1) { // printf("outputParam is ORBIS_AUDIO_OUT_PARAM_FORMAT_S16_8CH_STD"); // } - // if (outParamFirstByte == 32 && outParamSecondByte == 1 && outParamThirdByte == 1) { + // if (outParamFirstByte == 32 && outParamSecondByte == 1 && + // outParamThirdByte + // == 1) { // printf("outputParam is ORBIS_AUDIO_OUT_PARAM_FORMAT_FLOAT_8CH_STD"); // } // length byte will be inited after some time, so we wait for it - int samplesLengthByte; - while(true) { - samplesLengthByte = *((char *)controlPtr + firstNonEmptyByteIndex + 97); + int samplesLengthByte = 0; + while (true) { + samplesLengthByte = controlPtr[firstNonEmptyByteIndex + 97]; if (samplesLengthByte > 0) { break; } } - in_samples = samplesLengthByte * 256; + inSamples = samplesLengthByte * 256; - if (sox_init() != SOX_SUCCESS) { - exit(1); - } + sox_signalinfo_t out_si = { + .rate = sampleRate, + .channels = inChannels, + .precision = SOX_SAMPLE_PRECISION, + }; - sox_signalinfo_t out_si = {}; - out_si.rate = sample_rate; - out_si.channels = in_channels; - out_si.precision = SOX_SAMPLE_PRECISION; - - sox_format_t* output - = sox_open_write("default", &out_si, NULL, "alsa", NULL, NULL); + sox_format_t *output = + sox_open_write("default", &out_si, NULL, "alsa", NULL, NULL); if (!output) { - exit(1); + std::abort(); } - sox_sample_t samples[in_samples * in_channels]; + std::vector samples(inSamples * inChannels); + + std::size_t clips = 0; + SOX_SAMPLE_LOCALS; + + while (!exit.load(std::memory_order::relaxed)) { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + + if (isFloat == 0) { + auto data = reinterpret_cast(audioBuffer); + for (std::size_t i = 0; i < samples.size(); i++) { + samples[i] = SOX_SIGNED_16BIT_TO_SAMPLE(data[i], clips); + } + } else { + auto data = reinterpret_cast(audioBuffer); + for (std::size_t i = 0; i < samples.size(); i++) { + samples[i] = SOX_FLOAT_32BIT_TO_SAMPLE(data[i], clips); + } + } + + if (sox_write(output, samples.data(), samples.size()) != samples.size()) { + ORBIS_LOG_ERROR("AudioOut: sox_write failed"); + } - size_t clips = 0; SOX_SAMPLE_LOCALS; - size_t n_samples; - int size; - if (isFloatByte == 0) { - size = in_samples * in_channels * sizeof(int16_t); - n_samples = size / sizeof(int16_t); - } else if (isFloatByte == 1) { - size = in_samples * in_channels * sizeof(float); - n_samples = size / sizeof(float); - } - while(true) { // skip sceAudioOutMix%x event - sys_evf_set(((struct args*)vargp)->thread, ((struct args*)vargp)->evfId, bitPattern); + info.evf->set(bitPattern); + // set zero to freeing audiooutput for (size_t i = 0; i < 8; ++i) { - *((char *)controlPtr + firstNonEmptyByteIndex + i) = 0x00; - } - - // DumpHex(audioPtr, 1000); - // sleep 1ms - msleep(1); - if (isFloatByte == 0) { - int16_t data[size]; - memcpy(data, audioPtr, size); - for (size_t n = 0; n < n_samples; n++) { - samples[n] = SOX_SIGNED_16BIT_TO_SAMPLE(data[n], clips); - } - // free(data); - } - if (isFloatByte == 1) { - float data[size]; - memcpy(data, audioPtr, size); - for (size_t n = 0; n < n_samples; n++) { - samples[n] = SOX_FLOAT_32BIT_TO_SAMPLE(data[n], clips); - } - // free(data); - } - - if (sox_write(output, samples, n_samples) != n_samples) { - exit(1); + controlPtr[firstNonEmptyByteIndex + i] = 0; } } - pthread_exit(NULL); -} -namespace orbis { -class AudioOut { -public: - int32_t audioPort; - int32_t idControl; - int32_t idAudio; - int32_t evfId; - AudioOut() { + sox_close(output); + + ::munmap(audioBuffer, bufferStat.st_size); + ::munmap(controlPtr, controlStat.st_size); + + ::close(controlFd); + ::close(bufferFd); } - - ~AudioOut() { - } - - static AudioOut& getInstance() { - static AudioOut instance; - return instance; - } - - void setPortId(int32_t port) { - this->audioPort = port; - } - - void setControlId(int32_t id) { - this->idControl = id; - } - - void setAudioId(int32_t id) { - this->idAudio = id; - } - - void setEvfId(int32_t evfId) { - this->evfId = evfId; - } - - void start(orbis::Thread *thread) { - Ref file; - // probably need to close - auto result = thread->tproc->ops->open(thread, "/dev/audioHack", 0, 0, &file); - if (result.value() == 0) { - struct args *threadArgs = (struct args *)malloc(sizeof(struct args)); - threadArgs->audioPort = this->audioPort; - threadArgs->idControl = this->idControl; - threadArgs->idAudio = this->idAudio; - threadArgs->thread = thread; - threadArgs->evfId = this->evfId; - - pthread_t thread_id; - pthread_create(&thread_id, NULL, loop, (void *)threadArgs); - } - } - private: - AudioOut( const AudioOut&); - AudioOut& operator=( AudioOut& ); }; } // namespace orbis diff --git a/orbis-kernel/include/orbis/KernelContext.hpp b/orbis-kernel/include/orbis/KernelContext.hpp index 1a554405e..618375e5c 100644 --- a/orbis-kernel/include/orbis/KernelContext.hpp +++ b/orbis-kernel/include/orbis/KernelContext.hpp @@ -6,6 +6,7 @@ #include "utils/SharedCV.hpp" #include "utils/SharedMutex.hpp" +#include "AudioOut.hpp" #include "KernelAllocator.hpp" #include "orbis/thread/types.hpp" #include @@ -150,6 +151,7 @@ public: Ref shmDevice; Ref dmemDevice; Ref blockpoolDevice; + AudioOut *audioOut = nullptr; private: mutable pthread_mutex_t m_heap_mtx; diff --git a/orbis-kernel/src/sys/sys_sce.cpp b/orbis-kernel/src/sys/sys_sce.cpp index b39ba2c7b..82d9ec944 100644 --- a/orbis-kernel/src/sys/sys_sce.cpp +++ b/orbis-kernel/src/sys/sys_sce.cpp @@ -4,6 +4,7 @@ #include "evf.hpp" #include "module/ModuleInfo.hpp" #include "module/ModuleInfoEx.hpp" +#include "orbis/AudioOut.hpp" #include "orbis/time.hpp" #include "osem.hpp" #include "sys/sysproto.hpp" @@ -11,7 +12,6 @@ #include #include #include -#include "orbis/AudioOut.hpp" orbis::SysResult orbis::sys_netcontrol(Thread *thread, sint fd, uint op, ptr buf, uint nbuf) { @@ -1146,78 +1146,85 @@ orbis::SysResult orbis::sys_ipmimgr_call(Thread *thread, uint op, uint kid, uint32_t channelId; }; - static_assert(sizeof(SceSysAudioSystemIpcCheckSharedMemoryControlMethodArgs) == 0x4); + static_assert( + sizeof(SceSysAudioSystemIpcCheckSharedMemoryControlMethodArgs) == + 0x4); - if (dataInfo.size != sizeof(SceSysAudioSystemIpcCheckSharedMemoryControlMethodArgs)) { + if (dataInfo.size != + sizeof(SceSysAudioSystemIpcCheckSharedMemoryControlMethodArgs)) { return ErrorCode::INVAL; } SceSysAudioSystemIpcCheckSharedMemoryControlMethodArgs args; - uread(args, ptr(dataInfo.data)); + uread(args, ptr( + dataInfo.data)); - ORBIS_LOG_TODO("impi: SceSysAudioSystemIpcCheckSharedMemoryControlMethodArgs", args.channelId); - AudioOut& ao = AudioOut::getInstance(); - ao.setControlId(args.channelId); - } - if (syncCallParams.method == 0x1234000f) { // create event flag + ORBIS_LOG_TODO( + "impi: SceSysAudioSystemIpcCheckSharedMemoryControlMethodArgs", + args.channelId); + if (auto audioOut = g_context.audioOut) { + audioOut->channelInfo.idControl = args.channelId; + } + } else if (syncCallParams.method == 0x1234000f) { // create event flag struct SceSysAudioSystemIpcCreateEventFlagMethodArgs { uint32_t channelId; }; - static_assert(sizeof(SceSysAudioSystemIpcCreateEventFlagMethodArgs) == 0x4); + static_assert(sizeof(SceSysAudioSystemIpcCreateEventFlagMethodArgs) == + 0x4); - if (dataInfo.size != sizeof(SceSysAudioSystemIpcCreateEventFlagMethodArgs)) { + if (dataInfo.size != + sizeof(SceSysAudioSystemIpcCreateEventFlagMethodArgs)) { return ErrorCode::INVAL; } SceSysAudioSystemIpcCreateEventFlagMethodArgs args; - uread(args, ptr(dataInfo.data)); + uread(args, ptr( + dataInfo.data)); - // very bad - char buffer[32]; - sprintf(buffer, "sceAudioOutMix%x", args.channelId); - // const char* eventName = &buffer; - int32_t attrs = 0x100; - EventFlag *eventFlag; - if (attrs & kEvfAttrShared) { - auto [insertedEvf, inserted] = - thread->tproc->context->createEventFlag(buffer, attrs, 0); + if (auto audioOut = g_context.audioOut) { + // very bad + char buffer[32]; + std::snprintf(buffer, sizeof(buffer), "sceAudioOutMix%x", + args.channelId); + // const char* eventName = &buffer; + auto [eventFlag, inserted] = thread->tproc->context->createEventFlag( + buffer, kEvfAttrShared, 0); if (!inserted) { return ErrorCode::EXIST; // FIXME: verify } - eventFlag = insertedEvf; - } else { - eventFlag = knew(attrs, 0); - std::strncpy(eventFlag->name, buffer, 32); + audioOut->channelInfo.evf = eventFlag; } - - int32_t audioOutMixId = thread->tproc->evfMap.insert(eventFlag); - AudioOut& ao = AudioOut::getInstance(); - ao.setEvfId(audioOutMixId); - } - if (syncCallParams.method == 0x12340001) { // check shared memory audio + } else if (syncCallParams.method == + 0x12340001) { // check shared memory audio struct SceSysAudioSystemIpcCheckSharedMemoryAudioMethodArgs { uint32_t audioPort; uint32_t channelId; }; - static_assert(sizeof(SceSysAudioSystemIpcCheckSharedMemoryAudioMethodArgs) == 0x8); + static_assert( + sizeof(SceSysAudioSystemIpcCheckSharedMemoryAudioMethodArgs) == + 0x8); - if (dataInfo.size != sizeof(SceSysAudioSystemIpcCheckSharedMemoryAudioMethodArgs)) { + if (dataInfo.size != + sizeof(SceSysAudioSystemIpcCheckSharedMemoryAudioMethodArgs)) { return ErrorCode::INVAL; } SceSysAudioSystemIpcCheckSharedMemoryAudioMethodArgs args; - uread(args, ptr(dataInfo.data)); + uread(args, ptr( + dataInfo.data)); - ORBIS_LOG_TODO("impi: SceSysAudioSystemIpcCheckSharedMemoryAudioMethodArgs", args.audioPort, args.channelId); - AudioOut& ao = AudioOut::getInstance(); - ao.setPortId(args.audioPort); - ao.setAudioId(args.channelId); - } - if (syncCallParams.method == 0x12340002) { // something something open + ORBIS_LOG_TODO( + "impi: SceSysAudioSystemIpcCheckSharedMemoryAudioMethodArgs", + args.audioPort, args.channelId); + if (auto audioOut = g_context.audioOut) { + audioOut->channelInfo.port = args.audioPort; + audioOut->channelInfo.channel = args.channelId; + } + } else if (syncCallParams.method == 0x12340002) { // something like open struct SceSysAudioSystemIpcSomethingMethodArgs { uint32_t arg1; uint32_t arg2; @@ -1230,12 +1237,16 @@ orbis::SysResult orbis::sys_ipmimgr_call(Thread *thread, uint op, uint kid, } SceSysAudioSystemIpcSomethingMethodArgs args; - uread(args, ptr(dataInfo.data)); + uread(args, + ptr(dataInfo.data)); - ORBIS_LOG_TODO("impi: SceSysAudioSystemIpcSomethingMethodArgs", args.arg1, args.arg2); - // here startToListen - AudioOut& ao = AudioOut::getInstance(); - ao.start(thread); + ORBIS_LOG_TODO("impi: SceSysAudioSystemIpcSomethingMethodArgs", + args.arg1, args.arg2); + + if (auto audioOut = g_context.audioOut) { + // here startToListen + audioOut->start(); + } } } @@ -1326,6 +1337,10 @@ orbis::SysResult orbis::sys_ipmimgr_call(Thread *thread, uint op, uint kid, return {}; } + if (op == 0x243) { + return uwrite(result, 0); + } + return {}; } orbis::SysResult orbis::sys_get_gpo(Thread *thread /* TODO */) { diff --git a/rpcsx-os/main.cpp b/rpcsx-os/main.cpp index bd55297fd..2df55c9ac 100644 --- a/rpcsx-os/main.cpp +++ b/rpcsx-os/main.cpp @@ -239,7 +239,6 @@ struct StackWriter { }; static bool g_traceSyscalls = false; -static bool g_enableAudio = false; static const char *getSyscallName(orbis::Thread *thread, int sysno) { auto sysvec = thread->tproc->sysent; @@ -342,9 +341,6 @@ static int ps4Exec(orbis::Thread *mainThread, rx::vfs::mount("/dev/rng", createRngCharacterDevice()); rx::vfs::mount("/dev/sbl_srv", createSblSrvCharacterDevice()); rx::vfs::mount("/dev/ajm", createAjmCharacterDevice()); - if (g_enableAudio) { - rx::vfs::mount("/dev/audioHack", createNullCharacterDevice()); - } orbis::Ref stdinFile; orbis::Ref stdoutFile; @@ -531,6 +527,8 @@ int main(int argc, const char *argv[]) { setupSigHandlers(); rx::vfs::initialize(); + bool enableAudio = false; + int argIndex = 1; while (argIndex < argc) { if (argv[argIndex] == std::string_view("--mount") || @@ -575,7 +573,7 @@ int main(int argc, const char *argv[]) { if (argv[argIndex] == std::string_view("--enable-audio") || argv[argIndex] == std::string_view("-a")) { argIndex++; - g_enableAudio = true; + enableAudio = true; continue; } @@ -591,6 +589,10 @@ int main(int argc, const char *argv[]) { rx::vm::initialize(); runRpsxGpu(); + if (enableAudio) { + orbis::g_context.audioOut = orbis::knew(); + } + // rx::vm::printHostStats(); auto initProcess = orbis::g_context.createProcess(10); pthread_setname_np(pthread_self(), "10.MAINTHREAD");