It seems to me that the Audio object can not be easily played inside a JavaScript callback when running on a mobile device. The code below shows an onload function which, on a PC, plays the sound when the web page is loaded, but on Android phones plays nothing.
My uninformed guess is that the callback returns before the Audio object starts to play, and thus, for some deep reason, dies.
Is there any way over this? In the full version the JavaScript would read the sound to play from the URL.
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>Play Me</title>
<style>
body {background-color:lightgrey}
h1 {color:blue}
p {color:green;font-size:50px}
</style>
</head>
<body onload="playMySound()">
<P>
PLAY ME
<button onclick="playMySound()">sound me</button>
</P>
<br>
<script>
var mySound ;
function playMySound () {
var soundUrl = "http://www.letiketa.com/myapp/sound.ashx?sound=sound1" ;
var mySound = new Audio(soundUrl);
// Actually play the sound
mySound.play() ;
}
</script>
The button plays the sound correctly, on all devices and I suppose that is a callback...? Is there something special about the onload callback?
Argh, it is all to do with the fact that on mobile devices, currently, HTML5 disallows sounds to be played unless the user has done some input, presumably saying "I allow you to play sounds." The latest Firefox browser, V34 anyway, seems to have lifted the restrictions and all works as it should.
There is a fix in Chrome too, you need to, in the address bar, goto "about:flags" and find the "gesture required" option, disabling it.
After all this the program which I wrote two days ago now works...
Related
I have a custom WebRTC application that uses two video streams and one audio stream.
Everything is working nicely on Chrome (93.0) and Firefox (92.0), but Safari (14.1) refuses to play one of the streams (the one for the first video element with ID "stream").
HTML looks as follows (mostly placeholders):
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<link rel="icon" href="data:;base64,iVBORw0KGgo="/>
<script src="stream.js"></script>
<style>
</style>
</head>
<body>
<div style="display:grid">
<video style="grid-column:1;grid-row:1;width:720px;z-index:5" id="stream" autoplay playsinline>Your browser does not support video</video>
<canvas style="grid-column:1;grid-row:1;justify-self:end;width:1280px;height:720px;z-index:10" id="canvas"></canvas>
<video style="grid-column:1;grid-row:1;justify-self:end;width:1280px;height:720px" id="stream2" autoplay playsinline>Your browser does not support video</video>
</div>
</body>
</html>
The relevant part of the Javascript code (html5VideoElement == ID "stream", html5VideoElement2 == ID "stream2"):
function onAddRemoteStream(event) {
if (event.transceiver.mid == remotemap["front"]) {
frontstream.addTrack(event.track);
html5VideoElement.srcObject = frontstream;
html5VideoElement.play();
}
if (event.transceiver.mid == remotemap["audio"]) {
frontstream.addTrack(event.track);
}
if (event.transceiver.mid == remotemap["surface"]) {
surfacestream.addTrack(event.track);
html5VideoElement2.srcObject = surfacestream;
html5VideoElement2.play();
}
}
onAddRemoteStream is the onTrack method for the RTCPeerConnection object. remotemap contains a mapping from track type to MID value, sent by the remote peer. frontstream and surfacestream are two (initially empty) MediaStream objects.
Weirdly enough, there are no exceptions or warnings with any browser, the first video element just stays empty and silent with Safari.
All outgoing streams (camera, audio, canvas) work on all three browsers.
Related issue: https://github.com/floe/surfacestreams/issues/6
Bountysource: https://app.bountysource.com/issues/105533187-html5-client-is-b0rken-on-safari
Any suggestions welcome!
UPDATE 01/23: So after almost one year, I can finally confirm that this was apparently a bug in Safari 14/15. It's now working, without any change in the relevant code bits, on Safari 16+.
This question already has answers here:
Audio plays in Chrome but not Safari
(1 answer)
Programmatically play video with sound on Safari and Mobile Chrome
(2 answers)
Closed 3 years ago.
The following code plays fine in Chrome & Firefox but not Safari.
It plays perfectly in Safari if I move
inst.play(document.getElementById("abc").value, function() {});
out of $.get as you see in comments.
Any ideas as to differences in Safari that might cause this?
<!DOCTYPE html>
<html>
<head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<script type="text/javascript" src="orig_musical.js"></script>
<script type="text/javascript" src="jquery.js"></script>
</head>
<body style="font-family:Arial;padding:36px;">
<h2>Play ABC<span></span></h2>
<a onclick="playABC('https://gospelriver.com/dummylink/Music/BHB_Music/green_fields.abc');"><u>Click to play with musical.js</u></a><br>
<a onclick="inst.silence();"><u>Click to stop musical.js</u></a><br><br>
<textarea name="abc1" id="abc" rows="10" cols="100">
X:1
T:Green Fields (De Fleury)
T:8.8.8.8 D
C:Johann Sebastian Bach, arr. by Lewis Edson
L:1/8
Q:100
M:6/8
K:G
[G3D3]| [GD]D[GD] [BD][GD][BG]| [d3G3] ||
[c3G3]| [BG][dG][BG] [AF][GE][AF]| G3 ||
[G3D3]| [GD]D[GD] [BD][GD][BG]| [d3G3] ||
[c3G3]| [BG][dG][BG] [AF][GE][AF]| G3 ||
[d3G3]| [dG][BG][dG] [dG][BG][dG]| [e3G3] ||
[c3E3]| [BD][cD][dD] [dG][cG][BG]| [A3F3] ||
[G3D3]| [GD]D[GD] [BD][GD][BG]| [d3G3] ||
[c3G3]| [BG][dG][BG] [AF][GE][AF]| G3 |]
</textarea>
<hr />
<p>abcjs by Paul Rosen</p>
<p>For more information, see <a href="https://github.com/paulrosen/abcjs" >the project page</a>.</p>
<p>This web page is a demonstration of the use of
musical.js with a plain script tag.
For a song that uses more ABC notation features, see minuet.</p>
<script>
// Select a timbre that sounds like a piano.
var instrumentType = "piano";
var inst = new Instrument({wave: instrumentType, detune: 0});
//play song
function playABC(urlConverted) {
//playback works in Safari if played here.
//inst.play(document.getElementById("abc").value, function() {});
$.get(urlConverted,function(data){
//playback fails in Safari if played here
inst.play(document.getElementById("abc").value, function() {});
console.log('arrived here');
},'text')
.fail(function() {
console.log('failed');
});
}
</script>
</body></html>
This is very simplified code to show the issue, not to show the use case, which requires $.get to read the external file which contains the info in the text area.
Test location is https://gospelriver.com/abcSafari/indexSafari.html
I have tried changing $.get to ajax as well as using $.noConflict(); Neither make any difference. I'm out of ideas!
Edit: Thanks to the helpful comments and links, the solution was as follows:
//insert note, immediately silenced, to keep connection to the original play event for Safari
inst.play("X:1\nL:1/8\nQ:100\nM:6/8\nK:G\n[a4]|", function() {});
inst.silence();
$.get(urlConverted,function(data){
//playback fails in Safari if played here
inst.play(document.getElementById("abc").value, function() {});
I'm trying to create a simple proof-of-concept regarding the use of localStorage to trigger tabs in my application when changes occur. I know this is possible based on other articles I've seen. I understand the spec states the event will fire on ever page except the one I'm on - this is in fact what I want. However, I can't seem to get this simple demo to actually work.
I've taken the code below, and opened up multiple tabs of it. Using my Chrome Dev Tools, I can check >localStorage in the console and see the value before and after the "Add" and "Clear" buttons are pressed - they are in fact functioning as desired in storing and clearing the key value pair into local storage, yet the event isn't firing the alert.
I even placed breakpoints in the javascript in my Chrome Dev Tools of each tab, yet I can never seem to get the "onStorageEvent" function to hit in any tab opened.
What am I doing wrong?
<!DOCTYPE html>
<html>
<head>
<title>Tab1</title>
</head>
<body>
<button id="add" onclick="localStorage.setItem('tab','changed')">Add</button>
<button id="clear" onclick="localStorage.clear()">Clear</button>
<script type="text/javascript">
function onStorageEvent() {
alert("storage event: " + localStorage.getItem("tab"));
}
window.addEventListener('storage', onStorageEvent, false);
</script>
</body>
</html>
In order for the window.addEventListener to work on storage:
you MUST access the page using web-server (http://a.b.c.d/ or http://domain)
Direct access (using file:/// or c:\file.html will not work.
(chrome and ie ignore it, firefox and safari can run it anyway).
I would consider also removing the 3rd, it is not relevant to elements in your DOM tree, and it might cause troubles (let the browser have it's defaults).
This code was tested in Chrome 52, Firefox 47+48, IE 11, Safari 5.7.1
<!DOCTYPE html>
<html>
<head>
<title>Tab1</title>
</head>
<body>
<button id="add" onclick="localStorage.setItem('tab','changed')">Add</button>
<button id="clear" onclick="localStorage.clear()">Clear</button>
<script type="text/javascript">
function onStorageEvent() {
alert("storage event: " + localStorage.getItem("tab"));
}
window.addEventListener('storage', onStorageEvent);
</script>
</body>
</html>
I am trying to make a simple application in HTML5 with JavaScript. It's supposed to play a random sound, when you push the button.
It works fine, when uploaded to a website, but it doesen't work on my smartphone.
<!doctype html>
<html>
<head>
<script type="text/javascript" src="jquery.min.js"></script>
<script>
function playSounds() {
var sounds = new Array(
"musik/shut the f**k up.mp3",
"musik/My gun's bigger than yours!.mp3"
);
var index = Math.floor(Math.random() * (sounds.length));
$("#element").html("<embed src=\"" + sounds[index] + "\" hidden=\"true\" autostart=\"false\" />");
}
</script>
<title></title>
<meta charset="utf-8">
</head>
<body= "javascript:playSounds()">
<button onClick="playSounds()">
LAUGH</button>
<div id="element">
</div>
</body>
</html>
I copied the content in file jquery.min.js from a site and linked it directly in the application to the mainpage, where the sound needs to play.
The source is here:
http://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js
I tried debugging the JavaScript code, but I can't seem to find the issue.
How do I solve this?
Mobile devices in general do not support <embed>.
Your use of <embed> shows you have an imperfect understanding of what an "HTML5 app" is. Such an app would use <audio> and check canPlayType("audio/mpeg") to see if the browser supports MP3 playback.
I have approximatively 500 images that differ very slightly one from another. They are all of the same size. They hence form a sort of video when watched one after the other very fast.
I am looking for a way to display them in a browser (html file from disk), all in the same spot, to form that video looking effect. I want to be able to play, pause, stop, play faster, play slower (and if possible even more controls, such as maybe go to specific time (ie, image 47, if there's a slider for example; if there's only play,pause,fast and slow it's okay though).
I am not a programmer but I think javascript might do that. If there's a better technology, please redirect me to it. I'm just looking for a solution that works the way I intend, but I have no javascript knowledge. This surely has been done before though, so I would gladly accept a working solution.
Although you seem to be going the conversion route, here is a solution that uses javascript, allows pausing, jump to frame, and changing speed (I didn't bother with a slider for this [or a nice UI for any of it]):
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Untitled Document</title>
</head>
<body onload="launch()">
</body>
<script>
var frames=['frame1.png','frame2.png','frame3.png','frame4.png','frame5.png','frame6.png','frame7.png','frame8.png','frame9.png','frame10.png'];
var playing=true;
var on_frame=0;
var timer;
function launch(){
document.body.innerHTML='<img id="film" src="frames/'+frames[on_frame]+'"/><br/><button id="actionbutton">Play</button><button onclick="stop()">Stop</button><br/>Milliseconds between frames:<input type="text" id="framerate" value="50"/><br/>Go to frame:<input type="text" id="gotoframe"><button onclick="goFrame(document.getElementById(\'gotoframe\').value);">Go</button>';
document.getElementById('actionbutton').addEventListener('click',play);
play();
}
function change(){
document.getElementById('film').src='frames/'+frames[on_frame]; //I have my images in a folder named frames
on_frame++;
if(on_frame==frames.length){on_frame=0;}
if(playing){
timer=setTimeout(change,document.getElementById('framerate').value?document.getElementById('framerate').value:50);
}
}
function play(){
document.getElementById('actionbutton').removeEventListener('click',play);
document.getElementById('actionbutton').addEventListener('click',pause);
document.getElementById('actionbutton').innerHTML='Pause';
clearInterval(timer);
playing=true;
change();
}
function pause(){
document.getElementById('actionbutton').removeEventListener('click',pause);
document.getElementById('actionbutton').addEventListener('click',play);
document.getElementById('actionbutton').innerHTML='Play';
playing=false;
}
function stop(){
document.getElementById('actionbutton').removeEventListener('click',pause);
document.getElementById('actionbutton').addEventListener('click',play);
document.getElementById('actionbutton').innerHTML='Play';
playing=false;
on_frame=0;
}
function goFrame(x){
if((x>-1)&&(x<=frames.length)){
on_frame=x;
if(!playing){document.getElementById('film').src='frames/'+frames[on_frame];}
}
else{
alert('Out of range');
}
}
</script>
</html>