1 // Sound_as.cpp: ActionScript "Sound" class, for Gnash.
3 // Copyright (C) 2009, 2010 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
23 #include <boost/scoped_ptr.hpp>
24 #include <boost/scoped_array.hpp>
25 #include <boost/thread/mutex.hpp>
26 #include <boost/cstdint.hpp>
28 #include "RunResources.h"
30 #include "sound_handler.h"
31 #include "AudioDecoder.h"
32 #include "MediaHandler.h"
33 #include "sound_definition.h"
34 #include "movie_root.h"
35 #include "movie_definition.h"
37 #include "Global_as.h"
38 #include "GnashException.h" // for ActionException
39 #include "builtin_function.h" // need builtin_function
40 #include "NativeFunction.h" // need builtin_function
41 #include "smart_ptr.h" // for boost intrusive_ptr
43 #include "namedStrings.h"
44 #include "StreamProvider.h"
45 #include "ObjectURI.h"
51 // Forward declarations
53 as_value
sound_new(const fn_call
& fn
);
54 as_value
sound_attachsound(const fn_call
& fn
);
55 as_value
sound_getbytesloaded(const fn_call
& fn
);
56 as_value
sound_setPosition(const fn_call
& fn
);
57 as_value
sound_areSoundsInaccessible(const fn_call
& fn
);
58 as_value
sound_getbytestotal(const fn_call
& fn
);
59 as_value
sound_getpan(const fn_call
& fn
);
60 as_value
sound_setpan(const fn_call
& fn
);
61 as_value
sound_getDuration(const fn_call
& fn
);
62 as_value
sound_setDuration(const fn_call
& fn
);
63 as_value
sound_gettransform(const fn_call
& fn
);
64 as_value
sound_getPosition(const fn_call
& fn
);
65 as_value
sound_getvolume(const fn_call
& fn
);
66 as_value
sound_loadsound(const fn_call
& fn
);
67 as_value
sound_settransform(const fn_call
& fn
);
68 as_value
sound_setvolume(const fn_call
& fn
);
69 as_value
sound_start(const fn_call
& fn
);
70 as_value
sound_stop(const fn_call
& fn
);
71 as_value
checkPolicyFile_getset(const fn_call
& fn
);
72 void attachSoundInterface(as_object
& o
);
75 /// A Sound object in ActionScript can control and play sound
77 /// Two types of sound are handled:
79 /// 1. external sounds, either loaded or streamed
80 /// 2. embedded sounds, referenced by library (export) symbol.
82 /// Sound objects also control volume, pan, and other properties for a target
87 /// 1. May be associated with a particular DisplayObject.
88 /// 2. May be associated with one or more playing sounds.
90 /// A Sound_as that is not associated with a particular DisplayObject controls
91 /// the sound properties of the whole Movie.
92 class Sound_as
: public ActiveRelay
97 Sound_as(as_object
* owner
);
101 /// Make this sound control the given DisplayObject
103 /// NOTE: 0 is accepted, to implement an "invalid"
106 void attachCharacter(DisplayObject
* attachedChar
);
108 void attachSound(int si
, const std::string
& name
);
110 /// Get number of bytes loaded.
112 /// This only applies to external sounds. If unknown or not external, -1
114 long getBytesLoaded();
116 /// Get total number of bytes in the external sound being loaded
118 /// This only applies to external sounds. If unknown or not external, -1
120 long getBytesTotal();
122 /// Whether the Sound_as has any sound data
123 bool active() const {
124 return soundId
>= 0 || isStreaming
;
127 /// Get the pan setting of the attached DisplayObject.
129 /// If no object is attached, this retrieves settings for the whole Movie.
132 /// Get the sound transform of the attached DisplayObject.
134 /// If no object is attached, this retrieves settings for the whole Movie.
137 /// Get volume from associated resource
139 /// @return true of volume was obtained, false
140 /// otherwise (for example if the associated
141 /// DisplayObject was unloaded).
143 bool getVolume(int& volume
);
144 void setVolume(int volume
);
146 /// Load an external sound.
148 /// The Sound object is then associated with the external sound.
149 void loadSound(const std::string
& file
, bool streaming
);
155 void start(double secsStart
, int loops
);
159 /// Get the duration of the sound.
161 /// This is only meaningful when the Sound_as object has an associated
162 /// sound, that is after attachSound or loadSound has been called.
163 size_t getDuration() const;
165 /// Get the position within the sound.
167 /// This is only meaningful when the Sound_as object has an associated
168 /// sound, that is after attachSound or loadSound has been called.
169 size_t getPosition() const;
171 std::string soundName
;
175 void markReachableResources() const;
177 boost::scoped_ptr
<CharacterProxy
> _attachedCharacter
;
182 sound::sound_handler
* _soundHandler
;
184 media::MediaHandler
* _mediaHandler
;
186 boost::scoped_ptr
<media::MediaParser
> _mediaParser
;
188 boost::scoped_ptr
<media::AudioDecoder
> _audioDecoder
;
190 /// Number of milliseconds into the sound to start it
192 /// This is set by start()
193 boost::uint64_t _startTime
;
195 boost::scoped_array
<boost::uint8_t> _leftOverData
;
196 boost::uint8_t* _leftOverPtr
;
197 boost::uint32_t _leftOverSize
;
199 /// This is a sound_handler::aux_streamer_ptr type.
200 static unsigned int getAudioWrapper(void *owner
, boost::int16_t* samples
,
201 unsigned int nSamples
, bool& etEOF
);
203 unsigned int getAudio(boost::int16_t* samples
, unsigned int nSamples
,
206 /// The aux streamer for sound handler
207 sound::InputStream
* _inputStream
;
211 /// Query media parser for audio info, create decoder and attach aux streamer
214 /// @return an InputStream* if audio found and aux streamer attached,
215 /// 0 if no audio found.
217 /// May throw a MediaException if audio was found but
218 /// audio decoder could not be created
220 sound::InputStream
* attachAuxStreamerIfNeeded();
222 /// Register a timer for audio info probing
223 void startProbeTimer();
225 /// Unregister the probe timer
226 void stopProbeTimer();
228 virtual void update();
233 bool _soundCompleted
;
235 boost::mutex _soundCompletedMutex
;
237 /// Thread-safe setter for _soundCompleted
238 void markSoundCompleted(bool completed
);
240 // Does this sound have a live input stream?
241 bool isAttached() const {
242 return (_inputStream
);
247 Sound_as::Sound_as(as_object
* owner
)
250 _attachedCharacter(0),
252 externalSound(false),
254 _soundHandler(getRunResources(*owner
).soundHandler()),
255 _mediaHandler(getRunResources(*owner
).mediaHandler()),
262 _soundCompleted(false)
266 Sound_as::~Sound_as()
269 if (_inputStream
&& _soundHandler
) {
270 _soundHandler
->unplugInputStream(_inputStream
);
276 // extern (used by Global.cpp)
278 sound_class_init(as_object
& where
, const ObjectURI
& uri
)
281 Global_as
& gl
= getGlobal(where
);
282 as_object
* proto
= createObject(gl
);
283 as_object
* cl
= gl
.createClass(&sound_new
, proto
);
284 attachSoundInterface(*proto
);
285 proto
->set_member_flags(NSV::PROP_CONSTRUCTOR
, PropFlags::readOnly
);
286 proto
->set_member_flags(NSV::PROP_uuPROTOuu
, PropFlags::readOnly
, 0);
288 // Register _global.String
289 where
.init_member(uri
, cl
, as_object::DefaultFlags
);
294 registerSoundNative(as_object
& global
)
296 VM
& vm
= getVM(global
);
297 vm
.registerNative(sound_getpan
, 500, 0);
298 vm
.registerNative(sound_gettransform
, 500, 1);
299 vm
.registerNative(sound_getvolume
, 500, 2);
300 vm
.registerNative(sound_setpan
, 500, 3);
301 vm
.registerNative(sound_settransform
, 500, 4);
302 vm
.registerNative(sound_setvolume
, 500, 5);
303 vm
.registerNative(sound_stop
, 500, 6);
304 vm
.registerNative(sound_attachsound
, 500, 7);
305 vm
.registerNative(sound_start
, 500, 8);
306 vm
.registerNative(sound_getDuration
, 500, 9);
307 vm
.registerNative(sound_setDuration
, 500, 10);
308 vm
.registerNative(sound_getPosition
, 500, 11);
309 vm
.registerNative(sound_setPosition
, 500, 12);
310 vm
.registerNative(sound_loadsound
, 500, 13);
311 vm
.registerNative(sound_getbytesloaded
, 500, 14);
312 vm
.registerNative(sound_getbytestotal
, 500, 15);
313 vm
.registerNative(sound_areSoundsInaccessible
, 500, 16);
318 Sound_as::startProbeTimer()
320 getRoot(owner()).addAdvanceCallback(this);
325 Sound_as::stopProbeTimer()
327 #ifdef GNASH_DEBUG_SOUND_AS
328 log_debug("stopProbeTimer called");
330 getRoot(owner()).removeAdvanceCallback(this);
338 VM
& vm
= getVM(owner());
341 owner().set_member(getURI(vm
, "duration"), getDuration());
342 owner().set_member(getURI(vm
, "position"), getPosition());
347 Sound_as::probeAudio()
351 #ifdef GNASH_DEBUG_SOUND_AS
352 log_debug("Probing audio for end");
355 boost::mutex::scoped_lock
lock(_soundCompletedMutex
);
356 if (_soundCompleted
) {
357 // when _soundCompleted is true we're
359 _mediaParser
.reset(); // no use for this anymore...
361 _soundCompleted
= false;
364 // dispatch onSoundComplete
365 callMethod(&owner(), NSV::PROP_ON_SOUND_COMPLETE
);
368 else if (_mediaParser
) {
369 #ifdef GNASH_DEBUG_SOUND_AS
370 log_debug("Probing audio for start");
373 bool parsingCompleted
= _mediaParser
->parsingCompleted();
375 _inputStream
= attachAuxStreamerIfNeeded();
377 catch (const MediaException
& e
) {
378 assert(!_inputStream
);
379 assert(!_audioDecoder
.get());
380 log_error(_("Could not create audio decoder: %s"), e
.what());
381 _mediaParser
.reset(); // no use for this anymore...
386 if ( ! _inputStream
) {
387 if ( parsingCompleted
) {
388 log_debug("No audio in Sound input.");
390 _mediaParser
.reset(); // no use for this anymore...
395 // An audio decoder was constructed, good!
396 assert(_audioDecoder
.get());
403 Sound_as::markReachableResources() const
405 if (_attachedCharacter
) {
406 _attachedCharacter
->setReachable();
409 #endif // GNASH_USE_GC
412 Sound_as::markSoundCompleted(bool completed
)
414 boost::mutex::scoped_lock
lock(_soundCompletedMutex
);
415 _soundCompleted
=completed
;
419 Sound_as::attachCharacter(DisplayObject
* attachTo
)
421 _attachedCharacter
.reset(new CharacterProxy(attachTo
, getRoot(owner())));
425 Sound_as::attachSound(int si
, const std::string
& name
)
430 VM
& vm
= getVM(owner());
431 owner().set_member(getURI(vm
, "duration"), getDuration());
432 owner().set_member(getURI(vm
, "position"), getPosition());
437 Sound_as::getBytesLoaded()
439 if ( _mediaParser
) {
440 return _mediaParser
->getBytesLoaded();
447 Sound_as::getBytesTotal()
449 if ( _mediaParser
) {
450 return _mediaParser
->getBytesTotal();
459 LOG_ONCE(log_unimpl(__FUNCTION__
));
463 Sound_as::getTransform()
465 LOG_ONCE(log_unimpl(__FUNCTION__
));
469 Sound_as::getVolume(int& volume
)
471 // TODO: check what takes precedence in case we
472 // have both an attached DisplayObject *and*
473 // some other sound...
475 if ( _attachedCharacter
) {
476 //log_debug("Sound has an attached DisplayObject");
477 DisplayObject
* ch
= _attachedCharacter
->get();
479 log_debug("Character attached to Sound was unloaded and "
483 volume
= ch
->getVolume();
487 // If we're not attached to a DisplayObject we'll need to query
488 // sound_handler for volume. If we have no sound handler, we
489 // can't do much, so we'll return false
490 if (!_soundHandler
) {
491 log_debug("We have no sound handler here...");
495 // Now, we may be controlling a specific sound or
496 // the final output as a whole.
497 // If soundId is -1 we're controlling as a whole
500 volume
= _soundHandler
->getFinalVolume();
502 volume
= _soundHandler
->get_volume(soundId
);
509 Sound_as::loadSound(const std::string
& file
, bool streaming
)
511 if ( ! _mediaHandler
|| ! _soundHandler
) {
512 log_debug("No media or sound handlers, won't load any sound");
516 /// If we are already streaming stop doing so as we'll replace
518 if ( _inputStream
) {
519 _soundHandler
->unplugInputStream(_inputStream
);
523 /// Delete any media parser being used (make sure we have detached!)
524 _mediaParser
.reset();
526 /// Start at offset 0, in case a previous ::start() call
530 const RunResources
& rr
= getRunResources(owner());
531 URL
url(file
, rr
.streamProvider().baseURL());
533 const RcInitFile
& rcfile
= RcInitFile::getDefaultInstance();
535 const StreamProvider
& streamProvider
= rr
.streamProvider();
536 std::auto_ptr
<IOChannel
> inputStream(streamProvider
.getStream(url
,
537 rcfile
.saveStreamingMedia()));
538 if ( ! inputStream
.get() ) {
539 log_error( _("Gnash could not open this url: %s"), url
);
543 externalSound
= true;
544 isStreaming
= streaming
;
546 _mediaParser
.reset(_mediaHandler
->createMediaParser(inputStream
).release());
547 if ( ! _mediaParser
) {
548 log_error(_("Unable to create parser for Sound at %s"), url
);
549 // not necessarely correct, the stream might have been found...
553 // TODO: use global _soundbuftime
554 _mediaParser
->setBufferTime(60000); // one minute buffer... should be fine
560 LOG_ONCE(log_unimpl("Non-streaming Sound.loadSound: will behave "
561 "as a streaming one"));
562 // if not streaming, we'll probe on .start()
565 VM
& vm
= getVM(owner());
566 owner().set_member(getURI(vm
, "duration"), getDuration());
567 owner().set_member(getURI(vm
, "position"), getPosition());
571 Sound_as::attachAuxStreamerIfNeeded()
573 media::AudioInfo
* audioInfo
= _mediaParser
->getAudioInfo();
574 if (!audioInfo
) return 0;
576 // the following may throw an exception
577 _audioDecoder
.reset(_mediaHandler
->createAudioDecoder(*audioInfo
).release());
579 // start playing ASAP, a call to ::start will just change _startTime
580 #ifdef GNASH_DEBUG_SOUND_AS
581 log_debug("Attaching the aux streamer");
583 return _soundHandler
->attach_aux_streamer(getAudioWrapper
, (void*) this);
589 LOG_ONCE(log_unimpl(__FUNCTION__
));
593 Sound_as::setTransform()
595 LOG_ONCE(log_unimpl(__FUNCTION__
));
599 Sound_as::setVolume(int volume
)
601 // TODO: check what takes precedence in case we
602 // have both an attached DisplayObject *and*
603 // some other sound...
605 if ( _attachedCharacter
) {
606 DisplayObject
* ch
= _attachedCharacter
->get();
608 log_debug("Character attached to Sound was unloaded and "
612 ch
->setVolume(volume
);
616 // If we're not attached to a DisplayObject we'll need to use
617 // sound_handler for volume. If we have no sound handler, we
618 // can't do much, so we'll just return
619 if (!_soundHandler
) {
623 // Now, we may be controlling a specific sound or
624 // the final output as a whole.
625 // If soundId is -1 we're controlling as a whole
627 if ( soundId
== -1 ) {
628 _soundHandler
->setFinalVolume(volume
);
630 _soundHandler
->set_volume(soundId
, volume
);
635 Sound_as::start(double secOff
, int loops
)
637 if ( ! _soundHandler
) {
638 log_error("No sound handler, nothing to start...");
643 if ( ! _mediaParser
) {
644 log_error("No MediaParser initialized, can't start an external sound");
649 _startTime
= secOff
* 1000;
650 boost::uint32_t seekms
= boost::uint32_t(secOff
* 1000);
651 // TODO: boost::mutex::scoped_lock parserLock(_parserMutex);
652 _mediaParser
->seek(seekms
); // well, we try...
656 IF_VERBOSE_ASCODING_ERRORS(
657 log_aserror(_("Sound.start() has no effect on a streaming Sound"));
662 // Save how many loops to do (not when streaming)
664 remainingLoops
= loops
;
667 // TODO: we should really be waiting for the sound to be fully
668 // loaded before starting to play it (!isStreaming case)
672 unsigned int inPoint
= 0;
675 inPoint
= (secOff
*44100);
678 log_debug("Sound.start: secOff:%d", secOff
);
680 _soundHandler
->startSound(
684 true, // allow multiple instances (checked)
692 Sound_as::stop(int si
)
694 if ( ! _soundHandler
) {
695 log_error("No sound handler, nothing to stop...");
702 if ( _inputStream
) {
703 _soundHandler
->unplugInputStream(_inputStream
);
707 _soundHandler
->stop_sound(soundId
);
710 _soundHandler
->stop_sound(si
);
715 Sound_as::getDuration() const
717 if ( ! _soundHandler
) {
718 log_error("No sound handler, can't check duration...");
722 // If this is a event sound get the info from the soundhandler
723 if (!externalSound
) {
724 return _soundHandler
->get_duration(soundId
);
727 // If we have a media parser (we'd do for an externalSound)
728 // try fetching duration from it
729 if ( _mediaParser
) {
730 media::AudioInfo
* info
= _mediaParser
->getAudioInfo();
732 return info
->duration
;
740 Sound_as::getPosition() const
742 if (!_soundHandler
) {
743 log_error("No sound handler, can't check position (we're "
744 "likely not playing anyway)...");
748 // If this is a event sound get the info from the soundhandler
749 if (!externalSound
) {
750 return _soundHandler
->tell(soundId
);
755 if ( _mediaParser
->nextAudioFrameTimestamp(ts
) ) {
766 Sound_as::getAudio(boost::int16_t* samples
, unsigned int nSamples
, bool& atEOF
)
768 boost::uint8_t* stream
= reinterpret_cast<boost::uint8_t*>(samples
);
769 int len
= nSamples
*2;
771 //GNASH_REPORT_FUNCTION;
774 if ( ! _leftOverData
) {
775 bool parsingComplete
= _mediaParser
->parsingCompleted(); // check *before* calling nextAudioFrame
776 std::auto_ptr
<media::EncodedAudioFrame
> frame
= _mediaParser
->nextAudioFrame();
777 if ( ! frame
.get() ) {
778 // just wait some more if parsing isn't complete yet
779 if ( ! parsingComplete
) {
780 //log_debug("Parsing not complete and no more audio frames in input, try again later");
784 // or detach and stop here...
785 // (should really honour loopings if any,
786 // but that should be only done for non-streaming sound!)
787 //log_debug("Parsing complete and no more audio frames in input, detaching");
789 markSoundCompleted(true);
791 // Setting atEOF to true will detach us.
792 // We should change _inputStream, but need thread safety!
793 // So on probeAudio, if _soundCompleted is set
794 // we'll consider ourselves detached already and set
795 // _inputStream to zero
797 return nSamples
-(len
/2);
800 // if we've been asked to start at a specific time, skip
801 // any frame with earlier timestamp
802 if ( frame
->timestamp
< _startTime
) {
803 //log_debug("This audio frame timestamp (%d) < requested start time (%d)", frame->timestamp, _startTime);
807 _leftOverData
.reset( _audioDecoder
->decode(*frame
, _leftOverSize
) );
808 _leftOverPtr
= _leftOverData
.get();
809 if ( ! _leftOverData
) {
810 log_error("No samples decoded from input of %d bytes", frame
->dataSize
);
814 //log_debug(" decoded %d bytes of audio", _leftOverSize);
817 assert( !(_leftOverSize
%2) );
819 int n
= std::min
<int>(_leftOverSize
, len
);
820 //log_debug(" consuming %d bytes of decoded audio", n);
822 std::copy(_leftOverPtr
, _leftOverPtr
+n
, stream
);
829 if (_leftOverSize
== 0) {
830 _leftOverData
.reset();
836 // drop any queued video frame
837 while (_mediaParser
->nextVideoFrame().get()) {};
840 return nSamples
-(len
/2);
843 // audio callback is running in sound handler thread
845 Sound_as::getAudioWrapper(void* owner
, boost::int16_t* samples
,
846 unsigned int nSamples
, bool& atEOF
)
848 Sound_as
* so
= static_cast<Sound_as
*>(owner
);
849 return so
->getAudio(samples
, nSamples
, atEOF
);
856 attachSoundInterface(as_object
& o
)
859 int flags
= PropFlags::dontEnum
|
860 PropFlags::dontDelete
|
864 o
.init_member("getPan", vm
.getNative(500, 0), flags
);
865 o
.init_member("getTransform", vm
.getNative(500, 1), flags
);
866 o
.init_member("getVolume", vm
.getNative(500, 2), flags
);
867 o
.init_member("setPan", vm
.getNative(500, 3), flags
);
868 o
.init_member("setTransform", vm
.getNative(500, 4), flags
);
869 o
.init_member("setVolume", vm
.getNative(500, 5), flags
);
870 o
.init_member("stop", vm
.getNative(500, 6), flags
);
871 o
.init_member("attachSound", vm
.getNative(500, 7), flags
);
872 o
.init_member("start", vm
.getNative(500, 8), flags
);
874 int flagsn6
= flags
| PropFlags::onlySWF6Up
;
876 o
.init_member("getDuration", vm
.getNative(500, 9), flagsn6
);
877 o
.init_member("setDuration", vm
.getNative(500, 10), flagsn6
);
878 o
.init_member("getPosition", vm
.getNative(500, 11), flagsn6
);
879 o
.init_member("setPosition", vm
.getNative(500, 12), flagsn6
);
880 o
.init_member("loadSound", vm
.getNative(500, 13), flagsn6
);
881 o
.init_member("getBytesLoaded", vm
.getNative(500, 14), flagsn6
);
882 o
.init_member("getBytesTotal", vm
.getNative(500, 15), flagsn6
);
884 int flagsn9
= PropFlags::dontEnum
|
885 PropFlags::dontDelete
|
886 PropFlags::readOnly
|
887 PropFlags::onlySWF9Up
;
889 o
.init_member("areSoundsInaccessible", vm
.getNative(500, 16), flagsn9
);
891 int fl_hp
= PropFlags::dontEnum
| PropFlags::dontDelete
;
893 o
.init_property("checkPolicyFile", &checkPolicyFile_getset
,
894 &checkPolicyFile_getset
, fl_hp
);
899 sound_new(const fn_call
& fn
)
901 as_object
* so
= fn
.this_ptr
;
902 Sound_as
* s(new Sound_as(so
));
906 IF_VERBOSE_ASCODING_ERRORS(
908 std::stringstream ss
; fn
.dump_args(ss
);
909 log_aserror("new Sound(%d) : args after first one ignored",
915 const as_value
& arg0
= fn
.arg(0);
917 if (!arg0
.is_null() && !arg0
.is_undefined()) {
919 as_object
* obj
= toObject(arg0
, getVM(fn
));
920 DisplayObject
* ch
= get
<DisplayObject
>(obj
);
921 IF_VERBOSE_ASCODING_ERRORS(
923 std::stringstream ss
; fn
.dump_args(ss
);
924 log_aserror("new Sound(%s) : first argument isn't null "
925 "or undefined, and isn't a DisplayObject. "
926 "We'll take as an invalid DisplayObject ref.",
931 s
->attachCharacter(ch
);
939 sound_start(const fn_call
& fn
)
942 log_action(_("-- start sound"));
944 Sound_as
* so
= ensure
<ThisIsNative
<Sound_as
> >(fn
);
946 double secondOffset
= 0;
949 secondOffset
= toNumber(fn
.arg(0), getVM(fn
));
952 loop
= (int) toNumber(fn
.arg(1), getVM(fn
)) - 1;
954 // -1 means infinite playing of sound
956 loop
= loop
< 0 ? -1 : loop
;
959 so
->start(secondOffset
, loop
);
964 sound_stop(const fn_call
& fn
)
967 log_action(_("-- stop sound "));
969 Sound_as
* so
= ensure
<ThisIsNative
<Sound_as
> >(fn
);
974 const std::string
& name
= fn
.arg(0).to_string();
977 const movie_definition
* def
= fn
.callerDef
;
980 const boost::uint16_t id
= def
->exportID(name
);
982 IF_VERBOSE_MALFORMED_SWF(
983 log_swferror(_("No such export '%s'"),
989 sound_sample
* ss
= def
->get_sound_sample(id
);
991 IF_VERBOSE_MALFORMED_SWF(
992 log_swferror(_("Export '%s'is not a sound"), name
);
997 si
= ss
->m_sound_handler_id
;
1005 sound_attachsound(const fn_call
& fn
)
1008 log_action(_("-- attach sound"));
1012 IF_VERBOSE_ASCODING_ERRORS(
1013 log_aserror(_("attach sound needs one argument"));
1018 Sound_as
* so
= ensure
<ThisIsNative
<Sound_as
> >(fn
);
1020 const std::string
& name
= fn
.arg(0).to_string();
1022 IF_VERBOSE_ASCODING_ERRORS(
1023 log_aserror(_("attachSound needs a non-empty string"));
1028 // check the import.
1029 // NOTE: we should be checking in the SWF containing the calling code
1030 // (see 'winter bell' from orisinal morning sunshine for a testcase)
1031 const movie_definition
* def
= fn
.callerDef
;
1035 const boost::uint16_t id
= def
->exportID(name
);
1037 IF_VERBOSE_MALFORMED_SWF(
1038 log_swferror(_("No such export '%s'"),
1044 sound_sample
* ss
= def
->get_sound_sample(id
);
1046 IF_VERBOSE_MALFORMED_SWF(
1047 log_swferror(_("Export '%s'is not a sound"), name
);
1052 const int si
= ss
->m_sound_handler_id
;
1056 so
->attachSound(si
, name
);
1062 sound_getbytesloaded(const fn_call
& fn
)
1064 Sound_as
* so
= ensure
<ThisIsNative
<Sound_as
> >(fn
);
1065 long loaded
= so
->getBytesLoaded();
1066 if (loaded
< 0) return as_value();
1067 return as_value(loaded
);
1071 sound_getbytestotal(const fn_call
& fn
)
1073 Sound_as
* so
= ensure
<ThisIsNative
<Sound_as
> >(fn
);
1074 long total
= so
->getBytesTotal();
1075 if (total
< 0) return as_value();
1076 return as_value(total
);
1080 sound_getpan(const fn_call
& /*fn*/)
1082 LOG_ONCE( log_unimpl ("Sound.getPan()") );
1087 sound_getDuration(const fn_call
& fn
)
1089 Sound_as
* so
= ensure
<ThisIsNative
<Sound_as
> >(fn
);
1090 if (!so
->active()) return as_value();
1091 return as_value(so
->getDuration());
1095 sound_setDuration(const fn_call
& /*fn*/)
1097 LOG_ONCE( log_unimpl ("Sound.setDuration()") );
1102 sound_getPosition(const fn_call
& fn
)
1104 Sound_as
* so
= ensure
<ThisIsNative
<Sound_as
> >(fn
);
1105 if (!so
->active()) return as_value();
1106 return as_value(so
->getPosition());
1110 sound_setPosition(const fn_call
& /*fn*/)
1112 LOG_ONCE( log_unimpl ("Sound.setPosition()") );
1117 sound_gettransform(const fn_call
& /*fn*/)
1119 LOG_ONCE( log_unimpl ("Sound.getTransform()") );
1124 sound_getvolume(const fn_call
& fn
)
1127 Sound_as
* so
= ensure
<ThisIsNative
<Sound_as
> >(fn
);
1130 IF_VERBOSE_ASCODING_ERRORS(
1131 std::stringstream ss
; fn
.dump_args(ss
);
1132 log_aserror("Sound.getVolume(%s) : arguments ignored");
1137 if (so
->getVolume(volume
)) return as_value(volume
);
1142 sound_loadsound(const fn_call
& fn
)
1144 Sound_as
* so
= ensure
<ThisIsNative
<Sound_as
> >(fn
);
1147 IF_VERBOSE_ASCODING_ERRORS(
1148 log_aserror(_("Sound.loadSound() needs at least 1 argument"));
1153 std::string url
= fn
.arg(0).to_string();
1155 bool streaming
= false;
1156 if ( fn
.nargs
> 1 ) {
1157 streaming
= toBool(fn
.arg(1), getVM(fn
));
1159 IF_VERBOSE_ASCODING_ERRORS(
1162 std::stringstream ss
; fn
.dump_args(ss
);
1163 log_aserror(_("Sound.loadSound(%s): arguments after first 2 "
1164 "discarded"), ss
.str());
1169 so
->loadSound(url
, streaming
);
1175 sound_setpan(const fn_call
& /*fn*/)
1177 LOG_ONCE( log_unimpl ("Sound.setPan()") );
1182 sound_settransform(const fn_call
& /*fn*/)
1184 LOG_ONCE( log_unimpl ("Sound.setTransform()") );
1189 sound_setvolume(const fn_call
& fn
)
1192 IF_VERBOSE_ASCODING_ERRORS(
1193 log_aserror(_("set volume of sound needs one argument"));
1198 Sound_as
* so
= ensure
<ThisIsNative
<Sound_as
> >(fn
);
1199 int volume
= (int) toNumber(fn
.arg(0), getVM(fn
));
1201 so
->setVolume(volume
);
1206 checkPolicyFile_getset(const fn_call
& /*fn*/)
1208 LOG_ONCE( log_unimpl ("Sound.checkPolicyFile") );
1213 sound_areSoundsInaccessible(const fn_call
& /*fn*/)
1215 // TODO: I guess this would have to do with permissions (crossdomain stuff)
1216 // more then capability.
1217 // See http://www.actionscript.org/forums/showthread.php3?t=160028
1219 // naive test shows this always being undefined..
1221 LOG_ONCE( log_unimpl ("Sound.areSoundsInaccessible()") );
1225 } // anonymous namespace
1226 } // gnash namespace
1230 // indent-tabs-mode: nil