rpcsx-os: audio: refactoring

This commit is contained in:
DH 2024-10-04 16:45:19 +03:00
parent f838dbbeae
commit ff297652e7
7 changed files with 356 additions and 285 deletions

View file

@ -2,60 +2,86 @@
#include "orbis/utils/Logs.hpp" #include "orbis/utils/Logs.hpp"
#include "rx/hexdump.hpp" #include "rx/hexdump.hpp"
AlsaDevice::AlsaDevice() {}
void AlsaDevice::start() { void AlsaDevice::start() {
setAlsaFormat(); if (mWorking) {
int err; // FIXME: should probably return error in this case and in other places
if ((err = snd_pcm_open(&mPCMHandle, "default", SND_PCM_STREAM_PLAYBACK, return;
0)) < 0) { }
{
_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)); ORBIS_LOG_FATAL("Cannot open audio device", snd_strerror(err));
std::abort(); 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", ORBIS_LOG_FATAL("Cannot allocate hardware parameter structure",
snd_strerror(err)); snd_strerror(err));
std::abort(); 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", ORBIS_LOG_FATAL("Cannot initialize hardware parameter structure",
snd_strerror(err)); snd_strerror(err));
std::abort(); std::abort();
} }
if ((err = snd_pcm_hw_params_set_rate_resample(mPCMHandle, mHWParams, if (auto err = snd_pcm_hw_params_set_rate_resample(mPCMHandle, mHWParams, 0);
0)) < 0) { err < 0) {
ORBIS_LOG_FATAL("Cannot disable rate resampling", snd_strerror(err)); ORBIS_LOG_FATAL("Cannot disable rate resampling", snd_strerror(err));
std::abort(); std::abort();
} }
if ((err = snd_pcm_hw_params_set_access(mPCMHandle, mHWParams, if (auto err = snd_pcm_hw_params_set_access(mPCMHandle, mHWParams,
SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) { SND_PCM_ACCESS_RW_INTERLEAVED);
err < 0) {
ORBIS_LOG_FATAL("Cannot set access type", snd_strerror(err)); ORBIS_LOG_FATAL("Cannot set access type", snd_strerror(err));
std::abort(); std::abort();
} }
if ((err = snd_pcm_hw_params_set_format(mPCMHandle, mHWParams, if (auto err =
mAlsaFormat)) < 0) { snd_pcm_hw_params_set_format(mPCMHandle, mHWParams, mAlsaFormat);
err < 0) {
ORBIS_LOG_FATAL("Cannot set sample format", snd_strerror(err)); ORBIS_LOG_FATAL("Cannot set sample format", snd_strerror(err));
std::abort(); std::abort();
} }
if ((err = snd_pcm_hw_params_set_rate(mPCMHandle, mHWParams, mFrequency, if (auto err =
0)) < 0) { snd_pcm_hw_params_set_rate(mPCMHandle, mHWParams, mFrequency, 0);
err < 0) {
ORBIS_LOG_FATAL("Cannot set sample rate", snd_strerror(err)); ORBIS_LOG_FATAL("Cannot set sample rate", snd_strerror(err));
std::abort(); std::abort();
} }
if ((err = snd_pcm_hw_params_set_channels(mPCMHandle, mHWParams, mChannels)) < if (auto err =
0) { snd_pcm_hw_params_set_channels(mPCMHandle, mHWParams, mChannels);
err < 0) {
ORBIS_LOG_FATAL("cannot set channel count", snd_strerror(err), mChannels); ORBIS_LOG_FATAL("cannot set channel count", snd_strerror(err), mChannels);
std::abort(); std::abort();
} }
uint periods = mSampleCount; 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)); ORBIS_LOG_FATAL("Cannot set periods count", snd_strerror(err));
std::abort(); std::abort();
} }
@ -64,115 +90,195 @@ void AlsaDevice::start() {
snd_pcm_uframes_t size = mSampleSize / frameBytes; 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) { break;
ORBIS_LOG_FATAL("Cannot set buffer size", snd_strerror(err)); }
std::abort();
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)); auto trySize = size;
std::abort(); 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; 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)); ORBIS_LOG_FATAL("cannot set parameters", snd_strerror(err));
std::abort(); std::abort();
} }
snd_pcm_uframes_t bufferSize; 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)); ORBIS_LOG_FATAL("cannot set parameters", snd_strerror(err));
std::abort(); std::abort();
} }
ORBIS_LOG_TODO("period and buffer", periodSize, bufferSize); 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)); ORBIS_LOG_FATAL("cannot set parameters", snd_strerror(err));
std::abort(); 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", ORBIS_LOG_FATAL("Cannot allocate software parameter structure",
snd_strerror(err)); snd_strerror(err));
std::abort(); 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)); ORBIS_LOG_FATAL("cannot sw params current", snd_strerror(err));
std::abort(); 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)); ORBIS_LOG_FATAL("cannot set start threshold", snd_strerror(err));
std::abort(); 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)); ORBIS_LOG_FATAL("cannot set stop threshold", snd_strerror(err));
std::abort(); 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)); ORBIS_LOG_FATAL("cannot set parameters", snd_strerror(err));
std::abort(); 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", ORBIS_LOG_FATAL("cannot prepare audio interface for use",
snd_strerror(err)); snd_strerror(err));
std::abort(); std::abort();
} }
mWorking = true; mWorking = true;
} }
int AlsaDevice::fixXRun() int AlsaDevice::fixXRun() {
{ switch (snd_pcm_state(mPCMHandle)) {
switch (snd_pcm_state(mPCMHandle)) { case SND_PCM_STATE_XRUN:
case SND_PCM_STATE_XRUN: return snd_pcm_prepare(mPCMHandle);
return snd_pcm_prepare(mPCMHandle);
case SND_PCM_STATE_DRAINING: case SND_PCM_STATE_DRAINING:
if (snd_pcm_stream(mPCMHandle) == SND_PCM_STREAM_CAPTURE) if (snd_pcm_stream(mPCMHandle) == SND_PCM_STREAM_CAPTURE)
return snd_pcm_prepare(mPCMHandle); return snd_pcm_prepare(mPCMHandle);
break; break;
default:
break; default:
} break;
return -EIO; }
return -EIO;
} }
int AlsaDevice::resumeFromSupsend() int AlsaDevice::resume() {
{ int err;
int res; while (true) {
while ((res = snd_pcm_resume(mPCMHandle)) == -EAGAIN) err = snd_pcm_resume(mPCMHandle);
std::this_thread::sleep_for(std::chrono::seconds(1));
if (!res) if (err == -EAGAIN) {
return 0; std::this_thread::sleep_for(std::chrono::seconds(1));
return snd_pcm_prepare(mPCMHandle); continue;
}
break;
}
if (err == 0) {
return 0;
}
return snd_pcm_prepare(mPCMHandle);
} }
long AlsaDevice::write(void *buf, long len) { long AlsaDevice::write(void *buf, long len) {
if (!mWorking) return 0; if (!mWorking)
ssize_t r; return 0;
int frameBytes = snd_pcm_format_physical_width(mAlsaFormat) * mChannels / 8;
int frameBytes = snd_pcm_format_physical_width(mAlsaFormat) * mChannels / 8;
snd_pcm_uframes_t frames = len / frameBytes; snd_pcm_uframes_t frames = len / frameBytes;
r = snd_pcm_writei(mPCMHandle, buf, frames); while (true) {
if (r == -EPIPE) { snd_pcm_sframes_t r = snd_pcm_writei(mPCMHandle, buf, frames);
if (!(r = fixXRun())) if (r == -EPIPE) {
return write(buf, len); if (fixXRun() == 0) {
} else if (r == -ESTRPIPE) { return write(buf, len);
if (!(r = resumeFromSupsend())) }
return write(buf, len);
} continue;
r *= frameBytes; }
return r;
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() { void AlsaDevice::stop() {
if (!mWorking) {
return;
}
snd_pcm_hw_params_free(mHWParams); snd_pcm_hw_params_free(mHWParams);
snd_pcm_sw_params_free(mSWParams); snd_pcm_sw_params_free(mSWParams);
snd_pcm_drain(mPCMHandle); snd_pcm_drain(mPCMHandle);
@ -181,19 +287,24 @@ void AlsaDevice::stop() {
} }
void AlsaDevice::reset() { void AlsaDevice::reset() {
if (!mWorking) return; if (!mWorking)
int err; return;
err = snd_pcm_drop(mPCMHandle); int err = snd_pcm_drop(mPCMHandle);
if (err >= 0)
if (err >= 0) {
err = snd_pcm_prepare(mPCMHandle); 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() { audio_buf_info AlsaDevice::getOSpace() {
int err; int err;
snd_pcm_uframes_t periodSize; 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)); ORBIS_LOG_FATAL("cannot get period size", snd_strerror(err));
std::abort(); std::abort();
} }
@ -205,38 +316,14 @@ audio_buf_info AlsaDevice::getOSpace() {
} }
int frameBytes = snd_pcm_format_physical_width(mAlsaFormat) * mChannels / 8; int frameBytes = snd_pcm_format_physical_width(mAlsaFormat) * mChannels / 8;
snd_pcm_sframes_t avail, delay; snd_pcm_sframes_t avail = snd_pcm_avail_update(mPCMHandle);
audio_buf_info info;
avail = snd_pcm_avail_update(mPCMHandle);
if (avail < 0 || (snd_pcm_uframes_t)avail > bufferSize) if (avail < 0 || (snd_pcm_uframes_t)avail > bufferSize)
avail = bufferSize; avail = bufferSize;
info.fragsize = periodSize * frameBytes;
info.fragstotal = mSampleCount;
info.bytes = avail * frameBytes;
info.fragments = avail / periodSize;
return info;
}
void AlsaDevice::setAlsaFormat() { return {
if (mWorking) .fragments = static_cast<orbis::sint>(avail / periodSize),
return; .fragsize = static_cast<orbis::sint>(mSampleCount),
_snd_pcm_format fmt; .fragstotal = static_cast<orbis::sint>(periodSize * frameBytes),
switch (mFormat) { .bytes = static_cast<orbis::sint>(avail * frameBytes),
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;
} }
AlsaDevice::~AlsaDevice() {
stop();
}

View file

@ -13,8 +13,7 @@ private:
snd_pcm_sw_params_t *mSWParams; snd_pcm_sw_params_t *mSWParams;
public: public:
AlsaDevice(); ~AlsaDevice() { stop(); }
~AlsaDevice() override;
void init() override {}; void init() override {};
void start() override; void start() override;
@ -22,10 +21,8 @@ public:
void stop() override; void stop() override;
void reset() override; void reset() override;
void setAlsaFormat();
int fixXRun(); int fixXRun();
int resumeFromSupsend(); int resume();
audio_buf_info getOSpace() override; audio_buf_info getOSpace() override;
}; };

View file

@ -1,23 +1,7 @@
#include "AudioDevice.hpp" #include "AudioDevice.hpp"
#include "orbis/utils/Logs.hpp" #include "orbis/utils/Logs.hpp"
#include "rx/hexdump.hpp"
AudioDevice::AudioDevice() {} void AudioDevice::setFormat(AudioFormat format) {
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) {
if (mWorking) if (mWorking)
return; return;
mFormat = format; mFormat = format;
@ -39,17 +23,10 @@ void AudioDevice::setChannels(orbis::ushort channels) {
mChannels = channels; mChannels = channels;
} }
void AudioDevice::setSampleSize(orbis::uint sampleSize, orbis::uint sampleCount) { void AudioDevice::setSampleSize(orbis::uint sampleSize,
orbis::uint sampleCount) {
if (mWorking) if (mWorking)
return; return;
mSampleSize = sampleSize; mSampleSize = sampleSize;
mSampleCount = sampleCount; mSampleCount = sampleCount;
} }
audio_buf_info AudioDevice::getOSpace() {
audio_buf_info info;
return info;
}
AudioDevice::~AudioDevice() {}

View file

@ -1,44 +1,45 @@
#pragma once #pragma once
#define FMT_S16_LE 0x10 #include "orbis-config.hpp"
#define FMT_AC3 0x400 #include "orbis/utils/Rc.hpp"
#define FMT_S32_LE 0x1000
#include <cstdlib> #include <cstdlib>
#include <orbis/sys/sysproto.hpp> #include <orbis/sys/sysproto.hpp>
struct audio_buf_info { struct [[gnu::packed]] audio_buf_info {
int fragments; orbis::sint fragments;
int fragstotal; orbis::sint fragsize;
int fragsize; orbis::sint fragstotal;
int bytes; 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: protected:
bool mWorking = false; bool mWorking = false;
orbis::uint mFormat{}; AudioFormat mFormat{};
orbis::uint mFrequency{}; orbis::uint mFrequency{};
orbis::ushort mChannels{}; orbis::ushort mChannels{};
orbis::ushort mSampleSize{}; orbis::ushort mSampleSize{};
orbis::ushort mSampleCount{}; orbis::ushort mSampleCount{};
private:
public: public:
AudioDevice(); virtual ~AudioDevice() = default;
virtual ~AudioDevice();
virtual void init(); virtual void init() {}
virtual void start(); virtual void start() {}
virtual long write(void *buf, long len); virtual long write(void *buf, long len) { return -1; }
virtual void stop(); virtual void stop() {}
virtual void reset(); virtual void reset() {}
void setFormat(orbis::uint format); void setFormat(AudioFormat format);
void setFrequency(orbis::uint frequency); void setFrequency(orbis::uint frequency);
void setChannels(orbis::ushort channels); void setChannels(orbis::ushort channels);
void setSampleSize(orbis::uint sampleSize = 0, orbis::uint sampleCount = 0); void setSampleSize(orbis::uint sampleSize = 0, orbis::uint sampleCount = 0);
virtual audio_buf_info getOSpace(); virtual audio_buf_info getOSpace() { return {}; }
}; };

View file

@ -1,6 +1,8 @@
#pragma once #pragma once
#include "audio/AudioDevice.hpp"
#include <cstdint> #include <cstdint>
struct IoDevice; struct IoDevice;
IoDevice *createDceCharacterDevice(); IoDevice *createDceCharacterDevice();
@ -31,7 +33,7 @@ IoDevice *createXptCharacterDevice();
IoDevice *createCdCharacterDevice(); IoDevice *createCdCharacterDevice();
IoDevice *createMetaDbgCharacterDevice(); IoDevice *createMetaDbgCharacterDevice();
IoDevice *createHddCharacterDevice(std::uint64_t size); IoDevice *createHddCharacterDevice(std::uint64_t size);
IoDevice *createAoutCharacterDevice(std::int8_t id); IoDevice *createAoutCharacterDevice(std::int8_t id, AudioDevice *device);
IoDevice *createAVControlCharacterDevice(); IoDevice *createAVControlCharacterDevice();
IoDevice *createHDMICharacterDevice(); IoDevice *createHDMICharacterDevice();
IoDevice *createMBusAVCharacterDevice(); IoDevice *createMBusAVCharacterDevice();

View file

@ -1,6 +1,5 @@
#include "audio/AlsaDevice.hpp" #include "audio/AudioDevice.hpp"
#include "io-device.hpp" #include "io-device.hpp"
#include "iodev/mbus_av.hpp"
#include "orbis/KernelAllocator.hpp" #include "orbis/KernelAllocator.hpp"
#include "orbis/file.hpp" #include "orbis/file.hpp"
#include "orbis/thread/Process.hpp" #include "orbis/thread/Process.hpp"
@ -8,6 +7,7 @@
#include "orbis/thread/Thread.hpp" #include "orbis/thread/Thread.hpp"
#include "orbis/uio.hpp" #include "orbis/uio.hpp"
#include "orbis/utils/Logs.hpp" #include "orbis/utils/Logs.hpp"
#include "orbis/utils/Rc.hpp"
#include <bits/types/struct_iovec.h> #include <bits/types/struct_iovec.h>
// #include <rx/hexdump.hpp> // #include <rx/hexdump.hpp>
@ -29,9 +29,10 @@ struct AoutFile : orbis::File {};
struct AoutDevice : public IoDevice { struct AoutDevice : public IoDevice {
std::int8_t id; std::int8_t id;
AudioDevice *audioDevice; orbis::Ref<AudioDevice> audioDevice;
AoutDevice(std::int8_t id) : id(id) {} AoutDevice(std::int8_t id, AudioDevice *audioDevice)
: id(id), audioDevice(audioDevice) {}
orbis::ErrorCode open(orbis::Ref<orbis::File> *file, const char *path, orbis::ErrorCode open(orbis::Ref<orbis::File> *file, const char *path,
std::uint32_t flags, std::uint32_t mode, 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) { void *argp, orbis::Thread *thread) {
auto device = static_cast<AoutDevice *>(file->device.get()); auto device = static_cast<AoutDevice *>(file->device.get());
switch (request) { switch (request) {
case SNDCTL_DSP_RESET: { case SNDCTL_DSP_RESET: {
ORBIS_LOG_TODO("SNDCTL_DSP_RESET"); ORBIS_LOG_TODO("SNDCTL_DSP_RESET");
if (auto audioDevice = device->audioDevice) { if (auto audioDevice = device->audioDevice) {
audioDevice->reset(); audioDevice->reset();
}
return {};
} }
case SNDCTL_DSP_SETFRAGMENT: { return {};
struct Args { }
std::uint32_t fragment; case SNDCTL_DSP_SETFRAGMENT: {
}; struct Args {
auto args = reinterpret_cast<Args *>(argp); orbis::uint32_t fragment;
ORBIS_LOG_NOTICE("SNDCTL_DSP_SETFRAGMENT", args->fragment & 0xF, (args->fragment >> 16) & 0xF); };
if (auto audioDevice = device->audioDevice) { auto args = reinterpret_cast<Args *>(argp);
audioDevice->setSampleSize(1 << (args->fragment & 0xF), (args->fragment >> 16) & 0xF); ORBIS_LOG_NOTICE("SNDCTL_DSP_SETFRAGMENT", args->fragment & 0xF,
} (args->fragment >> 16) & 0xF);
return {}; if (auto audioDevice = device->audioDevice) {
audioDevice->setSampleSize(1 << (args->fragment & 0xF),
(args->fragment >> 16) & 0xF);
} }
case SNDCTL_DSP_SETFMT: { return {};
struct Args { }
std::uint32_t fmt; case SNDCTL_DSP_SETFMT: {
}; struct Args {
auto args = reinterpret_cast<Args *>(argp); orbis::uint32_t fmt;
ORBIS_LOG_NOTICE("SNDCTL_DSP_SETFMT", args->fmt); };
if (auto audioDevice = device->audioDevice) { auto args = reinterpret_cast<Args *>(argp);
audioDevice->setFormat(args->fmt); ORBIS_LOG_NOTICE("SNDCTL_DSP_SETFMT", args->fmt);
} if (auto audioDevice = device->audioDevice) {
return {}; audioDevice->setFormat(static_cast<AudioFormat>(args->fmt));
} }
case SNDCTL_DSP_SPEED: { return {};
struct Args { }
std::uint32_t speed; case SNDCTL_DSP_SPEED: {
}; struct Args {
auto args = reinterpret_cast<Args *>(argp); orbis::uint32_t speed;
if (auto audioDevice = device->audioDevice) { };
audioDevice->setFrequency(args->speed); auto args = reinterpret_cast<Args *>(argp);
} if (auto audioDevice = device->audioDevice) {
return {}; audioDevice->setFrequency(args->speed);
} }
case SNDCTL_DSP_CHANNELS: { return {};
struct Args { }
std::uint32_t channels; case SNDCTL_DSP_CHANNELS: {
}; struct Args {
auto args = reinterpret_cast<Args *>(argp); orbis::uint32_t channels;
if (auto audioDevice = device->audioDevice) { };
audioDevice->setChannels(args->channels); auto args = reinterpret_cast<Args *>(argp);
} if (auto audioDevice = device->audioDevice) {
return {}; audioDevice->setChannels(args->channels);
} }
case ORBIS_AUDIO_UPDATE_TICK_PARAMS: { return {};
struct Args { }
std::uint32_t tick; case ORBIS_AUDIO_UPDATE_TICK_PARAMS: {
}; struct Args {
auto args = reinterpret_cast<Args *>(argp); orbis::uint32_t tick;
ORBIS_LOG_NOTICE("ORBIS_AUDIO_UPDATE_TICK_PARAMS", args->tick); };
return {}; auto args = reinterpret_cast<Args *>(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<Args *>(argp);
args->unk0 = 0x100000000; // Disable SPDIF output
return {};
}
case SNDCTL_DSP_GETBLKSIZE: {
struct Args {
orbis::uint32_t blksize;
};
auto args = reinterpret_cast<Args *>(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<Args *>(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<audio_buf_info>(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: { return {};
struct Args { }
std::uint64_t unk0; case ORBIS_AUDIO_IOCTL_SETCONTROL: {
}; struct Args {
auto args = reinterpret_cast<Args *>(argp); orbis::uint64_t unk0;
args->unk0 = 0x100000000; // Disable SPDIF output };
return {}; auto args = reinterpret_cast<Args *>(argp);
} ORBIS_LOG_NOTICE("ORBIS_AUDIO_IOCTL_SETCONTROL", args->unk0);
case SNDCTL_DSP_GETBLKSIZE: { return {};
struct Args { }
std::uint32_t blksize; default:
}; ORBIS_LOG_FATAL("Unhandled aout ioctl", request);
auto args = reinterpret_cast<Args *>(argp); thread->where();
ORBIS_LOG_NOTICE("SNDCTL_DSP_GETBLKSIZE", args->blksize); break;
return {};
}
case SOUND_PCM_READ_BITS: {
struct Args {
std::uint32_t bits;
};
auto args = reinterpret_cast<Args *>(argp);
ORBIS_LOG_NOTICE("SOUND_PCM_READ_BITS", args->bits);
return {};
}
case SNDCTL_DSP_GETOSPACE: {
auto args = reinterpret_cast<audio_buf_info *>(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<Args *>(argp);
ORBIS_LOG_NOTICE("ORBIS_AUDIO_IOCTL_SETCONTROL", args->unk0);
return {};
}
default:
ORBIS_LOG_FATAL("Unhandled aout ioctl", request);
thread->where();
break;
} }
return {}; return {};
} }
@ -190,14 +193,9 @@ orbis::ErrorCode AoutDevice::open(orbis::Ref<orbis::File> *file,
thread->where(); thread->where();
*file = newFile; *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 {}; return {};
} }
IoDevice *createAoutCharacterDevice(std::int8_t id) { IoDevice *createAoutCharacterDevice(std::int8_t id, AudioDevice *device) {
return orbis::knew<AoutDevice>(id); return orbis::knew<AoutDevice>(id, device);
} }

View file

@ -1,5 +1,6 @@
#include "AudioOut.hpp" #include "AudioOut.hpp"
#include "amdgpu/bridge/bridge.hpp" #include "amdgpu/bridge/bridge.hpp"
#include "audio/AlsaDevice.hpp"
#include "backtrace.hpp" #include "backtrace.hpp"
#include "bridge.hpp" #include "bridge.hpp"
#include "io-device.hpp" #include "io-device.hpp"
@ -336,6 +337,14 @@ static void ps4InitDev() {
auto mbus = static_cast<MBusDevice *>(createMBusCharacterDevice()); auto mbus = static_cast<MBusDevice *>(createMBusCharacterDevice());
auto mbusAv = static_cast<MBusAVDevice *>(createMBusAVCharacterDevice()); auto mbusAv = static_cast<MBusAVDevice *>(createMBusAVCharacterDevice());
// FIXME: make it configurable
auto defaultAudioDevice = orbis::knew<AlsaDevice>();
auto nullAudioDevice = orbis::knew<AudioDevice>();
auto hdmiAudioDevice = defaultAudioDevice;
auto analogAudioDevice = nullAudioDevice;
auto spdifAudioDevice = nullAudioDevice;
rx::vfs::addDevice("dmem0", createDmemCharacterDevice(0)); rx::vfs::addDevice("dmem0", createDmemCharacterDevice(0));
rx::vfs::addDevice("npdrm", createNpdrmCharacterDevice()); rx::vfs::addDevice("npdrm", createNpdrmCharacterDevice());
rx::vfs::addDevice("icc_configuration", rx::vfs::addDevice("icc_configuration",
@ -404,9 +413,9 @@ static void ps4InitDev() {
rx::vfs::addDevice("notification3", createNotificationCharacterDevice(3)); rx::vfs::addDevice("notification3", createNotificationCharacterDevice(3));
rx::vfs::addDevice("notification4", createNotificationCharacterDevice(4)); rx::vfs::addDevice("notification4", createNotificationCharacterDevice(4));
rx::vfs::addDevice("notification5", createNotificationCharacterDevice(5)); rx::vfs::addDevice("notification5", createNotificationCharacterDevice(5));
rx::vfs::addDevice("aout0", createAoutCharacterDevice(0)); rx::vfs::addDevice("aout0", createAoutCharacterDevice(0, hdmiAudioDevice));
rx::vfs::addDevice("aout1", createAoutCharacterDevice(1)); rx::vfs::addDevice("aout1", createAoutCharacterDevice(1, analogAudioDevice));
rx::vfs::addDevice("aout2", createAoutCharacterDevice(2)); rx::vfs::addDevice("aout2", createAoutCharacterDevice(2, spdifAudioDevice));
rx::vfs::addDevice("av_control", createAVControlCharacterDevice()); rx::vfs::addDevice("av_control", createAVControlCharacterDevice());
rx::vfs::addDevice("hdmi", createHDMICharacterDevice()); rx::vfs::addDevice("hdmi", createHDMICharacterDevice());
rx::vfs::addDevice("mbus_av", mbusAv); rx::vfs::addDevice("mbus_av", mbusAv);