From ff297652e7b28bc5ecf27cf1677c0eaebf372cd4 Mon Sep 17 00:00:00 2001 From: DH Date: Fri, 4 Oct 2024 16:45:19 +0300 Subject: [PATCH] rpcsx-os: audio: refactoring --- rpcsx-os/audio/AlsaDevice.cpp | 303 +++++++++++++++++++++------------ rpcsx-os/audio/AlsaDevice.hpp | 7 +- rpcsx-os/audio/AudioDevice.cpp | 29 +--- rpcsx-os/audio/AudioDevice.hpp | 45 ++--- rpcsx-os/io-devices.hpp | 4 +- rpcsx-os/iodev/aout.cpp | 238 +++++++++++++------------- rpcsx-os/main.cpp | 15 +- 7 files changed, 356 insertions(+), 285 deletions(-) diff --git a/rpcsx-os/audio/AlsaDevice.cpp b/rpcsx-os/audio/AlsaDevice.cpp index 024a668a1..49ab4027c 100644 --- a/rpcsx-os/audio/AlsaDevice.cpp +++ b/rpcsx-os/audio/AlsaDevice.cpp @@ -2,60 +2,86 @@ #include "orbis/utils/Logs.hpp" #include "rx/hexdump.hpp" -AlsaDevice::AlsaDevice() {} - void AlsaDevice::start() { - setAlsaFormat(); - int err; - if ((err = snd_pcm_open(&mPCMHandle, "default", SND_PCM_STREAM_PLAYBACK, - 0)) < 0) { + if (mWorking) { + // FIXME: should probably return error in this case and in other places + return; + } + + { + _snd_pcm_format fmt; + switch (mFormat) { + case AudioFormat::S32_LE: + fmt = SND_PCM_FORMAT_S32_LE; + break; + case AudioFormat::S16_LE: + fmt = SND_PCM_FORMAT_S16_LE; + break; + case AudioFormat::AC3: + default: + ORBIS_LOG_FATAL("Format is not supported", int(mFormat)); + std::abort(); + break; + } + mAlsaFormat = fmt; + } + + if (auto err = + snd_pcm_open(&mPCMHandle, "default", SND_PCM_STREAM_PLAYBACK, 0); + err < 0) { ORBIS_LOG_FATAL("Cannot open audio device", snd_strerror(err)); std::abort(); } - if ((err = snd_pcm_hw_params_malloc(&mHWParams)) < 0) { + if (auto err = snd_pcm_hw_params_malloc(&mHWParams); err < 0) { ORBIS_LOG_FATAL("Cannot allocate hardware parameter structure", snd_strerror(err)); std::abort(); } - if ((err = snd_pcm_hw_params_any(mPCMHandle, mHWParams)) < 0) { + if (auto err = snd_pcm_hw_params_any(mPCMHandle, mHWParams); err < 0) { ORBIS_LOG_FATAL("Cannot initialize hardware parameter structure", snd_strerror(err)); std::abort(); } - if ((err = snd_pcm_hw_params_set_rate_resample(mPCMHandle, mHWParams, - 0)) < 0) { + if (auto err = snd_pcm_hw_params_set_rate_resample(mPCMHandle, mHWParams, 0); + err < 0) { ORBIS_LOG_FATAL("Cannot disable rate resampling", snd_strerror(err)); std::abort(); } - if ((err = snd_pcm_hw_params_set_access(mPCMHandle, mHWParams, - SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) { + if (auto err = snd_pcm_hw_params_set_access(mPCMHandle, mHWParams, + SND_PCM_ACCESS_RW_INTERLEAVED); + err < 0) { ORBIS_LOG_FATAL("Cannot set access type", snd_strerror(err)); std::abort(); } - if ((err = snd_pcm_hw_params_set_format(mPCMHandle, mHWParams, - mAlsaFormat)) < 0) { + if (auto err = + snd_pcm_hw_params_set_format(mPCMHandle, mHWParams, mAlsaFormat); + err < 0) { ORBIS_LOG_FATAL("Cannot set sample format", snd_strerror(err)); std::abort(); } - if ((err = snd_pcm_hw_params_set_rate(mPCMHandle, mHWParams, mFrequency, - 0)) < 0) { + if (auto err = + snd_pcm_hw_params_set_rate(mPCMHandle, mHWParams, mFrequency, 0); + err < 0) { ORBIS_LOG_FATAL("Cannot set sample rate", snd_strerror(err)); std::abort(); } - if ((err = snd_pcm_hw_params_set_channels(mPCMHandle, mHWParams, mChannels)) < - 0) { + if (auto err = + snd_pcm_hw_params_set_channels(mPCMHandle, mHWParams, mChannels); + err < 0) { ORBIS_LOG_FATAL("cannot set channel count", snd_strerror(err), mChannels); std::abort(); } uint periods = mSampleCount; - if ((err = snd_pcm_hw_params_set_periods_max(mPCMHandle, mHWParams, &periods, NULL)) < 0) { + if (auto err = snd_pcm_hw_params_set_periods_max(mPCMHandle, mHWParams, + &periods, nullptr); + err < 0) { ORBIS_LOG_FATAL("Cannot set periods count", snd_strerror(err)); std::abort(); } @@ -64,115 +90,195 @@ void AlsaDevice::start() { snd_pcm_uframes_t size = mSampleSize / frameBytes; - // TODO: it shouldn't work like this + { + auto trySize = size * mSampleCount; + int err = -1; + while (trySize >= 1024) { + err = snd_pcm_hw_params_set_buffer_size(mPCMHandle, mHWParams, trySize); + if (err < 0) { + trySize /= 2; + continue; + } - if ((err = snd_pcm_hw_params_set_buffer_size(mPCMHandle, mHWParams, size)) < 0) { - ORBIS_LOG_FATAL("Cannot set buffer size", snd_strerror(err)); - std::abort(); + break; + } + + if (err < 0) { + trySize = size; + err = snd_pcm_hw_params_set_buffer_size_near(mPCMHandle, mHWParams, + &trySize); + } + + if (err < 0) { + ORBIS_LOG_FATAL("Cannot set buffer size", snd_strerror(err)); + std::abort(); + } } - if ((err = snd_pcm_hw_params_set_period_size(mPCMHandle, mHWParams, size / 2, 0)) < 0) { - ORBIS_LOG_FATAL("Cannot set period size", snd_strerror(err)); - std::abort(); + { + auto trySize = size; + int err = -1; + while (trySize >= 256) { + err = + snd_pcm_hw_params_set_period_size(mPCMHandle, mHWParams, trySize, 0); + if (err < 0) { + trySize /= 2; + continue; + } + + break; + } + + if (err < 0) { + trySize = size; + err = snd_pcm_hw_params_set_period_size_near(mPCMHandle, mHWParams, + &trySize, 0); + } + + if (err < 0) { + ORBIS_LOG_FATAL("Cannot set period size", snd_strerror(err)); + std::abort(); + } } snd_pcm_uframes_t periodSize; - if ((err = snd_pcm_hw_params_get_period_size(mHWParams, &periodSize, NULL)) < 0) { + if (auto err = + snd_pcm_hw_params_get_period_size(mHWParams, &periodSize, nullptr); + err < 0) { ORBIS_LOG_FATAL("cannot set parameters", snd_strerror(err)); std::abort(); } snd_pcm_uframes_t bufferSize; - if ((err = snd_pcm_hw_params_get_buffer_size(mHWParams, &bufferSize)) < 0) { + if (auto err = snd_pcm_hw_params_get_buffer_size(mHWParams, &bufferSize); + err < 0) { ORBIS_LOG_FATAL("cannot set parameters", snd_strerror(err)); std::abort(); } ORBIS_LOG_TODO("period and buffer", periodSize, bufferSize); - if ((err = snd_pcm_hw_params(mPCMHandle, mHWParams)) < 0) { + if (auto err = snd_pcm_hw_params(mPCMHandle, mHWParams); err < 0) { ORBIS_LOG_FATAL("cannot set parameters", snd_strerror(err)); std::abort(); } - if ((err = snd_pcm_sw_params_malloc(&mSWParams)) < 0) { + if (auto err = snd_pcm_sw_params_malloc(&mSWParams); err < 0) { ORBIS_LOG_FATAL("Cannot allocate software parameter structure", snd_strerror(err)); std::abort(); } - if ((err = snd_pcm_sw_params_current(mPCMHandle, mSWParams)) < 0) { + if (auto err = snd_pcm_sw_params_current(mPCMHandle, mSWParams); err < 0) { ORBIS_LOG_FATAL("cannot sw params current", snd_strerror(err)); std::abort(); } - if ((err = snd_pcm_sw_params_set_start_threshold(mPCMHandle, mSWParams, periodSize)) < 0) { + if (auto err = snd_pcm_sw_params_set_start_threshold(mPCMHandle, mSWParams, + periodSize); + err < 0) { ORBIS_LOG_FATAL("cannot set start threshold", snd_strerror(err)); std::abort(); } - if ((err = snd_pcm_sw_params_set_stop_threshold(mPCMHandle, mSWParams, bufferSize)) < 0) { + if (auto err = snd_pcm_sw_params_set_stop_threshold(mPCMHandle, mSWParams, + bufferSize); + err < 0) { ORBIS_LOG_FATAL("cannot set stop threshold", snd_strerror(err)); std::abort(); } - if ((err = snd_pcm_sw_params(mPCMHandle, mSWParams)) < 0) { + if (auto err = snd_pcm_sw_params(mPCMHandle, mSWParams); err < 0) { ORBIS_LOG_FATAL("cannot set parameters", snd_strerror(err)); std::abort(); } - if ((err = snd_pcm_prepare(mPCMHandle)) < 0) { + if (auto err = snd_pcm_prepare(mPCMHandle); err < 0) { ORBIS_LOG_FATAL("cannot prepare audio interface for use", - snd_strerror(err)); + snd_strerror(err)); std::abort(); } + mWorking = true; } -int AlsaDevice::fixXRun() -{ - switch (snd_pcm_state(mPCMHandle)) { - case SND_PCM_STATE_XRUN: - return snd_pcm_prepare(mPCMHandle); - case SND_PCM_STATE_DRAINING: - if (snd_pcm_stream(mPCMHandle) == SND_PCM_STREAM_CAPTURE) - return snd_pcm_prepare(mPCMHandle); - break; - default: - break; - } - return -EIO; +int AlsaDevice::fixXRun() { + switch (snd_pcm_state(mPCMHandle)) { + case SND_PCM_STATE_XRUN: + return snd_pcm_prepare(mPCMHandle); + + case SND_PCM_STATE_DRAINING: + if (snd_pcm_stream(mPCMHandle) == SND_PCM_STREAM_CAPTURE) + return snd_pcm_prepare(mPCMHandle); + break; + + default: + break; + } + + return -EIO; } -int AlsaDevice::resumeFromSupsend() -{ - int res; - while ((res = snd_pcm_resume(mPCMHandle)) == -EAGAIN) - std::this_thread::sleep_for(std::chrono::seconds(1)); - if (!res) - return 0; - return snd_pcm_prepare(mPCMHandle); +int AlsaDevice::resume() { + int err; + while (true) { + err = snd_pcm_resume(mPCMHandle); + + if (err == -EAGAIN) { + std::this_thread::sleep_for(std::chrono::seconds(1)); + continue; + } + + break; + } + + if (err == 0) { + return 0; + } + + return snd_pcm_prepare(mPCMHandle); } long AlsaDevice::write(void *buf, long len) { - if (!mWorking) return 0; - ssize_t r; - int frameBytes = snd_pcm_format_physical_width(mAlsaFormat) * mChannels / 8; + if (!mWorking) + return 0; + + int frameBytes = snd_pcm_format_physical_width(mAlsaFormat) * mChannels / 8; snd_pcm_uframes_t frames = len / frameBytes; - r = snd_pcm_writei(mPCMHandle, buf, frames); - if (r == -EPIPE) { - if (!(r = fixXRun())) - return write(buf, len); - } else if (r == -ESTRPIPE) { - if (!(r = resumeFromSupsend())) - return write(buf, len); - } - r *= frameBytes; - return r; + while (true) { + snd_pcm_sframes_t r = snd_pcm_writei(mPCMHandle, buf, frames); + if (r == -EPIPE) { + if (fixXRun() == 0) { + return write(buf, len); + } + + continue; + } + + if (r == -ESTRPIPE) { + if (resume() == 0) { + return write(buf, len); + } + + continue; + } + + if (r < 0) { + ORBIS_LOG_ERROR(__PRETTY_FUNCTION__, snd_strerror(r)); + return r; + } + + r *= frameBytes; + return r; + } } void AlsaDevice::stop() { + if (!mWorking) { + return; + } + snd_pcm_hw_params_free(mHWParams); snd_pcm_sw_params_free(mSWParams); snd_pcm_drain(mPCMHandle); @@ -181,19 +287,24 @@ void AlsaDevice::stop() { } void AlsaDevice::reset() { - if (!mWorking) return; - int err; - err = snd_pcm_drop(mPCMHandle); - if (err >= 0) + if (!mWorking) + return; + int err = snd_pcm_drop(mPCMHandle); + + if (err >= 0) { err = snd_pcm_prepare(mPCMHandle); - if (err < 0) - err = err; + } + + if (err < 0) { + ORBIS_LOG_ERROR(__PRETTY_FUNCTION__, snd_strerror(err)); + } } audio_buf_info AlsaDevice::getOSpace() { int err; snd_pcm_uframes_t periodSize; - if ((err = snd_pcm_hw_params_get_period_size(mHWParams, &periodSize, NULL)) < 0) { + if ((err = snd_pcm_hw_params_get_period_size(mHWParams, &periodSize, NULL)) < + 0) { ORBIS_LOG_FATAL("cannot get period size", snd_strerror(err)); std::abort(); } @@ -205,38 +316,14 @@ audio_buf_info AlsaDevice::getOSpace() { } int frameBytes = snd_pcm_format_physical_width(mAlsaFormat) * mChannels / 8; - snd_pcm_sframes_t avail, delay; - audio_buf_info info; - avail = snd_pcm_avail_update(mPCMHandle); + snd_pcm_sframes_t avail = snd_pcm_avail_update(mPCMHandle); if (avail < 0 || (snd_pcm_uframes_t)avail > bufferSize) avail = bufferSize; - info.fragsize = periodSize * frameBytes; - info.fragstotal = mSampleCount; - info.bytes = avail * frameBytes; - info.fragments = avail / periodSize; - return info; -} -void AlsaDevice::setAlsaFormat() { - if (mWorking) - return; - _snd_pcm_format fmt; - switch (mFormat) { - case FMT_S32_LE: - fmt = SND_PCM_FORMAT_S32_LE; - break; - case FMT_S16_LE: - fmt = SND_PCM_FORMAT_S16_LE; - break; - case FMT_AC3: - default: - ORBIS_LOG_FATAL("Format is not supported", mFormat); - std::abort(); - break; - } - mAlsaFormat = fmt; + return { + .fragments = static_cast(avail / periodSize), + .fragsize = static_cast(mSampleCount), + .fragstotal = static_cast(periodSize * frameBytes), + .bytes = static_cast(avail * frameBytes), + }; } - -AlsaDevice::~AlsaDevice() { - stop(); -} \ No newline at end of file diff --git a/rpcsx-os/audio/AlsaDevice.hpp b/rpcsx-os/audio/AlsaDevice.hpp index 12328fa92..8bbe0bdad 100644 --- a/rpcsx-os/audio/AlsaDevice.hpp +++ b/rpcsx-os/audio/AlsaDevice.hpp @@ -13,8 +13,7 @@ private: snd_pcm_sw_params_t *mSWParams; public: - AlsaDevice(); - ~AlsaDevice() override; + ~AlsaDevice() { stop(); } void init() override {}; void start() override; @@ -22,10 +21,8 @@ public: void stop() override; void reset() override; - void setAlsaFormat(); - int fixXRun(); - int resumeFromSupsend(); + int resume(); audio_buf_info getOSpace() override; }; diff --git a/rpcsx-os/audio/AudioDevice.cpp b/rpcsx-os/audio/AudioDevice.cpp index 24a5778a7..eb56981c9 100644 --- a/rpcsx-os/audio/AudioDevice.cpp +++ b/rpcsx-os/audio/AudioDevice.cpp @@ -1,23 +1,7 @@ #include "AudioDevice.hpp" #include "orbis/utils/Logs.hpp" -#include "rx/hexdump.hpp" -AudioDevice::AudioDevice() {} - -void AudioDevice::init() {} - -void AudioDevice::start() {} - -long AudioDevice::write(void *buf, long len) { - return -1; -} - -void AudioDevice::stop() { -} - -void AudioDevice::reset() {} - -void AudioDevice::setFormat(orbis::uint format) { +void AudioDevice::setFormat(AudioFormat format) { if (mWorking) return; mFormat = format; @@ -39,17 +23,10 @@ void AudioDevice::setChannels(orbis::ushort channels) { mChannels = channels; } -void AudioDevice::setSampleSize(orbis::uint sampleSize, orbis::uint sampleCount) { +void AudioDevice::setSampleSize(orbis::uint sampleSize, + orbis::uint sampleCount) { if (mWorking) return; mSampleSize = sampleSize; mSampleCount = sampleCount; } - -audio_buf_info AudioDevice::getOSpace() { - audio_buf_info info; - return info; -} - - -AudioDevice::~AudioDevice() {} \ No newline at end of file diff --git a/rpcsx-os/audio/AudioDevice.hpp b/rpcsx-os/audio/AudioDevice.hpp index 95dfe2629..fb3e90f18 100644 --- a/rpcsx-os/audio/AudioDevice.hpp +++ b/rpcsx-os/audio/AudioDevice.hpp @@ -1,44 +1,45 @@ #pragma once -#define FMT_S16_LE 0x10 -#define FMT_AC3 0x400 -#define FMT_S32_LE 0x1000 - +#include "orbis-config.hpp" +#include "orbis/utils/Rc.hpp" #include #include -struct audio_buf_info { - int fragments; - int fragstotal; - int fragsize; - int bytes; +struct [[gnu::packed]] audio_buf_info { + orbis::sint fragments; + orbis::sint fragsize; + orbis::sint fragstotal; + orbis::sint bytes; }; -class AudioDevice { +enum class AudioFormat : std::uint32_t { + S16_LE = 0x10, + AC3 = 0x400, + S32_LE = 0x1000, +}; + +class AudioDevice : public orbis::RcBase { protected: bool mWorking = false; - orbis::uint mFormat{}; + AudioFormat mFormat{}; orbis::uint mFrequency{}; orbis::ushort mChannels{}; orbis::ushort mSampleSize{}; orbis::ushort mSampleCount{}; -private: - public: - AudioDevice(); - virtual ~AudioDevice(); + virtual ~AudioDevice() = default; - virtual void init(); - virtual void start(); - virtual long write(void *buf, long len); - virtual void stop(); - virtual void reset(); + virtual void init() {} + virtual void start() {} + virtual long write(void *buf, long len) { return -1; } + virtual void stop() {} + virtual void reset() {} - void setFormat(orbis::uint format); + void setFormat(AudioFormat format); void setFrequency(orbis::uint frequency); void setChannels(orbis::ushort channels); void setSampleSize(orbis::uint sampleSize = 0, orbis::uint sampleCount = 0); - virtual audio_buf_info getOSpace(); + virtual audio_buf_info getOSpace() { return {}; } }; diff --git a/rpcsx-os/io-devices.hpp b/rpcsx-os/io-devices.hpp index 99f11fd50..583cfd003 100644 --- a/rpcsx-os/io-devices.hpp +++ b/rpcsx-os/io-devices.hpp @@ -1,6 +1,8 @@ #pragma once +#include "audio/AudioDevice.hpp" #include + struct IoDevice; IoDevice *createDceCharacterDevice(); @@ -31,7 +33,7 @@ IoDevice *createXptCharacterDevice(); IoDevice *createCdCharacterDevice(); IoDevice *createMetaDbgCharacterDevice(); IoDevice *createHddCharacterDevice(std::uint64_t size); -IoDevice *createAoutCharacterDevice(std::int8_t id); +IoDevice *createAoutCharacterDevice(std::int8_t id, AudioDevice *device); IoDevice *createAVControlCharacterDevice(); IoDevice *createHDMICharacterDevice(); IoDevice *createMBusAVCharacterDevice(); diff --git a/rpcsx-os/iodev/aout.cpp b/rpcsx-os/iodev/aout.cpp index 4d036c01a..0bb578d24 100644 --- a/rpcsx-os/iodev/aout.cpp +++ b/rpcsx-os/iodev/aout.cpp @@ -1,6 +1,5 @@ -#include "audio/AlsaDevice.hpp" +#include "audio/AudioDevice.hpp" #include "io-device.hpp" -#include "iodev/mbus_av.hpp" #include "orbis/KernelAllocator.hpp" #include "orbis/file.hpp" #include "orbis/thread/Process.hpp" @@ -8,6 +7,7 @@ #include "orbis/thread/Thread.hpp" #include "orbis/uio.hpp" #include "orbis/utils/Logs.hpp" +#include "orbis/utils/Rc.hpp" #include // #include @@ -29,9 +29,10 @@ struct AoutFile : orbis::File {}; struct AoutDevice : public IoDevice { std::int8_t id; - AudioDevice *audioDevice; + orbis::Ref audioDevice; - AoutDevice(std::int8_t id) : id(id) {} + AoutDevice(std::int8_t id, AudioDevice *audioDevice) + : id(id), audioDevice(audioDevice) {} orbis::ErrorCode open(orbis::Ref *file, const char *path, std::uint32_t flags, std::uint32_t mode, @@ -42,122 +43,124 @@ static orbis::ErrorCode aout_ioctl(orbis::File *file, std::uint64_t request, void *argp, orbis::Thread *thread) { auto device = static_cast(file->device.get()); switch (request) { - case SNDCTL_DSP_RESET: { - ORBIS_LOG_TODO("SNDCTL_DSP_RESET"); - if (auto audioDevice = device->audioDevice) { - audioDevice->reset(); - } - return {}; + case SNDCTL_DSP_RESET: { + ORBIS_LOG_TODO("SNDCTL_DSP_RESET"); + if (auto audioDevice = device->audioDevice) { + audioDevice->reset(); } - case SNDCTL_DSP_SETFRAGMENT: { - struct Args { - std::uint32_t fragment; - }; - auto args = reinterpret_cast(argp); - ORBIS_LOG_NOTICE("SNDCTL_DSP_SETFRAGMENT", args->fragment & 0xF, (args->fragment >> 16) & 0xF); - if (auto audioDevice = device->audioDevice) { - audioDevice->setSampleSize(1 << (args->fragment & 0xF), (args->fragment >> 16) & 0xF); - } - return {}; + return {}; + } + case SNDCTL_DSP_SETFRAGMENT: { + struct Args { + orbis::uint32_t fragment; + }; + auto args = reinterpret_cast(argp); + ORBIS_LOG_NOTICE("SNDCTL_DSP_SETFRAGMENT", args->fragment & 0xF, + (args->fragment >> 16) & 0xF); + if (auto audioDevice = device->audioDevice) { + audioDevice->setSampleSize(1 << (args->fragment & 0xF), + (args->fragment >> 16) & 0xF); } - case SNDCTL_DSP_SETFMT: { - struct Args { - std::uint32_t fmt; - }; - auto args = reinterpret_cast(argp); - ORBIS_LOG_NOTICE("SNDCTL_DSP_SETFMT", args->fmt); - if (auto audioDevice = device->audioDevice) { - audioDevice->setFormat(args->fmt); - } - return {}; + return {}; + } + case SNDCTL_DSP_SETFMT: { + struct Args { + orbis::uint32_t fmt; + }; + auto args = reinterpret_cast(argp); + ORBIS_LOG_NOTICE("SNDCTL_DSP_SETFMT", args->fmt); + if (auto audioDevice = device->audioDevice) { + audioDevice->setFormat(static_cast(args->fmt)); } - case SNDCTL_DSP_SPEED: { - struct Args { - std::uint32_t speed; - }; - auto args = reinterpret_cast(argp); - if (auto audioDevice = device->audioDevice) { - audioDevice->setFrequency(args->speed); - } - return {}; + return {}; + } + case SNDCTL_DSP_SPEED: { + struct Args { + orbis::uint32_t speed; + }; + auto args = reinterpret_cast(argp); + if (auto audioDevice = device->audioDevice) { + audioDevice->setFrequency(args->speed); } - case SNDCTL_DSP_CHANNELS: { - struct Args { - std::uint32_t channels; - }; - auto args = reinterpret_cast(argp); - if (auto audioDevice = device->audioDevice) { - audioDevice->setChannels(args->channels); - } - return {}; + return {}; + } + case SNDCTL_DSP_CHANNELS: { + struct Args { + orbis::uint32_t channels; + }; + auto args = reinterpret_cast(argp); + if (auto audioDevice = device->audioDevice) { + audioDevice->setChannels(args->channels); } - case ORBIS_AUDIO_UPDATE_TICK_PARAMS: { - struct Args { - std::uint32_t tick; - }; - auto args = reinterpret_cast(argp); - ORBIS_LOG_NOTICE("ORBIS_AUDIO_UPDATE_TICK_PARAMS", args->tick); - return {}; + return {}; + } + case ORBIS_AUDIO_UPDATE_TICK_PARAMS: { + struct Args { + orbis::uint32_t tick; + }; + auto args = reinterpret_cast(argp); + ORBIS_LOG_NOTICE("ORBIS_AUDIO_UPDATE_TICK_PARAMS", args->tick); + return {}; + } + case SNDCTL_DSP_SYNCGROUP: { + ORBIS_LOG_NOTICE("SNDCTL_DSP_SYNCGROUP"); + return {}; + } + case ORBIS_AUDIO_CONFIG_SPDIF: { + struct Args { + orbis::uint64_t unk0; + }; + auto args = reinterpret_cast(argp); + args->unk0 = 0x100000000; // Disable SPDIF output + return {}; + } + case SNDCTL_DSP_GETBLKSIZE: { + struct Args { + orbis::uint32_t blksize; + }; + auto args = reinterpret_cast(argp); + ORBIS_LOG_NOTICE("SNDCTL_DSP_GETBLKSIZE", args->blksize); + return {}; + } + case SOUND_PCM_READ_BITS: { + struct Args { + orbis::uint32_t bits; + }; + auto args = reinterpret_cast(argp); + ORBIS_LOG_NOTICE("SOUND_PCM_READ_BITS", args->bits); + return {}; + } + case SNDCTL_DSP_GETOSPACE: { + + if (auto audioDevice = device->audioDevice) { + auto info = audioDevice->getOSpace(); + ORBIS_RET_ON_ERROR(orbis::uwrite(orbis::ptr(argp), info)); + + ORBIS_LOG_WARNING("SNDCTL_DSP_GETOSPACE", info.fragments, info.fragsize, + info.fragstotal, info.bytes); } - case SNDCTL_DSP_SYNCGROUP: { - ORBIS_LOG_NOTICE("SNDCTL_DSP_SYNCGROUP"); - return {}; + + return {}; + } + case SNDCTL_DSP_SYNCSTART: { + ORBIS_LOG_NOTICE("SNDCTL_DSP_SYNCSTART"); + if (auto audioDevice = device->audioDevice) { + audioDevice->start(); } - case ORBIS_AUDIO_CONFIG_SPDIF: { - struct Args { - std::uint64_t unk0; - }; - auto args = reinterpret_cast(argp); - args->unk0 = 0x100000000; // Disable SPDIF output - return {}; - } - case SNDCTL_DSP_GETBLKSIZE: { - struct Args { - std::uint32_t blksize; - }; - auto args = reinterpret_cast(argp); - ORBIS_LOG_NOTICE("SNDCTL_DSP_GETBLKSIZE", args->blksize); - return {}; - } - case SOUND_PCM_READ_BITS: { - struct Args { - std::uint32_t bits; - }; - auto args = reinterpret_cast(argp); - ORBIS_LOG_NOTICE("SOUND_PCM_READ_BITS", args->bits); - return {}; - } - case SNDCTL_DSP_GETOSPACE: { - auto args = reinterpret_cast(argp); - if (auto audioDevice = device->audioDevice) { - auto info = audioDevice->getOSpace(); - args->fragments = info.fragments; - args->fragstotal = info.fragstotal; - args->fragsize = info.fragsize; - args->bytes = info.bytes; - } - ORBIS_LOG_TODO("SNDCTL_DSP_GETOSPACE", args->fragments, args->fragstotal, args->fragsize, args->bytes); - return {}; - } - case SNDCTL_DSP_SYNCSTART: { - ORBIS_LOG_NOTICE("SNDCTL_DSP_SYNCSTART"); - if (auto audioDevice = device->audioDevice) { - audioDevice->start(); - } - return {}; - } - case ORBIS_AUDIO_IOCTL_SETCONTROL: { - struct Args { - std::uint64_t unk0; - }; - auto args = reinterpret_cast(argp); - ORBIS_LOG_NOTICE("ORBIS_AUDIO_IOCTL_SETCONTROL", args->unk0); - return {}; - } - default: - ORBIS_LOG_FATAL("Unhandled aout ioctl", request); - thread->where(); - break; + return {}; + } + case ORBIS_AUDIO_IOCTL_SETCONTROL: { + struct Args { + orbis::uint64_t unk0; + }; + auto args = reinterpret_cast(argp); + ORBIS_LOG_NOTICE("ORBIS_AUDIO_IOCTL_SETCONTROL", args->unk0); + return {}; + } + default: + ORBIS_LOG_FATAL("Unhandled aout ioctl", request); + thread->where(); + break; } return {}; } @@ -190,14 +193,9 @@ orbis::ErrorCode AoutDevice::open(orbis::Ref *file, thread->where(); *file = newFile; - // create audio device only for hdmi output, 0 - hdmi, 1 - analog, 2 - spdif - if (id == 0) { - // TODO: use factory to more backends support - audioDevice = new AlsaDevice(); - } return {}; } -IoDevice *createAoutCharacterDevice(std::int8_t id) { - return orbis::knew(id); +IoDevice *createAoutCharacterDevice(std::int8_t id, AudioDevice *device) { + return orbis::knew(id, device); } diff --git a/rpcsx-os/main.cpp b/rpcsx-os/main.cpp index db2e06feb..7e528ebf4 100644 --- a/rpcsx-os/main.cpp +++ b/rpcsx-os/main.cpp @@ -1,5 +1,6 @@ #include "AudioOut.hpp" #include "amdgpu/bridge/bridge.hpp" +#include "audio/AlsaDevice.hpp" #include "backtrace.hpp" #include "bridge.hpp" #include "io-device.hpp" @@ -336,6 +337,14 @@ static void ps4InitDev() { auto mbus = static_cast(createMBusCharacterDevice()); auto mbusAv = static_cast(createMBusAVCharacterDevice()); + // FIXME: make it configurable + auto defaultAudioDevice = orbis::knew(); + auto nullAudioDevice = orbis::knew(); + + auto hdmiAudioDevice = defaultAudioDevice; + auto analogAudioDevice = nullAudioDevice; + auto spdifAudioDevice = nullAudioDevice; + rx::vfs::addDevice("dmem0", createDmemCharacterDevice(0)); rx::vfs::addDevice("npdrm", createNpdrmCharacterDevice()); rx::vfs::addDevice("icc_configuration", @@ -404,9 +413,9 @@ static void ps4InitDev() { rx::vfs::addDevice("notification3", createNotificationCharacterDevice(3)); rx::vfs::addDevice("notification4", createNotificationCharacterDevice(4)); rx::vfs::addDevice("notification5", createNotificationCharacterDevice(5)); - rx::vfs::addDevice("aout0", createAoutCharacterDevice(0)); - rx::vfs::addDevice("aout1", createAoutCharacterDevice(1)); - rx::vfs::addDevice("aout2", createAoutCharacterDevice(2)); + rx::vfs::addDevice("aout0", createAoutCharacterDevice(0, hdmiAudioDevice)); + rx::vfs::addDevice("aout1", createAoutCharacterDevice(1, analogAudioDevice)); + rx::vfs::addDevice("aout2", createAoutCharacterDevice(2, spdifAudioDevice)); rx::vfs::addDevice("av_control", createAVControlCharacterDevice()); rx::vfs::addDevice("hdmi", createHDMICharacterDevice()); rx::vfs::addDevice("mbus_av", mbusAv);