Developing iOS application which uses CoreAudio framework, I am dealing with IMHO nonsense behavior of SDL reg. playing audio. SDL plays audio in loop, and only way how to trigger playback is to call SDL_PauseAudio(0)
, and the only way how to stop it (without other side effects, which I won't talk about here) is to call SDL_PauseAudio(1)
. As far as I know.
What is the problem for me in SDL here? Simply - next call to SDL_PauseAudio(1)
actually RESUMES the playback, causing the framework to play some mess *before asking for new sound data*. This is because of the way how SDL_CoreAudio.c implements the playback loop.
It means, that SDL does not implement STOP, it implements just PAUSE/RESUME and incorrectly manages audio processing. It means, that if you play sampleA, and want to play sampleB later on, you will hear also fragments of sampleA while expecting just to hear playback of sampleB.
If am wrong, please correct me.
If not, here's my diff, that I used to implement also STOP behavior: as soon as I finish playing sampleA, I call SDL_PauseAudio(2)
so that playback loop quits and next call to SDL_PauseAudio(0) starts it again, this time by playing no mess from sampleA, but correctly playing just data from smapleB.
Index: src/audio/coreaudio/SDL_coreaudio.c
===================================================================
--- src/audio/coreaudio/SDL_coreaudio.c
+++ src/audio/coreaudio/SDL_coreaudio.c
@@ -250,6 +250,12 @@
abuf = &ioData->mBuffers[i];
SDL_memset(abuf->mData, this->spec.silence, abuf->mDataByteSize);
}
+ if (2 == this->paused)
+ {
+ // this changes 'pause' behavior to 'stop' behavior - next
+ // plyaing starts from beginning, i.e. it won't resume
+ this->hidden->bufferOffset = this->hidden->bufferSize;
+ }
return 0;
}
I am shamed that I edited SDL code, but I have no connection to authors and haven't found any help around. Well, it is strange for me, that no one seems to need STOP behavior in SDL?
A way around your issue is for instance to better manage your audio device with SDL. Here is what I suggest :
void myAudioCallback(void *userdata, Uint8 *stream, int len) { ... }
SDL_AudioDeviceID audioDevice;
void startAudio()
{
// prepare the device
static SDL_AudioSpec audioSpec;
SDL_zero(audioSpec);
audioSpec.channels = 2;
audioSpec.freq = 44100;
audioSpec.format = AUDIO_S16SYS;
audioSpec.userdata = (void*)myDataLocation;
audioSpec.callback = myAudioCallback;
audioDevice = SDL_OpenAudioDevice(NULL, 0, &audioSpec, &audioSpec, 0);
// actually start playback
SDL_PauseAudioDevice(audioDevice, 0);
}
void stopAudio()
{
SDL_CloseAudioDevice(audioDevice);
}
This works for me, the callback is not called after stopAudio() and no garbage is sent to the speaker either.