mirror of
https://github.com/RPCSX/rpcsx.git
synced 2026-02-09 01:04:46 +01:00
rpcsx-os: audio: refactoring
This commit is contained in:
parent
f838dbbeae
commit
ff297652e7
|
|
@ -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<orbis::sint>(avail / periodSize),
|
||||
.fragsize = static_cast<orbis::sint>(mSampleCount),
|
||||
.fragstotal = static_cast<orbis::sint>(periodSize * frameBytes),
|
||||
.bytes = static_cast<orbis::sint>(avail * frameBytes),
|
||||
};
|
||||
}
|
||||
|
||||
AlsaDevice::~AlsaDevice() {
|
||||
stop();
|
||||
}
|
||||
|
|
@ -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;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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() {}
|
||||
|
|
@ -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 <cstdlib>
|
||||
#include <orbis/sys/sysproto.hpp>
|
||||
|
||||
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 {}; }
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include "audio/AudioDevice.hpp"
|
||||
#include <cstdint>
|
||||
|
||||
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();
|
||||
|
|
|
|||
|
|
@ -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 <bits/types/struct_iovec.h>
|
||||
// #include <rx/hexdump.hpp>
|
||||
|
||||
|
|
@ -29,9 +29,10 @@ struct AoutFile : orbis::File {};
|
|||
|
||||
struct AoutDevice : public IoDevice {
|
||||
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,
|
||||
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<AoutDevice *>(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<Args *>(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<Args *>(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<Args *>(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<Args *>(argp);
|
||||
ORBIS_LOG_NOTICE("SNDCTL_DSP_SETFMT", args->fmt);
|
||||
if (auto audioDevice = device->audioDevice) {
|
||||
audioDevice->setFormat(static_cast<AudioFormat>(args->fmt));
|
||||
}
|
||||
case SNDCTL_DSP_SPEED: {
|
||||
struct Args {
|
||||
std::uint32_t speed;
|
||||
};
|
||||
auto args = reinterpret_cast<Args *>(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<Args *>(argp);
|
||||
if (auto audioDevice = device->audioDevice) {
|
||||
audioDevice->setFrequency(args->speed);
|
||||
}
|
||||
case SNDCTL_DSP_CHANNELS: {
|
||||
struct Args {
|
||||
std::uint32_t channels;
|
||||
};
|
||||
auto args = reinterpret_cast<Args *>(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<Args *>(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<Args *>(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<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: {
|
||||
struct Args {
|
||||
std::uint64_t unk0;
|
||||
};
|
||||
auto args = reinterpret_cast<Args *>(argp);
|
||||
args->unk0 = 0x100000000; // Disable SPDIF output
|
||||
return {};
|
||||
}
|
||||
case SNDCTL_DSP_GETBLKSIZE: {
|
||||
struct Args {
|
||||
std::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 {
|
||||
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 {};
|
||||
}
|
||||
case ORBIS_AUDIO_IOCTL_SETCONTROL: {
|
||||
struct Args {
|
||||
orbis::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 {};
|
||||
}
|
||||
|
|
@ -190,14 +193,9 @@ orbis::ErrorCode AoutDevice::open(orbis::Ref<orbis::File> *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<AoutDevice>(id);
|
||||
IoDevice *createAoutCharacterDevice(std::int8_t id, AudioDevice *device) {
|
||||
return orbis::knew<AoutDevice>(id, device);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<MBusDevice *>(createMBusCharacterDevice());
|
||||
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("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);
|
||||
|
|
|
|||
Loading…
Reference in a new issue