update copyright date
[gnash.git] / libsound / sdl / sound_handler_sdl.cpp
blob4f7bf042667d3afcc702e36cd41a022ad322b940
1 // sound_handler_sdl.cpp: Sound handling using standard SDL
2 //
3 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010,
4 // 2011 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 <boost/scoped_array.hpp>
35 #include <SDL.h>
37 // Define this to get debugging call about pausing/unpausing audio
38 //#define GNASH_DEBUG_SDL_AUDIO_PAUSING
40 // Mixing and decoding debugging
41 //#define GNASH_DEBUG_MIXING
44 namespace gnash {
45 namespace sound {
48 void
49 SDL_sound_handler::initAudio()
51 // NOTE: we open and close the audio card for the sole purpose
52 // of throwing an exception on error (unavailable audio
53 // card). Normally we'd want to open the audio card only
54 // when needed (it has a cost in number of wakeups).
55 openAudio();
57 #ifdef WIN32
58 // SDL can hang on windows if SDL_CloseAudio() is called immediately
59 // after SDL_OpenAudio(). It's evidently to do with threading, but
60 // internal to SDL. This is a tacky solution, but it's only windows.
61 gnashSleep(1);
62 #endif
64 closeAudio();
68 void
69 SDL_sound_handler::openAudio()
71 if (_audioOpened) return; // nothing to do
73 // This is our sound settings
74 audioSpec.freq = 44100;
76 // Each sample is a signed 16-bit audio in system-endian format
77 audioSpec.format = AUDIO_S16SYS;
79 // We want to be pulling samples for 2 channels:
80 // {left,right},{left,right},...
81 audioSpec.channels = 2;
83 audioSpec.callback = SDL_sound_handler::sdl_audio_callback;
85 audioSpec.userdata = this;
87 //512 - not enough for videostream
88 audioSpec.samples = 2048;
90 if (SDL_OpenAudio(&audioSpec, NULL) < 0) {
91 boost::format fmt = boost::format(_("Couldn't open SDL audio: %s"))
92 % SDL_GetError();
93 throw SoundException(fmt.str());
96 _audioOpened = true;
99 void
100 SDL_sound_handler::closeAudio()
102 SDL_CloseAudio();
103 _audioOpened = false;
107 SDL_sound_handler::SDL_sound_handler(media::MediaHandler* m)
109 sound_handler(m),
110 _audioOpened(false)
112 initAudio();
115 void
116 SDL_sound_handler::reset()
118 boost::mutex::scoped_lock lock(_mutex);
119 sound_handler::stop_all_sounds();
122 SDL_sound_handler::~SDL_sound_handler()
124 boost::mutex::scoped_lock lock(_mutex);
125 #ifdef GNASH_DEBUG_SDL_AUDIO_PAUSING
126 log_debug("Pausing SDL Audio on destruction");
127 #endif
128 SDL_PauseAudio(1);
130 lock.unlock();
132 // we already locked, so we call
133 // the base class (non-locking) deleter
134 delete_all_sounds();
136 unplugAllInputStreams();
138 SDL_CloseAudio();
144 SDL_sound_handler::create_sound(std::auto_ptr<SimpleBuffer> data,
145 std::auto_ptr<media::SoundInfo> sinfo)
147 boost::mutex::scoped_lock lock(_mutex);
148 return sound_handler::create_sound(data, sinfo);
151 sound_handler::StreamBlockId
152 SDL_sound_handler::addSoundBlock(unsigned char* data,
153 unsigned int dataBytes, unsigned int nSamples,
154 int streamId)
157 boost::mutex::scoped_lock lock(_mutex);
158 return sound_handler::addSoundBlock(data, dataBytes, nSamples, streamId);
162 void
163 SDL_sound_handler::stop_sound(int soundHandle)
165 boost::mutex::scoped_lock lock(_mutex);
166 sound_handler::stop_sound(soundHandle);
170 void
171 SDL_sound_handler::delete_sound(int soundHandle)
173 boost::mutex::scoped_lock lock(_mutex);
174 sound_handler::delete_sound(soundHandle);
177 void
178 SDL_sound_handler::stop_all_sounds()
180 boost::mutex::scoped_lock lock(_mutex);
181 sound_handler::stop_all_sounds();
186 SDL_sound_handler::get_volume(int soundHandle)
188 boost::mutex::scoped_lock lock(_mutex);
189 return sound_handler::get_volume(soundHandle);
193 void
194 SDL_sound_handler::set_volume(int soundHandle, int volume)
196 boost::mutex::scoped_lock lock(_mutex);
197 sound_handler::set_volume(soundHandle, volume);
200 media::SoundInfo*
201 SDL_sound_handler::get_sound_info(int soundHandle)
203 boost::mutex::scoped_lock lock(_mutex);
204 return sound_handler::get_sound_info(soundHandle);
207 unsigned int
208 SDL_sound_handler::get_duration(int soundHandle)
210 boost::mutex::scoped_lock lock(_mutex);
211 return sound_handler::get_duration(soundHandle);
214 unsigned int
215 SDL_sound_handler::tell(int soundHandle)
217 boost::mutex::scoped_lock lock(_mutex);
218 return sound_handler::tell(soundHandle);
221 sound_handler*
222 create_sound_handler_sdl(media::MediaHandler* m)
224 return new SDL_sound_handler(m);
227 void
228 SDL_sound_handler::fetchSamples(boost::int16_t* to, unsigned int nSamples)
230 boost::mutex::scoped_lock lock(_mutex);
231 sound_handler::fetchSamples(to, nSamples);
233 // If nothing is left to play there is no reason to keep polling.
234 if ( ! hasInputStreams() )
236 #ifdef GNASH_DEBUG_SDL_AUDIO_PAUSING
237 log_debug("Pausing SDL Audio...");
238 #endif
239 SDL_PauseAudio(1);
243 // Callback invoked by the SDL audio thread.
244 void
245 SDL_sound_handler::sdl_audio_callback(void *udata, Uint8 *buf, int bufLenIn)
247 if (bufLenIn < 0) {
248 log_error(_("Negative buffer length in sdl_audio_callback (%d)"),
249 bufLenIn);
250 return;
253 if (bufLenIn == 0) {
254 log_error(_("Zero buffer length in sdl_audio_callback"));
255 return;
258 unsigned int bufLen = static_cast<unsigned int>(bufLenIn);
259 boost::int16_t* samples = reinterpret_cast<boost::int16_t*>(buf);
261 // 16 bit per sample, 2 channels == 4 bytes per fetch ?
262 assert(!(bufLen%4));
264 unsigned int nSamples = bufLen/2;
266 //log_debug("Fetching %d bytes (%d samples)", bufLen, nSamples);
268 // Get the soundhandler
269 SDL_sound_handler* handler = static_cast<SDL_sound_handler*>(udata);
270 handler->fetchSamples(samples, nSamples);
273 void
274 SDL_sound_handler::mix(boost::int16_t* outSamples, boost::int16_t* inSamples,
275 unsigned int nSamples, float volume)
277 Uint8* out = reinterpret_cast<Uint8*>(outSamples);
278 Uint8* in = reinterpret_cast<Uint8*>(inSamples);
279 unsigned int nBytes = nSamples*2;
281 SDL_MixAudio(out, in, nBytes, SDL_MIX_MAXVOLUME*volume);
284 void
285 SDL_sound_handler::plugInputStream(std::auto_ptr<InputStream> newStreamer)
287 boost::mutex::scoped_lock lock(_mutex);
289 sound_handler::plugInputStream(newStreamer);
291 { // TODO: this whole block should only be executed when adding
292 // the first stream.
294 #ifdef GNASH_DEBUG_SDL_AUDIO_PAUSING
295 log_debug("Unpausing SDL Audio on inpust stream plug...");
296 #endif
297 openAudio(); // lazy sound card initialization
298 SDL_PauseAudio(0); // start polling data from us
302 void
303 SDL_sound_handler::mute()
305 boost::mutex::scoped_lock lock(_mutedMutex);
306 sound_handler::mute();
309 void
310 SDL_sound_handler::unmute()
312 boost::mutex::scoped_lock lock(_mutedMutex);
313 sound_handler::unmute();
316 bool
317 SDL_sound_handler::is_muted() const
319 boost::mutex::scoped_lock lock(_mutedMutex);
320 return sound_handler::is_muted();
323 void
324 SDL_sound_handler::pause()
326 closeAudio();
327 sound_handler::pause();
330 void
331 SDL_sound_handler::unpause()
333 if (hasInputStreams()) {
334 openAudio();
335 SDL_PauseAudio(0);
338 sound_handler::unpause();
341 } // gnash.sound namespace
342 } // namespace gnash
344 // Local Variables:
345 // mode: C++
346 // End: