summaryrefslogtreecommitdiffstats
path: root/src/core/hle/service/audio/audren_u.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/hle/service/audio/audren_u.cpp')
-rw-r--r--src/core/hle/service/audio/audren_u.cpp268
1 files changed, 193 insertions, 75 deletions
diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp
index 6e8002bc9..2da936b27 100644
--- a/src/core/hle/service/audio/audren_u.cpp
+++ b/src/core/hle/service/audio/audren_u.cpp
@@ -17,7 +17,8 @@ constexpr u64 audio_ticks{static_cast<u64>(CoreTiming::BASE_CLOCK_RATE / 200)};
class IAudioRenderer final : public ServiceFramework<IAudioRenderer> {
public:
- IAudioRenderer() : ServiceFramework("IAudioRenderer") {
+ IAudioRenderer(AudioRendererParameter audren_params)
+ : ServiceFramework("IAudioRenderer"), worker_params(audren_params) {
static const FunctionInfo functions[] = {
{0, nullptr, "GetAudioRendererSampleRate"},
{1, nullptr, "GetAudioRendererSampleCount"},
@@ -46,6 +47,7 @@ public:
// Start the audio event
CoreTiming::ScheduleEvent(audio_ticks, audio_event);
+ voice_status_list.reserve(worker_params.voice_count);
}
~IAudioRenderer() {
CoreTiming::UnscheduleEvent(audio_event, 0);
@@ -57,30 +59,63 @@ private:
}
void RequestUpdateAudioRenderer(Kernel::HLERequestContext& ctx) {
- NGLOG_DEBUG(Service_Audio, "{}", ctx.Description());
- AudioRendererResponseData response_data{};
-
- response_data.section_0_size =
- static_cast<u32>(response_data.state_entries.size() * sizeof(AudioRendererStateEntry));
- response_data.section_1_size = static_cast<u32>(response_data.section_1.size());
- response_data.section_2_size = static_cast<u32>(response_data.section_2.size());
- response_data.section_3_size = static_cast<u32>(response_data.section_3.size());
- response_data.section_4_size = static_cast<u32>(response_data.section_4.size());
- response_data.section_5_size = static_cast<u32>(response_data.section_5.size());
- response_data.total_size = sizeof(AudioRendererResponseData);
-
- for (unsigned i = 0; i < response_data.state_entries.size(); i++) {
- // 4 = Busy and 5 = Ready?
- response_data.state_entries[i].state = 5;
+ UpdateDataHeader config{};
+ auto buf = ctx.ReadBuffer();
+ std::memcpy(&config, buf.data(), sizeof(UpdateDataHeader));
+ u32 memory_pool_count = worker_params.effect_count + (worker_params.voice_count * 4);
+
+ std::vector<MemoryPoolInfo> mem_pool_info(memory_pool_count);
+ std::memcpy(mem_pool_info.data(),
+ buf.data() + sizeof(UpdateDataHeader) + config.behavior_size,
+ memory_pool_count * sizeof(MemoryPoolInfo));
+
+ std::vector<VoiceInfo> voice_info(worker_params.voice_count);
+ std::memcpy(voice_info.data(),
+ buf.data() + sizeof(UpdateDataHeader) + config.behavior_size +
+ config.memory_pools_size + config.voice_resource_size,
+ worker_params.voice_count * sizeof(VoiceInfo));
+
+ UpdateDataHeader response_data{worker_params};
+
+ ASSERT(ctx.GetWriteBufferSize() == response_data.total_size);
+
+ std::vector<u8> output(response_data.total_size);
+ std::memcpy(output.data(), &response_data, sizeof(UpdateDataHeader));
+ std::vector<MemoryPoolEntry> memory_pool(memory_pool_count);
+ for (unsigned i = 0; i < memory_pool.size(); i++) {
+ if (mem_pool_info[i].pool_state == MemoryPoolStates::RequestAttach)
+ memory_pool[i].state = MemoryPoolStates::Attached;
+ else if (mem_pool_info[i].pool_state == MemoryPoolStates::RequestDetach)
+ memory_pool[i].state = MemoryPoolStates::Detached;
+ else
+ memory_pool[i].state = mem_pool_info[i].pool_state;
}
+ std::memcpy(output.data() + sizeof(UpdateDataHeader), memory_pool.data(),
+ response_data.memory_pools_size);
+
+ for (unsigned i = 0; i < voice_info.size(); i++) {
+ if (voice_info[i].is_new) {
+ voice_status_list[i].played_sample_count = 0;
+ voice_status_list[i].wave_buffer_consumed = 0;
+ } else if (voice_info[i].play_state == (u8)PlayStates::Started) {
+ for (u32 buff_idx = 0; buff_idx < voice_info[i].wave_buffer_count; buff_idx++) {
+ voice_status_list[i].played_sample_count +=
+ (voice_info[i].wave_buffer[buff_idx].end_sample_offset -
+ voice_info[i].wave_buffer[buff_idx].start_sample_offset) /
+ 2;
+ voice_status_list[i].wave_buffer_consumed++;
+ }
+ }
+ }
+ std::memcpy(output.data() + sizeof(UpdateDataHeader) + response_data.memory_pools_size,
+ voice_status_list.data(), response_data.voices_size);
- ctx.WriteBuffer(&response_data, response_data.total_size);
+ ctx.WriteBuffer(output);
IPC::ResponseBuilder rb{ctx, 2};
-
rb.Push(RESULT_SUCCESS);
- NGLOG_WARNING(Service_Audio, "(STUBBED) called");
+ LOG_WARNING(Service_Audio, "(STUBBED) called");
}
void StartAudioRenderer(Kernel::HLERequestContext& ctx) {
@@ -88,7 +123,7 @@ private:
rb.Push(RESULT_SUCCESS);
- NGLOG_WARNING(Service_Audio, "(STUBBED) called");
+ LOG_WARNING(Service_Audio, "(STUBBED) called");
}
void StopAudioRenderer(Kernel::HLERequestContext& ctx) {
@@ -96,7 +131,7 @@ private:
rb.Push(RESULT_SUCCESS);
- NGLOG_WARNING(Service_Audio, "(STUBBED) called");
+ LOG_WARNING(Service_Audio, "(STUBBED) called");
}
void QuerySystemEvent(Kernel::HLERequestContext& ctx) {
@@ -106,51 +141,132 @@ private:
rb.Push(RESULT_SUCCESS);
rb.PushCopyObjects(system_event);
- NGLOG_WARNING(Service_Audio, "(STUBBED) called");
+ LOG_WARNING(Service_Audio, "(STUBBED) called");
}
- struct AudioRendererStateEntry {
- u32_le state;
+ enum class MemoryPoolStates : u32 { // Should be LE
+ Invalid = 0x0,
+ Unknown = 0x1,
+ RequestDetach = 0x2,
+ Detached = 0x3,
+ RequestAttach = 0x4,
+ Attached = 0x5,
+ Released = 0x6,
+ };
+
+ enum class PlayStates : u8 {
+ Started = 0,
+ Stopped = 1,
+ };
+
+ struct MemoryPoolEntry {
+ MemoryPoolStates state;
u32_le unknown_4;
u32_le unknown_8;
u32_le unknown_c;
};
- static_assert(sizeof(AudioRendererStateEntry) == 0x10,
- "AudioRendererStateEntry has wrong size");
-
- struct AudioRendererResponseData {
- u32_le unknown_0;
- u32_le section_5_size;
- u32_le section_0_size;
- u32_le section_1_size;
- u32_le unknown_10;
- u32_le section_2_size;
- u32_le unknown_18;
- u32_le section_3_size;
- u32_le section_4_size;
- u32_le unknown_24;
- u32_le unknown_28;
- u32_le unknown_2c;
- u32_le unknown_30;
- u32_le unknown_34;
- u32_le unknown_38;
+ static_assert(sizeof(MemoryPoolEntry) == 0x10, "MemoryPoolEntry has wrong size");
+
+ struct MemoryPoolInfo {
+ u64_le pool_address;
+ u64_le pool_size;
+ MemoryPoolStates pool_state;
+ INSERT_PADDING_WORDS(3); // Unknown
+ };
+ static_assert(sizeof(MemoryPoolInfo) == 0x20, "MemoryPoolInfo has wrong size");
+
+ struct UpdateDataHeader {
+ UpdateDataHeader() {}
+
+ UpdateDataHeader(const AudioRendererParameter& config) {
+ revision = Common::MakeMagic('R', 'E', 'V', '4'); // 5.1.0 Revision
+ behavior_size = 0xb0;
+ memory_pools_size = (config.effect_count + (config.voice_count * 4)) * 0x10;
+ voices_size = config.voice_count * 0x10;
+ effects_size = config.effect_count * 0x10;
+ sinks_size = config.sink_count * 0x20;
+ performance_manager_size = 0x10;
+ total_size = sizeof(UpdateDataHeader) + behavior_size + memory_pools_size +
+ voices_size + effects_size + sinks_size + performance_manager_size;
+ }
+
+ u32_le revision;
+ u32_le behavior_size;
+ u32_le memory_pools_size;
+ u32_le voices_size;
+ u32_le voice_resource_size;
+ u32_le effects_size;
+ u32_le mixes_size;
+ u32_le sinks_size;
+ u32_le performance_manager_size;
+ INSERT_PADDING_WORDS(6);
u32_le total_size;
+ };
+ static_assert(sizeof(UpdateDataHeader) == 0x40, "UpdateDataHeader has wrong size");
- std::array<AudioRendererStateEntry, 0x18e> state_entries;
+ struct BiquadFilter {
+ u8 enable;
+ INSERT_PADDING_BYTES(1);
+ s16_le numerator[3];
+ s16_le denominator[2];
+ };
+ static_assert(sizeof(BiquadFilter) == 0xc, "BiquadFilter has wrong size");
+
+ struct WaveBuffer {
+ u64_le buffer_addr;
+ u64_le buffer_sz;
+ s32_le start_sample_offset;
+ s32_le end_sample_offset;
+ u8 loop;
+ u8 end_of_stream;
+ u8 sent_to_server;
+ INSERT_PADDING_BYTES(5);
+ u64 context_addr;
+ u64 context_sz;
+ INSERT_PADDING_BYTES(8);
+ };
+ static_assert(sizeof(WaveBuffer) == 0x38, "WaveBuffer has wrong size");
+
+ struct VoiceInfo {
+ u32_le id;
+ u32_le node_id;
+ u8 is_new;
+ u8 is_in_use;
+ u8 play_state;
+ u8 sample_format;
+ u32_le sample_rate;
+ u32_le priority;
+ u32_le sorting_order;
+ u32_le channel_count;
+ float_le pitch;
+ float_le volume;
+ BiquadFilter biquad_filter[2];
+ u32_le wave_buffer_count;
+ u16_le wave_buffer_head;
+ INSERT_PADDING_BYTES(6);
+ u64_le additional_params_addr;
+ u64_le additional_params_sz;
+ u32_le mix_id;
+ u32_le splitter_info_id;
+ WaveBuffer wave_buffer[4];
+ u32_le voice_channel_resource_ids[6];
+ INSERT_PADDING_BYTES(24);
+ };
+ static_assert(sizeof(VoiceInfo) == 0x170, "VoiceInfo is wrong size");
- std::array<u8, 0x600> section_1;
- std::array<u8, 0xe0> section_2;
- std::array<u8, 0x20> section_3;
- std::array<u8, 0x10> section_4;
- std::array<u8, 0xb0> section_5;
+ struct VoiceOutStatus {
+ u64_le played_sample_count;
+ u32_le wave_buffer_consumed;
+ INSERT_PADDING_WORDS(1);
};
- static_assert(sizeof(AudioRendererResponseData) == 0x20e0,
- "AudioRendererResponseData has wrong size");
+ static_assert(sizeof(VoiceOutStatus) == 0x10, "VoiceOutStatus has wrong size");
/// This is used to trigger the audio event callback.
CoreTiming::EventType* audio_event;
Kernel::SharedPtr<Kernel::Event> system_event;
+ AudioRendererParameter worker_params;
+ std::vector<VoiceOutStatus> voice_status_list;
};
class IAudioDevice final : public ServiceFramework<IAudioDevice> {
@@ -179,7 +295,7 @@ public:
private:
void ListAudioDeviceName(Kernel::HLERequestContext& ctx) {
- NGLOG_WARNING(Service_Audio, "(STUBBED) called");
+ LOG_WARNING(Service_Audio, "(STUBBED) called");
IPC::RequestParser rp{ctx};
const std::string audio_interface = "AudioInterface";
@@ -191,7 +307,7 @@ private:
}
void SetAudioDeviceOutputVolume(Kernel::HLERequestContext& ctx) {
- NGLOG_WARNING(Service_Audio, "(STUBBED) called");
+ LOG_WARNING(Service_Audio, "(STUBBED) called");
IPC::RequestParser rp{ctx};
f32 volume = static_cast<f32>(rp.Pop<u32>());
@@ -204,7 +320,7 @@ private:
}
void GetActiveAudioDeviceName(Kernel::HLERequestContext& ctx) {
- NGLOG_WARNING(Service_Audio, "(STUBBED) called");
+ LOG_WARNING(Service_Audio, "(STUBBED) called");
IPC::RequestParser rp{ctx};
const std::string audio_interface = "AudioDevice";
@@ -216,7 +332,7 @@ private:
}
void QueryAudioDeviceSystemEvent(Kernel::HLERequestContext& ctx) {
- NGLOG_WARNING(Service_Audio, "(STUBBED) called");
+ LOG_WARNING(Service_Audio, "(STUBBED) called");
buffer_event->Signal();
@@ -226,7 +342,7 @@ private:
}
void GetActiveChannelCount(Kernel::HLERequestContext& ctx) {
- NGLOG_WARNING(Service_Audio, "(STUBBED) called");
+ LOG_WARNING(Service_Audio, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push<u32>(1);
@@ -248,31 +364,33 @@ AudRenU::AudRenU() : ServiceFramework("audren:u") {
}
void AudRenU::OpenAudioRenderer(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ auto params = rp.PopRaw<AudioRendererParameter>();
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushIpcInterface<Audio::IAudioRenderer>();
+ rb.PushIpcInterface<Audio::IAudioRenderer>(std::move(params));
- NGLOG_DEBUG(Service_Audio, "called");
+ LOG_DEBUG(Service_Audio, "called");
}
void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
- auto params = rp.PopRaw<WorkerBufferParameters>();
+ auto params = rp.PopRaw<AudioRendererParameter>();
- u64 buffer_sz = Common::AlignUp(4 * params.unknown8, 0x40);
- buffer_sz += params.unknownC * 1024;
- buffer_sz += 0x940 * (params.unknownC + 1);
+ u64 buffer_sz = Common::AlignUp(4 * params.unknown_8, 0x40);
+ buffer_sz += params.unknown_c * 1024;
+ buffer_sz += 0x940 * (params.unknown_c + 1);
buffer_sz += 0x3F0 * params.voice_count;
- buffer_sz += Common::AlignUp(8 * (params.unknownC + 1), 0x10);
+ buffer_sz += Common::AlignUp(8 * (params.unknown_c + 1), 0x10);
buffer_sz += Common::AlignUp(8 * params.voice_count, 0x10);
buffer_sz +=
- Common::AlignUp((0x3C0 * (params.sink_count + params.unknownC) + 4 * params.sample_count) *
- (params.unknown8 + 6),
+ Common::AlignUp((0x3C0 * (params.sink_count + params.unknown_c) + 4 * params.sample_count) *
+ (params.unknown_8 + 6),
0x40);
- if (IsFeatureSupported(AudioFeatures::Splitter, params.magic)) {
- u32 count = params.unknownC + 1;
+ if (IsFeatureSupported(AudioFeatures::Splitter, params.revision)) {
+ u32 count = params.unknown_c + 1;
u64 node_count = Common::AlignUp(count, 0x40);
u64 node_state_buffer_sz =
4 * (node_count * node_count) + 0xC * node_count + 2 * (node_count / 8);
@@ -287,20 +405,20 @@ void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) {
}
buffer_sz += 0x20 * (params.effect_count + 4 * params.voice_count) + 0x50;
- if (IsFeatureSupported(AudioFeatures::Splitter, params.magic)) {
- buffer_sz += 0xE0 * params.unknown2c;
+ if (IsFeatureSupported(AudioFeatures::Splitter, params.revision)) {
+ buffer_sz += 0xE0 * params.unknown_2c;
buffer_sz += 0x20 * params.splitter_count;
- buffer_sz += Common::AlignUp(4 * params.unknown2c, 0x10);
+ buffer_sz += Common::AlignUp(4 * params.unknown_2c, 0x10);
}
buffer_sz = Common::AlignUp(buffer_sz, 0x40) + 0x170 * params.sink_count;
u64 output_sz = buffer_sz + 0x280 * params.sink_count + 0x4B0 * params.effect_count +
((params.voice_count * 256) | 0x40);
- if (params.unknown1c >= 1) {
+ if (params.unknown_1c >= 1) {
output_sz = Common::AlignUp(((16 * params.sink_count + 16 * params.effect_count +
16 * params.voice_count + 16) +
0x658) *
- (params.unknown1c + 1) +
+ (params.unknown_1c + 1) +
0xc0,
0x40) +
output_sz;
@@ -312,7 +430,7 @@ void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) {
rb.Push(RESULT_SUCCESS);
rb.Push<u64>(output_sz);
- NGLOG_DEBUG(Service_Audio, "called, buffer_size=0x{:X}", output_sz);
+ LOG_DEBUG(Service_Audio, "called, buffer_size=0x{:X}", output_sz);
}
void AudRenU::GetAudioDevice(Kernel::HLERequestContext& ctx) {
@@ -321,14 +439,14 @@ void AudRenU::GetAudioDevice(Kernel::HLERequestContext& ctx) {
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<Audio::IAudioDevice>();
- NGLOG_DEBUG(Service_Audio, "called");
+ LOG_DEBUG(Service_Audio, "called");
}
bool AudRenU::IsFeatureSupported(AudioFeatures feature, u32_le revision) const {
u32_be version_num = (revision - Common::MakeMagic('R', 'E', 'V', '0')); // Byte swap
switch (feature) {
case AudioFeatures::Splitter:
- return version_num >= 2;
+ return version_num >= 2u;
default:
return false;
}