SDLAudioDriver.cpp 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. #include "SDLAudioDriver.h"
  2. #include "WallpaperEngine/Logging/Log.h"
  3. #define SDL_AUDIO_BUFFER_SIZE 4096
  4. #define MAX_AUDIO_FRAME_SIZE 192000
  5. using namespace WallpaperEngine::Audio;
  6. using namespace WallpaperEngine::Audio::Drivers;
  7. void audio_callback (void* userdata, uint8_t* streamData, int length) {
  8. auto* driver = static_cast<SDLAudioDriver*> (userdata);
  9. memset (streamData, 0, length);
  10. // if audio is playing do not do anything here!
  11. if (driver->getAudioDetector ().anythingPlaying ()) {
  12. return;
  13. }
  14. SDL_LockMutex (driver->getStreamMutex ());
  15. for (const auto& buffer : driver->getStreams () | std::views::values) {
  16. uint8_t* streamDataPointer = streamData;
  17. int streamLength = length;
  18. // sound is not initialized or stopped and is not in loop mode
  19. // ignore mixing it in
  20. if (!buffer->stream->isInitialized ()) {
  21. continue;
  22. }
  23. // check if queue is empty and signal the read thread
  24. if (buffer->stream->isQueueEmpty ()) {
  25. SDL_CondSignal (buffer->stream->getWaitCondition ());
  26. continue;
  27. }
  28. while (streamLength > 0 && driver->getApplicationContext ().state.general.keepRunning) {
  29. if (buffer->audio_buf_index >= buffer->audio_buf_size) {
  30. // get more data to fill the buffer
  31. int audio_size = buffer->stream->decodeFrame (buffer->audio_buf, sizeof (buffer->audio_buf));
  32. if (audio_size < 0) {
  33. // fallback for errors, silence
  34. buffer->audio_buf_size = 1024;
  35. memset (buffer->audio_buf, 0, buffer->audio_buf_size);
  36. } else {
  37. buffer->audio_buf_size = audio_size;
  38. }
  39. buffer->audio_buf_index = 0;
  40. }
  41. int len1 = buffer->audio_buf_size - buffer->audio_buf_index;
  42. if (len1 > streamLength) {
  43. len1 = streamLength;
  44. }
  45. // mix the audio
  46. SDL_MixAudioFormat (
  47. streamDataPointer, &buffer->audio_buf[buffer->audio_buf_index], driver->getSpec ().format, len1,
  48. driver->getApplicationContext ().state.audio.volume
  49. );
  50. streamLength -= len1;
  51. streamDataPointer += len1;
  52. buffer->audio_buf_index += len1;
  53. }
  54. }
  55. // TODO: DO WE NEED TO ALSO LOCK WHILE THE AUDIO IS PLAYING? OR SOMEHOW WAIT UNTIL THE STREAM IS NOT IN USE ANYMORE?
  56. SDL_UnlockMutex (driver->getStreamMutex ());
  57. }
  58. SDLAudioDriver::SDLAudioDriver (
  59. Application::ApplicationContext& applicationContext, Detectors::AudioPlayingDetector& detector,
  60. Recorders::PlaybackRecorder& recorder
  61. ) : AudioDriver (applicationContext, detector, recorder), m_audioSpec () {
  62. this->m_streamListMutex = SDL_CreateMutex ();
  63. if (SDL_InitSubSystem (SDL_INIT_AUDIO) < 0) {
  64. sLog.error ("Cannot initialize SDL audio system, SDL_GetError: ", SDL_GetError ());
  65. sLog.error ("Continuing without audio support");
  66. return;
  67. }
  68. const SDL_AudioSpec requestedSpec = { .freq = 48000,
  69. .format = AUDIO_F32,
  70. .channels = 2,
  71. .samples = SDL_AUDIO_BUFFER_SIZE,
  72. .callback = audio_callback,
  73. .userdata = this };
  74. this->m_deviceID
  75. = SDL_OpenAudioDevice (nullptr, false, &requestedSpec, &this->m_audioSpec, SDL_AUDIO_ALLOW_ANY_CHANGE);
  76. if (this->m_deviceID == 0) {
  77. sLog.error ("SDL_OpenAudioDevice: ", SDL_GetError ());
  78. return;
  79. }
  80. SDL_PauseAudioDevice (this->m_deviceID, 0);
  81. this->m_initialized = true;
  82. }
  83. SDLAudioDriver::~SDLAudioDriver () {
  84. if (!this->m_initialized) {
  85. return;
  86. }
  87. if (this->m_deviceID != 0) {
  88. SDL_CloseAudioDevice (this->m_deviceID);
  89. }
  90. SDL_QuitSubSystem (SDL_INIT_AUDIO);
  91. }
  92. int SDLAudioDriver::addStream (AudioStream* stream) {
  93. const int newStreamId = this->m_lastStreamID;
  94. this->m_lastStreamID++;
  95. SDL_LockMutex (this->m_streamListMutex);
  96. this->m_streams.insert_or_assign (newStreamId, new SDLAudioBuffer { stream });
  97. SDL_UnlockMutex (this->m_streamListMutex);
  98. return newStreamId;
  99. }
  100. void SDLAudioDriver::removeStream (int streamId) { this->m_streams.erase (streamId); }
  101. const std::map<int, SDLAudioBuffer*>& SDLAudioDriver::getStreams () { return this->m_streams; }
  102. AVSampleFormat SDLAudioDriver::getFormat () const {
  103. switch (this->m_audioSpec.format) {
  104. case AUDIO_U8:
  105. case AUDIO_S8:
  106. return AV_SAMPLE_FMT_U8;
  107. case AUDIO_U16MSB:
  108. case AUDIO_U16LSB:
  109. case AUDIO_S16LSB:
  110. case AUDIO_S16MSB:
  111. return AV_SAMPLE_FMT_S16;
  112. case AUDIO_S32LSB:
  113. case AUDIO_S32MSB:
  114. return AV_SAMPLE_FMT_S32;
  115. case AUDIO_F32LSB:
  116. case AUDIO_F32MSB:
  117. return AV_SAMPLE_FMT_FLT;
  118. default:
  119. sLog.exception ("Cannot convert from SDL format to ffmpeg format, aborting...");
  120. }
  121. }
  122. int SDLAudioDriver::getSampleRate () const { return this->m_audioSpec.freq; }
  123. int SDLAudioDriver::getChannels () const { return this->m_audioSpec.channels; }
  124. const SDL_AudioSpec& SDLAudioDriver::getSpec () const { return this->m_audioSpec; }
  125. SDL_mutex* SDLAudioDriver::getStreamMutex () const { return this->m_streamListMutex; }