diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/audio_core/CMakeLists.txt | 3 | ||||
| -rw-r--r-- | src/audio_core/audio_renderer.cpp | 32 | ||||
| -rw-r--r-- | src/audio_core/audio_renderer.h | 5 | ||||
| -rw-r--r-- | src/audio_core/behavior_info.cpp | 100 | ||||
| -rw-r--r-- | src/audio_core/behavior_info.h | 66 | ||||
| -rw-r--r-- | src/audio_core/common.h | 47 | ||||
| -rw-r--r-- | src/core/hle/service/audio/audren_u.cpp | 9 |
7 files changed, 249 insertions, 13 deletions
diff --git a/src/audio_core/CMakeLists.txt b/src/audio_core/CMakeLists.txt index c381dbe1d..5ef38a337 100644 --- a/src/audio_core/CMakeLists.txt +++ b/src/audio_core/CMakeLists.txt | |||
| @@ -7,9 +7,12 @@ add_library(audio_core STATIC | |||
| 7 | audio_out.h | 7 | audio_out.h |
| 8 | audio_renderer.cpp | 8 | audio_renderer.cpp |
| 9 | audio_renderer.h | 9 | audio_renderer.h |
| 10 | behavior_info.cpp | ||
| 11 | behavior_info.h | ||
| 10 | buffer.h | 12 | buffer.h |
| 11 | codec.cpp | 13 | codec.cpp |
| 12 | codec.h | 14 | codec.h |
| 15 | common.h | ||
| 13 | null_sink.h | 16 | null_sink.h |
| 14 | sink.h | 17 | sink.h |
| 15 | sink_details.cpp | 18 | sink_details.cpp |
diff --git a/src/audio_core/audio_renderer.cpp b/src/audio_core/audio_renderer.cpp index 7a9dc61d4..d18ef6940 100644 --- a/src/audio_core/audio_renderer.cpp +++ b/src/audio_core/audio_renderer.cpp | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | #include "audio_core/audio_out.h" | 6 | #include "audio_core/audio_out.h" |
| 7 | #include "audio_core/audio_renderer.h" | 7 | #include "audio_core/audio_renderer.h" |
| 8 | #include "audio_core/codec.h" | 8 | #include "audio_core/codec.h" |
| 9 | #include "audio_core/common.h" | ||
| 9 | #include "common/assert.h" | 10 | #include "common/assert.h" |
| 10 | #include "common/logging/log.h" | 11 | #include "common/logging/log.h" |
| 11 | #include "core/core.h" | 12 | #include "core/core.h" |
| @@ -79,7 +80,7 @@ AudioRenderer::AudioRenderer(Core::Timing::CoreTiming& core_timing, Core::Memory | |||
| 79 | std::size_t instance_number) | 80 | std::size_t instance_number) |
| 80 | : worker_params{params}, buffer_event{buffer_event}, voices(params.voice_count), | 81 | : worker_params{params}, buffer_event{buffer_event}, voices(params.voice_count), |
| 81 | effects(params.effect_count), memory{memory_} { | 82 | effects(params.effect_count), memory{memory_} { |
| 82 | 83 | behavior_info.SetUserRevision(params.revision); | |
| 83 | audio_out = std::make_unique<AudioCore::AudioOut>(); | 84 | audio_out = std::make_unique<AudioCore::AudioOut>(); |
| 84 | stream = audio_out->OpenStream(core_timing, STREAM_SAMPLE_RATE, STREAM_NUM_CHANNELS, | 85 | stream = audio_out->OpenStream(core_timing, STREAM_SAMPLE_RATE, STREAM_NUM_CHANNELS, |
| 85 | fmt::format("AudioRenderer-Instance{}", instance_number), | 86 | fmt::format("AudioRenderer-Instance{}", instance_number), |
| @@ -109,17 +110,17 @@ Stream::State AudioRenderer::GetStreamState() const { | |||
| 109 | return stream->GetState(); | 110 | return stream->GetState(); |
| 110 | } | 111 | } |
| 111 | 112 | ||
| 112 | static constexpr u32 VersionFromRevision(u32_le rev) { | 113 | ResultVal<std::vector<u8>> AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_params) { |
| 113 | // "REV7" -> 7 | ||
| 114 | return ((rev >> 24) & 0xff) - 0x30; | ||
| 115 | } | ||
| 116 | |||
| 117 | std::vector<u8> AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_params) { | ||
| 118 | // Copy UpdateDataHeader struct | 114 | // Copy UpdateDataHeader struct |
| 119 | UpdateDataHeader config{}; | 115 | UpdateDataHeader config{}; |
| 120 | std::memcpy(&config, input_params.data(), sizeof(UpdateDataHeader)); | 116 | std::memcpy(&config, input_params.data(), sizeof(UpdateDataHeader)); |
| 121 | u32 memory_pool_count = worker_params.effect_count + (worker_params.voice_count * 4); | 117 | u32 memory_pool_count = worker_params.effect_count + (worker_params.voice_count * 4); |
| 122 | 118 | ||
| 119 | if (!behavior_info.UpdateInput(input_params, sizeof(UpdateDataHeader))) { | ||
| 120 | LOG_ERROR(Audio, "Failed to update behavior info input parameters"); | ||
| 121 | return Audren::ERR_INVALID_PARAMETERS; | ||
| 122 | } | ||
| 123 | |||
| 123 | // Copy MemoryPoolInfo structs | 124 | // Copy MemoryPoolInfo structs |
| 124 | std::vector<MemoryPoolInfo> mem_pool_info(memory_pool_count); | 125 | std::vector<MemoryPoolInfo> mem_pool_info(memory_pool_count); |
| 125 | std::memcpy(mem_pool_info.data(), | 126 | std::memcpy(mem_pool_info.data(), |
| @@ -173,8 +174,7 @@ std::vector<u8> AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_ | |||
| 173 | // Copy output header | 174 | // Copy output header |
| 174 | UpdateDataHeader response_data{worker_params}; | 175 | UpdateDataHeader response_data{worker_params}; |
| 175 | std::vector<u8> output_params(response_data.total_size); | 176 | std::vector<u8> output_params(response_data.total_size); |
| 176 | const auto audren_revision = VersionFromRevision(config.revision); | 177 | if (behavior_info.IsElapsedFrameCountSupported()) { |
| 177 | if (audren_revision >= 5) { | ||
| 178 | response_data.frame_count = 0x10; | 178 | response_data.frame_count = 0x10; |
| 179 | response_data.total_size += 0x10; | 179 | response_data.total_size += 0x10; |
| 180 | } | 180 | } |
| @@ -200,7 +200,19 @@ std::vector<u8> AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_ | |||
| 200 | sizeof(EffectOutStatus)); | 200 | sizeof(EffectOutStatus)); |
| 201 | effect_out_status_offset += sizeof(EffectOutStatus); | 201 | effect_out_status_offset += sizeof(EffectOutStatus); |
| 202 | } | 202 | } |
| 203 | return output_params; | 203 | |
| 204 | // Update behavior info output | ||
| 205 | const std::size_t behavior_out_status_offset{ | ||
| 206 | sizeof(UpdateDataHeader) + response_data.memory_pools_size + response_data.voices_size + | ||
| 207 | response_data.effects_size + response_data.sinks_size + | ||
| 208 | response_data.performance_manager_size}; | ||
| 209 | |||
| 210 | if (!behavior_info.UpdateOutput(output_params, behavior_out_status_offset)) { | ||
| 211 | LOG_ERROR(Audio, "Failed to update behavior info output parameters"); | ||
| 212 | return Audren::ERR_INVALID_PARAMETERS; | ||
| 213 | } | ||
| 214 | |||
| 215 | return MakeResult(output_params); | ||
| 204 | } | 216 | } |
| 205 | 217 | ||
| 206 | void AudioRenderer::VoiceState::SetWaveIndex(std::size_t index) { | 218 | void AudioRenderer::VoiceState::SetWaveIndex(std::size_t index) { |
diff --git a/src/audio_core/audio_renderer.h b/src/audio_core/audio_renderer.h index 62faf9f19..b42770fae 100644 --- a/src/audio_core/audio_renderer.h +++ b/src/audio_core/audio_renderer.h | |||
| @@ -8,11 +8,13 @@ | |||
| 8 | #include <memory> | 8 | #include <memory> |
| 9 | #include <vector> | 9 | #include <vector> |
| 10 | 10 | ||
| 11 | #include "audio_core/behavior_info.h" | ||
| 11 | #include "audio_core/stream.h" | 12 | #include "audio_core/stream.h" |
| 12 | #include "common/common_funcs.h" | 13 | #include "common/common_funcs.h" |
| 13 | #include "common/common_types.h" | 14 | #include "common/common_types.h" |
| 14 | #include "common/swap.h" | 15 | #include "common/swap.h" |
| 15 | #include "core/hle/kernel/object.h" | 16 | #include "core/hle/kernel/object.h" |
| 17 | #include "core/hle/result.h" | ||
| 16 | 18 | ||
| 17 | namespace Core::Timing { | 19 | namespace Core::Timing { |
| 18 | class CoreTiming; | 20 | class CoreTiming; |
| @@ -226,7 +228,7 @@ public: | |||
| 226 | std::shared_ptr<Kernel::WritableEvent> buffer_event, std::size_t instance_number); | 228 | std::shared_ptr<Kernel::WritableEvent> buffer_event, std::size_t instance_number); |
| 227 | ~AudioRenderer(); | 229 | ~AudioRenderer(); |
| 228 | 230 | ||
| 229 | std::vector<u8> UpdateAudioRenderer(const std::vector<u8>& input_params); | 231 | ResultVal<std::vector<u8>> UpdateAudioRenderer(const std::vector<u8>& input_params); |
| 230 | void QueueMixedBuffer(Buffer::Tag tag); | 232 | void QueueMixedBuffer(Buffer::Tag tag); |
| 231 | void ReleaseAndQueueBuffers(); | 233 | void ReleaseAndQueueBuffers(); |
| 232 | u32 GetSampleRate() const; | 234 | u32 GetSampleRate() const; |
| @@ -237,6 +239,7 @@ public: | |||
| 237 | private: | 239 | private: |
| 238 | class EffectState; | 240 | class EffectState; |
| 239 | class VoiceState; | 241 | class VoiceState; |
| 242 | BehaviorInfo behavior_info{}; | ||
| 240 | 243 | ||
| 241 | AudioRendererParameter worker_params; | 244 | AudioRendererParameter worker_params; |
| 242 | std::shared_ptr<Kernel::WritableEvent> buffer_event; | 245 | std::shared_ptr<Kernel::WritableEvent> buffer_event; |
diff --git a/src/audio_core/behavior_info.cpp b/src/audio_core/behavior_info.cpp new file mode 100644 index 000000000..94b7a3bf1 --- /dev/null +++ b/src/audio_core/behavior_info.cpp | |||
| @@ -0,0 +1,100 @@ | |||
| 1 | // Copyright 2020 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <cstring> | ||
| 6 | #include "audio_core/behavior_info.h" | ||
| 7 | #include "audio_core/common.h" | ||
| 8 | #include "common/logging/log.h" | ||
| 9 | |||
| 10 | namespace AudioCore { | ||
| 11 | |||
| 12 | BehaviorInfo::BehaviorInfo() : process_revision(CURRENT_PROCESS_REVISION) {} | ||
| 13 | BehaviorInfo::~BehaviorInfo() = default; | ||
| 14 | |||
| 15 | bool BehaviorInfo::UpdateInput(const std::vector<u8>& buffer, std::size_t offset) { | ||
| 16 | if (!CanConsumeBuffer(buffer.size(), offset, sizeof(InParams))) { | ||
| 17 | LOG_ERROR(Audio, "Buffer is an invalid size!"); | ||
| 18 | return false; | ||
| 19 | } | ||
| 20 | InParams params{}; | ||
| 21 | std::memcpy(¶ms, buffer.data() + offset, sizeof(InParams)); | ||
| 22 | |||
| 23 | if (!IsValidRevision(params.revision)) { | ||
| 24 | LOG_ERROR(Audio, "Invalid input revision, revision=0x{:08X}", params.revision); | ||
| 25 | return false; | ||
| 26 | } | ||
| 27 | |||
| 28 | if (user_revision != params.revision) { | ||
| 29 | LOG_ERROR(Audio, | ||
| 30 | "User revision differs from input revision, expecting 0x{:08X} but got 0x{:08X}", | ||
| 31 | user_revision, params.revision); | ||
| 32 | return false; | ||
| 33 | } | ||
| 34 | |||
| 35 | ClearError(); | ||
| 36 | UpdateFlags(params.flags); | ||
| 37 | |||
| 38 | // TODO(ogniK): Check input params size when InfoUpdater is used | ||
| 39 | |||
| 40 | return true; | ||
| 41 | } | ||
| 42 | |||
| 43 | bool BehaviorInfo::UpdateOutput(std::vector<u8>& buffer, std::size_t offset) { | ||
| 44 | if (!CanConsumeBuffer(buffer.size(), offset, sizeof(OutParams))) { | ||
| 45 | LOG_ERROR(Audio, "Buffer is an invalid size!"); | ||
| 46 | return false; | ||
| 47 | } | ||
| 48 | |||
| 49 | OutParams params{}; | ||
| 50 | std::memcpy(params.errors.data(), errors.data(), sizeof(ErrorInfo) * errors.size()); | ||
| 51 | params.error_count = static_cast<u32_le>(error_count); | ||
| 52 | std::memcpy(buffer.data() + offset, ¶ms, sizeof(OutParams)); | ||
| 53 | return true; | ||
| 54 | } | ||
| 55 | |||
| 56 | void BehaviorInfo::ClearError() { | ||
| 57 | error_count = 0; | ||
| 58 | } | ||
| 59 | |||
| 60 | void BehaviorInfo::UpdateFlags(u64_le dest_flags) { | ||
| 61 | flags = dest_flags; | ||
| 62 | } | ||
| 63 | |||
| 64 | void BehaviorInfo::SetUserRevision(u32_le revision) { | ||
| 65 | user_revision = revision; | ||
| 66 | } | ||
| 67 | |||
| 68 | bool BehaviorInfo::IsAdpcmLoopContextBugFixed() const { | ||
| 69 | return IsRevisionSupported(2, user_revision); | ||
| 70 | } | ||
| 71 | |||
| 72 | bool BehaviorInfo::IsSplitterSupported() const { | ||
| 73 | return IsRevisionSupported(2, user_revision); | ||
| 74 | } | ||
| 75 | |||
| 76 | bool BehaviorInfo::IsLongSizePreDelaySupported() const { | ||
| 77 | return IsRevisionSupported(3, user_revision); | ||
| 78 | } | ||
| 79 | |||
| 80 | bool BehaviorInfo::IsAudioRenererProcessingTimeLimit80PercentSupported() const { | ||
| 81 | return IsRevisionSupported(5, user_revision); | ||
| 82 | } | ||
| 83 | |||
| 84 | bool BehaviorInfo::IsAudioRenererProcessingTimeLimit75PercentSupported() const { | ||
| 85 | return IsRevisionSupported(4, user_revision); | ||
| 86 | } | ||
| 87 | |||
| 88 | bool BehaviorInfo::IsAudioRenererProcessingTimeLimit70PercentSupported() const { | ||
| 89 | return IsRevisionSupported(1, user_revision); | ||
| 90 | } | ||
| 91 | |||
| 92 | bool BehaviorInfo::IsElapsedFrameCountSupported() const { | ||
| 93 | return IsRevisionSupported(5, user_revision); | ||
| 94 | } | ||
| 95 | |||
| 96 | bool BehaviorInfo::IsMemoryPoolForceMappingEnabled() const { | ||
| 97 | return (flags & 1) != 0; | ||
| 98 | } | ||
| 99 | |||
| 100 | } // namespace AudioCore | ||
diff --git a/src/audio_core/behavior_info.h b/src/audio_core/behavior_info.h new file mode 100644 index 000000000..c5e91ab39 --- /dev/null +++ b/src/audio_core/behavior_info.h | |||
| @@ -0,0 +1,66 @@ | |||
| 1 | // Copyright 2020 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <array> | ||
| 8 | |||
| 9 | #include <vector> | ||
| 10 | #include "common/common_funcs.h" | ||
| 11 | #include "common/common_types.h" | ||
| 12 | #include "common/swap.h" | ||
| 13 | |||
| 14 | namespace AudioCore { | ||
| 15 | class BehaviorInfo { | ||
| 16 | public: | ||
| 17 | explicit BehaviorInfo(); | ||
| 18 | ~BehaviorInfo(); | ||
| 19 | |||
| 20 | bool UpdateInput(const std::vector<u8>& buffer, std::size_t offset); | ||
| 21 | bool UpdateOutput(std::vector<u8>& buffer, std::size_t offset); | ||
| 22 | |||
| 23 | void ClearError(); | ||
| 24 | void UpdateFlags(u64_le dest_flags); | ||
| 25 | void SetUserRevision(u32_le revision); | ||
| 26 | |||
| 27 | bool IsAdpcmLoopContextBugFixed() const; | ||
| 28 | bool IsSplitterSupported() const; | ||
| 29 | bool IsLongSizePreDelaySupported() const; | ||
| 30 | bool IsAudioRenererProcessingTimeLimit80PercentSupported() const; | ||
| 31 | bool IsAudioRenererProcessingTimeLimit75PercentSupported() const; | ||
| 32 | bool IsAudioRenererProcessingTimeLimit70PercentSupported() const; | ||
| 33 | bool IsElapsedFrameCountSupported() const; | ||
| 34 | bool IsMemoryPoolForceMappingEnabled() const; | ||
| 35 | |||
| 36 | private: | ||
| 37 | u32_le process_revision{}; | ||
| 38 | u32_le user_revision{}; | ||
| 39 | u64_le flags{}; | ||
| 40 | |||
| 41 | struct ErrorInfo { | ||
| 42 | u32_le result{}; | ||
| 43 | INSERT_PADDING_WORDS(1); | ||
| 44 | u64_le result_info{}; | ||
| 45 | }; | ||
| 46 | static_assert(sizeof(ErrorInfo) == 0x10, "ErrorInfo is an invalid size"); | ||
| 47 | |||
| 48 | std::array<ErrorInfo, 10> errors{}; | ||
| 49 | std::size_t error_count{}; | ||
| 50 | |||
| 51 | struct InParams { | ||
| 52 | u32_le revision{}; | ||
| 53 | u32_le padding{}; | ||
| 54 | u64_le flags{}; | ||
| 55 | }; | ||
| 56 | static_assert(sizeof(InParams) == 0x10, "InParams is an invalid size"); | ||
| 57 | |||
| 58 | struct OutParams { | ||
| 59 | std::array<ErrorInfo, 10> errors{}; | ||
| 60 | u32_le error_count{}; | ||
| 61 | INSERT_PADDING_BYTES(12); | ||
| 62 | }; | ||
| 63 | static_assert(sizeof(OutParams) == 0xb0, "OutParams is an invalid size"); | ||
| 64 | }; | ||
| 65 | |||
| 66 | } // namespace AudioCore | ||
diff --git a/src/audio_core/common.h b/src/audio_core/common.h new file mode 100644 index 000000000..98478b66b --- /dev/null +++ b/src/audio_core/common.h | |||
| @@ -0,0 +1,47 @@ | |||
| 1 | // Copyright 2020 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | #include "common/common_funcs.h" | ||
| 7 | #include "common/common_types.h" | ||
| 8 | #include "common/swap.h" | ||
| 9 | #include "core/hle/result.h" | ||
| 10 | |||
| 11 | namespace AudioCore { | ||
| 12 | namespace Audren { | ||
| 13 | constexpr ResultCode ERR_INVALID_PARAMETERS{ErrorModule::Audio, 41}; | ||
| 14 | } | ||
| 15 | |||
| 16 | constexpr u32_le CURRENT_PROCESS_REVISION = Common::MakeMagic('R', 'E', 'V', '8'); | ||
| 17 | |||
| 18 | static constexpr u32 VersionFromRevision(u32_le rev) { | ||
| 19 | // "REV7" -> 7 | ||
| 20 | return ((rev >> 24) & 0xff) - 0x30; | ||
| 21 | } | ||
| 22 | |||
| 23 | static constexpr bool IsRevisionSupported(u32 required, u32_le user_revision) { | ||
| 24 | const auto base = VersionFromRevision(user_revision); | ||
| 25 | return required <= base; | ||
| 26 | } | ||
| 27 | |||
| 28 | static constexpr bool IsValidRevision(u32_le revision) { | ||
| 29 | const auto base = VersionFromRevision(revision); | ||
| 30 | constexpr auto max_rev = VersionFromRevision(CURRENT_PROCESS_REVISION); | ||
| 31 | return base <= max_rev; | ||
| 32 | } | ||
| 33 | |||
| 34 | static constexpr bool CanConsumeBuffer(std::size_t size, std::size_t offset, std::size_t required) { | ||
| 35 | if (offset > size) { | ||
| 36 | return false; | ||
| 37 | } | ||
| 38 | if (size < required) { | ||
| 39 | return false; | ||
| 40 | } | ||
| 41 | if ((size - offset) < required) { | ||
| 42 | return false; | ||
| 43 | } | ||
| 44 | return true; | ||
| 45 | } | ||
| 46 | |||
| 47 | } // namespace AudioCore | ||
diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp index 07dd2caec..d8359abaa 100644 --- a/src/core/hle/service/audio/audren_u.cpp +++ b/src/core/hle/service/audio/audren_u.cpp | |||
| @@ -94,9 +94,14 @@ private: | |||
| 94 | void RequestUpdateImpl(Kernel::HLERequestContext& ctx) { | 94 | void RequestUpdateImpl(Kernel::HLERequestContext& ctx) { |
| 95 | LOG_DEBUG(Service_Audio, "(STUBBED) called"); | 95 | LOG_DEBUG(Service_Audio, "(STUBBED) called"); |
| 96 | 96 | ||
| 97 | ctx.WriteBuffer(renderer->UpdateAudioRenderer(ctx.ReadBuffer())); | 97 | auto result = renderer->UpdateAudioRenderer(ctx.ReadBuffer()); |
| 98 | |||
| 99 | if (result.Succeeded()) { | ||
| 100 | ctx.WriteBuffer(result.Unwrap()); | ||
| 101 | } | ||
| 102 | |||
| 98 | IPC::ResponseBuilder rb{ctx, 2}; | 103 | IPC::ResponseBuilder rb{ctx, 2}; |
| 99 | rb.Push(RESULT_SUCCESS); | 104 | rb.Push(result.Code()); |
| 100 | } | 105 | } |
| 101 | 106 | ||
| 102 | void Start(Kernel::HLERequestContext& ctx) { | 107 | void Start(Kernel::HLERequestContext& ctx) { |