2 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 Free Software
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 3 of the License, or
8 // (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 /// \page sound_handler_intro Sound handler introduction
22 /// The implementation of this class *must* be thread safe!
25 #ifndef SOUND_HANDLER_H
26 #define SOUND_HANDLER_H
29 #include "gnashconfig.h"
32 #include "dsodefs.h" // for DSOEXPORT
33 #include "MediaHandler.h" // for inlined ctor
34 #include "SoundEnvelope.h" // for SoundEnvelopes typedef
35 #include "AuxStream.h" // for aux_stramer_ptr typedef
36 #include "WAVWriter.h" // for dtor visibility
44 #include <set> // for composition
45 #include <boost/scoped_ptr.hpp>
60 /// Gnash %sound handling subsystem (libsound)
62 /// This subsystem takes care of mixing audio
63 /// and communicating to the system mixer.
69 /// Stores the audio found by the parser and plays on demand.
70 /// Also allows plugging auxiliary streamers for ActionScript
71 /// driven %sound (Sound, NetStream).
73 /// The main interface this class exposes to hosting application
74 /// is fetching of sound samples, in couples of signed 16bit integers
75 /// (left channel, right channel) in PCM.
78 /// Implementations of this class willing to allow
79 /// hosting application to use a thread for fetching
80 /// audio should make sure to take care about mutex
81 /// protecting the relevant datastores.
82 /// The default implementation uses NO locking.
84 /// @todo rename to gnash::sound::Mixer ?
86 class DSOEXPORT sound_handler
90 /// Identifier of a streaming sound block
92 /// Use coupled with a soundId for fully qualified identifier
94 typedef unsigned long StreamBlockId
;
96 /// Create a sound buffer slot, for on-demand playback.
99 /// The data to be stored. For soundstream this is NULL.
100 /// The data is in encoded format, with format specified
101 /// with the sinfo parameter, this is to allow on-demand
102 /// decoding (if the sound is never played, it's never decoded).
105 /// A SoundInfo object contained in an auto_ptr, which contains
106 /// info about samplerate, samplecount, stereo and more.
107 /// The SoundObject must be not-NULL!
109 /// @return the id given by the soundhandler for later identification.
111 virtual int create_sound(
112 std::auto_ptr
<SimpleBuffer
> data
,
113 std::auto_ptr
<media::SoundInfo
> sinfo
116 /// Append data to an existing sound buffer slot.
119 /// Gnash's parser calls this to fill up soundstreams data.
120 /// TODO: the current code uses memory reallocation to grow the sound,
121 /// which is suboptimal; instead, we should maintain sound sources as a
122 /// list of buffers, to avoid reallocations.
125 /// The sound data to be saved, allocated by new[].
126 /// Ownership is transferred.
127 /// TODO: use SimpleBuffer ?
130 /// Size of the data in bytes
132 /// @param sampleCount
133 /// Number of samples in the data
136 /// The soundhandlers id of the sound we want to add data to
138 /// @return an identifier for the new block for use in playSound
140 /// @throw SoundException on error
142 virtual StreamBlockId
addSoundBlock(unsigned char* data
,
143 unsigned int dataBytes
,
144 unsigned int sampleCount
,
148 /// Returns a pointer to the SoundInfo object for the sound
149 /// with the given id.
151 /// The SoundInfo object is still owned by the soundhandler.
153 /// @param soundHandle
154 /// The soundhandlers id of the sound we want some info about.
156 /// @return a pointer to the SoundInfo object for the sound with
159 virtual media::SoundInfo
* get_sound_info(int soundHandle
);
161 /// Start playback of an event sound
163 /// All scheduled sounds will be played on next output flush.
166 /// Id of the sound buffer slot schedule playback of.
169 /// loops == 0 means play the sound once (1 means play it twice, etc)
172 /// Offset in output samples this instance should start
173 /// playing from. These are post-resampling samples (44100
174 /// for one second of samples).
177 /// Offset in output samples this instance should stop
178 /// playing at. These are post-resampling samples (44100
179 /// for one second of samples).
180 /// Use std::numeric_limits<unsigned int>::max() for no limit
181 /// (default if missing)
184 /// Some eventsounds have some volume control mechanism called
186 /// They basically tells that from sample X the volume should be Y.
188 /// @param allowMultiple
189 /// If false, the sound will not be scheduled if there's another
190 /// instance of it already playing.
193 void startSound(int id
, int loops
,
194 const SoundEnvelopes
* env
,
195 bool allowMultiple
, unsigned int inPoint
=0,
196 unsigned int outPoint
=std::numeric_limits
<unsigned int>::max());
198 /// Start playback of a streaming sound, if not playing already
202 /// Id of the sound buffer slot schedule playback of.
203 /// It is assumed to refer to a straming sound
206 /// Identifier of the block to start decoding from.
208 void playStream(int id
, StreamBlockId blockId
);
210 /// Remove all scheduled request for playback of sound buffer slots
211 virtual void stop_all_sounds();
213 /// Gets the volume for a given sound buffer slot.
215 /// Only used by the AS Sound class
217 /// @param sound_handle
218 /// The sound_handlers id for the sound to be deleted
220 /// @return the sound volume level as an integer from 0 to 100,
221 /// where 0 is off and 100 is full volume. The default setting is 100.
223 virtual int get_volume(int sound_handle
);
225 /// Get the volume to apply to mixed output
227 /// @return percent value. 100 is full, 0 is none.
228 /// Can be negative or over 100 too.
230 int getFinalVolume() { return _volume
; }
232 /// Sets the volume for a given sound buffer slot.
234 /// Only used by the AS Sound class
236 /// @param sound_handle
237 /// The sound_handlers id for the sound to be deleted
240 /// A number from 0 to 100 representing a volume level.
241 /// 100 is full volume and 0 is no volume.
242 /// The default setting is 100.
244 virtual void set_volume(int sound_handle
, int volume
);
246 /// Set the volume to apply to mixed output
248 /// @param v percent value. 100 is full, 0 is none.
249 /// Can be negative or over 100 too.
251 void setFinalVolume(int v
) { _volume
=v
; }
253 /// Remove scheduled requests to play the specified sound buffer slot
255 /// Stop the specified sound if it's playing.
256 /// (Normally a full-featured sound API would take a
257 /// handle specifying the *instance* of a playing
258 /// sample, but SWF is not expressive that way.)
260 /// @param sound_handle
261 /// The sound_handlers id for the sound to be deleted
263 virtual void stop_sound(int sound_handle
);
265 /// Discard a sound buffer slot
267 /// @param sound_handle
268 /// The sound_handlers id for the sound to be deleted
270 virtual void delete_sound(int sound_handle
);
272 // Stop and delete all sounds
273 virtual void delete_all_sounds();
276 /// Discard all sound inputs (slots and aux streamers)
277 /// and clear scheduling
279 /// Gnash calls this on movie restart.
281 /// The function should stop all sounds and get ready
282 /// for a "parse from scratch" operation.
284 virtual void reset();
286 /// Call this to mute audio
289 /// Call this to unmute audio
290 virtual void unmute();
292 /// Returns whether or not sound is muted.
294 /// @return true if muted, false if not
296 virtual bool is_muted() const;
298 /// gnash calls this to pause audio
299 virtual void pause() { _paused
=true; }
301 /// gnash calls this to unpause audio
302 virtual void unpause() { _paused
=false; }
304 /// return true if audio is paused
305 bool isPaused() const { return _paused
; }
307 /// Plug an external InputStream into the mixer
309 /// This is called by AS classes NetStream or Sound to attach callback, so
310 /// that audio from the classes will be played through the soundhandler.
312 /// This is actually only used by the SDL sound_handler.
313 /// It uses these "auxiliary" streamers to fetch decoded audio data
314 /// to mix and send to the output channel.
316 /// The "aux streamer" will be called with the 'udata' pointer as
317 /// first argument, then will be passed a pointer to buffer of samples
318 /// as second argument and the number of samples to fetch as third.
320 /// The callbacks should fill the given buffer if possible, and return
321 /// the number of samples actually fetched and an eof flag (last argument).
322 /// The callback will be detached if it sets the 'eof' output parameter
326 /// The pointer to the callback function
329 /// User data pointer, passed as first argument to the registered
332 /// @return an InputStream pointer, for passing to unplugInputStream.
333 /// Callers do not own the InputStream, and should NOT realy
334 /// on it to be point to allocated memory! It is meant to be used
335 /// as an identifier for the newly created mixer channel.
337 /// @todo change to plugInputStream(InputStream* str),
338 /// implement in base class
340 /// @see unplugInputStream
342 virtual InputStream
* attach_aux_streamer(aux_streamer_ptr ptr
, void* udata
);
344 /// Unplug an external InputStream from the mixer
346 /// This is called by AS classes NetStream or Sound to dettach callback,
347 /// so that audio from the classes no longer will be played through the
351 /// The key identifying the auxiliary streamer, as returned
352 /// by attach_aux_streamer.
354 virtual void unplugInputStream(InputStream
* id
);
356 virtual ~sound_handler() {};
359 /// Gets the duration in milliseconds of an event sound connected
360 /// to an AS Sound obejct.
362 /// @param sound_handle
363 /// The id of the event sound
365 /// @return the duration of the sound in milliseconds
367 virtual unsigned int get_duration(int sound_handle
);
370 /// Gets the playhead position in milliseconds of an event sound connected
371 /// to an AS Sound obejct.
373 /// @param sound_handle
374 /// The id of the event sound
376 /// @return the duration of the sound in milliseconds
378 virtual unsigned int tell(int sound_handle
);
380 /// Special test-fuction. Reports how many times a sound has been started
382 /// @deprecated Use a TestingSoundHanlder !
384 size_t numSoundsStarted() const { return _soundsStarted
; }
386 /// Special test-fuction. Reports how many times a sound has been stopped
388 /// @deprecated Use a TestingSoundHanlder !
390 size_t numSoundsStopped() const { return _soundsStopped
; }
392 /// Fetch mixed samples
394 /// We run through all the plugged InputStreams fetching decoded
395 /// audio blocks and mixing them into the given output stream.
398 /// The buffer to write mixed samples to.
399 /// Buffer must be big enough to hold nSamples samples.
402 /// The amount of samples to fetch.
403 /// NOTE: this number currently refers to "mono" samples
404 /// due to some bad design decision. It is so expected
405 /// that the user fetches 44100 * 2 samples which has to
406 /// be interpreted as series of left,right channel couples.
407 /// TODO: use actual number of samples so that it's expected
408 /// to fetch 44100 per second and let expose a function
409 /// to give interpretation of what comes back (how many
410 /// bytes per channel, which format).
412 virtual void fetchSamples(boost::int16_t* to
, unsigned int nSamples
);
414 /// Mix nSamples from inSamples to outSamples, with given volume
416 /// @param outSamples
417 /// The output samples buffer, to mix to.
418 /// Must be big enough to contain nSamples.
422 /// The input samples buffer, to mix in.
423 /// It is non-const as this method *is* allowed
424 /// to mess with content, for example to apply
426 /// TODO: why not applying volume upstream ?!
429 /// The amount of samples to mix in.
432 /// The volume to apply to input samples, as a fraction (0..1)
434 /// TODO: this interface says nothing about how many channels we're
435 /// going to mix. It should, to be a sane interface.
436 /// Maybe, a Mixer instance should be created, initialized
437 /// with number of channels, at each fetching.
439 virtual void mix(boost::int16_t* outSamples
, boost::int16_t* inSamples
,
440 unsigned int nSamples
, float volume
) = 0;
443 /// Request to dump audio to the given filename
445 /// Every call to this function starts recording
446 /// to a new file, closing any existing other dump.
448 void setAudioDump(const std::string
& wavefile
);
453 sound_handler(media::MediaHandler
* m
)
466 /// Plug an InputStream to the mixer
469 /// The InputStream to plug, ownership transferred
471 virtual void plugInputStream(std::auto_ptr
<InputStream
> in
);
473 /// Unplug all input streams
474 virtual void unplugAllInputStreams();
476 /// Does the mixer have input streams ?
477 bool hasInputStreams() const;
481 /// Special test-member. Stores count of started sounds.
482 size_t _soundsStarted
;
484 /// Special test-member. Stores count of stopped sounds.
485 size_t _soundsStopped
;
487 /// True if sound is paused
490 /// True if sound is muted
493 /// Final output volume
496 typedef std::vector
<EmbedSound
*> Sounds
;
498 /// Vector containing all sounds.
500 /// Elements of the vector are owned by this class
504 /// Stop all instances of an embedded sound
505 void stopEmbedSoundInstances(EmbedSound
& def
);
507 typedef std::set
< InputStream
* > InputStreams
;
509 /// Sound input streams.
511 /// Elements owned by this class.
513 InputStreams _inputStreams
;
515 media::MediaHandler
* _mediaHandler
;
517 /// Unplug any completed input stream
518 void unplugCompletedInputStreams();
520 /// Schedule playing of a sound buffer slot
522 /// All scheduled sounds will be played on next output flush.
525 /// Id of the sound buffer slot schedule playback of.
528 /// loops == 0 means play the sound once (1 means play it twice, etc)
531 /// Offset in output samples this instance should start
532 /// playing from. These are post-resampling samples (44100
533 /// for one second of samples).
536 /// Offset in output samples this instance should stop
537 /// playing at. These are post-resampling samples (44100
538 /// for one second of samples).
541 /// When starting a soundstream from a random frame, this tells which
542 /// block to start decoding from.
543 /// If non-zero, the sound will only start when no other instances of
544 /// it are already playing.
547 /// Some eventsounds have some volume control mechanism called
549 /// They basically tells that from sample X the volume should be Y.
551 /// @param allowMultiple
552 /// If false, the sound will not be scheduled if there's another
553 /// instance of it already playing.
555 void playSound(int id
, int loops
,
556 unsigned int inPoint
,
557 unsigned int outPoint
,
558 StreamBlockId blockId
, const SoundEnvelopes
* env
,
561 /// Convert SWF-specified number of samples to output number of samples
563 /// SWF-specified number of samples are: delaySeek in DEFINESOUND,
564 /// latency in STREAMSOUNDHEAD and seekSamples in STREAMSOUNDBLOCK.
565 /// These refer to samples at the sampleRate of input.
567 /// As gnash will resample the sounds to match expected output
568 /// (44100 Hz, stereo 16bit) this function is handy to convert
569 /// for simpler use later.
571 /// It is non-static in the event we'll one day allow different
572 /// sound_handler instances to be configured with different output
573 /// sample rate (would need a lot more changes atm but let's keep
576 unsigned int swfToOutSamples(const media::SoundInfo
& sinfo
,
577 unsigned int swfSamples
);
579 boost::scoped_ptr
<WAVWriter
> _wavWriter
;
583 // TODO: move to appropriate specific sound handlers
586 /// @throw a SoundException if fails to initialize audio card.
587 DSOEXPORT sound_handler
* create_sound_handler_sdl(media::MediaHandler
* m
);
588 #elif defined(SOUND_AHI)
589 /// @throw a SoundException if fails to initialize audio card.
590 DSOEXPORT sound_handler
* create_sound_handler_aos4(media::MediaHandler
* m
);
591 #elif defined(SOUND_MKIT)
592 /// @throw a SoundException if fails to create node.
593 DSOEXPORT sound_handler
* create_sound_handler_mkit(media::MediaHandler
* m
);
596 } // gnash.sound namespace
599 #endif // SOUND_HANDLER_H
604 // indent-tabs-mode: t