sdl2_sink.cpp 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. // Copyright 2018 yuzu Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <algorithm>
  5. #include <atomic>
  6. #include <cstring>
  7. #include "audio_core/sdl2_sink.h"
  8. #include "audio_core/stream.h"
  9. #include "audio_core/time_stretch.h"
  10. #include "common/assert.h"
  11. #include "common/logging/log.h"
  12. //#include "common/settings.h"
  13. // Ignore -Wimplicit-fallthrough due to https://github.com/libsdl-org/SDL/issues/4307
  14. #ifdef __clang__
  15. #pragma clang diagnostic push
  16. #pragma clang diagnostic ignored "-Wimplicit-fallthrough"
  17. #endif
  18. #include <SDL.h>
  19. #ifdef __clang__
  20. #pragma clang diagnostic pop
  21. #endif
  22. namespace AudioCore {
  23. class SDLSinkStream final : public SinkStream {
  24. public:
  25. SDLSinkStream(u32 sample_rate, u32 num_channels_, const std::string& output_device)
  26. : num_channels{std::min(num_channels_, 6u)}, time_stretch{sample_rate, num_channels} {
  27. SDL_AudioSpec spec;
  28. spec.freq = sample_rate;
  29. spec.channels = static_cast<u8>(num_channels);
  30. spec.format = AUDIO_S16SYS;
  31. spec.samples = 4096;
  32. spec.callback = nullptr;
  33. SDL_AudioSpec obtained;
  34. if (output_device.empty()) {
  35. dev = SDL_OpenAudioDevice(nullptr, 0, &spec, &obtained, 0);
  36. } else {
  37. dev = SDL_OpenAudioDevice(output_device.c_str(), 0, &spec, &obtained, 0);
  38. }
  39. if (dev == 0) {
  40. LOG_CRITICAL(Audio_Sink, "Error opening sdl audio device: {}", SDL_GetError());
  41. return;
  42. }
  43. SDL_PauseAudioDevice(dev, 0);
  44. }
  45. ~SDLSinkStream() override {
  46. if (dev == 0) {
  47. return;
  48. }
  49. SDL_CloseAudioDevice(dev);
  50. }
  51. void EnqueueSamples(u32 source_num_channels, const std::vector<s16>& samples) override {
  52. if (source_num_channels > num_channels) {
  53. // Downsample 6 channels to 2
  54. ASSERT_MSG(source_num_channels == 6, "Channel count must be 6");
  55. std::vector<s16> buf;
  56. buf.reserve(samples.size() * num_channels / source_num_channels);
  57. for (std::size_t i = 0; i < samples.size(); i += source_num_channels) {
  58. // Downmixing implementation taken from the ATSC standard
  59. const s16 left{samples[i + 0]};
  60. const s16 right{samples[i + 1]};
  61. const s16 center{samples[i + 2]};
  62. const s16 surround_left{samples[i + 4]};
  63. const s16 surround_right{samples[i + 5]};
  64. // Not used in the ATSC reference implementation
  65. [[maybe_unused]] const s16 low_frequency_effects{samples[i + 3]};
  66. constexpr s32 clev{707}; // center mixing level coefficient
  67. constexpr s32 slev{707}; // surround mixing level coefficient
  68. buf.push_back(static_cast<s16>(left + (clev * center / 1000) +
  69. (slev * surround_left / 1000)));
  70. buf.push_back(static_cast<s16>(right + (clev * center / 1000) +
  71. (slev * surround_right / 1000)));
  72. }
  73. int ret = SDL_QueueAudio(dev, static_cast<const void*>(buf.data()),
  74. static_cast<u32>(buf.size() * sizeof(s16)));
  75. if (ret < 0)
  76. LOG_WARNING(Audio_Sink, "Could not queue audio buffer: {}", SDL_GetError());
  77. return;
  78. }
  79. int ret = SDL_QueueAudio(dev, static_cast<const void*>(samples.data()),
  80. static_cast<u32>(samples.size() * sizeof(s16)));
  81. if (ret < 0)
  82. LOG_WARNING(Audio_Sink, "Could not queue audio buffer: {}", SDL_GetError());
  83. }
  84. std::size_t SamplesInQueue(u32 channel_count) const override {
  85. if (dev == 0)
  86. return 0;
  87. return SDL_GetQueuedAudioSize(dev) / (channel_count * sizeof(s16));
  88. }
  89. void Flush() override {
  90. should_flush = true;
  91. }
  92. u32 GetNumChannels() const {
  93. return num_channels;
  94. }
  95. private:
  96. SDL_AudioDeviceID dev = 0;
  97. u32 num_channels{};
  98. std::atomic<bool> should_flush{};
  99. TimeStretcher time_stretch;
  100. };
  101. SDLSink::SDLSink(std::string_view target_device_name) {
  102. if (!SDL_WasInit(SDL_INIT_AUDIO)) {
  103. if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) {
  104. LOG_CRITICAL(Audio_Sink, "SDL_InitSubSystem audio failed: {}", SDL_GetError());
  105. return;
  106. }
  107. }
  108. if (target_device_name != auto_device_name && !target_device_name.empty()) {
  109. output_device = target_device_name;
  110. } else {
  111. output_device.clear();
  112. }
  113. }
  114. SDLSink::~SDLSink() = default;
  115. SinkStream& SDLSink::AcquireSinkStream(u32 sample_rate, u32 num_channels, const std::string&) {
  116. sink_streams.push_back(
  117. std::make_unique<SDLSinkStream>(sample_rate, num_channels, output_device));
  118. return *sink_streams.back();
  119. }
  120. std::vector<std::string> ListSDLSinkDevices() {
  121. std::vector<std::string> device_list;
  122. if (!SDL_WasInit(SDL_INIT_AUDIO)) {
  123. if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) {
  124. LOG_CRITICAL(Audio_Sink, "SDL_InitSubSystem audio failed: {}", SDL_GetError());
  125. return {};
  126. }
  127. }
  128. const int device_count = SDL_GetNumAudioDevices(0);
  129. for (int i = 0; i < device_count; ++i) {
  130. device_list.emplace_back(SDL_GetAudioDeviceName(i, 0));
  131. }
  132. return device_list;
  133. }
  134. } // namespace AudioCore