CSDLAudioDriver.cpp 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. #include "common.h"
  2. #include "CSDLAudioDriver.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. {
  9. auto* driver = reinterpret_cast <CSDLAudioDriver*> (userdata);
  10. memset (streamData, 0, length);
  11. // if audio is playing do not do anything here!
  12. if (driver->getAudioDetector ().anythingPlaying ())
  13. return;
  14. for (const auto& buffer : driver->getStreams ())
  15. {
  16. uint8_t* streamDataPointer = streamData;
  17. int streamLength = length;
  18. int len1, audio_size;
  19. // sound is not initialized or stopped and is not in loop mode
  20. // ignore mixing it in
  21. if (!buffer->stream->isInitialized ())
  22. continue;
  23. // check if queue is empty and signal the read thread
  24. if (buffer->stream->isQueueEmpty ())
  25. {
  26. SDL_CondSignal (buffer->stream->getWaitCondition ());
  27. continue;
  28. }
  29. while (streamLength > 0 && driver->getApplicationContext ().state.general.keepRunning)
  30. {
  31. if (buffer->audio_buf_index >= buffer->audio_buf_size)
  32. {
  33. // get more data to fill the buffer
  34. audio_size = buffer->stream->decodeFrame (buffer->audio_buf, sizeof (buffer->audio_buf));
  35. if (audio_size < 0)
  36. {
  37. // fallback for errors, silence
  38. buffer->audio_buf_size = 1024;
  39. memset(buffer->audio_buf, 0, buffer->audio_buf_size);
  40. }
  41. else
  42. {
  43. buffer->audio_buf_size = audio_size;
  44. }
  45. buffer->audio_buf_index = 0;
  46. }
  47. len1 = buffer->audio_buf_size - buffer->audio_buf_index;
  48. if (len1 > streamLength)
  49. len1 = streamLength;
  50. // mix the audio
  51. SDL_MixAudioFormat (
  52. streamDataPointer, &buffer->audio_buf [buffer->audio_buf_index],
  53. driver->getSpec ().format, len1, driver->getApplicationContext ().state.audio.volume
  54. );
  55. streamLength -= len1;
  56. streamDataPointer += len1;
  57. buffer->audio_buf_index += len1;
  58. }
  59. }
  60. }
  61. CSDLAudioDriver::CSDLAudioDriver (Application::CApplicationContext& applicationContext, Detectors::CAudioPlayingDetector& detector, Recorders::CPlaybackRecorder& recorder) :
  62. CAudioDriver (applicationContext, detector, recorder),
  63. m_initialized (false),
  64. m_audioSpec ()
  65. {
  66. if (SDL_InitSubSystem (SDL_INIT_AUDIO) < 0)
  67. {
  68. sLog.error ("Cannot initialize SDL audio system, SDL_GetError: ", SDL_GetError ());
  69. sLog.error ("Continuing without audio support");
  70. return;
  71. }
  72. SDL_AudioSpec requestedSpec;
  73. memset (&requestedSpec, 0, sizeof (requestedSpec));
  74. requestedSpec.freq = 48000;
  75. requestedSpec.format = AUDIO_F32;
  76. requestedSpec.channels = 2;
  77. requestedSpec.samples = SDL_AUDIO_BUFFER_SIZE;
  78. requestedSpec.callback = audio_callback;
  79. requestedSpec.userdata = this;
  80. this->m_deviceID = SDL_OpenAudioDevice (nullptr, false, &requestedSpec, &this->m_audioSpec, SDL_AUDIO_ALLOW_ANY_CHANGE);
  81. if (this->m_deviceID == 0)
  82. {
  83. sLog.error ("SDL_OpenAudioDevice: ", SDL_GetError ());
  84. return;
  85. }
  86. SDL_PauseAudioDevice (this->m_deviceID, 0);
  87. this->m_initialized = true;
  88. }
  89. CSDLAudioDriver::~CSDLAudioDriver ()
  90. {
  91. if (!this->m_initialized)
  92. return;
  93. SDL_CloseAudioDevice (this->m_deviceID);
  94. SDL_QuitSubSystem (SDL_INIT_AUDIO);
  95. }
  96. void CSDLAudioDriver::addStream (CAudioStream* stream)
  97. {
  98. this->m_streams.push_back (new CSDLAudioBuffer { stream });
  99. }
  100. const std::vector <CSDLAudioBuffer*>& CSDLAudioDriver::getStreams ()
  101. {
  102. return this->m_streams;
  103. }
  104. AVSampleFormat CSDLAudioDriver::getFormat () const
  105. {
  106. switch (this->m_audioSpec.format)
  107. {
  108. case AUDIO_U8: case AUDIO_S8: return AV_SAMPLE_FMT_U8;
  109. case AUDIO_U16MSB: case AUDIO_U16LSB: case AUDIO_S16LSB: case AUDIO_S16MSB: return AV_SAMPLE_FMT_S16;
  110. case AUDIO_S32LSB: case AUDIO_S32MSB: return AV_SAMPLE_FMT_S32;
  111. case AUDIO_F32LSB: case AUDIO_F32MSB: return AV_SAMPLE_FMT_FLT;
  112. }
  113. sLog.exception ("Cannot convert from SDL format to ffmpeg format, aborting...");
  114. }
  115. int CSDLAudioDriver::getSampleRate () const
  116. {
  117. return this->m_audioSpec.freq;
  118. }
  119. int CSDLAudioDriver::getChannels () const
  120. {
  121. return this->m_audioSpec.channels;
  122. }
  123. const SDL_AudioSpec& CSDLAudioDriver::getSpec () const
  124. {
  125. return this->m_audioSpec;
  126. }