Update with current status
[gnash.git] / libsound / sdl / sound_handler_sdl.cpp
blob7516869fa1dd2eec20d04dcbb85d31e49dccbe0e
1 // sound_handler_sdl.cpp: Sound handling using standard SDL
2 //
3 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
4 // Free Software Foundation, Inc
5 //
6 // This program is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either version 3 of the License, or
9 // (at your option) any later version.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
15 //
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software
18 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 // Based on sound_handler_sdl.cpp by Thatcher Ulrich http://tulrich.com 2003
22 // which has been donated to the Public Domain.
24 #include "sound_handler_sdl.h"
25 #include "SoundInfo.h"
26 #include "EmbedSound.h"
27 #include "AuxStream.h" // for use..
28 #include "GnashSleep.h"
30 #include "log.h" // will import boost::format too
31 #include "GnashException.h" // for SoundException
33 #include <vector>
34 #include <SDL.h>
36 // Define this to get debugging call about pausing/unpausing audio
37 //#define GNASH_DEBUG_SDL_AUDIO_PAUSING
39 // Mixing and decoding debugging
40 //#define GNASH_DEBUG_MIXING
43 namespace gnash {
44 namespace sound {
47 void
48 SDL_sound_handler::initAudio()
50 // NOTE: we open and close the audio card for the sole purpose
51 // of throwing an exception on error (unavailable audio
52 // card). Normally we'd want to open the audio card only
53 // when needed (it has a cost in number of wakeups).
54 openAudio();
56 #ifdef WIN32
57 // SDL can hang on windows if SDL_CloseAudio() is called immediately
58 // after SDL_OpenAudio(). It's evidently to do with threading, but
59 // internal to SDL. This is a tacky solution, but it's only windows.
60 gnashSleep(1);
61 #endif
63 closeAudio();
67 void
68 SDL_sound_handler::openAudio()
70 if (_audioOpened) return; // nothing to do
72 // This is our sound settings
73 audioSpec.freq = 44100;
75 // Each sample is a signed 16-bit audio in system-endian format
76 audioSpec.format = AUDIO_S16SYS;
78 // We want to be pulling samples for 2 channels:
79 // {left,right},{left,right},...
80 audioSpec.channels = 2;
82 audioSpec.callback = SDL_sound_handler::sdl_audio_callback;
84 audioSpec.userdata = this;
86 //512 - not enough for videostream
87 audioSpec.samples = 1024;
89 if (SDL_OpenAudio(&audioSpec, nullptr) < 0) {
90 boost::format fmt = boost::format(_("Couldn't open SDL audio: %s"))
91 % SDL_GetError();
92 throw SoundException(fmt.str());
95 _audioOpened = true;
98 void
99 SDL_sound_handler::closeAudio()
101 SDL_CloseAudio();
102 _audioOpened = false;
106 SDL_sound_handler::SDL_sound_handler(media::MediaHandler* m)
108 sound_handler(m),
109 _audioOpened(false)
111 initAudio();
114 void
115 SDL_sound_handler::reset()
117 std::lock_guard<std::mutex> lock(_mutex);
118 sound_handler::stop_all_sounds();
121 SDL_sound_handler::~SDL_sound_handler()
123 std::lock_guard<std::mutex> lock(_mutex);
125 #ifdef GNASH_DEBUG_SDL_AUDIO_PAUSING
126 log_debug("Pausing SDL Audio on destruction");
127 #endif
128 SDL_PauseAudio(1);
130 // this one takes 2 seconds on my machine ...
131 SDL_CloseAudio();
136 SDL_sound_handler::createStreamingSound(const media::SoundInfo& sinfo)
138 std::lock_guard<std::mutex> lock(_mutex);
139 return sound_handler::createStreamingSound(sinfo);
143 SDL_sound_handler::create_sound(std::unique_ptr<SimpleBuffer> data,
144 const media::SoundInfo& sinfo)
146 std::lock_guard<std::mutex> lock(_mutex);
147 return sound_handler::create_sound(std::move(data), sinfo);
150 sound_handler::StreamBlockId
151 SDL_sound_handler::addSoundBlock(SimpleBuffer buf,
152 size_t sampleCount, int seekSamples, int handle)
155 std::lock_guard<std::mutex> lock(_mutex);
156 return sound_handler::addSoundBlock(std::move(buf), sampleCount, seekSamples, handle);
160 void
161 SDL_sound_handler::stopEventSound(int soundHandle)
163 std::lock_guard<std::mutex> lock(_mutex);
164 sound_handler::stopEventSound(soundHandle);
167 void
168 SDL_sound_handler::stopAllEventSounds()
170 std::lock_guard<std::mutex> lock(_mutex);
171 sound_handler::stopAllEventSounds();
174 void
175 SDL_sound_handler::stopStreamingSound(int soundHandle)
177 std::lock_guard<std::mutex> lock(_mutex);
178 sound_handler::stopStreamingSound(soundHandle);
182 void
183 SDL_sound_handler::delete_sound(int soundHandle)
185 std::lock_guard<std::mutex> lock(_mutex);
186 sound_handler::delete_sound(soundHandle);
189 void
190 SDL_sound_handler::stop_all_sounds()
192 std::lock_guard<std::mutex> lock(_mutex);
193 sound_handler::stop_all_sounds();
198 SDL_sound_handler::get_volume(int soundHandle) const
200 std::lock_guard<std::mutex> lock(_mutex);
201 return sound_handler::get_volume(soundHandle);
205 void
206 SDL_sound_handler::set_volume(int soundHandle, int volume)
208 std::lock_guard<std::mutex> lock(_mutex);
209 sound_handler::set_volume(soundHandle, volume);
212 media::SoundInfo*
213 SDL_sound_handler::get_sound_info(int soundHandle) const
215 std::lock_guard<std::mutex> lock(_mutex);
216 return sound_handler::get_sound_info(soundHandle);
219 unsigned int
220 SDL_sound_handler::get_duration(int soundHandle) const
222 std::lock_guard<std::mutex> lock(_mutex);
223 return sound_handler::get_duration(soundHandle);
226 unsigned int
227 SDL_sound_handler::tell(int soundHandle) const
229 std::lock_guard<std::mutex> lock(_mutex);
230 return sound_handler::tell(soundHandle);
233 sound_handler*
234 create_sound_handler_sdl(media::MediaHandler* m)
236 return new SDL_sound_handler(m);
239 void
240 SDL_sound_handler::fetchSamples(std::int16_t* to, unsigned int nSamples)
242 std::lock_guard<std::mutex> lock(_mutex);
243 sound_handler::fetchSamples(to, nSamples);
245 // If nothing is left to play there is no reason to keep polling.
246 if ( ! hasInputStreams() )
248 #ifdef GNASH_DEBUG_SDL_AUDIO_PAUSING
249 log_debug("Pausing SDL Audio...");
250 #endif
251 SDL_PauseAudio(1);
255 // Callback invoked by the SDL audio thread.
256 void
257 SDL_sound_handler::sdl_audio_callback(void *udata, Uint8 *buf, int bufLenIn)
259 if (bufLenIn < 0) {
260 log_error(_("Negative buffer length in sdl_audio_callback (%d)"),
261 bufLenIn);
262 return;
265 if (bufLenIn == 0) {
266 log_error(_("Zero buffer length in sdl_audio_callback"));
267 return;
270 unsigned int bufLen = static_cast<unsigned int>(bufLenIn);
271 std::int16_t* samples = reinterpret_cast<std::int16_t*>(buf);
273 // 16 bit per sample, 2 channels == 4 bytes per fetch ?
274 assert(!(bufLen%4));
276 unsigned int nSamples = bufLen/2;
278 //log_debug("Fetching %d bytes (%d samples)", bufLen, nSamples);
280 // Get the soundhandler
281 SDL_sound_handler* handler = static_cast<SDL_sound_handler*>(udata);
282 handler->fetchSamples(samples, nSamples);
285 void
286 SDL_sound_handler::mix(std::int16_t* outSamples, std::int16_t* inSamples,
287 unsigned int nSamples, float volume)
289 Uint8* out = reinterpret_cast<Uint8*>(outSamples);
290 Uint8* in = reinterpret_cast<Uint8*>(inSamples);
291 unsigned int nBytes = nSamples*2;
293 SDL_MixAudio(out, in, nBytes, SDL_MIX_MAXVOLUME*volume);
296 void
297 SDL_sound_handler::plugInputStream(std::unique_ptr<InputStream> newStreamer)
299 std::lock_guard<std::mutex> lock(_mutex);
301 sound_handler::plugInputStream(std::move(newStreamer));
303 { // TODO: this whole block should only be executed when adding
304 // the first stream.
306 #ifdef GNASH_DEBUG_SDL_AUDIO_PAUSING
307 log_debug("Unpausing SDL Audio on inpust stream plug...");
308 #endif
309 openAudio(); // lazy sound card initialization
310 SDL_PauseAudio(0); // start polling data from us
314 void
315 SDL_sound_handler::pause()
317 closeAudio();
318 sound_handler::pause();
321 void
322 SDL_sound_handler::unpause()
324 if (hasInputStreams()) {
325 openAudio();
326 SDL_PauseAudio(0);
329 sound_handler::unpause();
332 void
333 SDL_sound_handler::unplugInputStream(InputStream* id)
335 std::lock_guard<std::mutex> lock(_mutex);
337 sound_handler::unplugInputStream(id);
340 } // gnash.sound namespace
341 } // namespace gnash
343 // Local Variables:
344 // mode: C++
345 // End: