audout_u.cpp 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  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 <vector>
  6. #include "audio_core/codec.h"
  7. #include "common/logging/log.h"
  8. #include "core/core.h"
  9. #include "core/hle/ipc_helpers.h"
  10. #include "core/hle/kernel/event.h"
  11. #include "core/hle/kernel/hle_ipc.h"
  12. #include "core/hle/service/audio/audout_u.h"
  13. namespace Service::Audio {
  14. namespace ErrCodes {
  15. enum {
  16. ErrorUnknown = 2,
  17. BufferCountExceeded = 8,
  18. };
  19. }
  20. constexpr std::array<char, 10> DefaultDevice{{"DeviceOut"}};
  21. constexpr int DefaultSampleRate{48000};
  22. class IAudioOut final : public ServiceFramework<IAudioOut> {
  23. public:
  24. IAudioOut(AudoutParams audio_params, AudioCore::AudioOut& audio_core)
  25. : ServiceFramework("IAudioOut"), audio_core(audio_core), audio_params(audio_params) {
  26. static const FunctionInfo functions[] = {
  27. {0, &IAudioOut::GetAudioOutState, "GetAudioOutState"},
  28. {1, &IAudioOut::StartAudioOut, "StartAudioOut"},
  29. {2, &IAudioOut::StopAudioOut, "StopAudioOut"},
  30. {3, &IAudioOut::AppendAudioOutBufferImpl, "AppendAudioOutBuffer"},
  31. {4, &IAudioOut::RegisterBufferEvent, "RegisterBufferEvent"},
  32. {5, &IAudioOut::GetReleasedAudioOutBufferImpl, "GetReleasedAudioOutBuffer"},
  33. {6, &IAudioOut::ContainsAudioOutBuffer, "ContainsAudioOutBuffer"},
  34. {7, &IAudioOut::AppendAudioOutBufferImpl, "AppendAudioOutBufferAuto"},
  35. {8, &IAudioOut::GetReleasedAudioOutBufferImpl, "GetReleasedAudioOutBufferAuto"},
  36. {9, &IAudioOut::GetAudioOutBufferCount, "GetAudioOutBufferCount"},
  37. {10, nullptr, "GetAudioOutPlayedSampleCount"},
  38. {11, nullptr, "FlushAudioOutBuffers"},
  39. };
  40. RegisterHandlers(functions);
  41. // This is the event handle used to check if the audio buffer was released
  42. auto& kernel = Core::System::GetInstance().Kernel();
  43. buffer_event =
  44. Kernel::Event::Create(kernel, Kernel::ResetType::Sticky, "IAudioOutBufferReleased");
  45. stream = audio_core.OpenStream(audio_params.sample_rate, audio_params.channel_count,
  46. "IAudioOut", [=]() { buffer_event->Signal(); });
  47. }
  48. private:
  49. struct AudioBuffer {
  50. u64_le next;
  51. u64_le buffer;
  52. u64_le buffer_capacity;
  53. u64_le buffer_size;
  54. u64_le offset;
  55. };
  56. static_assert(sizeof(AudioBuffer) == 0x28, "AudioBuffer is an invalid size");
  57. void GetAudioOutState(Kernel::HLERequestContext& ctx) {
  58. LOG_DEBUG(Service_Audio, "called");
  59. IPC::ResponseBuilder rb{ctx, 3};
  60. rb.Push(RESULT_SUCCESS);
  61. rb.Push(static_cast<u32>(stream->IsPlaying() ? AudioState::Started : AudioState::Stopped));
  62. }
  63. void StartAudioOut(Kernel::HLERequestContext& ctx) {
  64. LOG_DEBUG(Service_Audio, "called");
  65. if (stream->IsPlaying()) {
  66. IPC::ResponseBuilder rb{ctx, 2};
  67. rb.Push(ResultCode(ErrorModule::Audio, ErrCodes::ErrorUnknown));
  68. return;
  69. }
  70. audio_core.StartStream(stream);
  71. IPC::ResponseBuilder rb{ctx, 2};
  72. rb.Push(RESULT_SUCCESS);
  73. }
  74. void StopAudioOut(Kernel::HLERequestContext& ctx) {
  75. LOG_DEBUG(Service_Audio, "called");
  76. audio_core.StopStream(stream);
  77. IPC::ResponseBuilder rb{ctx, 2};
  78. rb.Push(RESULT_SUCCESS);
  79. }
  80. void RegisterBufferEvent(Kernel::HLERequestContext& ctx) {
  81. LOG_DEBUG(Service_Audio, "called");
  82. IPC::ResponseBuilder rb{ctx, 2, 1};
  83. rb.Push(RESULT_SUCCESS);
  84. rb.PushCopyObjects(buffer_event);
  85. }
  86. void AppendAudioOutBufferImpl(Kernel::HLERequestContext& ctx) {
  87. LOG_DEBUG(Service_Audio, "(STUBBED) called {}", ctx.Description());
  88. IPC::RequestParser rp{ctx};
  89. const auto& input_buffer{ctx.ReadBuffer()};
  90. ASSERT_MSG(input_buffer.size() == sizeof(AudioBuffer),
  91. "AudioBuffer input is an invalid size!");
  92. AudioBuffer audio_buffer{};
  93. std::memcpy(&audio_buffer, input_buffer.data(), sizeof(AudioBuffer));
  94. const u64 tag{rp.Pop<u64>()};
  95. std::vector<s16> samples(audio_buffer.buffer_size / sizeof(s16));
  96. Memory::ReadBlock(audio_buffer.buffer, samples.data(), audio_buffer.buffer_size);
  97. if (!audio_core.QueueBuffer(stream, tag, std::move(samples))) {
  98. IPC::ResponseBuilder rb{ctx, 2};
  99. rb.Push(ResultCode(ErrorModule::Audio, ErrCodes::BufferCountExceeded));
  100. }
  101. IPC::ResponseBuilder rb{ctx, 2};
  102. rb.Push(RESULT_SUCCESS);
  103. }
  104. void GetReleasedAudioOutBufferImpl(Kernel::HLERequestContext& ctx) {
  105. LOG_DEBUG(Service_Audio, "called {}", ctx.Description());
  106. IPC::RequestParser rp{ctx};
  107. const u64 max_count{ctx.GetWriteBufferSize() / sizeof(u64)};
  108. const auto released_buffers{audio_core.GetTagsAndReleaseBuffers(stream, max_count)};
  109. std::vector<u64> tags{released_buffers};
  110. tags.resize(max_count);
  111. ctx.WriteBuffer(tags);
  112. IPC::ResponseBuilder rb{ctx, 3};
  113. rb.Push(RESULT_SUCCESS);
  114. rb.Push<u32>(static_cast<u32>(released_buffers.size()));
  115. }
  116. void ContainsAudioOutBuffer(Kernel::HLERequestContext& ctx) {
  117. LOG_DEBUG(Service_Audio, "called");
  118. IPC::RequestParser rp{ctx};
  119. const u64 tag{rp.Pop<u64>()};
  120. IPC::ResponseBuilder rb{ctx, 3};
  121. rb.Push(RESULT_SUCCESS);
  122. rb.Push(stream->ContainsBuffer(tag));
  123. }
  124. void GetAudioOutBufferCount(Kernel::HLERequestContext& ctx) {
  125. LOG_DEBUG(Service_Audio, "called");
  126. IPC::ResponseBuilder rb{ctx, 3};
  127. rb.Push(RESULT_SUCCESS);
  128. rb.Push(static_cast<u32>(stream->GetQueueSize()));
  129. }
  130. AudioCore::AudioOut& audio_core;
  131. AudioCore::StreamPtr stream;
  132. AudoutParams audio_params{};
  133. /// This is the evend handle used to check if the audio buffer was released
  134. Kernel::SharedPtr<Kernel::Event> buffer_event;
  135. };
  136. void AudOutU::ListAudioOutsImpl(Kernel::HLERequestContext& ctx) {
  137. LOG_DEBUG(Service_Audio, "called");
  138. IPC::RequestParser rp{ctx};
  139. ctx.WriteBuffer(DefaultDevice);
  140. IPC::ResponseBuilder rb = rp.MakeBuilder(3, 0, 0);
  141. rb.Push(RESULT_SUCCESS);
  142. rb.Push<u32>(1); // Amount of audio devices
  143. }
  144. void AudOutU::OpenAudioOutImpl(Kernel::HLERequestContext& ctx) {
  145. LOG_DEBUG(Service_Audio, "called");
  146. ctx.WriteBuffer(DefaultDevice);
  147. IPC::RequestParser rp{ctx};
  148. auto params{rp.PopRaw<AudoutParams>()};
  149. if (params.channel_count <= 2) {
  150. // Mono does not exist for audout
  151. params.channel_count = 2;
  152. } else {
  153. params.channel_count = 6;
  154. }
  155. if (!params.sample_rate) {
  156. params.sample_rate = DefaultSampleRate;
  157. }
  158. // TODO(bunnei): Support more than one IAudioOut interface. When we add this, ListAudioOutsImpl
  159. // will likely need to be updated as well.
  160. ASSERT_MSG(!audio_out_interface, "Unimplemented");
  161. audio_out_interface = std::make_shared<IAudioOut>(params, *audio_core);
  162. IPC::ResponseBuilder rb{ctx, 6, 0, 1};
  163. rb.Push(RESULT_SUCCESS);
  164. rb.Push<u32>(DefaultSampleRate);
  165. rb.Push<u32>(params.channel_count);
  166. rb.Push<u32>(static_cast<u32>(AudioCore::Codec::PcmFormat::Int16));
  167. rb.Push<u32>(static_cast<u32>(AudioState::Stopped));
  168. rb.PushIpcInterface<Audio::IAudioOut>(audio_out_interface);
  169. }
  170. AudOutU::AudOutU() : ServiceFramework("audout:u") {
  171. static const FunctionInfo functions[] = {{0, &AudOutU::ListAudioOutsImpl, "ListAudioOuts"},
  172. {1, &AudOutU::OpenAudioOutImpl, "OpenAudioOut"},
  173. {2, &AudOutU::ListAudioOutsImpl, "ListAudioOutsAuto"},
  174. {3, &AudOutU::OpenAudioOutImpl, "OpenAudioOutAuto"}};
  175. RegisterHandlers(functions);
  176. audio_core = std::make_unique<AudioCore::AudioOut>();
  177. }
  178. AudOutU::~AudOutU() = default;
  179. } // namespace Service::Audio