/******************************************************************************* * Copyright 2009-2016 Jörg Müller * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ******************************************************************************/ #include "SDLDevice.h" #include "devices/DeviceManager.h" #include "devices/IDeviceFactory.h" #include "Exception.h" #include "IReader.h" AUD_NAMESPACE_BEGIN void SDLDevice::SDL_mix(void* data, Uint8* buffer, int length) { SDLDevice* device = (SDLDevice*)data; if(!device->m_playback) { SDL_PauseAudio(1); std::memset(buffer, 0, length); return; } device->mix((data_t*)buffer, length / AUD_DEVICE_SAMPLE_SIZE(device->m_specs)); } void SDLDevice::playing(bool playing) { if(!m_playback) SDL_PauseAudio(playing ? 0 : 1); m_playback = playing; } SDLDevice::SDLDevice(DeviceSpecs specs, int buffersize) : m_playback(false) { if(specs.channels == CHANNELS_INVALID) specs.channels = CHANNELS_STEREO; if(specs.format == FORMAT_INVALID) specs.format = FORMAT_S16; if(specs.rate == RATE_INVALID) specs.rate = RATE_48000; m_specs = specs; SDL_AudioSpec format, obtained; format.freq = m_specs.rate; if(m_specs.format == FORMAT_U8) format.format = AUDIO_U8; else format.format = AUDIO_S16SYS; format.channels = m_specs.channels; format.samples = buffersize; format.callback = SDLDevice::SDL_mix; format.userdata = this; if(SDL_OpenAudio(&format, &obtained) != 0) AUD_THROW(DeviceException, "The audio device couldn't be opened with SDL."); m_specs.rate = (SampleRate)obtained.freq; m_specs.channels = (Channels)obtained.channels; if(obtained.format == AUDIO_U8) m_specs.format = FORMAT_U8; else if(obtained.format == AUDIO_S16LSB || obtained.format == AUDIO_S16MSB) m_specs.format = FORMAT_S16; else { SDL_CloseAudio(); AUD_THROW(DeviceException, "The sample format obtained from SDL is not supported."); } create(); } SDLDevice::~SDLDevice() { SDL_PauseAudio(1); SDL_CloseAudio(); destroy(); } class SDLDeviceFactory : public IDeviceFactory { private: DeviceSpecs m_specs; int m_buffersize; public: SDLDeviceFactory() : m_buffersize(AUD_DEFAULT_BUFFER_SIZE) { m_specs.format = FORMAT_S16; m_specs.channels = CHANNELS_STEREO; m_specs.rate = RATE_48000; } virtual std::shared_ptr openDevice() { return std::shared_ptr(new SDLDevice(m_specs, m_buffersize)); } virtual int getPriority() { return 1 << 5; } virtual void setSpecs(DeviceSpecs specs) { m_specs = specs; } virtual void setBufferSize(int buffersize) { m_buffersize = buffersize; } virtual void setName(std::string name) { } }; void SDLDevice::registerPlugin() { DeviceManager::registerDevice("SDL", std::shared_ptr(new SDLDeviceFactory)); } #ifdef SDL_PLUGIN extern "C" AUD_PLUGIN_API void registerPlugin() { SDLDevice::registerPlugin(); } extern "C" AUD_PLUGIN_API const char* getName() { return "SDL"; } #endif AUD_NAMESPACE_END