audout_u.cpp 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. // Copyright 2018 yuzu emulator team
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <array>
  5. #include <cstring>
  6. #include <vector>
  7. #include "audio_core/audio_out.h"
  8. #include "audio_core/codec.h"
  9. #include "common/common_funcs.h"
  10. #include "common/logging/log.h"
  11. #include "common/swap.h"
  12. #include "core/core.h"
  13. #include "core/hle/ipc_helpers.h"
  14. #include "core/hle/kernel/hle_ipc.h"
  15. #include "core/hle/kernel/kernel.h"
  16. #include "core/hle/kernel/readable_event.h"
  17. #include "core/hle/kernel/writable_event.h"
  18. #include "core/hle/service/audio/audout_u.h"
  19. #include "core/memory.h"
  20. namespace Service::Audio {
  21. namespace ErrCodes {
  22. enum {
  23. ErrorUnknown = 2,
  24. BufferCountExceeded = 8,
  25. };
  26. }
  27. constexpr std::array<char, 10> DefaultDevice{{"DeviceOut"}};
  28. constexpr int DefaultSampleRate{48000};
  29. struct AudoutParams {
  30. s32_le sample_rate;
  31. u16_le channel_count;
  32. INSERT_PADDING_BYTES(2);
  33. };
  34. static_assert(sizeof(AudoutParams) == 0x8, "AudoutParams is an invalid size");
  35. enum class AudioState : u32 {
  36. Started,
  37. Stopped,
  38. };
  39. class IAudioOut final : public ServiceFramework<IAudioOut> {
  40. public:
  41. IAudioOut(AudoutParams audio_params, AudioCore::AudioOut& audio_core, std::string&& device_name,
  42. std::string&& unique_name)
  43. : ServiceFramework("IAudioOut"), audio_core(audio_core),
  44. device_name(std::move(device_name)), audio_params(audio_params) {
  45. static const FunctionInfo functions[] = {
  46. {0, &IAudioOut::GetAudioOutState, "GetAudioOutState"},
  47. {1, &IAudioOut::StartAudioOut, "StartAudioOut"},
  48. {2, &IAudioOut::StopAudioOut, "StopAudioOut"},
  49. {3, &IAudioOut::AppendAudioOutBufferImpl, "AppendAudioOutBuffer"},
  50. {4, &IAudioOut::RegisterBufferEvent, "RegisterBufferEvent"},
  51. {5, &IAudioOut::GetReleasedAudioOutBufferImpl, "GetReleasedAudioOutBuffer"},
  52. {6, &IAudioOut::ContainsAudioOutBuffer, "ContainsAudioOutBuffer"},
  53. {7, &IAudioOut::AppendAudioOutBufferImpl, "AppendAudioOutBufferAuto"},
  54. {8, &IAudioOut::GetReleasedAudioOutBufferImpl, "GetReleasedAudioOutBufferAuto"},
  55. {9, &IAudioOut::GetAudioOutBufferCount, "GetAudioOutBufferCount"},
  56. {10, nullptr, "GetAudioOutPlayedSampleCount"},
  57. {11, nullptr, "FlushAudioOutBuffers"},
  58. };
  59. RegisterHandlers(functions);
  60. // This is the event handle used to check if the audio buffer was released
  61. auto& system = Core::System::GetInstance();
  62. buffer_event = Kernel::WritableEvent::CreateEventPair(
  63. system.Kernel(), Kernel::ResetType::Sticky, "IAudioOutBufferReleased");
  64. stream = audio_core.OpenStream(system.CoreTiming(), audio_params.sample_rate,
  65. audio_params.channel_count, std::move(unique_name),
  66. [=]() { buffer_event.writable->Signal(); });
  67. }
  68. private:
  69. struct AudioBuffer {
  70. u64_le next;
  71. u64_le buffer;
  72. u64_le buffer_capacity;
  73. u64_le buffer_size;
  74. u64_le offset;
  75. };
  76. static_assert(sizeof(AudioBuffer) == 0x28, "AudioBuffer is an invalid size");
  77. void GetAudioOutState(Kernel::HLERequestContext& ctx) {
  78. LOG_DEBUG(Service_Audio, "called");
  79. IPC::ResponseBuilder rb{ctx, 3};
  80. rb.Push(RESULT_SUCCESS);
  81. rb.Push(static_cast<u32>(stream->IsPlaying() ? AudioState::Started : AudioState::Stopped));
  82. }
  83. void StartAudioOut(Kernel::HLERequestContext& ctx) {
  84. LOG_DEBUG(Service_Audio, "called");
  85. if (stream->IsPlaying()) {
  86. IPC::ResponseBuilder rb{ctx, 2};
  87. rb.Push(ResultCode(ErrorModule::Audio, ErrCodes::ErrorUnknown));
  88. return;
  89. }
  90. audio_core.StartStream(stream);
  91. IPC::ResponseBuilder rb{ctx, 2};
  92. rb.Push(RESULT_SUCCESS);
  93. }
  94. void StopAudioOut(Kernel::HLERequestContext& ctx) {
  95. LOG_DEBUG(Service_Audio, "called");
  96. audio_core.StopStream(stream);
  97. IPC::ResponseBuilder rb{ctx, 2};
  98. rb.Push(RESULT_SUCCESS);
  99. }
  100. void RegisterBufferEvent(Kernel::HLERequestContext& ctx) {
  101. LOG_DEBUG(Service_Audio, "called");
  102. IPC::ResponseBuilder rb{ctx, 2, 1};
  103. rb.Push(RESULT_SUCCESS);
  104. rb.PushCopyObjects(buffer_event.readable);
  105. }
  106. void AppendAudioOutBufferImpl(Kernel::HLERequestContext& ctx) {
  107. LOG_DEBUG(Service_Audio, "(STUBBED) called {}", ctx.Description());
  108. IPC::RequestParser rp{ctx};
  109. const auto& input_buffer{ctx.ReadBuffer()};
  110. ASSERT_MSG(input_buffer.size() == sizeof(AudioBuffer),
  111. "AudioBuffer input is an invalid size!");
  112. AudioBuffer audio_buffer{};
  113. std::memcpy(&audio_buffer, input_buffer.data(), sizeof(AudioBuffer));
  114. const u64 tag{rp.Pop<u64>()};
  115. std::vector<s16> samples(audio_buffer.buffer_size / sizeof(s16));
  116. Memory::ReadBlock(audio_buffer.buffer, samples.data(), audio_buffer.buffer_size);
  117. if (!audio_core.QueueBuffer(stream, tag, std::move(samples))) {
  118. IPC::ResponseBuilder rb{ctx, 2};
  119. rb.Push(ResultCode(ErrorModule::Audio, ErrCodes::BufferCountExceeded));
  120. }
  121. IPC::ResponseBuilder rb{ctx, 2};
  122. rb.Push(RESULT_SUCCESS);
  123. }
  124. void GetReleasedAudioOutBufferImpl(Kernel::HLERequestContext& ctx) {
  125. LOG_DEBUG(Service_Audio, "called {}", ctx.Description());
  126. IPC::RequestParser rp{ctx};
  127. const u64 max_count{ctx.GetWriteBufferSize() / sizeof(u64)};
  128. const auto released_buffers{audio_core.GetTagsAndReleaseBuffers(stream, max_count)};
  129. std::vector<u64> tags{released_buffers};
  130. tags.resize(max_count);
  131. ctx.WriteBuffer(tags);
  132. IPC::ResponseBuilder rb{ctx, 3};
  133. rb.Push(RESULT_SUCCESS);
  134. rb.Push<u32>(static_cast<u32>(released_buffers.size()));
  135. }
  136. void ContainsAudioOutBuffer(Kernel::HLERequestContext& ctx) {
  137. LOG_DEBUG(Service_Audio, "called");
  138. IPC::RequestParser rp{ctx};
  139. const u64 tag{rp.Pop<u64>()};
  140. IPC::ResponseBuilder rb{ctx, 3};
  141. rb.Push(RESULT_SUCCESS);
  142. rb.Push(stream->ContainsBuffer(tag));
  143. }
  144. void GetAudioOutBufferCount(Kernel::HLERequestContext& ctx) {
  145. LOG_DEBUG(Service_Audio, "called");
  146. IPC::ResponseBuilder rb{ctx, 3};
  147. rb.Push(RESULT_SUCCESS);
  148. rb.Push(static_cast<u32>(stream->GetQueueSize()));
  149. }
  150. AudioCore::AudioOut& audio_core;
  151. AudioCore::StreamPtr stream;
  152. std::string device_name;
  153. AudoutParams audio_params{};
  154. /// This is the event handle used to check if the audio buffer was released
  155. Kernel::EventPair buffer_event;
  156. };
  157. void AudOutU::ListAudioOutsImpl(Kernel::HLERequestContext& ctx) {
  158. LOG_DEBUG(Service_Audio, "called");
  159. IPC::RequestParser rp{ctx};
  160. ctx.WriteBuffer(DefaultDevice);
  161. IPC::ResponseBuilder rb{ctx, 3};
  162. rb.Push(RESULT_SUCCESS);
  163. rb.Push<u32>(1); // Amount of audio devices
  164. }
  165. void AudOutU::OpenAudioOutImpl(Kernel::HLERequestContext& ctx) {
  166. LOG_DEBUG(Service_Audio, "called");
  167. const auto device_name_data{ctx.ReadBuffer()};
  168. std::string device_name;
  169. if (device_name_data[0] != '\0') {
  170. device_name.assign(device_name_data.begin(), device_name_data.end());
  171. } else {
  172. device_name.assign(DefaultDevice.begin(), DefaultDevice.end());
  173. }
  174. ctx.WriteBuffer(device_name);
  175. IPC::RequestParser rp{ctx};
  176. auto params{rp.PopRaw<AudoutParams>()};
  177. if (params.channel_count <= 2) {
  178. // Mono does not exist for audout
  179. params.channel_count = 2;
  180. } else {
  181. params.channel_count = 6;
  182. }
  183. if (!params.sample_rate) {
  184. params.sample_rate = DefaultSampleRate;
  185. }
  186. std::string unique_name{fmt::format("{}-{}", device_name, audio_out_interfaces.size())};
  187. auto audio_out_interface = std::make_shared<IAudioOut>(
  188. params, *audio_core, std::move(device_name), std::move(unique_name));
  189. IPC::ResponseBuilder rb{ctx, 6, 0, 1};
  190. rb.Push(RESULT_SUCCESS);
  191. rb.Push<u32>(DefaultSampleRate);
  192. rb.Push<u32>(params.channel_count);
  193. rb.Push<u32>(static_cast<u32>(AudioCore::Codec::PcmFormat::Int16));
  194. rb.Push<u32>(static_cast<u32>(AudioState::Stopped));
  195. rb.PushIpcInterface<Audio::IAudioOut>(audio_out_interface);
  196. audio_out_interfaces.push_back(std::move(audio_out_interface));
  197. }
  198. AudOutU::AudOutU() : ServiceFramework("audout:u") {
  199. static const FunctionInfo functions[] = {{0, &AudOutU::ListAudioOutsImpl, "ListAudioOuts"},
  200. {1, &AudOutU::OpenAudioOutImpl, "OpenAudioOut"},
  201. {2, &AudOutU::ListAudioOutsImpl, "ListAudioOutsAuto"},
  202. {3, &AudOutU::OpenAudioOutImpl, "OpenAudioOutAuto"}};
  203. RegisterHandlers(functions);
  204. audio_core = std::make_unique<AudioCore::AudioOut>();
  205. }
  206. AudOutU::~AudOutU() = default;
  207. } // namespace Service::Audio