[orbis-kernel]: AudioOut: relatively correct parsing (#52)

This commit is contained in:
Nikita Savyolov 2023-08-20 15:35:13 +03:00 committed by GitHub
parent b87f8f6ea0
commit ca58c03eb6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 85 additions and 66 deletions

View file

@ -20,8 +20,32 @@ struct AudioOutChannelInfo {
Ref<EventFlag> evf; Ref<EventFlag> evf;
}; };
struct AudioOutParams {
std::uint64_t control{};
std::uint32_t formatChannels{};
float unk0{};
float unk1{};
float unk2{};
float unk3{};
float unk4{};
float unk5{};
float unk6{};
float unk7{};
std::uint32_t formatIsFloat{};
std::uint64_t freq{};
std::uint32_t formatIsStd{};
std::uint32_t seek{};
std::uint32_t seekPart{};
std::uint64_t unk8{};
std::uint32_t port{};
std::uint32_t unk9{};
std::uint64_t unk10{};
std::uint32_t sampleLength{};
};
struct AudioOut { struct AudioOut {
std::mutex thrMtx; std::mutex thrMtx;
std::mutex soxMtx;
std::vector<std::thread> threads; std::vector<std::thread> threads;
AudioOutChannelInfo channelInfo; AudioOutChannelInfo channelInfo;
std::atomic<bool> exit{false}; std::atomic<bool> exit{false};
@ -95,96 +119,75 @@ private:
MAP_SHARED, bufferFd, 0); MAP_SHARED, bufferFd, 0);
auto bitPattern = 1u << info.port; auto bitPattern = 1u << info.port;
int firstNonEmptyByteIndex = -1; auto portOffset = 32 + 0x94 * info.port * 4;
for (std::size_t i = 24; i < controlStat.st_size; ++i) { auto *params = reinterpret_cast<AudioOutParams *>(controlPtr + portOffset);
if (controlPtr[i] != 0) {
firstNonEmptyByteIndex = i - 8;
break;
}
// FIXME: following line triggers error, investigate _C shm layout // samples length will be inited after some time, so we wait for it
// std::this_thread::sleep_for(std::chrono::milliseconds(1)); while (params->sampleLength == 0) {
if (exit.load(std::memory_order::relaxed)) {
break;
}
} }
if (firstNonEmptyByteIndex < 0) { ORBIS_LOG_NOTICE("AudioOut: params", params->port, params->control,
ORBIS_LOG_ERROR("AudioOut: Failed to find first non zero byte index"); params->formatChannels, params->formatIsFloat,
std::abort(); params->formatIsStd, params->freq, params->sampleLength);
}
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 inChannels = 2;
unsigned inSamples = 256; unsigned inSamples = params->sampleLength;
sox_rate_t sampleRate = 48000; // probably there is no point to parse sox_rate_t sampleRate = 48000; // probably there is no point to parse
// frequency, because it's always 48000 // frequency, because it's always 48000
if (outParamFirstByte == 2 && isFloat == 0) { if (params->formatChannels == 2 && !params->formatIsFloat) {
inChannels = 1; inChannels = 1;
ORBIS_LOG_NOTICE( ORBIS_LOG_NOTICE(
"AudioOut: outputParam is ORBIS_AUDIO_OUT_PARAM_FORMAT_S16_MONO"); "AudioOut: format is ORBIS_AUDIO_OUT_PARAM_FORMAT_S16_MONO");
} else if (outParamFirstByte == 4 && isFloat == 0) { } else if (params->formatChannels == 4 && !params->formatIsFloat) {
inChannels = 2; inChannels = 2;
ORBIS_LOG_NOTICE( ORBIS_LOG_NOTICE(
"AudioOut: outputParam is ORBIS_AUDIO_OUT_PARAM_FORMAT_S16_STEREO"); "AudioOut: format is ORBIS_AUDIO_OUT_PARAM_FORMAT_S16_STEREO");
} else if (outParamFirstByte == 16 && isFloat == 0) { } else if (params->formatChannels == 16 && !params->formatIsFloat &&
!params->formatIsStd) {
inChannels = 8; inChannels = 8;
ORBIS_LOG_NOTICE( ORBIS_LOG_NOTICE(
"AudioOut: outputParam is ORBIS_AUDIO_OUT_PARAM_FORMAT_S16_8CH"); "AudioOut: format is ORBIS_AUDIO_OUT_PARAM_FORMAT_S16_8CH");
} else if (outParamFirstByte == 4 && isFloat == 1) { } else if (params->formatChannels == 16 && !params->formatIsFloat &&
params->formatIsStd) {
inChannels = 8;
ORBIS_LOG_NOTICE(
"AudioOut: outputParam is ORBIS_AUDIO_OUT_PARAM_FORMAT_S16_8CH_STD");
} else if (params->formatChannels == 4 && params->formatIsFloat) {
inChannels = 1; inChannels = 1;
ORBIS_LOG_NOTICE( ORBIS_LOG_NOTICE(
"AudioOut: outputParam is ORBIS_AUDIO_OUT_PARAM_FORMAT_FLOAT_MONO"); "AudioOut: format is ORBIS_AUDIO_OUT_PARAM_FORMAT_FLOAT_MONO");
} else if (outParamFirstByte == 8 && isFloat == 1) { } else if (params->formatChannels == 8 && params->formatIsFloat) {
inChannels = 2; inChannels = 2;
ORBIS_LOG_NOTICE( ORBIS_LOG_NOTICE(
"AudioOut: outputParam is ORBIS_AUDIO_OUT_PARAM_FORMAT_FLOAT_STEREO"); "AudioOut: format is ORBIS_AUDIO_OUT_PARAM_FORMAT_FLOAT_STEREO");
} else if (outParamFirstByte == 32 && isFloat == 1) { } else if (params->formatChannels == 32 && params->formatIsFloat &&
!params->formatIsStd) {
inChannels = 8; inChannels = 8;
ORBIS_LOG_NOTICE( ORBIS_LOG_NOTICE(
"AudioOut: outputParam is ORBIS_AUDIO_OUT_PARAM_FORMAT_FLOAT_8CH"); "AudioOut: format is ORBIS_AUDIO_OUT_PARAM_FORMAT_FLOAT_8CH");
} else if (params->formatChannels == 32 && params->formatIsFloat &&
params->formatIsStd) {
inChannels = 8;
ORBIS_LOG_NOTICE("AudioOut: format is "
"ORBIS_AUDIO_OUT_PARAM_FORMAT_FLOAT_8CH_STD");
} else { } else {
ORBIS_LOG_ERROR("AudioOut: unknown output type"); ORBIS_LOG_ERROR("AudioOut: unknown format type");
} }
// 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) {
// 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 = 0;
while (true) {
samplesLengthByte = controlPtr[firstNonEmptyByteIndex + 97];
if (samplesLengthByte > 0) {
break;
}
}
inSamples = samplesLengthByte * 256;
sox_signalinfo_t out_si = { sox_signalinfo_t out_si = {
.rate = sampleRate, .rate = sampleRate,
.channels = inChannels, .channels = inChannels,
.precision = SOX_SAMPLE_PRECISION, .precision = SOX_SAMPLE_PRECISION,
}; };
// need to be locked because libsox doesn't like simultaneous opening of the
// output
std::unique_lock lock(soxMtx);
sox_format_t *output = sox_format_t *output =
sox_open_write("default", &out_si, NULL, "alsa", NULL, NULL); sox_open_write("default", &out_si, NULL, "alsa", NULL, NULL);
soxMtx.unlock();
if (!output) { if (!output) {
std::abort(); std::abort();
} }
@ -197,7 +200,7 @@ private:
while (!exit.load(std::memory_order::relaxed)) { while (!exit.load(std::memory_order::relaxed)) {
std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::sleep_for(std::chrono::milliseconds(1));
if (isFloat == 0) { if (!params->formatIsFloat) {
auto data = reinterpret_cast<const std::int16_t *>(audioBuffer); auto data = reinterpret_cast<const std::int16_t *>(audioBuffer);
for (std::size_t i = 0; i < samples.size(); i++) { for (std::size_t i = 0; i < samples.size(); i++) {
samples[i] = SOX_SIGNED_16BIT_TO_SAMPLE(data[i], clips); samples[i] = SOX_SIGNED_16BIT_TO_SAMPLE(data[i], clips);
@ -217,9 +220,7 @@ private:
info.evf->set(bitPattern); info.evf->set(bitPattern);
// set zero to freeing audiooutput // set zero to freeing audiooutput
for (size_t i = 0; i < 8; ++i) { params->control = 0;
controlPtr[firstNonEmptyByteIndex + i] = 0;
}
} }
sox_close(output); sox_close(output);

View file

@ -1234,8 +1234,8 @@ orbis::SysResult orbis::sys_ipmimgr_call(Thread *thread, uint op, uint kid,
} }
} else if (syncCallParams.method == 0x12340002) { // something like open } else if (syncCallParams.method == 0x12340002) { // something like open
struct SceSysAudioSystemIpcSomethingMethodArgs { struct SceSysAudioSystemIpcSomethingMethodArgs {
uint32_t arg1; uint32_t audioPort;
uint32_t arg2; uint32_t channelId;
}; };
static_assert(sizeof(SceSysAudioSystemIpcSomethingMethodArgs) == 0x8); static_assert(sizeof(SceSysAudioSystemIpcSomethingMethodArgs) == 0x8);
@ -1249,12 +1249,30 @@ orbis::SysResult orbis::sys_ipmimgr_call(Thread *thread, uint op, uint kid,
ptr<SceSysAudioSystemIpcSomethingMethodArgs>(dataInfo.data)); ptr<SceSysAudioSystemIpcSomethingMethodArgs>(dataInfo.data));
ORBIS_LOG_TODO("impi: SceSysAudioSystemIpcSomethingMethodArgs", ORBIS_LOG_TODO("impi: SceSysAudioSystemIpcSomethingMethodArgs",
args.arg1, args.arg2); args.audioPort, args.channelId);
if (auto audioOut = g_context.audioOut) { if (auto audioOut = g_context.audioOut) {
// here startToListen // here startToListen
audioOut->start(); audioOut->start();
} }
} else if (syncCallParams.method == 0x12340006) { // close port
struct SceSysAudioSystemIpcCloseAudioMethodArgs {
uint32_t audioPort;
uint32_t channelId;
};
static_assert(sizeof(SceSysAudioSystemIpcCloseAudioMethodArgs) == 0x8);
if (dataInfo.size != sizeof(SceSysAudioSystemIpcCloseAudioMethodArgs)) {
return ErrorCode::INVAL;
}
SceSysAudioSystemIpcCloseAudioMethodArgs args;
uread(args,
ptr<SceSysAudioSystemIpcCloseAudioMethodArgs>(dataInfo.data));
ORBIS_LOG_TODO("impi: SceSysAudioSystemIpcCloseAudioMethodArgs",
args.audioPort, args.channelId);
} }
} }