| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164 |
- #include "SDLAudioDriver.h"
- #include "WallpaperEngine/Logging/Log.h"
- #define SDL_AUDIO_BUFFER_SIZE 4096
- #define MAX_AUDIO_FRAME_SIZE 192000
- using namespace WallpaperEngine::Audio;
- using namespace WallpaperEngine::Audio::Drivers;
- void audio_callback (void* userdata, uint8_t* streamData, int length) {
- auto* driver = static_cast<SDLAudioDriver*> (userdata);
- memset (streamData, 0, length);
- // if audio is playing do not do anything here!
- if (driver->getAudioDetector ().anythingPlaying ()) {
- return;
- }
- SDL_LockMutex (driver->getStreamMutex ());
- for (const auto& buffer : driver->getStreams () | std::views::values) {
- uint8_t* streamDataPointer = streamData;
- int streamLength = length;
- // sound is not initialized or stopped and is not in loop mode
- // ignore mixing it in
- if (!buffer->stream->isInitialized ()) {
- continue;
- }
- // check if queue is empty and signal the read thread
- if (buffer->stream->isQueueEmpty ()) {
- SDL_CondSignal (buffer->stream->getWaitCondition ());
- continue;
- }
- while (streamLength > 0 && driver->getApplicationContext ().state.general.keepRunning) {
- if (buffer->audio_buf_index >= buffer->audio_buf_size) {
- // get more data to fill the buffer
- int audio_size = buffer->stream->decodeFrame (buffer->audio_buf, sizeof (buffer->audio_buf));
- if (audio_size < 0) {
- // fallback for errors, silence
- buffer->audio_buf_size = 1024;
- memset (buffer->audio_buf, 0, buffer->audio_buf_size);
- } else {
- buffer->audio_buf_size = audio_size;
- }
- buffer->audio_buf_index = 0;
- }
- int len1 = buffer->audio_buf_size - buffer->audio_buf_index;
- if (len1 > streamLength) {
- len1 = streamLength;
- }
- // mix the audio
- SDL_MixAudioFormat (
- streamDataPointer, &buffer->audio_buf[buffer->audio_buf_index], driver->getSpec ().format, len1,
- driver->getApplicationContext ().state.audio.volume
- );
- streamLength -= len1;
- streamDataPointer += len1;
- buffer->audio_buf_index += len1;
- }
- }
- // TODO: DO WE NEED TO ALSO LOCK WHILE THE AUDIO IS PLAYING? OR SOMEHOW WAIT UNTIL THE STREAM IS NOT IN USE ANYMORE?
- SDL_UnlockMutex (driver->getStreamMutex ());
- }
- SDLAudioDriver::SDLAudioDriver (
- Application::ApplicationContext& applicationContext, Detectors::AudioPlayingDetector& detector,
- Recorders::PlaybackRecorder& recorder
- ) : AudioDriver (applicationContext, detector, recorder), m_audioSpec () {
- this->m_streamListMutex = SDL_CreateMutex ();
- if (SDL_InitSubSystem (SDL_INIT_AUDIO) < 0) {
- sLog.error ("Cannot initialize SDL audio system, SDL_GetError: ", SDL_GetError ());
- sLog.error ("Continuing without audio support");
- return;
- }
- const SDL_AudioSpec requestedSpec = { .freq = 48000,
- .format = AUDIO_F32,
- .channels = 2,
- .samples = SDL_AUDIO_BUFFER_SIZE,
- .callback = audio_callback,
- .userdata = this };
- this->m_deviceID
- = SDL_OpenAudioDevice (nullptr, false, &requestedSpec, &this->m_audioSpec, SDL_AUDIO_ALLOW_ANY_CHANGE);
- if (this->m_deviceID == 0) {
- sLog.error ("SDL_OpenAudioDevice: ", SDL_GetError ());
- return;
- }
- SDL_PauseAudioDevice (this->m_deviceID, 0);
- this->m_initialized = true;
- }
- SDLAudioDriver::~SDLAudioDriver () {
- if (!this->m_initialized) {
- return;
- }
- if (this->m_deviceID != 0) {
- SDL_CloseAudioDevice (this->m_deviceID);
- }
- SDL_QuitSubSystem (SDL_INIT_AUDIO);
- }
- int SDLAudioDriver::addStream (AudioStream* stream) {
- const int newStreamId = this->m_lastStreamID;
- this->m_lastStreamID++;
- SDL_LockMutex (this->m_streamListMutex);
- this->m_streams.insert_or_assign (newStreamId, new SDLAudioBuffer { stream });
- SDL_UnlockMutex (this->m_streamListMutex);
- return newStreamId;
- }
- void SDLAudioDriver::removeStream (int streamId) { this->m_streams.erase (streamId); }
- const std::map<int, SDLAudioBuffer*>& SDLAudioDriver::getStreams () { return this->m_streams; }
- AVSampleFormat SDLAudioDriver::getFormat () const {
- switch (this->m_audioSpec.format) {
- case AUDIO_U8:
- case AUDIO_S8:
- return AV_SAMPLE_FMT_U8;
- case AUDIO_U16MSB:
- case AUDIO_U16LSB:
- case AUDIO_S16LSB:
- case AUDIO_S16MSB:
- return AV_SAMPLE_FMT_S16;
- case AUDIO_S32LSB:
- case AUDIO_S32MSB:
- return AV_SAMPLE_FMT_S32;
- case AUDIO_F32LSB:
- case AUDIO_F32MSB:
- return AV_SAMPLE_FMT_FLT;
- default:
- sLog.exception ("Cannot convert from SDL format to ffmpeg format, aborting...");
- }
- }
- int SDLAudioDriver::getSampleRate () const { return this->m_audioSpec.freq; }
- int SDLAudioDriver::getChannels () const { return this->m_audioSpec.channels; }
- const SDL_AudioSpec& SDLAudioDriver::getSpec () const { return this->m_audioSpec; }
- SDL_mutex* SDLAudioDriver::getStreamMutex () const { return this->m_streamListMutex; }
|