Make automated FSCommand invocation tests show player-side output.
[gnash.git] / libsound / sound_handler.h
blobea993f373001673b5db597415d2a2810ebec7140
1 //
2 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
3 // Free Software 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
19 #ifndef SOUND_HANDLER_H
20 #define SOUND_HANDLER_H
22 #ifdef HAVE_CONFIG_H
23 #include "gnashconfig.h"
24 #endif
26 #include <atomic>
27 #include <limits>
28 #include <memory>
29 #include <set>
30 #include <string>
31 #include <vector>
33 #include "dsodefs.h" // for DSOEXPORT
34 #include "SoundEnvelope.h" // for SoundEnvelopes typedef
35 #include "AuxStream.h" // for aux_streamer_ptr typedef
36 #include "WAVWriter.h"
38 namespace gnash {
39 namespace media {
40 class MediaHandler;
41 class SoundInfo;
43 namespace sound {
44 class EmbedSound;
45 class StreamingSound;
46 class StreamingSoundData;
47 class InputStream;
49 class SimpleBuffer;
52 namespace gnash {
54 /// Gnash %sound handling subsystem (libsound)
56 /// This subsystem takes care of mixing audio
57 /// and communicating to the system mixer.
58 ///
59 namespace sound {
61 /// %Sound mixer.
63 /// Stores the audio found by the parser and plays on demand.
64 /// Also allows plugging auxiliary streamers for ActionScript
65 /// driven %sound (Sound, NetStream).
66 ///
67 /// The main interface this class exposes to hosting application
68 /// is fetching of sound samples, in couples of signed 16bit integers
69 /// (left channel, right channel) in PCM.
70 /// See fetchSamples.
71 ///
72 /// Implementations of this class willing to allow
73 /// hosting application to use a thread for fetching
74 /// audio should make sure to take care about mutex
75 /// protecting the relevant datastores.
76 /// The default implementation uses NO locking.
77 ///
78 /// @todo rename to gnash::sound::Mixer ?
79 ///
80 /// The sound_handler class stores embedded sounds. Embedded sounds can be
81 /// either streaming sounds (embedded in many StreamSoundBlock tags through
82 /// the SWF) or event sounds (defined in a single DefineSoundTag).
84 /// The interface is partly divided into separate functions for these types
85 /// of sound.
86 /// TODO: separate the functions fully.
87 class DSOEXPORT sound_handler
89 public:
91 virtual ~sound_handler();
93 /// Identifier of a streaming sound block
95 /// Use coupled with a soundId for fully qualified identifier
96 ///
97 typedef unsigned long StreamBlockId;
99 ////////////////////////////////////////////////
100 /// Mixed functions:
101 ////////////////////////////////////////////////
103 /// Remove all scheduled request for playback of sound buffer slots
105 /// This applies both to streaming and event sounds.
106 virtual void stop_all_sounds();
108 ////////////////////////////////////////////////
109 /// Event sound functions:
110 ////////////////////////////////////////////////
112 /// Create a sound buffer slot, for on-demand playback.
114 /// @param data The sound data to be stored. May not be null.
115 /// This should be appropriately padded (@see
116 /// MediaHandler::getInputPaddingBytes()), or a
117 /// reallocation will take place here.
118 /// @param sinfo A SoundInfo object containing info about
119 /// samplerate, samplecount, stereo etc.
120 /// @return handle for later identification.
121 virtual int create_sound(std::unique_ptr<SimpleBuffer> data,
122 const media::SoundInfo& sinfo);
124 /// Remove scheduled requests to play the specified sound buffer slot
126 /// Stop all instances of the specified event sound if it's playing.
127 /// (Normally a full-featured sound API would take a
128 /// handle specifying the *instance* of a playing
129 /// sample, but SWF is not expressive that way.)
131 /// @param sound_handle id for the sound to be stopped
132 virtual void stopEventSound(int sound_handle);
134 /// Stop all instances of all playing event sounds.
136 virtual void stopAllEventSounds();
138 /// Discard the sound data for an embedded event sound
140 /// Only embedded event sounds are deleted; this happens when the
141 /// associated sound_sample is deleted.
143 /// @param sound_handle The id for the event sound to be deleted
144 virtual void delete_sound(int sound_handle);
146 /// Start playback of an event sound
148 /// All scheduled sounds will be played on next output flush.
150 /// @param id
151 /// Id of the sound buffer slot to schedule playback of.
153 /// @param loops
154 /// loops == 0 means play the sound once (1 means play it twice, etc)
156 /// @param inPoint
157 /// Offset in output samples this instance should start
158 /// playing from. These are post-resampling samples (44100
159 /// for one second of samples).
161 /// @param outPoint
162 /// Offset in output samples this instance should stop
163 /// playing at. These are post-resampling samples (44100
164 /// for one second of samples).
165 /// Use std::numeric_limits<unsigned int>::max() for no limit
166 /// (default if missing)
168 /// @param env
169 /// Some eventsounds have some volume control mechanism called
170 /// envelopes.
171 /// They basically tells that from sample X the volume should be Y.
173 /// @param allowMultiple
174 /// If false, the sound will not be scheduled if there's another
175 /// instance of it already playing.
176 void startSound(int id, int loops, const SoundEnvelopes* env,
177 bool allowMultiple, unsigned int inPoint = 0,
178 unsigned int outPoint =
179 std::numeric_limits<unsigned int>::max());
181 /// Check if an event sound is playing
183 /// Note: this should not be used for streaming sounds.
185 /// @param id Id of the sound buffer slot check for being alive
186 bool isSoundPlaying(int id) const;
188 /// Sets the volume for a given event sound.
190 /// Only used by the AS Sound class
192 /// @param sound_handle The handle of the event sound to set volume for.
193 /// @param volume A number from 0 to 100 representing a volume
194 /// level. 100 is full volume and 0 is no volume.
195 /// The default setting is 100.
196 virtual void set_volume(int sound_handle, int volume);
198 /// Gets the duration in milliseconds of an event sound.
200 /// @param sound_handle The id of the event sound
201 /// @return the duration of the sound in milliseconds
202 virtual unsigned int get_duration(int sound_handle) const;
204 /// Gets the playhead position in milliseconds of an event sound.
206 /// @param sound_handle The id of the event sound
207 /// @return The playhead position of the sound in
208 /// milliseconds
209 virtual unsigned int tell(int sound_handle) const;
211 /// Gets the volume for a given sound buffer slot.
213 /// Only use for event sounds!
215 /// @param sound_handle The sound to get the volume for.
216 /// @return the sound volume level as an integer from
217 /// 0 to 100, where 0 is off and 100 is full
218 /// volume. The default setting is 100.
219 virtual int get_volume(int sound_handle) const;
221 ////////////////////////////////////////////////
222 /// Streaming sound functions:
223 ////////////////////////////////////////////////
225 virtual int createStreamingSound(const media::SoundInfo& sinfo);
227 /// Remove scheduled requests to play the specified sound buffer slot
229 /// @param sound_handle The sound_handlers id for the sound to be
230 /// stopped.
231 virtual void stopStreamingSound(int handle);
233 /// Append data for a streaming sound.
235 /// Gnash's parser calls this to fill up soundstreams data.
237 /// @param data The sound data to be stored.
238 /// This should be appropriately padded (@see
239 /// MediaHandler::getInputPaddingBytes()), or a
240 /// reallocation will take place here.
241 /// @param sampleCount Number of samples in the data
242 /// @param seekSamples Offset of sound to frame data
243 /// @param streamId The soundhandlers id of the sound we want
244 /// to add data to
245 /// @return a handler for the new block for use in playStream()
246 /// @throw SoundException on error
247 virtual StreamBlockId addSoundBlock(SimpleBuffer data,
248 size_t sampleCount, int seekSamples, int streamId);
250 /// Returns a SoundInfo object for the sound with the given id.
252 /// Note: This should only be used for streaming sounds.
254 /// The SoundInfo object is still owned by the soundhandler.
256 /// @param soundHandle The soundhandlers id of the sound we want some
257 /// info about.
258 /// @return a pointer to the SoundInfo object for the sound
259 /// with the given id or 0 if no such sound exists.
260 virtual media::SoundInfo* get_sound_info(int handle) const;
262 /// Start playback of a streaming sound, if not playing already
264 /// TODO: the samples count in the stream sound head (stored in a SoundInfo
265 /// object) should drive the timeline while a stream is playing.
267 /// TODO: only the number of samples advertised in each stream block should
268 /// be played for mp3 sounds, not the complete data! Currently we don't
269 /// store this value.
271 /// @param handle Id of the sound buffer slot schedule playback of.
272 /// @param blockId Identifier of the block to start decoding from.
273 void playStream(int handle, StreamBlockId blockId);
275 /// Get the identifier for the block playing in a specific stream.
277 /// This is used by movie_root to check which part of the stream is
278 /// actually playing. Streaming sound is used to synchronize the frame
279 /// rate. The returned block id can be matched with a specific frame.
281 /// @param handle The handle of the stream sound to query.
282 /// @return The identifier of the stream block that the
283 /// sound_handler is currently playing (it may be only
284 /// approximate, as we can't really know what's coming out
285 /// of the speakers). Returns -1 if the specified stream
286 /// sound is not playing or doesn't exist.
287 int getStreamBlock(int handle) const;
289 ////////////////////////////////////////////////
290 /// Sound output functions.
291 ////////////////////////////////////////////////
293 /// Get the volume to apply to mixed output
295 /// @return percent value. 100 is full, 0 is none.
296 /// Can be negative or over 100 too.
297 int getFinalVolume() const { return _volume; }
299 /// Set the volume to apply to mixed output
301 /// @param v percent value. 100 is full, 0 is none.
302 /// Can be negative or over 100 too.
303 void setFinalVolume(int v) { _volume = v; }
305 /// \brief
306 /// Discard all sound inputs (slots and aux streamers)
307 /// and clear scheduling
309 /// Gnash calls this on movie restart.
311 /// The function should stop all sounds and get ready
312 /// for a "parse from scratch" operation.
313 virtual void reset();
315 /// Call this to mute audio
316 void mute();
318 /// Call this to unmute audio
319 void unmute();
321 /// Returns whether or not sound is muted.
323 /// @return true if muted, false if not
324 bool is_muted() const;
326 /// gnash calls this to pause audio
327 virtual void pause() { _paused=true; }
329 /// gnash calls this to unpause audio
330 virtual void unpause() { _paused=false; }
332 /// return true if audio is paused
333 bool isPaused() const { return _paused; }
335 /// Plug an external InputStream into the mixer
337 /// This is called by AS classes NetStream or Sound to attach callback, so
338 /// that audio from the classes will be played through the soundhandler.
340 /// This is actually only used by the SDL sound_handler.
341 /// It uses these "auxiliary" streamers to fetch decoded audio data
342 /// to mix and send to the output channel.
344 /// The "aux streamer" will be called with the 'udata' pointer as
345 /// first argument, then will be passed a pointer to buffer of samples
346 /// as second argument and the number of samples to fetch as third.
348 /// The callbacks should fill the given buffer if possible, and return
349 /// the number of samples actually fetched and an eof flag (last argument).
350 /// The callback will be detached if it sets the 'eof' output parameter
351 /// to true.
353 /// @param ptr
354 /// The pointer to the callback function
356 /// @param udata
357 /// User data pointer, passed as first argument to the registered
358 /// callback.
360 /// @return an InputStream pointer, for passing to unplugInputStream.
361 /// Callers do not own the InputStream, and should NOT rely
362 /// on it to point to allocated memory! It is meant to be used
363 /// as an identifier for the newly created mixer channel.
365 /// @todo change to plugInputStream(InputStream* str),
366 /// implement in base class
368 /// @see unplugInputStream
370 virtual InputStream* attach_aux_streamer(aux_streamer_ptr ptr, void* udata);
372 /// Unplug an external InputStream from the mixer
374 /// This is called by AS classes NetStream or Sound to dettach callback,
375 /// so that audio from the classes no longer will be played through the
376 /// soundhandler.
378 /// @param id
379 /// The key identifying the auxiliary streamer, as returned
380 /// by attach_aux_streamer.
382 virtual void unplugInputStream(InputStream* id);
384 /// Special test-fuction. Reports how many times a sound has been started
386 /// @deprecated Use a TestingSoundHanlder !
388 size_t numSoundsStarted() const { return _soundsStarted; }
390 /// Special test-fuction. Reports how many times a sound has been stopped
392 /// @deprecated Use a TestingSoundHanlder !
394 size_t numSoundsStopped() const { return _soundsStopped; }
396 /// Fetch mixed samples
398 /// We run through all the plugged InputStreams fetching decoded
399 /// audio blocks and mixing them into the given output stream.
401 /// @param to
402 /// The buffer to write mixed samples to.
403 /// Buffer must be big enough to hold nSamples samples.
405 /// @param nSamples
406 /// The amount of samples to fetch.
407 /// NOTE: this number currently refers to "mono" samples
408 /// due to some bad design decision. It is so expected
409 /// that the user fetches 44100 * 2 samples which has to
410 /// be interpreted as series of left,right channel couples.
411 /// TODO: use actual number of samples so that it's expected
412 /// to fetch 44100 per second and let expose a function
413 /// to give interpretation of what comes back (how many
414 /// bytes per channel, which format).
416 virtual void fetchSamples(std::int16_t* to, unsigned int nSamples);
418 /// Mix nSamples from inSamples to outSamples, with given volume
420 /// @param outSamples
421 /// The output samples buffer, to mix to.
422 /// Must be big enough to contain nSamples.
423 /// Can be larger.
425 /// @param inSamples
426 /// The input samples buffer, to mix in.
427 /// It is non-const as this method *is* allowed
428 /// to mess with content, for example to apply
429 /// volume.
430 /// TODO: why not applying volume upstream ?!
432 /// @param nSamples
433 /// The amount of samples to mix in.
435 /// @param volume
436 /// The volume to apply to input samples, as a fraction (0..1)
438 /// TODO: this interface says nothing about how many channels we're
439 /// going to mix. It should, to be a sane interface.
440 /// Maybe, a Mixer instance should be created, initialized
441 /// with number of channels, at each fetching.
443 virtual void mix(std::int16_t* outSamples, std::int16_t* inSamples,
444 unsigned int nSamples, float volume);
446 /// Request to dump audio to the given filename
448 /// Every call to this function starts recording
449 /// to a new file, closing any existing other dump.
451 void setAudioDump(const std::string& wavefile);
453 /// Check if a streaming sound is playing.
455 /// @return true if any streaming sound is playing, false if not.
456 bool streamingSound() const;
458 protected:
460 sound_handler(media::MediaHandler* m)
462 _soundsStarted(0),
463 _soundsStopped(0),
464 _paused(false),
465 _muted(false),
466 _volume(100),
467 _mediaHandler(m)
471 /// Plug an InputStream to the mixer
473 /// @param in
474 /// The InputStream to plug, ownership transferred
476 virtual void plugInputStream(std::unique_ptr<InputStream> in);
478 /// Unplug all input streams
479 virtual void unplugAllInputStreams();
481 /// Does the mixer have input streams ?
482 bool hasInputStreams() const;
484 /// Stop and delete all sounds
486 /// This is used only on reset.
487 virtual void delete_all_sounds();
489 private:
491 /// Special test-member. Stores count of started sounds.
492 size_t _soundsStarted;
494 /// Special test-member. Stores count of stopped sounds.
495 size_t _soundsStopped;
497 /// True if sound is paused
498 bool _paused;
500 /// True if sound is muted
501 std::atomic<bool> _muted;
503 /// Final output volume
504 int _volume;
506 typedef std::vector<EmbedSound*> Sounds;
508 /// Vector containing event sounds.
510 /// Elements of the vector are owned by this class
511 Sounds _sounds;
513 typedef std::vector<StreamingSoundData*> StreamingSounds;
515 /// Vector containing streaming sounds.
517 /// Elements of the vector are owned by this class
518 StreamingSounds _streamingSounds;
520 /// Stop all instances of an embedded sound
521 void stopEmbedSoundInstances(EmbedSound& def);
523 /// Stop all instances of an embedded sound
524 void stopEmbedSoundInstances(StreamingSoundData& def);
526 typedef std::set<InputStream*> InputStreams;
528 /// Sound input streams.
530 /// Elements owned by this class.
531 InputStreams _inputStreams;
533 media::MediaHandler* _mediaHandler;
535 /// Unplug any completed input stream
536 void unplugCompletedInputStreams();
538 std::unique_ptr<WAVWriter> _wavWriter;
542 // TODO: move to appropriate specific sound handlers
544 #ifdef SOUND_SDL
545 /// @throw a SoundException if fails to initialize audio card.
546 DSOEXPORT sound_handler* create_sound_handler_sdl(media::MediaHandler* m);
547 #elif defined(SOUND_AHI)
548 /// @throw a SoundException if fails to initialize audio card.
549 DSOEXPORT sound_handler* create_sound_handler_aos4(media::MediaHandler* m);
550 #elif defined(SOUND_MKIT)
551 /// @throw a SoundException if fails to create node.
552 DSOEXPORT sound_handler* create_sound_handler_mkit(media::MediaHandler* m);
553 #endif
555 } // gnash.sound namespace
556 } // namespace gnash
558 #endif // SOUND_HANDLER_H
561 // Local Variables:
562 // mode: C++
563 // indent-tabs-mode: t
564 // End: