2 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014,
3 // 2015, 2016 Free Software Foundation, Inc
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 #include "sound_handler.h"
22 #include <cstdint> // For C99 int types
26 #include "EmbedSound.h" // for use
27 #include "InputStream.h" // for use
28 #include "EmbedSoundInst.h" // for upcasting to InputStream
29 #include "log.h" // for use
30 #include "StreamingSound.h"
31 #include "StreamingSoundData.h"
32 #include "SimpleBuffer.h"
33 #include "MediaHandler.h"
35 // Debug create_sound/delete_sound/playSound/stop_sound, loops
36 //#define GNASH_DEBUG_SOUNDS_MANAGEMENT
38 // Debug samples fetching
39 //#define GNASH_DEBUG_SAMPLES_FETCHING 1
47 silentStream(void*, std::int16_t* stream
, unsigned int len
, bool& atEOF
)
49 std::fill(stream
, stream
+ len
, 0);
56 validHandle(const T
& container
, int handle
)
58 return handle
>= 0 && static_cast<size_t>(handle
) < container
.size();
61 /// Ensure that each buffer has appropriate padding for the decoder.
63 /// Note: all callers passing a SimpleBuffer should already do this,
64 /// so this is a paranoid check.
66 ensurePadding(SimpleBuffer
& data
, media::MediaHandler
* m
)
68 const size_t padding
= m
? m
->getInputPaddingSize() : 0;
69 if (data
.capacity() - data
.size() < padding
) {
70 log_error(_("Sound data creator didn't appropriately pad "
71 "buffer. We'll do so now, but will cost memory copies."));
72 data
.reserve(data
.size() + padding
);
76 /* The volume ranges from 0 - 128 */
77 #define MIX_MAXVOLUME 128
78 #define ADJUST_VOLUME(s, v) (s = (s*v)/MIX_MAXVOLUME)
81 mixAudio(std::uint8_t *dst
, const std::uint8_t *src
, std::uint32_t len
, int volume
)
83 if ( volume
== 0 ) return;
91 int lsb
= ( isbig
.c
[0] == 1 );
93 std::int16_t src1
, src2
;
95 const int max_audioval
= ((1<<(16-1))-1);
96 const int min_audioval
= -(1<<(16-1));
103 src1
= ((src
[1])<<8|src
[0]);
104 ADJUST_VOLUME(src1
, volume
);
105 src2
= ((dst
[1])<<8|dst
[0]);
107 dst_sample
= src1
+src2
;
108 if ( dst_sample
> max_audioval
) {
109 dst_sample
= max_audioval
;
111 if ( dst_sample
< min_audioval
) {
112 dst_sample
= min_audioval
;
114 dst
[0] = dst_sample
&0xFF;
116 dst
[1] = dst_sample
&0xFF;
125 src1
= ((src
[0])<<8|src
[1]);
126 ADJUST_VOLUME(src1
, volume
);
127 src2
= ((dst
[0])<<8|dst
[1]);
129 dst_sample
= src1
+src2
;
130 if ( dst_sample
> max_audioval
) {
131 dst_sample
= max_audioval
;
133 if ( dst_sample
< min_audioval
) {
134 dst_sample
= min_audioval
;
136 dst
[1] = dst_sample
&0xFF;
138 dst
[0] = dst_sample
&0xFF;
144 } // anonymous namespace
146 sound_handler::StreamBlockId
147 sound_handler::addSoundBlock(SimpleBuffer data
,
148 size_t sampleCount
, int seekSamples
, int handle
)
150 if (!validHandle(_streamingSounds
, handle
)) {
151 log_error(_("Invalid (%d) handle passed to fill_stream_data, "
152 "doing nothing"), handle
);
156 StreamingSoundData
* sounddata
= _streamingSounds
[handle
];
158 log_error(_("handle passed to fill_stream_data (%d) "
159 "was deleted"), handle
);
163 ensurePadding(data
, _mediaHandler
);
165 return sounddata
->append(std::move(data
), sampleCount
, seekSamples
);
169 sound_handler::delete_all_sounds()
171 for (EmbedSound
* sdef
: _sounds
)
173 // The sound may have been deleted already.
176 stopEmbedSoundInstances(*sdef
);
177 assert(!sdef
->numPlayingInstances());
183 for (StreamingSoundData
* sdef
: _streamingSounds
)
185 // Streaming sounds are never deleted.
188 stopEmbedSoundInstances(*sdef
);
189 assert(!sdef
->numPlayingInstances());
193 _streamingSounds
.clear();
198 sound_handler::delete_sound(int handle
)
200 // Check if the sound exists
201 if (!validHandle(_sounds
, handle
)) {
202 log_error(_("Invalid (%d) handle passed to delete_sound, "
203 "doing nothing"), handle
);
207 #ifdef GNASH_DEBUG_SOUNDS_MANAGEMENT
208 log_debug("deleting sound :%d", handle
);
211 EmbedSound
* def
= _sounds
[handle
];
213 log_error(_("handle passed to delete_sound (%d) "
214 "already deleted"), handle
);
218 stopEmbedSoundInstances(*def
);
220 _sounds
[handle
] = nullptr;
225 sound_handler::stop_all_sounds()
227 for (EmbedSound
* sounddata
: _sounds
)
229 if ( ! sounddata
) continue; // could have been deleted already
230 stopEmbedSoundInstances(*sounddata
);
233 for (StreamingSoundData
* sounddata
: _streamingSounds
)
235 if (!sounddata
) continue;
236 stopEmbedSoundInstances(*sounddata
);
241 sound_handler::get_volume(int handle
) const
243 if (validHandle(_sounds
, handle
)) return _sounds
[handle
]->volume
;
250 sound_handler::set_volume(int handle
, int volume
)
252 // Set volume for this sound.
253 // Should this only apply to the active sounds?
254 if (validHandle(_sounds
, handle
)) _sounds
[handle
]->volume
= volume
;
258 sound_handler::get_sound_info(int handle
) const
260 // Check if the sound exists.
261 if (validHandle(_streamingSounds
, handle
)) {
262 return &_streamingSounds
[handle
]->soundinfo
;
268 sound_handler::stopStreamingSound(int handle
)
270 // Check if the sound exists.
271 if (!validHandle(_streamingSounds
, handle
)) {
272 log_debug("stop_sound(%d): invalid sound id", handle
);
276 StreamingSoundData
* sounddata
= _streamingSounds
[handle
];
279 stopEmbedSoundInstances(*sounddata
);
283 sound_handler::stopEventSound(int handle
)
285 // Check if the sound exists.
286 if (!validHandle(_sounds
, handle
)) {
287 log_debug("stop_sound(%d): invalid sound id", handle
);
291 EmbedSound
* sounddata
= _sounds
[handle
];
293 log_error(_("stop_sound(%d): sound was deleted"), handle
);
297 #ifdef GNASH_DEBUG_SOUNDS_MANAGEMENT
298 log_debug("stop_sound %d called", handle
);
301 stopEmbedSoundInstances(*sounddata
);
306 sound_handler::stopAllEventSounds()
308 #ifdef GNASH_DEBUG_SOUNDS_MANAGEMENT
309 log_debug("stopAllEventSounds called");
312 for (EmbedSound
* sounddata
: _sounds
)
314 if (!sounddata
) continue; // possible ?
316 stopEmbedSoundInstances(*sounddata
);
322 sound_handler::stopEmbedSoundInstances(StreamingSoundData
& def
)
324 // Assert _mutex is locked ...
325 typedef std::vector
<InputStream
*> InputStreamVect
;
326 InputStreamVect playing
;
327 def
.getPlayingInstances(playing
);
329 // Now, for each playing InputStream, unplug it!
330 // NOTE: could be optimized...
331 for (InputStream
* stream
: playing
)
333 #ifdef GNASH_DEBUG_SOUNDS_MANAGEMENT
334 log_debug(" unplugging input stream %p from stopEmbedSoundInstances", stream
);
337 // Explicitly calling the base class implementation
338 // is a (dirty?) way to avoid mutex-locking overrides
339 // in subclasses causing deadlocks.
340 sound_handler::unplugInputStream(stream
);
343 def
.clearInstances();
348 sound_handler::stopEmbedSoundInstances(EmbedSound
& def
)
350 // Assert _mutex is locked ...
351 typedef std::vector
<InputStream
*> InputStreamVect
;
352 InputStreamVect playing
;
353 def
.getPlayingInstances(playing
);
355 // Now, for each playing InputStream, unplug it!
356 // NOTE: could be optimized...
357 for (InputStream
* stream
: playing
)
359 #ifdef GNASH_DEBUG_SOUNDS_MANAGEMENT
360 log_debug(" unplugging input stream %p from stopEmbedSoundInstances", stream
);
363 // Explicitly calling the base class implementation
364 // is a (dirty?) way to avoid mutex-locking overrides
365 // in subclasses causing deadlocks.
366 sound_handler::unplugInputStream(stream
);
369 def
.clearInstances();
373 sound_handler::unplugInputStream(InputStream
* id
)
375 // WARNING: erasing would break any iteration in the set
376 InputStreams::iterator it2
=_inputStreams
.find(id
);
377 if (it2
== _inputStreams
.end()) {
378 log_error(_("sound_handler::unplugInputStream: "
379 "Aux streamer %p not found. "),
381 return; // we won't delete it, as it's likely deleted already
384 _inputStreams
.erase(it2
);
386 // Increment number of sound stop request for the testing framework
389 #ifdef GNASH_DEBUG_SOUNDS_MANAGEMENT
390 log_debug("Unplugged InputStream %p", id
);
393 // Delete the InputStream (we own it..)
398 sound_handler::tell(int handle
) const
400 // Check if the sound exists.
401 if (!validHandle(_sounds
, handle
)) return 0;
403 const EmbedSound
* sounddata
= _sounds
[handle
];
405 // If there is no active sounds, return 0
406 if (!sounddata
->isPlaying()) return 0;
408 // We use the first active sound of this.
409 const InputStream
* asound
= sounddata
->firstPlayingInstance();
411 // Return the playhead position in milliseconds
412 unsigned int samplesPlayed
= asound
->samplesFetched();
414 unsigned int ret
= samplesPlayed
/ 44100 * 1000;
415 ret
+= ((samplesPlayed
% 44100) * 1000) / 44100;
416 ret
= ret
/ 2; // 2 channels
421 sound_handler::get_duration(int handle
) const
423 // Check if the sound exists.
424 if (!validHandle(_sounds
, handle
)) return 0;
426 const EmbedSound
* sounddata
= _sounds
[handle
];
428 const std::uint32_t sampleCount
= sounddata
->soundinfo
.getSampleCount();
429 const std::uint32_t sampleRate
= sounddata
->soundinfo
.getSampleRate();
431 // Return the sound duration in milliseconds
432 if (sampleCount
> 0 && sampleRate
> 0) {
433 // TODO: should we cache this in the EmbedSound object ?
434 unsigned int ret
= sampleCount
/ sampleRate
* 1000;
435 ret
+= ((sampleCount
% sampleRate
) * 1000) / sampleRate
;
442 sound_handler::createStreamingSound(const media::SoundInfo
& sinfo
)
444 std::unique_ptr
<StreamingSoundData
> sounddata(
445 new StreamingSoundData(sinfo
, 100));
447 int sound_id
= _streamingSounds
.size();
448 // the vector takes ownership
449 _streamingSounds
.push_back(sounddata
.release());
455 sound_handler::create_sound(std::unique_ptr
<SimpleBuffer
> data
,
456 const media::SoundInfo
& sinfo
)
459 ensurePadding(*data
, _mediaHandler
);
462 log_debug("Event sound with no data!");
464 std::unique_ptr
<EmbedSound
> sounddata(new EmbedSound(std::move(data
), sinfo
, 100));
466 int sound_id
= _sounds
.size();
468 #ifdef GNASH_DEBUG_SOUNDS_MANAGEMENT
469 log_debug("create_sound: sound %d, format %s %s %dHz, %d samples (%d bytes)",
470 sound_id
, sounddata
->soundinfo
.getFormat(),
471 sounddata
->soundinfo
.isStereo() ? "stereo" : "mono",
472 sounddata
->soundinfo
.getSampleRate(),
473 sounddata
->soundinfo
.getSampleCount(),
477 // the vector takes ownership
478 _sounds
.push_back(sounddata
.release());
485 sound_handler::isSoundPlaying(int handle
) const
487 if (!validHandle(_sounds
, handle
)) return false;
489 EmbedSound
& sounddata
= *(_sounds
[handle
]);
491 // When this is called from a StreamSoundBlockTag,
492 // we only start if this sound isn't already playing.
493 return sounddata
.isPlaying();
497 sound_handler::playStream(int soundId
, StreamBlockId blockId
)
499 StreamingSoundData
& s
= *_streamingSounds
[soundId
];
500 if (s
.isPlaying() || s
.empty()) return;
503 if (!_mediaHandler
) {
504 throw MediaException("No media handler available");
507 std::unique_ptr
<InputStream
> is(
508 s
.createInstance(*_mediaHandler
, blockId
));
509 plugInputStream(std::move(is
));
511 catch (const MediaException
& e
) {
512 log_error(_("Could not start streaming sound: %s"), e
.what());
517 sound_handler::startSound(int handle
, int loops
, const SoundEnvelopes
* env
,
518 bool allowMultiple
, unsigned int inPoint
,
519 unsigned int outPoint
)
521 // Check if the sound exists
522 if (!validHandle(_sounds
, handle
)) {
523 log_error(_("Invalid (%d) sound_handle passed to startSound, "
524 "doing nothing"), handle
);
529 EmbedSound
& sounddata
= *(_sounds
[handle
]);
530 const media::SoundInfo
& sinfo
= sounddata
.soundinfo
;
532 const int swfDelaySeek
= sinfo
.getDelaySeek();
534 // NOTE: differences between delaySeek and inPoint:
536 // - Sample count semantic:
537 // inPoint uses output sample rate (44100 for one second)
538 // while delaySeek uses source sample rate
539 // (SoundInfo.getSampleRate() for one second)
541 // - Loop-back semantic:
542 // An event sound always loops-back from inPoint with no gaps
543 // When delaySeek is specified it is still used as a start
544 // for the initial playback but when it comes to looping back
545 // it seems to play silence instead of samples for the amount
549 // loop1 *****************
550 // loop2 ----------------*****************
551 // loop3 ----------------*****************
554 // loop1 *****************
555 // loop2 *****************
556 // loop3 *****************
558 LOG_ONCE(log_unimpl("MP3 delaySeek"));
560 unsigned int outDelaySeek
= swfToOutSamples(sinfo
, swfDelaySeek
);
562 log_debug("inPoint(%d) + delaySeek(%d -> %d) == %d",
563 inPoint
, swfDelaySeek
, outDelaySeek
,
564 inPoint
+outDelaySeek
);
566 inPoint
+= outDelaySeek
;
570 #ifdef GNASH_DEBUG_SOUNDS_MANAGEMENT
571 log_debug("startSound %d called, SoundInfo format is %s",
572 handle
, sounddata
.soundinfo
.getFormat());
575 // When this is called from a StreamSoundBlockTag,
576 // we only start if this sound isn't already playing.
577 if (!allowMultiple
&& sounddata
.isPlaying()) {
578 #ifdef GNASH_DEBUG_SOUNDS_MANAGEMENT
579 log_debug(" playSound: multiple instances not allowed, "
580 "and sound is already playing");
585 // Make sure sound actually got some data
586 if (sounddata
.empty()) {
587 // @@ should this be a log_error ? or even an assert ?
588 IF_VERBOSE_MALFORMED_SWF(
589 log_swferror(_("Trying to play sound with size 0"));
595 if (!_mediaHandler
) {
596 throw MediaException("No media handler available");
599 // Make an InputStream for this sound and plug it into
600 // the set of InputStream channels
601 std::unique_ptr
<InputStream
> sound(
602 sounddata
.createInstance(*_mediaHandler
, inPoint
, outPoint
,
604 plugInputStream(std::move(sound
));
606 catch (const MediaException
& e
) {
607 log_error(_("Could not start event sound: %s"), e
.what());
613 sound_handler::plugInputStream(std::unique_ptr
<InputStream
> newStreamer
)
615 #ifdef GNASH_DEBUG_SOUNDS_MANAGEMENT
616 InputStream
* newStream
= newStreamer
.get(); // for debugging
619 if (!_inputStreams
.insert(newStreamer
.release()).second
) {
620 // this should never happen !
621 log_error(_("_inputStreams container still has a pointer "
622 "to deleted InputStream %p!"), newStreamer
.get());
623 // FIXME: replace the old element with the new one !
627 #ifdef GNASH_DEBUG_SOUNDS_MANAGEMENT
628 log_debug("Plugged InputStream %p", newStream
);
631 // Increment number of sound start request for the testing framework
636 sound_handler::unplugAllInputStreams()
638 for (const InputStream
* stream
: _inputStreams
)
642 _inputStreams
.clear();
646 sound_handler::fetchSamples(std::int16_t* to
, unsigned int nSamples
)
648 if (isPaused()) return; // should we write wav file anyway ?
650 float finalVolumeFact
= getFinalVolume()/100.0;
652 std::fill(to
, to
+ nSamples
, 0);
654 // call NetStream or Sound audio callbacks
655 if (!_inputStreams
.empty()) {
657 // A buffer to fetch InputStream samples into
658 std::unique_ptr
<std::int16_t[]> buf(new std::int16_t[nSamples
]);
660 #ifdef GNASH_DEBUG_SAMPLES_FETCHING
661 log_debug("Fetching %d samples from each of %d input streams", nSamples
, _inputStreams
.size());
664 // Loop through the aux streamers sounds
665 for (InputStream
* is
: _inputStreams
)
667 unsigned int wrote
= is
->fetchSamples(buf
.get(), nSamples
);
668 if (wrote
< nSamples
) {
669 // fill what wasn't written
670 std::fill(buf
.get()+wrote
, buf
.get()+nSamples
, 0);
673 #if GNASH_DEBUG_SAMPLES_FETCHING > 1
674 log_debug(" fetched %d/%d samples from input stream %p"
675 " (%d samples fetchehd in total)",
676 wrote
, nSamples
, is
, is
->samplesFetched());
679 mix(to
, buf
.get(), nSamples
, finalVolumeFact
);
682 unplugCompletedInputStreams();
685 // TODO: move this to base class !
686 if (_wavWriter
.get()) {
687 _wavWriter
->pushSamples(to
, nSamples
);
689 // now, mute all audio
690 std::fill(to
, to
+nSamples
, 0);
693 // Now, after having "consumed" all sounds, blank out
694 // the buffer if muted..
696 std::fill(to
, to
+nSamples
, 0);
701 sound_handler::setAudioDump(const std::string
& wavefile
)
703 bool wasDumping
= (_wavWriter
.get() != nullptr);
705 if (!wavefile
.empty()) {
706 _wavWriter
.reset(new WAVWriter(wavefile
));
709 // TODO: just avoid pausing instead ...
711 // add a silent stream to the audio pool so that our
712 // output file is homogenous; we actually want silent
713 // wave data when no sounds are playing on the stage
714 attach_aux_streamer(silentStream
, (void*) this);
719 sound_handler::streamingSound() const
721 if (_inputStreams
.empty()) return false;
723 for (StreamingSoundData
* const stream
: _streamingSounds
) {
724 if (stream
->isPlaying()) return true;
730 sound_handler::getStreamBlock(int handle
) const
732 if (!validHandle(_streamingSounds
, handle
)) return -1;
733 if (!_streamingSounds
[handle
]->isPlaying()) return -1;
734 InputStream
* i
= _streamingSounds
[handle
]->firstPlayingInstance();
736 return static_cast<StreamingSound
*>(i
)->currentBlock();
740 sound_handler::unplugCompletedInputStreams()
743 #ifdef GNASH_DEBUG_SOUNDS_MANAGEMENT
744 log_debug("Scanning %d input streams for completion", _inputStreams
.size());
747 for (InputStreams::iterator it
= _inputStreams
.begin(),
748 end
= _inputStreams
.end(); it
!= end
;) {
750 InputStream
* is
= *it
;
754 // InputStream EOF, detach
755 InputStreams::iterator it2
= it
;
756 ++it2
; // before we erase it
757 InputStreams::size_type erased
= _inputStreams
.erase(is
);
759 log_error(_("Expected 1 InputStream element, found %d"), erased
);
764 #ifdef GNASH_DEBUG_SOUNDS_MANAGEMENT
765 log_debug(" Input stream %p reached EOF, unplugging", is
);
768 // WARNING! deleting the InputStream here means
769 // a lot of things will happen from a
770 // separate thread. Instead, if we
771 // extend sound_handler interface to
772 // have an unplugCompletedInputStreams
773 // we may call it at heart-beating intervals
774 // and drop any threading paranoia!
777 // Increment number of sound stop request for the testing framework
785 sound_handler::hasInputStreams() const
787 return !_inputStreams
.empty();
791 sound_handler::is_muted() const
793 // TODO: lock a mutex ?
794 return _muted
.load();
798 sound_handler::mute()
800 // TODO: lock a mutex ?
805 sound_handler::unmute()
807 // TODO: lock a mutex ?
812 sound_handler::reset()
814 // Do not delete sounds on reset or there'd be nothing to play
815 // on restart. For a new SWF, we need a new sound_handler.
816 sound_handler::stop_all_sounds();
820 sound_handler::attach_aux_streamer(aux_streamer_ptr ptr
, void* owner
)
825 std::unique_ptr
<InputStream
> newStreamer ( new AuxStream(ptr
, owner
) );
827 InputStream
* ret
= newStreamer
.get();
829 plugInputStream(std::move(newStreamer
));
834 sound_handler::~sound_handler()
837 unplugAllInputStreams();
841 sound_handler::mix(std::int16_t* outSamples
, std::int16_t* inSamples
, unsigned int nSamples
, float volume
)
843 unsigned int nBytes
= nSamples
*2;
845 std::uint8_t *out
= reinterpret_cast<std::uint8_t*>(outSamples
);
846 std::uint8_t* in
= reinterpret_cast<std::uint8_t*>(inSamples
);
848 mixAudio(out
, in
, nBytes
, static_cast<int>(MIX_MAXVOLUME
*volume
));
851 } // gnash.sound namespace