summaryrefslogtreecommitdiff
path: root/src/audio_core/opus/decoder.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/audio_core/opus/decoder.cpp')
-rw-r--r--src/audio_core/opus/decoder.cpp179
1 files changed, 179 insertions, 0 deletions
diff --git a/src/audio_core/opus/decoder.cpp b/src/audio_core/opus/decoder.cpp
new file mode 100644
index 000000000..5b23fce14
--- /dev/null
+++ b/src/audio_core/opus/decoder.cpp
@@ -0,0 +1,179 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "audio_core/opus/decoder.h"
5#include "audio_core/opus/hardware_opus.h"
6#include "audio_core/opus/parameters.h"
7#include "common/alignment.h"
8#include "common/swap.h"
9#include "core/core.h"
10
11namespace AudioCore::OpusDecoder {
12using namespace Service::Audio;
13namespace {
14OpusPacketHeader ReverseHeader(OpusPacketHeader header) {
15 OpusPacketHeader out;
16 out.size = Common::swap32(header.size);
17 out.final_range = Common::swap32(header.final_range);
18 return out;
19}
20} // namespace
21
22OpusDecoder::OpusDecoder(Core::System& system_, HardwareOpus& hardware_opus_)
23 : system{system_}, hardware_opus{hardware_opus_} {}
24
25OpusDecoder::~OpusDecoder() {
26 if (decode_object_initialized) {
27 hardware_opus.ShutdownDecodeObject(shared_buffer.get(), shared_buffer_size);
28 }
29}
30
31Result OpusDecoder::Initialize(OpusParametersEx& params, Kernel::KTransferMemory* transfer_memory,
32 u64 transfer_memory_size) {
33 auto frame_size{params.use_large_frame_size ? 5760 : 1920};
34 shared_buffer_size = transfer_memory_size;
35 shared_buffer = std::make_unique<u8[]>(shared_buffer_size);
36 shared_memory_mapped = true;
37
38 buffer_size =
39 Common::AlignUp((frame_size * params.channel_count) / (48'000 / params.sample_rate), 16);
40
41 out_data = {shared_buffer.get() + shared_buffer_size - buffer_size, buffer_size};
42 size_t in_data_size{0x600u};
43 in_data = {out_data.data() - in_data_size, in_data_size};
44
45 ON_RESULT_FAILURE {
46 if (shared_memory_mapped) {
47 shared_memory_mapped = false;
48 ASSERT(R_SUCCEEDED(hardware_opus.UnmapMemory(shared_buffer.get(), shared_buffer_size)));
49 }
50 };
51
52 R_TRY(hardware_opus.InitializeDecodeObject(params.sample_rate, params.channel_count,
53 shared_buffer.get(), shared_buffer_size));
54
55 sample_rate = params.sample_rate;
56 channel_count = params.channel_count;
57 use_large_frame_size = params.use_large_frame_size;
58 decode_object_initialized = true;
59 R_SUCCEED();
60}
61
62Result OpusDecoder::Initialize(OpusMultiStreamParametersEx& params,
63 Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size) {
64 auto frame_size{params.use_large_frame_size ? 5760 : 1920};
65 shared_buffer_size = transfer_memory_size;
66 shared_buffer = std::make_unique<u8[]>(shared_buffer_size);
67 shared_memory_mapped = true;
68
69 buffer_size =
70 Common::AlignUp((frame_size * params.channel_count) / (48'000 / params.sample_rate), 16);
71
72 out_data = {shared_buffer.get() + shared_buffer_size - buffer_size, buffer_size};
73 size_t in_data_size{Common::AlignUp(1500ull * params.total_stream_count, 64u)};
74 in_data = {out_data.data() - in_data_size, in_data_size};
75
76 ON_RESULT_FAILURE {
77 if (shared_memory_mapped) {
78 shared_memory_mapped = false;
79 ASSERT(R_SUCCEEDED(hardware_opus.UnmapMemory(shared_buffer.get(), shared_buffer_size)));
80 }
81 };
82
83 R_TRY(hardware_opus.InitializeMultiStreamDecodeObject(
84 params.sample_rate, params.channel_count, params.total_stream_count,
85 params.stereo_stream_count, params.mappings.data(), shared_buffer.get(),
86 shared_buffer_size));
87
88 sample_rate = params.sample_rate;
89 channel_count = params.channel_count;
90 total_stream_count = params.total_stream_count;
91 stereo_stream_count = params.stereo_stream_count;
92 use_large_frame_size = params.use_large_frame_size;
93 decode_object_initialized = true;
94 R_SUCCEED();
95}
96
97Result OpusDecoder::DecodeInterleaved(u32* out_data_size, u64* out_time_taken,
98 u32* out_sample_count, std::span<const u8> input_data,
99 std::span<u8> output_data, bool reset) {
100 u32 out_samples;
101 u64 time_taken{};
102
103 R_UNLESS(input_data.size_bytes() > sizeof(OpusPacketHeader), ResultInputDataTooSmall);
104
105 auto* header_p{reinterpret_cast<const OpusPacketHeader*>(input_data.data())};
106 OpusPacketHeader header{ReverseHeader(*header_p)};
107
108 R_UNLESS(in_data.size_bytes() >= header.size &&
109 header.size + sizeof(OpusPacketHeader) <= input_data.size_bytes(),
110 ResultBufferTooSmall);
111
112 if (!shared_memory_mapped) {
113 R_TRY(hardware_opus.MapMemory(shared_buffer.get(), shared_buffer_size));
114 shared_memory_mapped = true;
115 }
116
117 std::memcpy(in_data.data(), input_data.data() + sizeof(OpusPacketHeader), header.size);
118
119 R_TRY(hardware_opus.DecodeInterleaved(out_samples, out_data.data(), out_data.size_bytes(),
120 channel_count, in_data.data(), header.size,
121 shared_buffer.get(), time_taken, reset));
122
123 std::memcpy(output_data.data(), out_data.data(), out_samples * channel_count * sizeof(s16));
124
125 *out_data_size = header.size + sizeof(OpusPacketHeader);
126 *out_sample_count = out_samples;
127 if (out_time_taken) {
128 *out_time_taken = time_taken / 1000;
129 }
130 R_SUCCEED();
131}
132
133Result OpusDecoder::SetContext([[maybe_unused]] std::span<const u8> context) {
134 R_SUCCEED_IF(shared_memory_mapped);
135 shared_memory_mapped = true;
136 R_RETURN(hardware_opus.MapMemory(shared_buffer.get(), shared_buffer_size));
137}
138
139Result OpusDecoder::DecodeInterleavedForMultiStream(u32* out_data_size, u64* out_time_taken,
140 u32* out_sample_count,
141 std::span<const u8> input_data,
142 std::span<u8> output_data, bool reset) {
143 u32 out_samples;
144 u64 time_taken{};
145
146 R_UNLESS(input_data.size_bytes() > sizeof(OpusPacketHeader), ResultInputDataTooSmall);
147
148 auto* header_p{reinterpret_cast<const OpusPacketHeader*>(input_data.data())};
149 OpusPacketHeader header{ReverseHeader(*header_p)};
150
151 LOG_ERROR(Service_Audio, "header size 0x{:X} input data size 0x{:X} in_data size 0x{:X}",
152 header.size, input_data.size_bytes(), in_data.size_bytes());
153
154 R_UNLESS(in_data.size_bytes() >= header.size &&
155 header.size + sizeof(OpusPacketHeader) <= input_data.size_bytes(),
156 ResultBufferTooSmall);
157
158 if (!shared_memory_mapped) {
159 R_TRY(hardware_opus.MapMemory(shared_buffer.get(), shared_buffer_size));
160 shared_memory_mapped = true;
161 }
162
163 std::memcpy(in_data.data(), input_data.data() + sizeof(OpusPacketHeader), header.size);
164
165 R_TRY(hardware_opus.DecodeInterleavedForMultiStream(
166 out_samples, out_data.data(), out_data.size_bytes(), channel_count, in_data.data(),
167 header.size, shared_buffer.get(), time_taken, reset));
168
169 std::memcpy(output_data.data(), out_data.data(), out_samples * channel_count * sizeof(s16));
170
171 *out_data_size = header.size + sizeof(OpusPacketHeader);
172 *out_sample_count = out_samples;
173 if (out_time_taken) {
174 *out_time_taken = time_taken / 1000;
175 }
176 R_SUCCEED();
177}
178
179} // namespace AudioCore::OpusDecoder