diff options
| author | 2022-07-16 23:48:45 +0100 | |
|---|---|---|
| committer | 2022-07-22 01:11:32 +0100 | |
| commit | 458da8a94877677f086f06cdeecf959ec4283a33 (patch) | |
| tree | 583166d77602ad90a0d552f37de8729ad80fd6c1 /src/audio_core/out | |
| parent | Merge pull request #8598 from Link4565/recv-dontwait (diff) | |
| download | yuzu-458da8a94877677f086f06cdeecf959ec4283a33.tar.gz yuzu-458da8a94877677f086f06cdeecf959ec4283a33.tar.xz yuzu-458da8a94877677f086f06cdeecf959ec4283a33.zip | |
Project Andio
Diffstat (limited to 'src/audio_core/out')
| -rw-r--r-- | src/audio_core/out/audio_out.cpp | 100 | ||||
| -rw-r--r-- | src/audio_core/out/audio_out.h | 147 | ||||
| -rw-r--r-- | src/audio_core/out/audio_out_system.cpp | 207 | ||||
| -rw-r--r-- | src/audio_core/out/audio_out_system.h | 257 |
4 files changed, 711 insertions, 0 deletions
diff --git a/src/audio_core/out/audio_out.cpp b/src/audio_core/out/audio_out.cpp new file mode 100644 index 000000000..9a8d8a742 --- /dev/null +++ b/src/audio_core/out/audio_out.cpp | |||
| @@ -0,0 +1,100 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "audio_core/audio_out_manager.h" | ||
| 5 | #include "audio_core/out/audio_out.h" | ||
| 6 | #include "core/hle/kernel/k_event.h" | ||
| 7 | |||
| 8 | namespace AudioCore::AudioOut { | ||
| 9 | |||
| 10 | Out::Out(Core::System& system_, Manager& manager_, Kernel::KEvent* event_, size_t session_id_) | ||
| 11 | : manager{manager_}, parent_mutex{manager.mutex}, event{event_}, system{system_, event, | ||
| 12 | session_id_} {} | ||
| 13 | |||
| 14 | void Out::Free() { | ||
| 15 | std::scoped_lock l{parent_mutex}; | ||
| 16 | manager.ReleaseSessionId(system.GetSessionId()); | ||
| 17 | } | ||
| 18 | |||
| 19 | System& Out::GetSystem() { | ||
| 20 | return system; | ||
| 21 | } | ||
| 22 | |||
| 23 | AudioOut::State Out::GetState() { | ||
| 24 | std::scoped_lock l{parent_mutex}; | ||
| 25 | return system.GetState(); | ||
| 26 | } | ||
| 27 | |||
| 28 | Result Out::StartSystem() { | ||
| 29 | std::scoped_lock l{parent_mutex}; | ||
| 30 | return system.Start(); | ||
| 31 | } | ||
| 32 | |||
| 33 | void Out::StartSession() { | ||
| 34 | std::scoped_lock l{parent_mutex}; | ||
| 35 | system.StartSession(); | ||
| 36 | } | ||
| 37 | |||
| 38 | Result Out::StopSystem() { | ||
| 39 | std::scoped_lock l{parent_mutex}; | ||
| 40 | return system.Stop(); | ||
| 41 | } | ||
| 42 | |||
| 43 | Result Out::AppendBuffer(const AudioOutBuffer& buffer, const u64 tag) { | ||
| 44 | std::scoped_lock l{parent_mutex}; | ||
| 45 | |||
| 46 | if (system.AppendBuffer(buffer, tag)) { | ||
| 47 | return ResultSuccess; | ||
| 48 | } | ||
| 49 | return Service::Audio::ERR_BUFFER_COUNT_EXCEEDED; | ||
| 50 | } | ||
| 51 | |||
| 52 | void Out::ReleaseAndRegisterBuffers() { | ||
| 53 | std::scoped_lock l{parent_mutex}; | ||
| 54 | if (system.GetState() == State::Started) { | ||
| 55 | system.ReleaseBuffers(); | ||
| 56 | system.RegisterBuffers(); | ||
| 57 | } | ||
| 58 | } | ||
| 59 | |||
| 60 | bool Out::FlushAudioOutBuffers() { | ||
| 61 | std::scoped_lock l{parent_mutex}; | ||
| 62 | return system.FlushAudioOutBuffers(); | ||
| 63 | } | ||
| 64 | |||
| 65 | u32 Out::GetReleasedBuffers(std::span<u64> tags) { | ||
| 66 | std::scoped_lock l{parent_mutex}; | ||
| 67 | return system.GetReleasedBuffers(tags); | ||
| 68 | } | ||
| 69 | |||
| 70 | Kernel::KReadableEvent& Out::GetBufferEvent() { | ||
| 71 | std::scoped_lock l{parent_mutex}; | ||
| 72 | return event->GetReadableEvent(); | ||
| 73 | } | ||
| 74 | |||
| 75 | f32 Out::GetVolume() { | ||
| 76 | std::scoped_lock l{parent_mutex}; | ||
| 77 | return system.GetVolume(); | ||
| 78 | } | ||
| 79 | |||
| 80 | void Out::SetVolume(const f32 volume) { | ||
| 81 | std::scoped_lock l{parent_mutex}; | ||
| 82 | system.SetVolume(volume); | ||
| 83 | } | ||
| 84 | |||
| 85 | bool Out::ContainsAudioBuffer(const u64 tag) { | ||
| 86 | std::scoped_lock l{parent_mutex}; | ||
| 87 | return system.ContainsAudioBuffer(tag); | ||
| 88 | } | ||
| 89 | |||
| 90 | u32 Out::GetBufferCount() { | ||
| 91 | std::scoped_lock l{parent_mutex}; | ||
| 92 | return system.GetBufferCount(); | ||
| 93 | } | ||
| 94 | |||
| 95 | u64 Out::GetPlayedSampleCount() { | ||
| 96 | std::scoped_lock l{parent_mutex}; | ||
| 97 | return system.GetPlayedSampleCount(); | ||
| 98 | } | ||
| 99 | |||
| 100 | } // namespace AudioCore::AudioOut | ||
diff --git a/src/audio_core/out/audio_out.h b/src/audio_core/out/audio_out.h new file mode 100644 index 000000000..f6b921645 --- /dev/null +++ b/src/audio_core/out/audio_out.h | |||
| @@ -0,0 +1,147 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <mutex> | ||
| 7 | |||
| 8 | #include "audio_core/out/audio_out_system.h" | ||
| 9 | |||
| 10 | namespace Core { | ||
| 11 | class System; | ||
| 12 | } | ||
| 13 | |||
| 14 | namespace Kernel { | ||
| 15 | class KEvent; | ||
| 16 | class KReadableEvent; | ||
| 17 | } // namespace Kernel | ||
| 18 | |||
| 19 | namespace AudioCore::AudioOut { | ||
| 20 | class Manager; | ||
| 21 | |||
| 22 | /** | ||
| 23 | * Interface between the service and audio out system. Mainly responsible for forwarding service | ||
| 24 | * calls to the system. | ||
| 25 | */ | ||
| 26 | class Out { | ||
| 27 | public: | ||
| 28 | explicit Out(Core::System& system, Manager& manager, Kernel::KEvent* event, size_t session_id); | ||
| 29 | |||
| 30 | /** | ||
| 31 | * Free this audio out from the audio out manager. | ||
| 32 | */ | ||
| 33 | void Free(); | ||
| 34 | |||
| 35 | /** | ||
| 36 | * Get this audio out's system. | ||
| 37 | */ | ||
| 38 | System& GetSystem(); | ||
| 39 | |||
| 40 | /** | ||
| 41 | * Get the current state. | ||
| 42 | * | ||
| 43 | * @return Started or Stopped. | ||
| 44 | */ | ||
| 45 | AudioOut::State GetState(); | ||
| 46 | |||
| 47 | /** | ||
| 48 | * Start the system | ||
| 49 | * | ||
| 50 | * @return Result code | ||
| 51 | */ | ||
| 52 | Result StartSystem(); | ||
| 53 | |||
| 54 | /** | ||
| 55 | * Start the system's device session. | ||
| 56 | */ | ||
| 57 | void StartSession(); | ||
| 58 | |||
| 59 | /** | ||
| 60 | * Stop the system. | ||
| 61 | * | ||
| 62 | * @return Result code | ||
| 63 | */ | ||
| 64 | Result StopSystem(); | ||
| 65 | |||
| 66 | /** | ||
| 67 | * Append a new buffer to the system, the buffer event will be signalled when it is filled. | ||
| 68 | * | ||
| 69 | * @param buffer - The new buffer to append. | ||
| 70 | * @param tag - Unique tag for this buffer. | ||
| 71 | * @return Result code. | ||
| 72 | */ | ||
| 73 | Result AppendBuffer(const AudioOutBuffer& buffer, u64 tag); | ||
| 74 | |||
| 75 | /** | ||
| 76 | * Release all completed buffers, and register any appended. | ||
| 77 | */ | ||
| 78 | void ReleaseAndRegisterBuffers(); | ||
| 79 | |||
| 80 | /** | ||
| 81 | * Flush all buffers. | ||
| 82 | */ | ||
| 83 | bool FlushAudioOutBuffers(); | ||
| 84 | |||
| 85 | /** | ||
| 86 | * Get all of the currently released buffers. | ||
| 87 | * | ||
| 88 | * @param tags - Output container for the buffer tags which were released. | ||
| 89 | * @return The number of buffers released. | ||
| 90 | */ | ||
| 91 | u32 GetReleasedBuffers(std::span<u64> tags); | ||
| 92 | |||
| 93 | /** | ||
| 94 | * Get the buffer event for this audio out, this event will be signalled when a buffer is | ||
| 95 | * filled. | ||
| 96 | * @return The buffer event. | ||
| 97 | */ | ||
| 98 | Kernel::KReadableEvent& GetBufferEvent(); | ||
| 99 | |||
| 100 | /** | ||
| 101 | * Get the current system volume. | ||
| 102 | * | ||
| 103 | * @return The current volume. | ||
| 104 | */ | ||
| 105 | f32 GetVolume(); | ||
| 106 | |||
| 107 | /** | ||
| 108 | * Set the system volume. | ||
| 109 | * | ||
| 110 | * @param volume - The volume to set. | ||
| 111 | */ | ||
| 112 | void SetVolume(f32 volume); | ||
| 113 | |||
| 114 | /** | ||
| 115 | * Check if a buffer is in the system. | ||
| 116 | * | ||
| 117 | * @param tag - The tag to search for. | ||
| 118 | * @return True if the buffer is in the system, otherwise false. | ||
| 119 | */ | ||
| 120 | bool ContainsAudioBuffer(u64 tag); | ||
| 121 | |||
| 122 | /** | ||
| 123 | * Get the maximum number of buffers. | ||
| 124 | * | ||
| 125 | * @return The maximum number of buffers. | ||
| 126 | */ | ||
| 127 | u32 GetBufferCount(); | ||
| 128 | |||
| 129 | /** | ||
| 130 | * Get the total played sample count for this audio out. | ||
| 131 | * | ||
| 132 | * @return The played sample count. | ||
| 133 | */ | ||
| 134 | u64 GetPlayedSampleCount(); | ||
| 135 | |||
| 136 | private: | ||
| 137 | /// The AudioOut::Manager this audio out is registered with | ||
| 138 | Manager& manager; | ||
| 139 | /// Manager's mutex | ||
| 140 | std::recursive_mutex& parent_mutex; | ||
| 141 | /// Buffer event, signalled when buffers are ready to be released | ||
| 142 | Kernel::KEvent* event; | ||
| 143 | /// Main audio out system | ||
| 144 | System system; | ||
| 145 | }; | ||
| 146 | |||
| 147 | } // namespace AudioCore::AudioOut | ||
diff --git a/src/audio_core/out/audio_out_system.cpp b/src/audio_core/out/audio_out_system.cpp new file mode 100644 index 000000000..35afddf06 --- /dev/null +++ b/src/audio_core/out/audio_out_system.cpp | |||
| @@ -0,0 +1,207 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include <mutex> | ||
| 5 | |||
| 6 | #include "audio_core/audio_event.h" | ||
| 7 | #include "audio_core/audio_manager.h" | ||
| 8 | #include "audio_core/out/audio_out_system.h" | ||
| 9 | #include "common/logging/log.h" | ||
| 10 | #include "core/core.h" | ||
| 11 | #include "core/core_timing.h" | ||
| 12 | #include "core/hle/kernel/k_event.h" | ||
| 13 | |||
| 14 | namespace AudioCore::AudioOut { | ||
| 15 | |||
| 16 | System::System(Core::System& system_, Kernel::KEvent* event_, size_t session_id_) | ||
| 17 | : system{system_}, buffer_event{event_}, | ||
| 18 | session_id{session_id_}, session{std::make_unique<DeviceSession>(system_)} {} | ||
| 19 | |||
| 20 | System::~System() { | ||
| 21 | Finalize(); | ||
| 22 | } | ||
| 23 | |||
| 24 | void System::Finalize() { | ||
| 25 | Stop(); | ||
| 26 | session->Finalize(); | ||
| 27 | buffer_event->GetWritableEvent().Signal(); | ||
| 28 | } | ||
| 29 | |||
| 30 | std::string_view System::GetDefaultOutputDeviceName() { | ||
| 31 | return "DeviceOut"; | ||
| 32 | } | ||
| 33 | |||
| 34 | Result System::IsConfigValid(std::string_view device_name, const AudioOutParameter& in_params) { | ||
| 35 | if ((device_name.size() > 0) && (device_name != GetDefaultOutputDeviceName())) { | ||
| 36 | return Service::Audio::ERR_INVALID_DEVICE_NAME; | ||
| 37 | } | ||
| 38 | |||
| 39 | if (in_params.sample_rate != TargetSampleRate && in_params.sample_rate > 0) { | ||
| 40 | return Service::Audio::ERR_INVALID_SAMPLE_RATE; | ||
| 41 | } | ||
| 42 | |||
| 43 | if (in_params.channel_count == 0 || in_params.channel_count == 2 || | ||
| 44 | in_params.channel_count == 6) { | ||
| 45 | return ResultSuccess; | ||
| 46 | } | ||
| 47 | |||
| 48 | return Service::Audio::ERR_INVALID_CHANNEL_COUNT; | ||
| 49 | } | ||
| 50 | |||
| 51 | Result System::Initialize(std::string& device_name, const AudioOutParameter& in_params, u32 handle_, | ||
| 52 | u64& applet_resource_user_id_) { | ||
| 53 | auto result = IsConfigValid(device_name, in_params); | ||
| 54 | if (result.IsError()) { | ||
| 55 | return result; | ||
| 56 | } | ||
| 57 | |||
| 58 | handle = handle_; | ||
| 59 | applet_resource_user_id = applet_resource_user_id_; | ||
| 60 | if (device_name.empty() || device_name[0] == '\0') { | ||
| 61 | name = std::string(GetDefaultOutputDeviceName()); | ||
| 62 | } else { | ||
| 63 | name = std::move(device_name); | ||
| 64 | } | ||
| 65 | |||
| 66 | sample_rate = TargetSampleRate; | ||
| 67 | sample_format = SampleFormat::PcmInt16; | ||
| 68 | channel_count = in_params.channel_count <= 2 ? 2 : 6; | ||
| 69 | volume = 1.0f; | ||
| 70 | return ResultSuccess; | ||
| 71 | } | ||
| 72 | |||
| 73 | void System::StartSession() { | ||
| 74 | session->Start(); | ||
| 75 | } | ||
| 76 | |||
| 77 | size_t System::GetSessionId() const { | ||
| 78 | return session_id; | ||
| 79 | } | ||
| 80 | |||
| 81 | Result System::Start() { | ||
| 82 | if (state != State::Stopped) { | ||
| 83 | return Service::Audio::ERR_OPERATION_FAILED; | ||
| 84 | } | ||
| 85 | |||
| 86 | session->Initialize(name, sample_format, channel_count, session_id, handle, | ||
| 87 | applet_resource_user_id, Sink::StreamType::Out); | ||
| 88 | session->SetVolume(volume); | ||
| 89 | session->Start(); | ||
| 90 | state = State::Started; | ||
| 91 | |||
| 92 | std::vector<AudioBuffer> buffers_to_flush{}; | ||
| 93 | buffers.RegisterBuffers(buffers_to_flush); | ||
| 94 | session->AppendBuffers(buffers_to_flush); | ||
| 95 | |||
| 96 | return ResultSuccess; | ||
| 97 | } | ||
| 98 | |||
| 99 | Result System::Stop() { | ||
| 100 | if (state == State::Started) { | ||
| 101 | session->Stop(); | ||
| 102 | session->SetVolume(0.0f); | ||
| 103 | state = State::Stopped; | ||
| 104 | } | ||
| 105 | |||
| 106 | return ResultSuccess; | ||
| 107 | } | ||
| 108 | |||
| 109 | bool System::AppendBuffer(const AudioOutBuffer& buffer, u64 tag) { | ||
| 110 | if (buffers.GetTotalBufferCount() == BufferCount) { | ||
| 111 | return false; | ||
| 112 | } | ||
| 113 | |||
| 114 | AudioBuffer new_buffer{ | ||
| 115 | .played_timestamp = 0, .samples = buffer.samples, .tag = tag, .size = buffer.size}; | ||
| 116 | |||
| 117 | buffers.AppendBuffer(new_buffer); | ||
| 118 | RegisterBuffers(); | ||
| 119 | |||
| 120 | return true; | ||
| 121 | } | ||
| 122 | |||
| 123 | void System::RegisterBuffers() { | ||
| 124 | if (state == State::Started) { | ||
| 125 | std::vector<AudioBuffer> registered_buffers{}; | ||
| 126 | buffers.RegisterBuffers(registered_buffers); | ||
| 127 | session->AppendBuffers(registered_buffers); | ||
| 128 | } | ||
| 129 | } | ||
| 130 | |||
| 131 | void System::ReleaseBuffers() { | ||
| 132 | bool signal{buffers.ReleaseBuffers(system.CoreTiming(), *session)}; | ||
| 133 | if (signal) { | ||
| 134 | // Signal if any buffer was released, or if none are registered, we need more. | ||
| 135 | buffer_event->GetWritableEvent().Signal(); | ||
| 136 | } | ||
| 137 | } | ||
| 138 | |||
| 139 | u32 System::GetReleasedBuffers(std::span<u64> tags) { | ||
| 140 | return buffers.GetReleasedBuffers(tags); | ||
| 141 | } | ||
| 142 | |||
| 143 | bool System::FlushAudioOutBuffers() { | ||
| 144 | if (state != State::Started) { | ||
| 145 | return false; | ||
| 146 | } | ||
| 147 | |||
| 148 | u32 buffers_released{}; | ||
| 149 | buffers.FlushBuffers(buffers_released); | ||
| 150 | |||
| 151 | if (buffers_released > 0) { | ||
| 152 | buffer_event->GetWritableEvent().Signal(); | ||
| 153 | } | ||
| 154 | return true; | ||
| 155 | } | ||
| 156 | |||
| 157 | u16 System::GetChannelCount() const { | ||
| 158 | return channel_count; | ||
| 159 | } | ||
| 160 | |||
| 161 | u32 System::GetSampleRate() const { | ||
| 162 | return sample_rate; | ||
| 163 | } | ||
| 164 | |||
| 165 | SampleFormat System::GetSampleFormat() const { | ||
| 166 | return sample_format; | ||
| 167 | } | ||
| 168 | |||
| 169 | State System::GetState() { | ||
| 170 | switch (state) { | ||
| 171 | case State::Started: | ||
| 172 | case State::Stopped: | ||
| 173 | return state; | ||
| 174 | default: | ||
| 175 | LOG_ERROR(Service_Audio, "AudioOut invalid state!"); | ||
| 176 | state = State::Stopped; | ||
| 177 | break; | ||
| 178 | } | ||
| 179 | return state; | ||
| 180 | } | ||
| 181 | |||
| 182 | std::string System::GetName() const { | ||
| 183 | return name; | ||
| 184 | } | ||
| 185 | |||
| 186 | f32 System::GetVolume() const { | ||
| 187 | return volume; | ||
| 188 | } | ||
| 189 | |||
| 190 | void System::SetVolume(const f32 volume_) { | ||
| 191 | volume = volume_; | ||
| 192 | session->SetVolume(volume_); | ||
| 193 | } | ||
| 194 | |||
| 195 | bool System::ContainsAudioBuffer(const u64 tag) { | ||
| 196 | return buffers.ContainsBuffer(tag); | ||
| 197 | } | ||
| 198 | |||
| 199 | u32 System::GetBufferCount() { | ||
| 200 | return buffers.GetAppendedRegisteredCount(); | ||
| 201 | } | ||
| 202 | |||
| 203 | u64 System::GetPlayedSampleCount() const { | ||
| 204 | return session->GetPlayedSampleCount(); | ||
| 205 | } | ||
| 206 | |||
| 207 | } // namespace AudioCore::AudioOut | ||
diff --git a/src/audio_core/out/audio_out_system.h b/src/audio_core/out/audio_out_system.h new file mode 100644 index 000000000..4ca2f3417 --- /dev/null +++ b/src/audio_core/out/audio_out_system.h | |||
| @@ -0,0 +1,257 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <atomic> | ||
| 7 | #include <memory> | ||
| 8 | #include <span> | ||
| 9 | #include <string> | ||
| 10 | |||
| 11 | #include "audio_core/common/common.h" | ||
| 12 | #include "audio_core/device/audio_buffers.h" | ||
| 13 | #include "audio_core/device/device_session.h" | ||
| 14 | #include "core/hle/service/audio/errors.h" | ||
| 15 | |||
| 16 | namespace Core { | ||
| 17 | class System; | ||
| 18 | } | ||
| 19 | |||
| 20 | namespace Kernel { | ||
| 21 | class KEvent; | ||
| 22 | } | ||
| 23 | |||
| 24 | namespace AudioCore::AudioOut { | ||
| 25 | |||
| 26 | constexpr SessionTypes SessionType = SessionTypes::AudioOut; | ||
| 27 | |||
| 28 | struct AudioOutParameter { | ||
| 29 | /* 0x0 */ s32_le sample_rate; | ||
| 30 | /* 0x4 */ u16_le channel_count; | ||
| 31 | /* 0x6 */ u16_le reserved; | ||
| 32 | }; | ||
| 33 | static_assert(sizeof(AudioOutParameter) == 0x8, "AudioOutParameter is an invalid size"); | ||
| 34 | |||
| 35 | struct AudioOutParameterInternal { | ||
| 36 | /* 0x0 */ u32_le sample_rate; | ||
| 37 | /* 0x4 */ u32_le channel_count; | ||
| 38 | /* 0x8 */ u32_le sample_format; | ||
| 39 | /* 0xC */ u32_le state; | ||
| 40 | }; | ||
| 41 | static_assert(sizeof(AudioOutParameterInternal) == 0x10, | ||
| 42 | "AudioOutParameterInternal is an invalid size"); | ||
| 43 | |||
| 44 | struct AudioOutBuffer { | ||
| 45 | /* 0x00 */ AudioOutBuffer* next; | ||
| 46 | /* 0x08 */ VAddr samples; | ||
| 47 | /* 0x10 */ u64 capacity; | ||
| 48 | /* 0x18 */ u64 size; | ||
| 49 | /* 0x20 */ u64 offset; | ||
| 50 | }; | ||
| 51 | static_assert(sizeof(AudioOutBuffer) == 0x28, "AudioOutBuffer is an invalid size"); | ||
| 52 | |||
| 53 | enum class State { | ||
| 54 | Started, | ||
| 55 | Stopped, | ||
| 56 | }; | ||
| 57 | |||
| 58 | /** | ||
| 59 | * Controls and drives audio output. | ||
| 60 | */ | ||
| 61 | class System { | ||
| 62 | public: | ||
| 63 | explicit System(Core::System& system, Kernel::KEvent* event, size_t session_id); | ||
| 64 | ~System(); | ||
| 65 | |||
| 66 | /** | ||
| 67 | * Get the default audio output device name. | ||
| 68 | * | ||
| 69 | * @return The default audio output device name. | ||
| 70 | */ | ||
| 71 | std::string_view GetDefaultOutputDeviceName(); | ||
| 72 | |||
| 73 | /** | ||
| 74 | * Is the given initialize config valid? | ||
| 75 | * | ||
| 76 | * @param device_name - The name of the requested output device. | ||
| 77 | * @param in_params - Input parameters, see AudioOutParameter. | ||
| 78 | * @return Result code. | ||
| 79 | */ | ||
| 80 | Result IsConfigValid(std::string_view device_name, const AudioOutParameter& in_params); | ||
| 81 | |||
| 82 | /** | ||
| 83 | * Initialize this system. | ||
| 84 | * | ||
| 85 | * @param device_name - The name of the requested output device. | ||
| 86 | * @param in_params - Input parameters, see AudioOutParameter. | ||
| 87 | * @param handle - Unused. | ||
| 88 | * @param applet_resource_user_id - Unused. | ||
| 89 | * @return Result code. | ||
| 90 | */ | ||
| 91 | Result Initialize(std::string& device_name, const AudioOutParameter& in_params, u32 handle, | ||
| 92 | u64& applet_resource_user_id); | ||
| 93 | |||
| 94 | /** | ||
| 95 | * Start this system. | ||
| 96 | * | ||
| 97 | * @return Result code. | ||
| 98 | */ | ||
| 99 | Result Start(); | ||
| 100 | |||
| 101 | /** | ||
| 102 | * Stop this system. | ||
| 103 | * | ||
| 104 | * @return Result code. | ||
| 105 | */ | ||
| 106 | Result Stop(); | ||
| 107 | |||
| 108 | /** | ||
| 109 | * Finalize this system. | ||
| 110 | */ | ||
| 111 | void Finalize(); | ||
| 112 | |||
| 113 | /** | ||
| 114 | * Start this system's device session. | ||
| 115 | */ | ||
| 116 | void StartSession(); | ||
| 117 | |||
| 118 | /** | ||
| 119 | * Get this system's id. | ||
| 120 | */ | ||
| 121 | size_t GetSessionId() const; | ||
| 122 | |||
| 123 | /** | ||
| 124 | * Append a new buffer to the device. | ||
| 125 | * | ||
| 126 | * @param buffer - New buffer to append. | ||
| 127 | * @param tag - Unique tag of the buffer. | ||
| 128 | * @return True if the buffer was appended, otherwise false. | ||
| 129 | */ | ||
| 130 | bool AppendBuffer(const AudioOutBuffer& buffer, u64 tag); | ||
| 131 | |||
| 132 | /** | ||
| 133 | * Register all appended buffers. | ||
| 134 | */ | ||
| 135 | void RegisterBuffers(); | ||
| 136 | |||
| 137 | /** | ||
| 138 | * Release all registered buffers. | ||
| 139 | */ | ||
| 140 | void ReleaseBuffers(); | ||
| 141 | |||
| 142 | /** | ||
| 143 | * Get all released buffers. | ||
| 144 | * | ||
| 145 | * @param tags - Container to be filled with the released buffers' tags. | ||
| 146 | * @return The number of buffers released. | ||
| 147 | */ | ||
| 148 | u32 GetReleasedBuffers(std::span<u64> tags); | ||
| 149 | |||
| 150 | /** | ||
| 151 | * Flush all appended and registered buffers. | ||
| 152 | * | ||
| 153 | * @return True if buffers were successfully flushed, otherwise false. | ||
| 154 | */ | ||
| 155 | bool FlushAudioOutBuffers(); | ||
| 156 | |||
| 157 | /** | ||
| 158 | * Get this system's current channel count. | ||
| 159 | * | ||
| 160 | * @return The channel count. | ||
| 161 | */ | ||
| 162 | u16 GetChannelCount() const; | ||
| 163 | |||
| 164 | /** | ||
| 165 | * Get this system's current sample rate. | ||
| 166 | * | ||
| 167 | * @return The sample rate. | ||
| 168 | */ | ||
| 169 | u32 GetSampleRate() const; | ||
| 170 | |||
| 171 | /** | ||
| 172 | * Get this system's current sample format. | ||
| 173 | * | ||
| 174 | * @return The sample format. | ||
| 175 | */ | ||
| 176 | SampleFormat GetSampleFormat() const; | ||
| 177 | |||
| 178 | /** | ||
| 179 | * Get this system's current state. | ||
| 180 | * | ||
| 181 | * @return The current state. | ||
| 182 | */ | ||
| 183 | State GetState(); | ||
| 184 | |||
| 185 | /** | ||
| 186 | * Get this system's name. | ||
| 187 | * | ||
| 188 | * @return The system's name. | ||
| 189 | */ | ||
| 190 | std::string GetName() const; | ||
| 191 | |||
| 192 | /** | ||
| 193 | * Get this system's current volume. | ||
| 194 | * | ||
| 195 | * @return The system's current volume. | ||
| 196 | */ | ||
| 197 | f32 GetVolume() const; | ||
| 198 | |||
| 199 | /** | ||
| 200 | * Set this system's current volume. | ||
| 201 | * | ||
| 202 | * @param The new volume. | ||
| 203 | */ | ||
| 204 | void SetVolume(f32 volume); | ||
| 205 | |||
| 206 | /** | ||
| 207 | * Does the system contain this buffer? | ||
| 208 | * | ||
| 209 | * @param tag - Unique tag to search for. | ||
| 210 | * @return True if the buffer is in the system, otherwise false. | ||
| 211 | */ | ||
| 212 | bool ContainsAudioBuffer(u64 tag); | ||
| 213 | |||
| 214 | /** | ||
| 215 | * Get the maximum number of usable buffers (default 32). | ||
| 216 | * | ||
| 217 | * @return The number of buffers. | ||
| 218 | */ | ||
| 219 | u32 GetBufferCount(); | ||
| 220 | |||
| 221 | /** | ||
| 222 | * Get the total number of samples played by this system. | ||
| 223 | * | ||
| 224 | * @return The number of samples. | ||
| 225 | */ | ||
| 226 | u64 GetPlayedSampleCount() const; | ||
| 227 | |||
| 228 | private: | ||
| 229 | /// Core system | ||
| 230 | Core::System& system; | ||
| 231 | /// (Unused) | ||
| 232 | u32 handle{}; | ||
| 233 | /// (Unused) | ||
| 234 | u64 applet_resource_user_id{}; | ||
| 235 | /// Buffer event, signalled when a buffer is ready | ||
| 236 | Kernel::KEvent* buffer_event; | ||
| 237 | /// Session id of this system | ||
| 238 | size_t session_id{}; | ||
| 239 | /// Device session for this system | ||
| 240 | std::unique_ptr<DeviceSession> session; | ||
| 241 | /// Audio buffers in use by this system | ||
| 242 | AudioBuffers<BufferCount> buffers{BufferCount}; | ||
| 243 | /// Sample rate of this system | ||
| 244 | u32 sample_rate{}; | ||
| 245 | /// Sample format of this system | ||
| 246 | SampleFormat sample_format{SampleFormat::PcmInt16}; | ||
| 247 | /// Channel count of this system | ||
| 248 | u16 channel_count{}; | ||
| 249 | /// State of this system | ||
| 250 | std::atomic<State> state{State::Stopped}; | ||
| 251 | /// Name of this system | ||
| 252 | std::string name{}; | ||
| 253 | /// Volume of this system | ||
| 254 | f32 volume{1.0f}; | ||
| 255 | }; | ||
| 256 | |||
| 257 | } // namespace AudioCore::AudioOut | ||