mirror of
https://github.com/RPCSX/rpcsx.git
synced 2025-12-31 22:00:10 +01:00
211 lines
6 KiB
C++
211 lines
6 KiB
C++
#include "audio/AudioDevice.hpp"
|
|
#include "io-device.hpp"
|
|
#include "orbis/KernelAllocator.hpp"
|
|
#include "orbis/file.hpp"
|
|
#include "orbis/thread/Process.hpp"
|
|
#include "orbis/thread/ProcessOps.hpp"
|
|
#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>
|
|
|
|
#define SNDCTL_DSP_RESET 0x20005000
|
|
#define SNDCTL_DSP_SETFRAGMENT 0xc004500a
|
|
#define SNDCTL_DSP_SETFMT 0xc0045005
|
|
#define SNDCTL_DSP_SPEED 0xc0045002
|
|
#define SNDCTL_DSP_CHANNELS 0xc0045006
|
|
#define ORBIS_AUDIO_UPDATE_TICK_PARAMS 0xc004505c
|
|
#define SNDCTL_DSP_SYNCGROUP 0xc048501c
|
|
#define ORBIS_AUDIO_CONFIG_SPDIF 0xc0085063
|
|
#define SNDCTL_DSP_GETBLKSIZE 0x40045004
|
|
#define SOUND_PCM_READ_BITS 0x40045005
|
|
#define SNDCTL_DSP_GETOSPACE 0x4010500c
|
|
#define SNDCTL_DSP_SYNCSTART 0x8004501d
|
|
#define ORBIS_AUDIO_IOCTL_SETCONTROL 0x80085062
|
|
|
|
struct AoutFile : orbis::File {};
|
|
|
|
struct AoutDevice : public IoDevice {
|
|
std::int8_t id;
|
|
orbis::Ref<AudioDevice> audioDevice;
|
|
|
|
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,
|
|
orbis::Thread *thread) override;
|
|
};
|
|
|
|
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_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);
|
|
}
|
|
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));
|
|
}
|
|
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);
|
|
}
|
|
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);
|
|
}
|
|
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);
|
|
}
|
|
|
|
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 {
|
|
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 {};
|
|
}
|
|
|
|
static orbis::ErrorCode aout_write(orbis::File *file, orbis::Uio *uio,
|
|
orbis::Thread *thread) {
|
|
auto device = static_cast<AoutDevice *>(file->device.get());
|
|
std::uint64_t totalSize = 0;
|
|
if (auto audioDevice = device->audioDevice) {
|
|
for (auto vec : std::span(uio->iov, uio->iovcnt)) {
|
|
auto result = audioDevice->write(vec.base, vec.len);
|
|
|
|
if (result < 0) {
|
|
return static_cast<orbis::ErrorCode>(-result);
|
|
}
|
|
|
|
// rx::hexdump({(std::byte*)vec.base, vec.len});
|
|
uio->offset += result;
|
|
totalSize += result;
|
|
}
|
|
}
|
|
|
|
thread->retval[0] = totalSize;
|
|
return {};
|
|
}
|
|
|
|
static const orbis::FileOps fileOps = {
|
|
.ioctl = aout_ioctl,
|
|
.write = aout_write,
|
|
};
|
|
|
|
orbis::ErrorCode AoutDevice::open(orbis::Ref<orbis::File> *file,
|
|
const char *path, std::uint32_t flags,
|
|
std::uint32_t mode, orbis::Thread *thread) {
|
|
ORBIS_LOG_FATAL("aout device open", path, flags, mode);
|
|
auto newFile = orbis::knew<AoutFile>();
|
|
newFile->ops = &fileOps;
|
|
newFile->device = this;
|
|
thread->where();
|
|
|
|
*file = newFile;
|
|
return {};
|
|
}
|
|
|
|
IoDevice *createAoutCharacterDevice(std::int8_t id, AudioDevice *device) {
|
|
return orbis::knew<AoutDevice>(id, device);
|
|
}
|