With Javascript, I have a function that creates an audio element with createElement("audio"), and start playing in loop without using appendChild(), I mean without appending it to the DOM.
The element created is kept in a variable, let's called it music1:
music = document.createElement("audio");
music.addEventListener("loadeddata", function() {
music.play();
});
music.setAttribute("src", music_Source);
What I would like to do, is to change the music played, if possible using the same function, and storing the element in the same variable.
What I do is that before the code above:
if(typeof(music) == "object") {
music.pause();
music = null;
}
But: if I remove music.pause(), the first music keeps playing, and the second starts playing too at the same time, which makes me think that the first music is always somewhere in the document/in the memory. Also, music = null seems useless. I don't want to use jQuery.
Do you have any idea to properly remove the first music, delete the element, or so on?
Actually, kennis' comment is right, I tried to just change the src attribute, and not modify the "music" variable (neither setting it to null, nor re-creating an Element) and it seem to work too. So, for the record: For each source changing here is the function:
if(typeof(music) != "object") {
//audio element does not exist yet:
music = document.createElement("audio");
music.addEventListener("loadeddata", function() {
music.play();
});
}
music.setAttribute("src", music_Source);
rather than delete, the better way of doing it would be to change the src
music.setAttribute('src',theNewSource); //change the source
music.load(); //load the new source
music.play(); //play
that way you're always dealing with the same object so you hit the DOM less often, and also you avoid your problem of having two player at the same time
Also make sure you use the .load method to load the new audio, otherwise it will keep playing the old one.
The original object would be deleted, but only when the garbage collector determines that it's time. The fact that it's audio may complicate things and make it difficult for the browser to make that determination.
So, yes, just re-use the original object instead.
While reusing the HTMLAudioElements is definitely the best option -for completeness- you should be able to dispose it by just clearing the src or srcObj:
music.srcObj = null;
This more or less lets the GC of your browser know that the element is ready for removal.
Related
How to properly pause or stop audio track with javascript?, I tried this:
var track1 = new Audio('track1.mp3');
$('#play').click(function() {
track1.play();
});
$('#stop').click(function() {
track1.stop();
});
It plays but can't make it stop, I'm basically trying to make an small player with the basic options, super simple without using any framework.
Audio elements don't have a "stop" method. I think you may be looking for track1.pause() instead.
Reference to HTMLMediaElement methods and properties: https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement
I'm developing a web application in which I've got a video element. This, as I've had good experiences with it, is controlled via the VideoJS scripts.
However, on my app, there are some points in which the video needs to be paused until played by the user (or by a script, it's not relevant), but not after.
What I have
Basically - and the basic information you need - what I have is an array of items, let's say item_array, with objects in it. Each object has an id, a media object with some information of it, including a src, and an indications array - which would be the pause-times objects. Something like that:
var items_array = [
{
id: 1234,
media: {
id: 2345,
src: 'video_source.mp4',
duration: 302.56
},
indications: [
{
id: 1,
time: 65.380
},
{
id: 2,
time: 89.238
},
{
id: 3,
time: 123.765
}
]
}
]
Of course, I've got the video variable, which stores the VideoJS reference and is accessible all along the code as a global variable (maybe it's useful for you to know that).
What I need
Basically, I need to be able to load a video source and tell the script that the video must pause at 1:05.380, 1:29.238 and 2:03.765, for example.
Once paused, the user can play the video again, and it will not be paused (at least, by the script) again until the next time mark is reached.
Then, the user can specify a new video to load, with its new pause-points, so old pause-points should be removed and new ones set.
Also, it would be necessary to perform other actions apart from pausing the video (such as showing a message, etc.). But it's not necessary for you to know any of these - just I have to be able to write some actions to do on every pause-point.
What I've tried
Well, I've been playing with timeupdate. The first problem is that this only fires every now and then, so video.currentTime() == NN.NNN will not always work.
The script video.currentTime() >= NN.NNN is not possible neither, because the user must be able to play further the pause-time (yes, the event can be set off once reached, but if the user skips it on the time line, the video must not be paused).
So, if the pause-time is at 1:05 and the user skips from 0:45 to 1:25, the pause-time set to 1:05 must not be triggered, thus the video must not be paused - so the line written before does not work as I'd like to.
Thank you everyone in advance for your time and help! If you need any further information, please ask me and I will submit it as soon as I can!
Best regards.
Finally, I've come up with a possible solution. Sure it's not the best in performance, but it does what it's meant to.
I write it here and maybe someone will find it useful.
The solution
What I do is to fire a custom event everytime the timeupdate event is triggered, so I can delete all actions attached to this custom event without breaking VideoJS default event actions.
Then, I set a time_range, so I can make the comparison between video.currentTime() with the desired indication.time without being exact, but with some space to happen.
Finally, when it happens, I pause the video (and show the indication, those actions I told you I needed to do) and set a new property of the indication, has_shown to true.
At every custom_timeupdate I check if the video.currentTime() is inside that space of time I told you and if that indication.has_shown is set to false. If so, the process triggers. If not, nothing happens (so if an indication has already been shown it does not pause the video again).
But, as I wanted it to show it again if the user returned to that point, I set a last check so if video.currentTime() is - a little bit - far from that point, the property has_shown is set to false again.
This is done, of course, for every indication we have.
Here you have the code:
var time_range = 0.125
video.on("timeupdate", function(){
video.trigger("indications_timeupdate")
})
function load_indications(indications){
/*
Function actions ...
*/
// If the video is defined, as we are loading them new, we set off old Indication timers
if(video !== undefined) video.off("indications_timeupdate")
$.each(indications, function(i, ind){
video.on("indications_timeupdate", function(){
if(video.currentTime() >= ind.time - time_range && video.currentTime() <= ind.time + time_range && !ind.has_shown){
video.pause()
ind.has_shown = true
}else if(video.currentTime() >= ind.time + time_range || video.currentTime() <= ind.time - time_range){
ind.has_shown = false
}
})
})
}
As I said, maybe it's not the best solution, but it's the best one that I've been able to think of.
Thank you for your time to everyone who has tried to think of an approach for this question!
Best regards.
I am trying to get an event fired once the youtube video reached its end.
The video embedding works, but nothing happens once the video ends.
I think I am missing something for the EventListener...
this is my code:
var params = { allowScriptAccess: "always" };
var atts = { id: "myytplayer" };
var video = swfobject.embedSWF("http://www.youtube.com/v/elvOZm0d4H0?enablejsapi=1&playerapiid=ytplayer&version=3&rel=0&autoplay=1&controls=1","ytapiplayer", "450", "250", "8", null, null, params, atts);
XXXXX.addEventListener("onStateChange", function(state){
if(state === 0){
alert("Stack Overflow rocks!");
}
});
What I do not get is, what I should listen to?
Marked with "XXXXX" in the code, what do i need to put there? I tried myytplayer, video, ytplayer, ytapiplayer... most of them give me an error, e.g. "ytplayer can not be found".
"ytapiplayer" did not throw an error, but also nothing happens once the video is finished playing.
I searched stack Overflow, but all the "answers" I found so far are just naming this event listener, but do not explain what I have to put at "XXXXX".
I am pretty new to this and any help is very welcome, thanks!
JSFIDDLE: http://jsfiddle.net/T5HBZ/
edit: edited code for controls, added jsfiddle
Here's your working code, and then I'll explain it:
var params = {
allowScriptAccess: "always"
};
var atts = {
id: "myytplayer"
};
var video = swfobject.embedSWF("http://www.youtube.com/v/elvOZm0d4H0?enablejsapi=1&playerapiid=ytplayer&version=3&rel=0&autoplay=1&controls=1", "ytapiplayer", "450", "250", "8", null, null, params, atts);
onYouTubePlayerReady = function (playerId) {
ytplayer = document.getElementById("myytplayer");
ytplayer.addEventListener("onStateChange", "onPlayerStateChange");
};
onPlayerStateChange = function (state) {
if (state === 0) {
alert("Stack Overflow rocks!");
}
};
The first thing is to note that, when you embed the player SWF with swfobject, you are telling that library to REPLACE the div you reference with the one generated by swfobject. So the ytapiplayer div will no longer exist, but there will be an element with the id of 'myytplayer.' Note that, when you append the 'enablejsapi=1' to your swf URL, then the swf will load the video AND load the javascript allowing you to control the video.
This is key; when that javascript is done loading, it will automatically call a function named "onYouTubePlayerReady" -- there isn't a way to change that name, as it's part of the javascript loaded from youtube. If you don't define that function, nothing happens. If you do define that function, though, you have the opportunity to start interacting with the player.
So what your code was missing was a definition of that function, within which you add an event listener directly onto the element that was created by swfobject (it HAS to take place inside this function; if you try to do it outside of the callback, the object might not exist yet).
Also note that, for some reason, it seems to be more consistently workable to have the event listener reference an actual function as its callback (rather than an anonymous one), so you'll see that in the code as well.
Of course, all this discussion can be superseded by pointing out that you might be much better served by using the iFrame player API instead of the SWF/Javascript API. The info is here:
https://developers.google.com/youtube/iframe_api_reference
It's a similar methodology, in that you load a javascript library, which automatically will call a callback that you define, inside of which you set up your bindings to the player, add event listeners, etc. The real advantage is that it will determine whether to serve the HTML5 or the Flash player automatically, with the API on your side being able to talk to either player.
Code I am creating is a function which with the function it should .play() it... here is the code
function playSound() {
document.getElementById('newMessage').play();
}
var sound = document.createElement('audio');
sound.setAttribute("src","http://www.soundjay.com/button/beep-2.wav");
sound.id="newMessage";
sound.setAttribute('autoplay','false');
document.body.appendChild(sound);
Though everytime in console trying to do playSound(); it says playSound is undefined. So then I try doing document.getElementById('newMessage').play(); and it doesn't play either, nor does $('#newMessage').play(); which comes with an error of object [object Object] has no method play.
Any suggestions as this is the first time trying to dynamically create the audio file and use a function to play it. I've looked at a few other SO topics and well they don't seem to be leading me in the right direction. Thanks
My guess is you're defining the playSound method after the page has already loaded, maybe in some onload method. If this is the case, try attaching the method to the window object:
window.playSound = function() {
document.getElementById('newMessage').play();
}
This is make the function available even if the function is defined after the page loads. Also you shouldn't set autoplay to false. It defaults to false, and if you want to set it to true you set autoplay="autoplay".
JSFiddle
I'm creating my own HTML5 audio player capable of handling playlists. I have created a custom myPlaylist object with includes all play(), pause(), stop() and other needed functionality. This is all working correctly, but moreover, I need to be aware about when an audio file has ended in order to automatically start playing the next one.
Here's the relevant parts of the code I'm using:
function myPlaylist(){
var player = document.createElement('audio');
var audio = $(player).get(0);
this.next = function next(){
// Picks next song in the playlist and plays it
...
};
$(audio).bind('ended', function() {
alert("Song is finished!");
// Here I want to call to my next() function
});
}
I haven't been able to figure out how to do it. I've tried already several combinations, like $(this).next(), which seems the most reasonable and actually displays the alert, but then does nothing ¿?, also this.next(), which also displays the alert but then shows an error since this refers to the HTML5 audio element, which does not have a next() function.
I've also tried another approach, using
audio.onended = function(){
alert("Song is finished!");
$(this).next();
};
But those do not even trigger the alert. Also audio.ended does not work.
So, I'm basically clueless right now, does anyone have any idea what am I doing wrong? Thanks in advance.
Oh, and I've tested all this in the latest versions of Google Chrome and Safari in Mac OS X.
EDIT Following the advice given in HTML5 audio playlist - how to play a second audio file after the first has ended?, I've also tried the following code
player.addEventListener("ended", function() {
alert("Song is finished!");
$(this).next();
});
And
player.addEventListener("ended", next);
None of them work either, although the first one shows the alert properly.
EDIT 2 Using the search I came across this question, which might also have something to do with my problem, so in order to get rid of any possible troubles with the reference to this, I added a new variable referring to the object itself, so now I'm basically working with:
function myPlaylist(){
var player = document.createElement('audio');
var audio = $(player).get(0);
var me = $(this);
this.next = function next(){
// Picks next song in the playlist and plays it
...
};
$(audio).bind('ended', function() {
alert("Song is finished!");
me.next();
});
}
But then I get an error saying that the Object does not have a method next().
I don't know what else can I try... Any extra information will be highly appreciated, thank you!
there's an HTML5 playlist example handling the ended event here, if that helps?
in your event handler you reference this, but in this context this refers to the DOM element that caught the event, i.e. your audio element.. try this instead:
function myPlaylist(){
var self = this;
var player = document.createElement('audio');
this.next = function (){
// Picks next song in the playlist and plays it
...
};
player.addEventListener("ended", function() {
alert("Song is finished!");
self.next();
});
}
see the MDN for more info on the this keyword