initialize validbounds on ::init, log_debug sizes
[gnash.git] / libsound / sound_handler.h
blob6d4acdbca15930b4c3036e5534d1aecb626d309e
1 //
2 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 Free Software
3 // Foundation, Inc
4 //
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.
9 //
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.
14 //
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
21 ///
22 /// The implementation of this class *must* be thread safe!
23 ///
25 #ifndef SOUND_HANDLER_H
26 #define SOUND_HANDLER_H
28 #ifdef HAVE_CONFIG_H
29 #include "gnashconfig.h"
30 #endif
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
38 #include <string>
39 #include <vector>
40 #include <memory>
41 #include <cassert>
42 #include <cstring>
43 #include <limits>
44 #include <set> // for composition
45 #include <boost/scoped_ptr.hpp>
47 namespace gnash {
48 namespace media {
49 class SoundInfo;
51 namespace sound {
52 class EmbedSound;
53 class InputStream;
55 class SimpleBuffer;
58 namespace gnash {
60 /// Gnash %sound handling subsystem (libsound)
62 /// This subsystem takes care of mixing audio
63 /// and communicating to the system mixer.
64 ///
65 namespace sound {
67 /// %Sound 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).
72 ///
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.
76 /// See fetchSamples.
77 ///
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.
83 ///
84 /// @todo rename to gnash::sound::Mixer ?
85 ///
86 class DSOEXPORT sound_handler
88 public:
90 /// Identifier of a streaming sound block
92 /// Use coupled with a soundId for fully qualified identifier
93 ///
94 typedef unsigned long StreamBlockId;
96 /// Create a sound buffer slot, for on-demand playback.
98 /// @param data
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).
104 /// @param sinfo
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.
124 /// @param data
125 /// The sound data to be saved, allocated by new[].
126 /// Ownership is transferred.
127 /// TODO: use SimpleBuffer ?
129 /// @param dataBytes
130 /// Size of the data in bytes
132 /// @param sampleCount
133 /// Number of samples in the data
135 /// @param streamId
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,
145 int streamId);
147 /// \brief
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
157 /// the given id.
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.
165 /// @param id
166 /// Id of the sound buffer slot schedule playback of.
168 /// @param loops
169 /// loops == 0 means play the sound once (1 means play it twice, etc)
171 /// @param inPoint
172 /// Offset in output samples this instance should start
173 /// playing from. These are post-resampling samples (44100
174 /// for one second of samples).
176 /// @param outPoint
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)
183 /// @param env
184 /// Some eventsounds have some volume control mechanism called
185 /// envelopes.
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
201 /// @param streamId
202 /// Id of the sound buffer slot schedule playback of.
203 /// It is assumed to refer to a straming sound
205 /// @param blockId
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
239 /// @param volume
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();
275 /// \brief
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
287 virtual void mute();
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
323 /// to true.
325 /// @param ptr
326 /// The pointer to the callback function
328 /// @param udata
329 /// User data pointer, passed as first argument to the registered
330 /// callback.
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
348 /// soundhandler.
350 /// @param id
351 /// The key identifying the auxiliary streamer, as returned
352 /// by attach_aux_streamer.
354 virtual void unplugInputStream(InputStream* id);
356 virtual ~sound_handler() {};
358 /// \brief
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);
369 /// \brief
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.
397 /// @param to
398 /// The buffer to write mixed samples to.
399 /// Buffer must be big enough to hold nSamples samples.
401 /// @param nSamples
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.
419 /// Can be larger.
421 /// @param inSamples
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
425 /// volume.
426 /// TODO: why not applying volume upstream ?!
428 /// @param nSamples
429 /// The amount of samples to mix in.
431 /// @param volume
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);
450 protected:
453 sound_handler(media::MediaHandler* m)
455 _soundsStarted(0),
456 _soundsStopped(0),
457 _paused(false),
458 _muted(false),
459 _volume(100),
460 _sounds(),
461 _inputStreams(),
462 _mediaHandler(m)
466 /// Plug an InputStream to the mixer
468 /// @param in
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;
479 private:
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
488 bool _paused;
490 /// True if sound is muted
491 bool _muted;
493 /// Final output volume
494 int _volume;
496 typedef std::vector<EmbedSound*> Sounds;
498 /// Vector containing all sounds.
500 /// Elements of the vector are owned by this class
502 Sounds _sounds;
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.
524 /// @param id
525 /// Id of the sound buffer slot schedule playback of.
527 /// @param loops
528 /// loops == 0 means play the sound once (1 means play it twice, etc)
530 /// @param inPoint
531 /// Offset in output samples this instance should start
532 /// playing from. These are post-resampling samples (44100
533 /// for one second of samples).
535 /// @param outPoint
536 /// Offset in output samples this instance should stop
537 /// playing at. These are post-resampling samples (44100
538 /// for one second of samples).
540 /// @param blockId
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.
546 /// @param env
547 /// Some eventsounds have some volume control mechanism called
548 /// envelopes.
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,
559 bool allowMultiple);
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
574 /// that in mind).
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
585 #ifdef SOUND_SDL
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);
594 #endif
596 } // gnash.sound namespace
597 } // namespace gnash
599 #endif // SOUND_HANDLER_H
602 // Local Variables:
603 // mode: C++
604 // indent-tabs-mode: t
605 // End: