diff --git a/SDL2pp/Audio.hh b/SDL2pp/Audio.hh index 49311b1..e9c7511 100644 --- a/SDL2pp/Audio.hh +++ b/SDL2pp/Audio.hh @@ -32,19 +32,10 @@ namespace SDL2pp { class AudioSpec : public SDL_AudioSpec { -public: - typedef std::function AudioCallback; - -private: - AudioCallback callback_; - -private: - static void SDLCallback(void *userdata, Uint8* stream, int len); public: AudioSpec(); - AudioSpec(int freq, SDL_AudioFormat format, Uint8 channels, Uint16 samples, AudioCallback&& callback = AudioCallback()); - AudioSpec(const AudioSpec& other, AudioCallback&& callback = AudioCallback()); + AudioSpec(int freq, SDL_AudioFormat format, Uint8 channels, Uint16 samples); ~AudioSpec(); AudioSpec(AudioSpec&& other); @@ -52,8 +43,6 @@ public: AudioSpec(const AudioSpec& other) = delete; AudioSpec& operator=(const AudioSpec& other) = delete; - void ChangeCallback(AudioCallback&& callback); // should be called with audio device using this spec locked! - void MergeChanges(const SDL_AudioSpec& obtained); const SDL_AudioSpec* Get() const; @@ -61,9 +50,6 @@ public: }; class AudioDevice { -private: - SDL_AudioDeviceID device_id_; - public: class LockHandle { friend class AudioDevice; @@ -74,6 +60,7 @@ public: LockHandle(AudioDevice* device); public: + LockHandle(); ~LockHandle(); LockHandle(LockHandle&& other) noexcept; @@ -83,9 +70,18 @@ public: LockHandle& operator=(const LockHandle& other) = delete; }; + typedef std::function AudioCallback; + +private: + SDL_AudioDeviceID device_id_; + AudioCallback callback_; + +private: + static void SDLCallback(void *userdata, Uint8* stream, int len); + public: - AudioDevice(const std::string& device, bool iscapture, const AudioSpec& spec); - AudioDevice(const std::string& device, bool iscapture, AudioSpec& spec, int allowed_changes); + AudioDevice(const std::string& device, bool iscapture, const AudioSpec& spec, AudioCallback&& callback = AudioCallback()); + AudioDevice(const std::string& device, bool iscapture, AudioSpec& spec, int allowed_changes, AudioCallback&& callback = AudioCallback()); virtual ~AudioDevice(); AudioDevice(const AudioDevice& other) = delete; @@ -98,6 +94,8 @@ public: void Pause(bool pause_on); SDL_AudioStatus GetStatus() const; + void ChangeCallback(AudioCallback&& callback); + LockHandle Lock(); #ifdef SDL2PP_WITH_2_0_4 diff --git a/SDL2pp/AudioDevice.cc b/SDL2pp/AudioDevice.cc index ba13a50..9a464b1 100644 --- a/SDL2pp/AudioDevice.cc +++ b/SDL2pp/AudioDevice.cc @@ -25,20 +25,39 @@ namespace SDL2pp { -AudioDevice::AudioDevice(const std::string& device, bool iscapture, const AudioSpec& spec) { - SDL_AudioSpec obtained; - - if ((device_id_ = SDL_OpenAudioDevice(device.empty() ? nullptr : device.c_str(), iscapture ? 1 : 0, &spec, &obtained, 0)) == 0) - throw Exception("SDL_OpenAudioDevice failed"); +void AudioDevice::SDLCallback(void *userdata, Uint8* stream, int len) { + AudioDevice* audiodevice = static_cast(userdata); + audiodevice->callback_(stream, len); } -AudioDevice::AudioDevice(const std::string& device, bool iscapture, AudioSpec& spec, int allowed_changes) { +AudioDevice::AudioDevice(const std::string& device, bool iscapture, const AudioSpec& spec, AudioDevice::AudioCallback&& callback) { + SDL_AudioSpec spec_with_callback = *spec.Get(); + if (callback) { + spec_with_callback.callback = SDLCallback; + spec_with_callback.userdata = static_cast(this); + } SDL_AudioSpec obtained; - if ((device_id_ = SDL_OpenAudioDevice(device.empty() ? nullptr : device.c_str(), iscapture ? 1 : 0, &spec, &obtained, allowed_changes)) == 0) + if ((device_id_ = SDL_OpenAudioDevice(device.empty() ? nullptr : device.c_str(), iscapture ? 1 : 0, &spec_with_callback, &obtained, 0)) == 0) + throw Exception("SDL_OpenAudioDevice failed"); + + callback_ = std::move(callback); +} + +AudioDevice::AudioDevice(const std::string& device, bool iscapture, AudioSpec& spec, int allowed_changes, AudioDevice::AudioCallback&& callback) { + SDL_AudioSpec spec_with_callback = *spec.Get(); + if (callback) { + spec_with_callback.callback = SDLCallback; + spec_with_callback.userdata = static_cast(this); + } + SDL_AudioSpec obtained; + + if ((device_id_ = SDL_OpenAudioDevice(device.empty() ? nullptr : device.c_str(), iscapture ? 1 : 0, &spec_with_callback, &obtained, allowed_changes)) == 0) throw Exception("SDL_OpenAudioDevice failed"); spec.MergeChanges(obtained); + + callback_ = std::move(callback); } AudioDevice::~AudioDevice() { @@ -46,7 +65,7 @@ AudioDevice::~AudioDevice() { SDL_CloseAudioDevice(device_id_); } -AudioDevice::AudioDevice(AudioDevice&& other) noexcept : device_id_(other.device_id_) { +AudioDevice::AudioDevice(AudioDevice&& other) noexcept : device_id_(other.device_id_), callback_(std::move(other.callback_)) { other.device_id_ = 0; } @@ -58,6 +77,7 @@ AudioDevice& AudioDevice::operator=(AudioDevice&& other) noexcept { SDL_CloseAudioDevice(device_id_); device_id_ = other.device_id_; + callback_ = std::move(other.callback_); other.device_id_ = 0; return *this; @@ -75,6 +95,13 @@ SDL_AudioStatus AudioDevice::GetStatus() const { return SDL_GetAudioDeviceStatus(device_id_); } +void AudioDevice::ChangeCallback(AudioDevice::AudioCallback&& callback) { + // make sure callback is not called while it's being replaced + LockHandle lock = Lock(); + + callback_ = std::move(callback); +} + AudioDevice::LockHandle AudioDevice::Lock() { return LockHandle(this); } diff --git a/SDL2pp/AudioLock.cc b/SDL2pp/AudioLock.cc index c60f87b..b2d8754 100644 --- a/SDL2pp/AudioLock.cc +++ b/SDL2pp/AudioLock.cc @@ -23,6 +23,9 @@ namespace SDL2pp { +AudioDevice::LockHandle::LockHandle() : device_(nullptr) { +} + AudioDevice::LockHandle::LockHandle(AudioDevice* device) : device_(device) { SDL_LockAudioDevice(device_->device_id_); } diff --git a/SDL2pp/AudioSpec.cc b/SDL2pp/AudioSpec.cc index 4737adf..e584384 100644 --- a/SDL2pp/AudioSpec.cc +++ b/SDL2pp/AudioSpec.cc @@ -25,33 +25,16 @@ namespace SDL2pp { -void AudioSpec::SDLCallback(void *userdata, Uint8* stream, int len) { - AudioSpec* audiospec = static_cast(userdata); - audiospec->callback_(stream, len); -} - AudioSpec::AudioSpec() { std::fill((char*)this, (char*)this + sizeof(SDL_AudioSpec), 0); } -AudioSpec::AudioSpec(int freq, SDL_AudioFormat format, Uint8 channels, Uint16 samples, AudioSpec::AudioCallback&& callback) - : callback_(std::move(callback)) { +AudioSpec::AudioSpec(int freq, SDL_AudioFormat format, Uint8 channels, Uint16 samples) { std::fill((char*)this, (char*)this + sizeof(SDL_AudioSpec), 0); SDL_AudioSpec::freq = freq; SDL_AudioSpec::format = format; SDL_AudioSpec::channels = channels; SDL_AudioSpec::samples = samples; - if (callback) { - SDL_AudioSpec::callback = SDLCallback; - SDL_AudioSpec::userdata = static_cast(this); - } -} - -AudioSpec::AudioSpec(const AudioSpec& other, AudioSpec::AudioCallback&& callback) : SDL_AudioSpec(*other.Get()), callback_(std::move(callback)) { - if (callback) { - SDL_AudioSpec::callback = SDLCallback; - SDL_AudioSpec::userdata = static_cast(this); - } } AudioSpec::~AudioSpec() { @@ -60,10 +43,6 @@ AudioSpec::~AudioSpec() { AudioSpec::AudioSpec(AudioSpec&&) = default; AudioSpec& AudioSpec::operator=(AudioSpec&&) = default; -void AudioSpec::ChangeCallback(AudioCallback&& callback) { - callback_ = callback; -} - void AudioSpec::MergeChanges(const SDL_AudioSpec& obtained) { freq = obtained.freq; format = obtained.format; diff --git a/demos/audio_sine.cc b/demos/audio_sine.cc index 9b64172..142b8ed 100644 --- a/demos/audio_sine.cc +++ b/demos/audio_sine.cc @@ -35,16 +35,16 @@ int Run() { int64_t nsample = 0; // Setup audio device, and provide callback which plays sine wave with specified frequency - AudioSpec spec(samplerate, AUDIO_S16SYS, 1, 4096, [&nsample, frequency, samplerate](Uint8* stream, int len) { + AudioSpec spec(samplerate, AUDIO_S16SYS, 1, 4096); + + // Open audio device + AudioDevice dev("", 0, spec, [&nsample, frequency, samplerate](Uint8* stream, int len) { // fill provided buffer with sine wave for (Uint8* ptr = stream; ptr < stream + len; ptr += 2) *(Uint16*)ptr = (Uint16)(32766.0f * sin(nsample++ / (float)samplerate * frequency)); } ); - // Open audio device - AudioDevice dev("", 0, spec); - // Sound plays after this call dev.Pause(false); diff --git a/demos/audio_wav.cc b/demos/audio_wav.cc index b321650..303aac9 100644 --- a/demos/audio_wav.cc +++ b/demos/audio_wav.cc @@ -32,10 +32,10 @@ int Run() { SDL sdl(SDL_INIT_AUDIO); Wav wav(TESTDATA_DIR "/test.wav"); - - // Setup audio device, and provide callback which plays looped wave sound Uint8* wav_pos = wav.GetBuffer(); - AudioSpec spec(wav.GetSpec(), [&wav, &wav_pos](Uint8* stream, int len) { + + // Open audio device + AudioDevice dev("", 0, wav.GetSpec(), [&wav, &wav_pos](Uint8* stream, int len) { // Fill provided buffer with wave contents Uint8* stream_pos = stream; Uint8* stream_end = stream + len; @@ -54,13 +54,6 @@ int Run() { } ); - // Open audio device - AudioDevice dev("", 0, spec); - - // Ensure SDL has set up format conversion for us - if (!spec.IsSameFormat(wav.GetSpec())) - throw std::runtime_error("WAV format is not the same as output format"); - // Sound plays after this call dev.Pause(false);