summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Liam2023-12-17 00:11:20 -0500
committerGravatar Liam2023-12-17 01:42:59 -0500
commit7239547eada6ad4a24e65957dfab180a51818947 (patch)
tree39b090bb0b9f74d8764a3c8d23ebd12c5e18f1f0 /src
parentMerge pull request #12378 from liamwhite/offsetof (diff)
downloadyuzu-7239547eada6ad4a24e65957dfab180a51818947.tar.gz
yuzu-7239547eada6ad4a24e65957dfab180a51818947.tar.xz
yuzu-7239547eada6ad4a24e65957dfab180a51818947.zip
android: add oboe audio sink
Diffstat (limited to 'src')
-rw-r--r--src/audio_core/CMakeLists.txt11
-rw-r--r--src/audio_core/sink/oboe_sink.cpp184
-rw-r--r--src/audio_core/sink/oboe_sink.h75
-rw-r--r--src/audio_core/sink/sink_details.cpp13
-rw-r--r--src/common/settings_enums.h7
5 files changed, 286 insertions, 4 deletions
diff --git a/src/audio_core/CMakeLists.txt b/src/audio_core/CMakeLists.txt
index 400988c5f..e982d03be 100644
--- a/src/audio_core/CMakeLists.txt
+++ b/src/audio_core/CMakeLists.txt
@@ -253,6 +253,17 @@ if (ENABLE_SDL2)
253 target_compile_definitions(audio_core PRIVATE HAVE_SDL2) 253 target_compile_definitions(audio_core PRIVATE HAVE_SDL2)
254endif() 254endif()
255 255
256if (ANDROID)
257 target_sources(audio_core PRIVATE
258 sink/oboe_sink.cpp
259 sink/oboe_sink.h
260 )
261
262 # FIXME: this port seems broken, it cannot be imported with find_package(oboe REQUIRED)
263 target_link_libraries(audio_core PRIVATE "${VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/lib/liboboe.a")
264 target_compile_definitions(audio_core PRIVATE HAVE_OBOE)
265endif()
266
256if (YUZU_USE_PRECOMPILED_HEADERS) 267if (YUZU_USE_PRECOMPILED_HEADERS)
257 target_precompile_headers(audio_core PRIVATE precompiled_headers.h) 268 target_precompile_headers(audio_core PRIVATE precompiled_headers.h)
258endif() 269endif()
diff --git a/src/audio_core/sink/oboe_sink.cpp b/src/audio_core/sink/oboe_sink.cpp
new file mode 100644
index 000000000..fc62faaee
--- /dev/null
+++ b/src/audio_core/sink/oboe_sink.cpp
@@ -0,0 +1,184 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <span>
5#include <vector>
6
7#include <oboe/Oboe.h>
8
9#include "audio_core/common/common.h"
10#include "audio_core/sink/oboe_sink.h"
11#include "audio_core/sink/sink_stream.h"
12#include "common/logging/log.h"
13#include "common/scope_exit.h"
14#include "core/core.h"
15
16namespace AudioCore::Sink {
17
18class OboeSinkStream final : public SinkStream,
19 public oboe::AudioStreamDataCallback,
20 public oboe::AudioStreamErrorCallback {
21public:
22 explicit OboeSinkStream(Core::System& system_, StreamType type_, const std::string& name_,
23 u32 device_channels_, u32 system_channels_)
24 : SinkStream(system_, type_) {
25 name = name_;
26 system_channels = system_channels_;
27 device_channels = device_channels_;
28
29 this->OpenStream();
30 }
31
32 ~OboeSinkStream() override {
33 LOG_DEBUG(Audio_Sink, "Destructing Oboe stream {}", name);
34 }
35
36 void Finalize() override {
37 this->Stop();
38 m_stream.reset();
39 }
40
41 void Start(bool resume = false) override {
42 if (!m_stream || !paused) {
43 return;
44 }
45
46 paused = false;
47
48 if (m_stream->start() != oboe::Result::OK) {
49 LOG_CRITICAL(Audio_Sink, "Error starting Oboe stream");
50 }
51 }
52
53 void Stop() override {
54 if (!m_stream || paused) {
55 return;
56 }
57
58 this->SignalPause();
59
60 if (m_stream->stop() != oboe::Result::OK) {
61 LOG_CRITICAL(Audio_Sink, "Error stopping Oboe stream");
62 }
63 }
64
65protected:
66 oboe::DataCallbackResult onAudioReady(oboe::AudioStream*, void* audio_data,
67 s32 num_buffer_frames) override {
68 const size_t num_channels = this->GetDeviceChannels();
69 const size_t frame_size = num_channels;
70 const size_t num_frames = static_cast<size_t>(num_buffer_frames);
71
72 if (type == StreamType::In) {
73 std::span<const s16> input_buffer{reinterpret_cast<const s16*>(audio_data),
74 num_frames * frame_size};
75 this->ProcessAudioIn(input_buffer, num_frames);
76 } else {
77 std::span<s16> output_buffer{reinterpret_cast<s16*>(audio_data),
78 num_frames * frame_size};
79 this->ProcessAudioOutAndRender(output_buffer, num_frames);
80 }
81
82 return oboe::DataCallbackResult::Continue;
83 }
84
85 void onErrorAfterClose(oboe::AudioStream*, oboe::Result) override {
86 LOG_INFO(Audio_Sink, "Audio stream closed, reinitializing");
87
88 if (this->OpenStream()) {
89 m_stream->start();
90 }
91 }
92
93private:
94 bool OpenStream() {
95 const auto direction = [&]() {
96 switch (type) {
97 case StreamType::In:
98 return oboe::Direction::Input;
99 case StreamType::Out:
100 case StreamType::Render:
101 return oboe::Direction::Output;
102 default:
103 ASSERT(false);
104 return oboe::Direction::Output;
105 }
106 }();
107
108 const auto channel_mask = [&]() {
109 switch (device_channels) {
110 case 1:
111 return oboe::ChannelMask::Mono;
112 case 2:
113 return oboe::ChannelMask::Stereo;
114 case 6:
115 return oboe::ChannelMask::CM5Point1;
116 default:
117 ASSERT(false);
118 return oboe::ChannelMask::Unspecified;
119 }
120 }();
121
122 oboe::AudioStreamBuilder builder;
123 const auto result = builder.setDirection(direction)
124 ->setSampleRate(TargetSampleRate)
125 ->setChannelCount(device_channels)
126 ->setChannelMask(channel_mask)
127 ->setFormat(oboe::AudioFormat::I16)
128 ->setFormatConversionAllowed(true)
129 ->setDataCallback(this)
130 ->setErrorCallback(this)
131 ->openStream(m_stream);
132
133 ASSERT(result == oboe::Result::OK);
134 return result == oboe::Result::OK;
135 }
136
137 std::shared_ptr<oboe::AudioStream> m_stream{};
138};
139
140OboeSink::OboeSink() {
141 // TODO: how do we get the number of channels, or device list?
142 // This seems to be missing from NDK.
143 device_channels = 2;
144}
145
146OboeSink::~OboeSink() = default;
147
148SinkStream* OboeSink::AcquireSinkStream(Core::System& system, u32 system_channels,
149 const std::string& name, StreamType type) {
150 SinkStreamPtr& stream = sink_streams.emplace_back(
151 std::make_unique<OboeSinkStream>(system, type, name, device_channels, system_channels));
152
153 return stream.get();
154}
155
156void OboeSink::CloseStream(SinkStream* to_remove) {
157 sink_streams.remove_if([&](auto& stream) { return stream.get() == to_remove; });
158}
159
160void OboeSink::CloseStreams() {
161 sink_streams.clear();
162}
163
164f32 OboeSink::GetDeviceVolume() const {
165 if (sink_streams.empty()) {
166 return 1.0f;
167 }
168
169 return sink_streams.front()->GetDeviceVolume();
170}
171
172void OboeSink::SetDeviceVolume(f32 volume) {
173 for (auto& stream : sink_streams) {
174 stream->SetDeviceVolume(volume);
175 }
176}
177
178void OboeSink::SetSystemVolume(f32 volume) {
179 for (auto& stream : sink_streams) {
180 stream->SetSystemVolume(volume);
181 }
182}
183
184} // namespace AudioCore::Sink
diff --git a/src/audio_core/sink/oboe_sink.h b/src/audio_core/sink/oboe_sink.h
new file mode 100644
index 000000000..8f6f54ab5
--- /dev/null
+++ b/src/audio_core/sink/oboe_sink.h
@@ -0,0 +1,75 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <list>
7#include <string>
8
9#include "audio_core/sink/sink.h"
10
11namespace Core {
12class System;
13}
14
15namespace AudioCore::Sink {
16class SinkStream;
17
18class OboeSink final : public Sink {
19public:
20 explicit OboeSink();
21 ~OboeSink() override;
22
23 /**
24 * Create a new sink stream.
25 *
26 * @param system - Core system.
27 * @param system_channels - Number of channels the audio system expects.
28 * May differ from the device's channel count.
29 * @param name - Name of this stream.
30 * @param type - Type of this stream, render/in/out.
31 *
32 * @return A pointer to the created SinkStream
33 */
34 SinkStream* AcquireSinkStream(Core::System& system, u32 system_channels,
35 const std::string& name, StreamType type) override;
36
37 /**
38 * Close a given stream.
39 *
40 * @param stream - The stream to close.
41 */
42 void CloseStream(SinkStream* stream) override;
43
44 /**
45 * Close all streams.
46 */
47 void CloseStreams() override;
48
49 /**
50 * Get the device volume. Set from calls to the IAudioDevice service.
51 *
52 * @return Volume of the device.
53 */
54 f32 GetDeviceVolume() const override;
55
56 /**
57 * Set the device volume. Set from calls to the IAudioDevice service.
58 *
59 * @param volume - New volume of the device.
60 */
61 void SetDeviceVolume(f32 volume) override;
62
63 /**
64 * Set the system volume. Comes from the audio system using this stream.
65 *
66 * @param volume - New volume of the system.
67 */
68 void SetSystemVolume(f32 volume) override;
69
70private:
71 /// List of streams managed by this sink
72 std::list<SinkStreamPtr> sink_streams{};
73};
74
75} // namespace AudioCore::Sink
diff --git a/src/audio_core/sink/sink_details.cpp b/src/audio_core/sink/sink_details.cpp
index 7c9a4e3ac..449af659d 100644
--- a/src/audio_core/sink/sink_details.cpp
+++ b/src/audio_core/sink/sink_details.cpp
@@ -7,6 +7,9 @@
7#include <vector> 7#include <vector>
8 8
9#include "audio_core/sink/sink_details.h" 9#include "audio_core/sink/sink_details.h"
10#ifdef HAVE_OBOE
11#include "audio_core/sink/oboe_sink.h"
12#endif
10#ifdef HAVE_CUBEB 13#ifdef HAVE_CUBEB
11#include "audio_core/sink/cubeb_sink.h" 14#include "audio_core/sink/cubeb_sink.h"
12#endif 15#endif
@@ -36,6 +39,16 @@ struct SinkDetails {
36 39
37// sink_details is ordered in terms of desirability, with the best choice at the top. 40// sink_details is ordered in terms of desirability, with the best choice at the top.
38constexpr SinkDetails sink_details[] = { 41constexpr SinkDetails sink_details[] = {
42#ifdef HAVE_OBOE
43 SinkDetails{
44 Settings::AudioEngine::Oboe,
45 [](std::string_view device_id) -> std::unique_ptr<Sink> {
46 return std::make_unique<OboeSink>();
47 },
48 [](bool capture) { return std::vector<std::string>{"Default"}; },
49 []() { return true; },
50 },
51#endif
39#ifdef HAVE_CUBEB 52#ifdef HAVE_CUBEB
40 SinkDetails{ 53 SinkDetails{
41 Settings::AudioEngine::Cubeb, 54 Settings::AudioEngine::Cubeb,
diff --git a/src/common/settings_enums.h b/src/common/settings_enums.h
index d6351e57e..617036588 100644
--- a/src/common/settings_enums.h
+++ b/src/common/settings_enums.h
@@ -82,16 +82,15 @@ enum class AudioEngine : u32 {
82 Cubeb, 82 Cubeb,
83 Sdl2, 83 Sdl2,
84 Null, 84 Null,
85 Oboe,
85}; 86};
86 87
87template <> 88template <>
88inline std::vector<std::pair<std::string, AudioEngine>> 89inline std::vector<std::pair<std::string, AudioEngine>>
89EnumMetadata<AudioEngine>::Canonicalizations() { 90EnumMetadata<AudioEngine>::Canonicalizations() {
90 return { 91 return {
91 {"auto", AudioEngine::Auto}, 92 {"auto", AudioEngine::Auto}, {"cubeb", AudioEngine::Cubeb}, {"sdl2", AudioEngine::Sdl2},
92 {"cubeb", AudioEngine::Cubeb}, 93 {"null", AudioEngine::Null}, {"oboe", AudioEngine::Oboe},
93 {"sdl2", AudioEngine::Sdl2},
94 {"null", AudioEngine::Null},
95 }; 94 };
96} 95}
97 96