Is there anyway to control sound file added to timeline layer
like to pause and resume the sound with timeline
Or is there anyway to detect what sound is being played in the browser with creatjs
Thanks
Have a look at the exported lib code. There is a frame script that will have a playSound() call.
The frame script probably looks something like this:
this.frame_12 = function() {
playSound("sound_id");
}
You can store off the result of this call, and control it.
this.frame_12 = function() {
// Store the result as part of the current object.
this.mySound = playSound("sound_id");
}
To control it, you need to know where it resides. If it is on your main timeline, it will be part of your exportRoot:
exportRoot.mySound.stop();
I would need to know more about your setup to help more than that.
Related
I have a StackBlitz minimum code example which illustrates the problem. For brevity, I've also placed the problematic code below.
Whenever the user clicks on a track of a number of tracks, I want the Audio component to immediately play that track, think Spotify etc.
Currently, the source of the audio component is updating, but it does not play the track unless there is a triple click.
I'm not sure why a triple click is needed to create a successful play call.
const changeSource = newSource => {
setSource(newSource);
togglePlayPause();
};
Here is the setSource hook, which is initialised to a default track:
const [source, setSource] = useState(
'https://www.soundhelix.com/examples/mp3/SoundHelix-Song-4.mp3'
);
const togglePlayPause = () => {
const prevValue = isPlaying;
setIsPlaying(!prevValue);
if (!prevValue) {
audioPlayer.current.play();
} else {
audioPlayer.current.pause();
}
};
It'll do that, unless you preload your audio data. The <audio> element would need to go out, bring the data into the browser, process it, then begin to play. There is a way to try to preload the data. By setting <audio preload="auto"> it will "attempt" to preload tracks on page load. But, when dynamically setting source, you can't really get that data until you know what the source is. You can get around this, a little, by using the autoplay attribute, which will cause the browser to automatically begin fetching the source once it is set. (But then, it will also start playing it right away as well.)
I worked on a HTML5 game. I used createjs to preload images. When the images finish preloading, a BGM need to play automatically.
I known that chrome new audio policies. And I am very confused that I use function handleComplete to trigger the audio. Why does it still not work? How should I make it work?
Here is my code:
function Sound (id_str){ this.id = id_str; }
Sound.prototype.play = function () {
//there are other logics, but can simply like below
let audio = document.getElementById(this.id);
audio.play().catch(e =>console.log(e));
};
var audio_bg = new Sound('bgm_id');
windows.onload = function preload (handleFileProgress,handleComplete){
let manifest = [...];
loader = new createjs.LoadQueue(false);
loader.setMaxConnections(100);
loader.maintainScriptOrder=true;
loader.installPlugin(createjs.Sound);
loader.loadManifest(manifest);
loader.addEventListener('progress', handleFileProgress);
loader.addEventListener('complete', handleComplete);
};
function handleFileProgress(){...}
function handleComplete(){
//...
audio_bg.play();
}
The error I caught was:
NotAllowedError: play() failed because the user didn't interact with the document first.
The error you are seeing is due to changes in security in the browser, where you can't play audio without a user action to kick it off. SoundJS already listens for a browser input event (mouse/keyboard/touch) to unlock audio, but if you try to play audio before this happens, then it will fail.
To show this, quickly click in the browser before the file is loaded, and it will likely play.
The recommendation is to put audio behind a user event, like "click to get started" or something similar. It is an unfortunate side-effect of the security improvements in browsers :)
I'm using the Howler js library to set a player in an app running through Electron. First everything seemed to work well, but after a few weeks using the app, a bug occurs repeatedly, but not constantly : the pause() function doesn't work. Here's some piece of code :
Initialization :
var is_paused = true;
var currentTrack = "track1";
var tracks = {"track1" : new Howl({urls: ['path/to/track1.mp3']}),
"track2" : new Howl({urls: ['path/to/track2.mp3']}),
"track3" : new Howl({urls: ['path/to/track3.mp3']})
};
Then I have a few buttons for play/resume, pause, stop, and play a specific track :
$('#playS').click(function(){
if (is_paused){
tracks[currentTrack].play();
is_paused = false;
}
});
$('#pauseS').click(function(){
tracks[currentTrack].pause();
is_paused = true;
});
$('.trackBtn').click(function(){
tracks[currentTrack].stop();
currentTrack = $(this).attr('id');
tracks[currentTrack].play();
is_paused = false;
});
The problem is that sometimes (generally after 40-45 min of a track playing), the pause() function just do nothing, which is really annoying cause I need to pause the track and play another 30 sec file and then resume the current track. I checked the console while the bug occurs, it says absolutely nothing. I have no idea where the bug comes from, there's not a lot of information about how works the library. I really need some help here, thank's in advance.
EDIT : one more thing, when pause() doesn't work, if I click play() the track plays from the begining, and I have control on this second instance of the track. It's like the first instance has reached end, but still playing.
Without knowing what version of Howler you're using, or what other code might be messing things up, there is one thing I think might help: You don't need to track the paused state. The "playing" method takes care of that. I've made it work using something like this:
// If it's paused, it's not playing, so...
paused = !myHowlInstance.playing();
Another thing I noticed is that you have currentTrack = $(this).attr('id'); in your (I think it's a) stop button. Unfortunately I don't know JQuery well enough to know if there's anything wrong with that (I'm more of a Dojo fan myself). But it looks like currentTrack may be set to some value not in your list (which would break tracks[currentTrack]). You might want to go into the console and type tracks["track1"], currentTrack etc. to see their values. You can even do tracks[currentTrack].play(); and see what happens. I wasn't sure if you knew you could do that (it was a huge help to me when I found out about it).
And as far as the "un-pausing" starting from the beginning, I'm currently struggling with it myself; at this time there's no clear way to do this (no resume(), pause(false) etc.), and I've seen a few more questions on the subject on Google and SO, so you're not alone. I've experimented with the seek method, but with no luck. I'll post a comment if/when I reach a breakthrough on that. :)
EDIT: I figured out the play-from-beginning thing. It does involve "seek", and also the whole "instance ID" concept (which I never really understood the importance of from the documentation).
Here's an example from a project I'm working on (also a game); it doesn't involve JQuery (sorry), but it should give you the gist of how to fix the problem.
var myBgMusic = new Howl(...);
var myMusicID = myBgMusic.play(); // The docs say play() returns an ID, and I'll be passing that to "seek" later.
var paused = false;
var saveSeek;
function TogglePause() {
if (paused) {
myBgMusic.play(myMusicID);
myBgMusic.seek(saveSeek, myMusicID);
} else {
myBgMusic.pause();
saveSeek = myBgMusic.seek(myMusicID);
}
};
I am using navigateToURL for file downloading from server. Is there anyway possible to know when navigateToURL has finished, more like when browser download dialog has opened?
Sometimes it takes 5 seconds to complete, user might get confused and start clicking download button like psychopath, which can result in multiple download dialogs opened.
I want to add some "please wait" text or something before it finishes (I already have one, I just need to know when to stop).
Maybe it can be done using javascript and get info from ExternalInterface?
This is kind of crazy, but I can't think of any other way: you could put the request object into a dictionary which is set to weak reference the keys, and then check on intervals whether the key was removed.
However, I'm not sure what will happen first, either the SWF itself will be disposed or the dictionary will be cleaned. It's also possible that given the one-time-ness of the function the reference to the request object isn't deleted because it is assumed to be deleted together with the whole SWF.
One more thing that I know is that uncaught error events will catch events from navigateToURL - not really helpful, but at least may give you the indication if it didn't work.
One more simple thing I can think of - just disable the button for a short time, like 1-2 seconds. If it worked, no one will see the delay, and if it didn't, they won't be able to press it too often.
private var _requestStore:Dictionary = new Dictionary(true);
private var _timer:Timer = new Timer(10);
. . .
_timer.addEventListener(TimerEvent.TIMER, timerHandler);
. . .
public function openURL(url:String):void
{
var request:URLRequest = new URLRequest(url);
_requestStore[request] = true;
_timer.start();
navigateToURL(request);
}
private function timerHandler(event:TimerEvent):void
{
var found:Boolean;
for (var o:Object in _requestStore)
{
found = true;
break;
}
if (!found) // the request got disposed
}
Is there anyway possible to know when navigateToURL has finished, more
like when browser download dialog has opened?
No, there is not. Once you pass a request onto the browser; the Flash Player no longer has any control or access to it.
You mention using ExternalInterface as part of a possible solution, but how would your HTML/JavaScript page know that a download had been finished?
navigateToURL does not fire a complete event. Try using this event from Adobe's help documentation:
public function URLRequestExample() {
loader = new URLLoader();
configureListeners(loader);
var request:URLRequest = new URLRequest("XMLFile.xml");
try {
loader.load(request);
} catch (error:Error) {
trace("Unable to load requested document.");
}
}
private function configureListeners(dispatcher:IEventDispatcher):void {
dispatcher.addEventListener(Event.COMPLETE, completeHandler);
dispatcher.addEventListener(Event.OPEN, openHandler);
dispatcher.addEventListener(ProgressEvent.PROGRESS, progressHandler);
dispatcher.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
dispatcher.addEventListener(HTTPStatusEvent.HTTP_STATUS, httpStatusHandler);
dispatcher.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
}
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/net/URLRequest.html#includeExamplesSummary
I'm stuck with a little problem with MediaElement.js player.
To get the instance of the player, I do this (works with html5 compatible browser):
// Get player
this.playerId = $('div#shotlist-player video').attr('id');
this.player = window[this.playerId];
But it's not working as soon as it fallback in flash. In fact, it's not working because I'm not calling an instance of MediaElement itself. But I don't see how I can call it.
The player is created with
$('video').mediaelementplayer({....});
How can I get the mediaelement object?
------------EDIT----------------
Ok I finally found how to make it works:
// Get player
mePlayer = $('div#shotlist-player video.video-js')[0];
this.player = new MediaElementPlayer(mePlayer);
Now I can user mediaElement instance correctly.
This post is a lot of speculation, but may be correct. Docs are lacking (;
The answer by sidonaldson is perfectly acceptable if you wish to create a new MediaElement instance and get a handle on it. If there's one already present, it seems to try to reinitialize another instance on that element and freaks out.
I am pretty sure mediaelement.js augments the builtin HTML5 controls by providing a JavaScript API to manipulate Flash/Silverlight players via those elements. I may be wrong, but other advice I've seen on this issue in multiple places is to do something like:
$playButton.click(function() {
$('video, audio').each(function() {
$(this)[0].player.play();
});
});
To create a play button as an external DOM element which will fire off all players on the page. This indicates to me that the implementation is something like I've described.
Try:
var player = $('video').mediaelementplayer({
success: function (me) {
me.play();
}
});
// then you can use player.id to return the id
// or player.play();