diff options
Diffstat (limited to 'src/core/hle/service/audio/audren_u.cpp')
-rw-r--r-- | src/core/hle/service/audio/audren_u.cpp | 268 |
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; } |