Sometimes my HTML5 video does not generate an "ended" event on the iPad. Seems only to happen when I omit the "controls" attribute and start playback from javascript. It usually works fine the first time, but the second time the video plays out but does not generate an "ended" event. I do call "load()" after each playback in order to reset to the beginning of the clip (because seeking doesn't seem to work at all - see this thread). I have a workaround, which is to track "timeupdate" events and perform my end-of-play actions when vid.currentTime>=vid.duration, but I was wondering if anyone else had experienced this problem. Some relevant code follows.
Cheers
-Chris
The document onload function:
function load() {
var vid = document.getElementById('vid');
vid.addEventListener('ended', function() {
alert('video ended');
vid.load();
},false);
}
The html:
<body onload="load();">
<h1>HTML5 Video Test</h1>
<input type="submit" value="Play" onclick="document.getElementById('vid').play();">
<video id="vid" src="test.mov" width="640" height="480"></video>
</body>
Don't use load() to force the seek. If you set video.currentTime to 0.1 instead of 0 the video will jump to the beginning and the ended event will still dispatch properly. (Tested on iOS 3.2 and 4.2)
Related
I have a Dailymotion embedded player using the Player api ( http://www.dailymotion.com/doc/api/player.html ) . It works well on a Desktop and a Android Tablet. But on a iOS device, the video just doesn't start. My code is as follows:
<!-- This <div> tag will be replaced the <iframe> video player -->
<div id="player"></div>
<script>
// This code loads the Dailymotion Javascript SDK asynchronously.
(function() {
var e = document.createElement('script'); e.async = true;
e.src = document.location.protocol + '//api.dmcdn.net/all.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(e, s);
}());
// This function init the player once the SDK is loaded
window.dmAsyncInit = function()
{
// PARAMS is a javascript object containing parameters to pass to the player if any (eg: {autoplay: 1})
var player = DM.player("player", {video: 'somevideoid', width: "100%", height: "100%", params: {autoplay: 0}});
// 4. We can attach some events on the player (using standard DOM events)
player.addEventListener("apiready", function(e)
{
e.target.play();
});
};
</script>
Your code is perfectly valid. The thing is that most mobile devices, including iOS devices, prevent videos from being played automatically (see Apple documentation : Safari HTML5 Audio and Video Guide). On those devices, the first play must be triggered by a user interaction, such as touching the play button, otherwise it's ignored by the browser.
The apiready event is triggered by the Dailymotion SDK and is not a user event. That's why the play() method as no effect on the video.
[Edit]: You'd rather call the play() method from another event listener, such as a click or touchend event..
Also, as the Dailymotion Player is embedded within an <iframe>, the communication between the parent page and the <iframe> will always be considered as a programmatic event by the browser, no matter if the original event from the parent page comes from a user or not.
TLDR: On mobile device, you must wait for the user to touch the player's start screen.
I've been struggling with an elusive audio distortion bug using webkitAudioContext in HTML5 under iOS 6. It can happen in other circumstances, but the only way I can get 100% repro is on the first visit to my page after power cycling the device. It seems like if you visit any audio-capable page prior to visiting this one, the problem will not occur.
The distortion only happens to audio generated by webkitAudioContext.decodeAudioData() and then played through webkitAudioContext.createBufferSource(). Audio playback of webkitAudioContext.createMediaElementSource() will not distort.
Am I missing some initialisation step? Here's the code and HTML in its entirety that I submitted to Apple as a bug report (but have received no reply):
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript">
var buffer = null;
var context = null;
var voice = null;
function load_music(file) {
context = new webkitAudioContext();
voice = context.createBufferSource();
var request = new XMLHttpRequest();
request.onload = function() {
context.decodeAudioData(request.response, function(result) {
buffer = result;
document.getElementById("start").value = "Start";
});
};
var base = window.location.pathname;
base = base.substring(0, base.lastIndexOf("/") + 1);
request.open("GET", base + file, true);
request.responseType = "arraybuffer";
request.send(null);
}
function start_music() {
if (!buffer) {
alert("Not ready yet");
return;
}
voice.buffer = buffer;
voice.connect(context.destination);
voice.noteOn(0);
document.getElementById("compare").style.display = "block";
}
</script>
</head>
<body onload="load_music('music.mp3')">
<p>This is a simple demo page to reproduce a <strong>webkitAudio</strong>
problem occurring in Safari on iOS 6.1.4. This is a stripped down demo
of a phenomenon discovered in our HTML5 game under development,
using different assets.</p>
<p><u>Steps to reproduce:</u></p>
<ol>
<li>Power cycle <strong>iPhone 5 with iOS 6.1.4</strong>.</li>
<li>Launch Safari immediately, and visit this page.</li>
<li>Wait for "Loading..." below to change to
"Start".</li>
<li>Tap "Start".</li>
</ol>
<p><u>Issue:</u></p>
<p>Audio will be excessively distorted and play at wrong pitch. If
another audio-enabled web site is visited before this one, or this
site is reloaded, the audio will fix. The distortion only happens on
the first visit after cold boot. <strong>To reproduce the bug, it is
critical to power cycle before testing.</strong></p>
<p>This bug has not been observed on any other iOS version (e.g. does
not occur on iPad Mini or iPod 5 using iOS 6.1.3).</p>
<input id="start" type="button" value="Loading..." onmousedown="start_music()" />
<span id="compare" style="display:none;"><p>Direct link to audio file, for
comparison.</p></span>
</body>
</html>
Note: The body text suggests this only occurs on iOS 6.1.4, but I mean to say that the problem only occurs upon power cycling in this situation. I've experienced the problem on the iPad Mini under 6.1.3, too, but not upon power cycling.
Edit: a few things I've tried... Deferring the creation of the buffer source makes no difference. Using different transcoders to generate the .mp3 file it plays makes no difference. Playing throwaway silence as the first sound makes no difference as the distortion continues for every decodeAudioData sound until the page reloads. If createMediaElementSource and createBufferSource sources are mixed in the same page, only the createBufferSource audio (using decodeAudioData) will distort. When I check the request.response.byteLength in the failure case and the non-failure case, they are the same, suggesting the XMLHttpRequest is not returning incorrect data, though I would think corruption of the data would damage the MP3 header and render the file unplayable anyway.
There is one observable difference between the failure condition and the non-failure condition. The read-only value context.sampleRate will be 48000 in the failure state and 44100 in the non-failure state. (Yet the failure state sounds lower pitch than the non-failure state.) The only thing that occurs to me is a hack wherein I refresh the page via JavaScript if 48000 is detected on a browser that should be reporting 44100, but that's serious userAgent screening and not very future proof, which makes me nervous.
I have been having similar problems, even on iOS 9.2.
Even without a <video> tag, playback is distorted when first playing audio on the page after cold boot. After a reload, it works fine.
The initial AudioContext seems to default to 48 kHz, which is where distortion is happening (even with our audio at 48 kHz sample rate). When playback is working properly, the AudioContext has a sample rate of 44.1 kHz.
I did find a workaround: it is possible to re-create the AudioContext after playing an initial sound. The newly-created AudioContext seems to have the correct sample rate. To do this:
// inside the click/touch handler
var playInitSound = function playInitSound() {
var source = context.createBufferSource();
source.buffer = context.createBuffer(1, 1, 48000);
source.connect(context.destination);
if (source.start) {
source.start(0);
} else {
source.noteOn(0);
}
};
playInit();
if (context.sampleRate === 48000) {
context = new AudioContext();
playInit();
}
I found a related bug with HTML5 video and think I discovered the root of the problem.
I noticed that if you play a video using a <video> tag, it sets the context.sampleRate value to whatever the video's audio was encoded at. It seems as if iOS Safari has one global sampleRate that it uses for everything. To see this, try the following:
// Play a video with audio encoded at 44100 Hz
video.play();
// This will console log 44100
var ctx = new webkitAudioContext();
console.log(ctx.sampleRate);
// Play a video with audio encoded at 48000 Hz
video2.play();
// This will console log 48000
var ctx = new webkitAudioContext();
console.log(ctx.sampleRate);
This global sample rate appears to persist across page loads and is shared between tabs and browser instances. So, playing a youtube video in another tab could break all your decoded audio.
The audio becomes distorted when it is decoded at one sample rate and played at another one.
Decode audio and store the buffer
Do something to change the sample rate, such as playing a video or audio file
Play buffer (distorted)
I don't know why it's happening after a cold start. If I had to guess, it's that Safari doesn't initialize this global sample rate until you try to use it.
The problem is still there on iOS 7, so I don't think a fix is coming anytime soon. We're stuck with hacks in the mean time like checking for a changed sample rate.
An npm package is online to fix this:
https://github.com/Jam3/ios-safe-audio-context
npm install ios-safe-audio-context
I have a literal JS object that create and plays my playlist.
In the HTML page I have a list with all my tracks.
When I click on some track all works fine but when I click in one track and wait the end of track, the next track not play.
this is the part of my code:
playSound : function(track){
console.log("Play this song");
DG_PLAYER.TrackPlaying = track;
soundManager.destroySound('MySoundID');
DG_PLAYER.Sound = soundManager.createSound({
id:'MySoundID',
url:track.sound,
autoLoad: true,
autoPlay: true,
onload: function() { console.log('sound loaded!', this); },
onfinish: function(){
console.log('end song');
var nextSong = DG_PLAYER.getNextSong();
DG_PLAYER.playSound(nextSong);
},
onfailure : function(){console.log('some error')},
whileloading : function(){console.log('i m loading');},
whileplaying : function(){console.log('i m playing');}
});
},
If I change the line on onfinish event like this :
setTimeOut(function(){DG_PLAYER.playSound(nextSong);},2000) it works fine.
Some one can help me ?
One other things, when the first song finish and call Play for next Song the track is not loaded (no message back from onload event).
Thanks, and sorry for my bad English.
A.
OK ,
I try to add "flashVersion: 9" on setup and this fix the problem but on IE 8 I have un action script message now.
From SoundManager2's Revision History:
Flash Player 11.6.602.171, released by Adobe on 02/26/2013, introduced an issue with SM2's default Flash 8 (flashVersion: 8) API-based JS/Flash interaction, where SM2 methods called from callbacks such as onfinish() would not work. This primarily broke methods used for playing sounds in sequence, serially loading a series of sounds and so on. (See discussion for more.)
Note that this does not affect cases where soundManager.setup({ flashVersion: 9}) is being used; however, SM2 does use flashVersion: 8 by default.
Specifically, Flash-initiated events (such as a sound finishing) make Flash -> JS calls to the SM2 API, which subsequently call user-specified event handlers. If the user-specified SM2 onfinish() handler immediately calls a SM2 method like play() that makes a JS -> Flash call, this call either silently fails or is blocked. Other JS + Flash libraries that use similar callback patterns may also be affected, if their SWF is built targeting the Flash 8 API.
Suspecting a timing or recursion/stack issue, it was found that introducing a setTimeout(callback, 0) to user-specified SM2 callbacks like onfinish() restored sequential/playlist functionality.
Flash Player 11.6.602.180, relased by Adobe on 3/12/2013, exhibits the same behaviour. To avoid additional hacks, SM2 applies this to all Flash 8-based API callbacks regardless of what version of Flash Player is installed. No regressions are anticipated as a result of this change.
Alternately, this issue can be avoided by using soundManager.setup({ flashVersion: 9 }) as the Flash 9-based API does not appear to have this problem.
How can stop youtube video sound after closing webview opened by inappbrowser(Android Phonegap 2.4.0 plugin)
I used two week to fix that problem and tired out..............
When I click 'Done' button to close webview(youtube page), the video still play in the background.
Even after shutting down app, can't stop video sound.
To stop video I had to turn off phone.
This is my code
<script type="text/javascript" charset="utf-8">
function OpenWin(juso) {
window.open(juso, '_blank', 'location=yes');
}
</script>
<body>
...................
<a href="#" onclick="OpenWin('http://m.youtube.com')">
...................
</body>
Is there any wrong in my code?
May I get some help?
I am using Sencha Touch and using the following trick to stop the Youtube Video sound. You may take it as reference.
var ref = window.open(url,'_blank',options);
ref.addEventListener('exit',function(){
Ext.defer(function(){
ref.removeEventListener('exit',function(){
console.log('Closed');
});
var ref2 = window.open('about:blank','_blank','hidden=yes');
Ext.defer(function(){
ref2.close();
},350);
},350);
});
I'm trying to to write a javascript app that use the [SoundManager 2][1] api and aim to run in
all desktop and mobile browsers. On the iPad platform, Soundmanager is using the HTML5 audio api since there is on flash support. Now, when I'm trying to play two audio files back to back, both loaded in response to a click event, a [HTML5::stalled][2] event is occasionally raised. How do I set an event handler to catch the stalled event?
Since sound objects in my app are created on the fly and I don't know how to access directly to tags that are created by SoundManager, I tried to use a delegate to handle the stalled event:
document.delegate('audio', 'stalled', function (event) {...});
It doesn't work. the event did not raised in respond to stalled. (I had an alert in my handler).
Also tried to use [Sound::onsuspend()][3] to listen for stalled, but onsuspend pops out
on the end of sound::play(). How can we distinguish between stalled and other events that may raise the audio::suspend? Is there any other way to access the tags that SoundManager must create in order to play HTML audio?
I solved it with the following solution. This is not documented and found by reverse engineering.
It is all about accessing the html audio object, which is availalbe under _a.
currentSound = soundManager.createSound({..});
currentSound._a.addEventListener('stalled', function() {
if (!self.currentSound) return;
var audio = this;
audio.load();
audio.play();
});
The body of the method is based on this post about html5 stalled callback in safari
I can suggest a different "fix" I use with an html5 using platform (samsung smart TV):
var mySound = soundManager.createSound({..});
mySound.load();
setTimeout(function() {
if (mySound.readyState == 1) {
// this object is probably stalled
}
}, 1500);
This works since in html5, unlike flash, the 'readystate' property jumps from '0' to '3' almost instantanously, skipping '1'. ('cause if the track started buffering it's playable...).
Hope this works for you as well.