How to make audio playback on work on mobile? - javascript

On desktop browsers im able to playback audio however, on mobile it doesnt playback any audio.
Im not getting any errors in the console either.
How can i make audio playback work on mobile?
function initAudio(){
var audio, dir, ext, mynoteslist;
dir = "audio/";
ext = ".mp3";
// Audio Object
audio = new Audio();
audio.src = dir+ext;
var arr = document.getElementsByClassName("mynoteslist");
for (var k=0; k<arr.length; k++){
arr[k].addEventListener("change", changeNote);
}
// Functions
function changeNote(event){
audio.src = dir+event.target.value+ext;
audio.play();
}
}
window.addEventListener("load", initAudio);

Many mobile devices will not play audio (or video if it has a soundtrack and is not muted) unless as a direct result of a user gesture.
For example for an Apple mobile device
the call to video.play(), for example, must have directly resulted from a handler for a touchend, click, doubleclick, or keydown event
You will probably therefore have to get the user to click or touch or sense a key down and use that event to play the audio. It seems that a change event will not be enough.

Related

Capturing audio from <video> in web audio API, can't mute original audio

I'm working on a project where I'm using <video> elements as sources for canvas animations, and I'm aiming to send their audio through the Web Audio API using Tone.js. The canvas animations are fine, it's the audio that's giving me trouble. I'd like to keep the audio synced to the video if possible, so I'm using MediaStream.
When a video loads, it's initially muted on the element itself. I do muted="false" once audio is enabled with a button press that runs Tone.start(). I grab the video's audio via captureStream(), and hook it up to a gain node with the gain set to 0, essentially muting it again. In Firefox, everything works fine, and I can set the gain to whatever desired value. But in Chrome, I can't get rid of the original video audio – it's still going in the background. My "unmute" works, but it clearly plays a second copy of the audio, causing comb filtering.
I'm intending on doing more than just muting and unmuting, so while it's tempting to just use video.volume instead of putting in all this work, this is just a proof of concept that isn't proving much at all right now. Any help is appreciated!
let video = document.querySelector(video);
// lower the video element's audio until we're ready
// might not be necessary, but it's just a cautionary step
video.volume = 0;
// unhook the audio from the video; works in FF, but not Chrome
let stream = video.mozCaptureStream ? video.mozCaptureStream() : video.captureStream();
let audioTrack = new MediaStream(stream.getAudioTracks());
let speaker = Tone.context.createMediaStreamSource(audioTrack);
// gain node is the *actual* volume control that I'm intending to use; it starts at 0 to mute the unhooked audio
let gain = new Tone.Gain(0);
Tone.connect(speaker, gain);
Tone.connect(gain, Tone.context.destination);
// if video.volume stays at 0, we hear nothing
video.volume = 1;
Edit: It may be worth mentioning that I did start with this Vonage API support page to better understand how to go about using captureStream() like this, but the cloning and disabling process described in that article didn't work for me in FF or Chrome.
Chrome's behavior is actually the "more correct" one here (surprisingly given the many bugs they have in that area).
You are creating a clone MediaStream from the MediaElement's source. This MediaStream should not be affected by the volume set on the <video> element (specs), both Firefox and Chrome do fail here.
The captured MediaStream should thus have its own graph and when you connect it to the AudioContext, the original stream from the MediaElement should continue its life and completely ignore the captured MediaStream. This however is correctly handled by Chrome, but Firefox has it wrong (which is in part why they still do prefix the MediaElement#mozCaptureStream() method name).
But since what you want is actually Firefox's behavior, you can reproduce it by using a MediaElementAudioSourceNode, which will take the ownership of the MediaElement's audio stream, and disconnect it entirely from the MediaElement's graph. You'll thus have complete control over the output volume.
const btn = document.querySelector("button");
const vid = document.querySelector("video");
const inp = document.querySelector("input");
btn.onclick = evt => {
btn.remove();
vid.play();
const context = new AudioContext();
const gain = context.createGain();
const source = context.createMediaElementSource(vid);
source.connect(gain);
gain.connect(context.destination);
inp.oninput = evt => {
gain.gain.value = inp.value;
};
gain.gain.value = 0;
const meter = new OscilloMeter(document.querySelector("canvas"));
meter.listen(source, context);
};
button~*,button~.cont { display: none }
.cont { display: flex }
<script>class OscilloMeter{constructor(a){this.ctx=a.getContext("2d")}listen(a,b){function c(){g.getByteTimeDomainData(j),d.clearRect(0,0,e,f),d.beginPath();let a=0;for(let c=0;c<h;c++){const e=j[c]/128;var b=e*f/2;d.lineTo(a,b),a+=k}d.lineTo(d.canvas.width,d.canvas.height/2),d.stroke(),requestAnimationFrame(c)}const d=this.ctx,e=d.canvas.width,f=d.canvas.height,g=b.createAnalyser(),h=g.fftSize=256,j=new Uint8Array(h),k=e/h;d.lineWidth=2,a.connect(g),c()}}</script>
<button>Start</button>
<label>Output volume: <input type=range min=0 max=1 step=0.01 value=0></label>
<div class="cont">
<section>
<p>You can still control the input's volume through the video's UI:</p>
<video src=https://upload.wikimedia.org/wikipedia/commons/2/22/Volcano_Lava_Sample.webm id=vid controls crossorigin=anonymous height=200></video>
</section>
<section>
<p>
Processed audio (using input volume):<br>
<canvas></canvas>
</p>
</section>
</div>

Vimeo API. Trouble with SetVolume method

I'm using Vimeo api in my project, but I have a problem with volume setting.
If I do so:
// Create the player
var player = new Vimeo.Player('video2', options);
//Ready event
player.ready().then(function() {
player.play();
});
Everything works, but without sound.
However, if I do so:
// Create the player
var player = new Vimeo.Player('video2', options);
//Ready event
player.ready().then(function() {
player.play();
player.setVolume(0.5);
});
The video does not play, and the screen hangs his screensaver.
What could be the problem?
Essentially by calling play when the video is ready, you are attempting to autoplay. However, this volume problem occurs because browsers no longer allow autoplay with sound (especially Chrome). You can read more about this on our Help article as well.
Therefore, it is impossible to programmatically play a video with volume without a user clicking/interacting with the video first. Only afterwards will a call to setVolume work.

safari browser doesn’t support HTML5 audio tag in ipad/iphone,Android

I am working on a project based on jquery animation its animation works fine on desktop (Firefox,chrome,opera,IE) also support HTML 5 audio tag but in Ipad/iphone/ Android safari audio tag doesn’t support.Its works fine on Ipad/iphone/ Android firefox.i have searched it in many forum don’t get desire Result. I have used this function :
function playmusic(file1,file2)
{
document.getElementById('music11').innerHTML='<audio id="music1"><source src="'+file1+'" type="audio/ogg"><source src="'+file2+'" type="audio/mpeg"></audio>';
$("#music1").get(0).play();
}
I have called function like : playmusic(2.ogg','2.mp3');
If I give autoplay in audio tag it works but play method not working and I have to use play method as in my application needs sound in particular event see the link
http://solutions.hariomtech.com/jarmies/
I have also changed my function and give direct audio tag in div and call function the same problem I face as I mentioned above. I need sound play in background without any click.if I use auto play method so it play sound only one time but I need sound multiple time on event.
Try to add an autoplay attribute on the audio tag:
function playmusic(file1, file2) {
document.getElementById('music11').innerHTML='<audio autoplay id="music1"><source src="'+file1+'" type="audio/ogg"><source src="'+file2+'" type="audio/mpeg"></audio>';
}
I would however recommend building a proper element and insert that into the DOM - something like this:
function playmusic(file1, file2) {
var audio = document.createElement('audio');
audio.preload = 'auto';
audio.autoplay = true;
if (audio.canPlayType('audio/ogg')) {
audio.src = file1;
}
else if (audio.canPlayType('audio/mpg')) {
audio.src = file2;
}
document.getElementById('music11').appendChild(audio);
}

Play audio from a direct link

I'm working on a mobile device running iOS.
I have a DIRECT download link to an audio file (when I open it on desktop the download starts immediately). I try this but it plays only one time.
<script>var audio = new Audio("'+downloadUrl+'");</script> <button onclick="audio.play();">Play</button>
I also try to catch it with an <iframe> but it plays only one time.
When I use <audio> ,"streaming" appears and I have the same problem :
I think it's because my file is not saved on my phone. So how can I fix it, so that it plays as required.
Thanks in advance,
Let's take a look at the HTMLMediaElement DOM interface and Media Events
var audio = new Audio(downloadUrl);
audio.addEventListener('ended', function () {
audio.currentTime = 0; // seek to position 0 when ended playing
/* // alternatively, not sure about compatibility
audio.fastSeek(0);
*/
});
If you wanted it to loop rather than be playable again, set loop to true instead.

Play (and replay) a sound on safari mobile

I need to play a sound when a new message appears on a website. It works fine on Chrome and Safari but I can't make it work on Safari mobile.
I saw that the sound has to be initialised with a user action so I tried that:
var sound = new Audio('./path/to/my/sound.mp3');
var hasPlayed = false;
$('body').bind('click touchstart', function() {
sound.load();
});
sound.addEventListener('play', function() {
hasPlayed = true;
});
var playSound = function() {
if(hasPlayed) {
sound.currentTime = 0;
}
sound.play();
}
Unfortunately, the sound still don't play. I also tried with the Buzz library, and the issue is the same.
So, the question is : how can I play a sound programmatically on mobile browsers ?
First of all: HTML5 audio support in Mobile Safari on iOS (5.01, 5.1) is rather limited. But I have managed to get some small 'event type' sounds working in my iPad 2 web apps. Since you are talking about only one sound file for your app, you don't have to fall back on audio sprites tricks (i.e. merging multiple MP3's into one MP3 file and changing the play position within the merged file depending on the sound you want to be played).
As you have noticed, you cannot play audio automatically in Mobile Safari, i.e. without the user clicking on some element. Technically speaking, the audio must be played (not loaded) in the same call stack as a click event. But you will probably experience a 0,5 second delay then, when Mobile Safari creates the audio object. Here is a solution to this 'problem':
At the start of your app (while loading/initializing), add a click handler to the HTML document that starts playing your audio file as soon as the user clicks/taps anywhere in the app. This will force Safari to start loading the audio.
Listen for the 'play' event that is triggered when the audio is ready to be played, and immediately pause.
Now start playing the audio (without delay) again when you need it.
Here is some quick JavaScript code:
function initAudio() {
var audio = new Audio('./path/to/my/sound.mp3');
audio.addEventListener('play', function () {
// When the audio is ready to play, immediately pause.
audio.pause();
audio.removeEventListener('play', arguments.callee, false);
}, false);
document.addEventListener('click', function () {
// Start playing audio when the user clicks anywhere on the page,
// to force Mobile Safari to load the audio.
document.removeEventListener('click', arguments.callee, false);
audio.play();
}, false);
}
For those that are coming across this problem and the solution by Jeroen is not working here is a solution that works and ensures the proper scoping is correctly enforced.
Make sure initAudio is called on page load. I.e. in your Init function or for jquery inside the document.ready ($(function(){});)
function initAudio(){
var audio = new Audio('./path/to/my/sound.mp3');
var self = this;
//not sure if you need this, but it's better to be safe
self.audio = audio;
var startAudio = function(){
self.audio.play();
document.removeEventListener("touchstart", self.startAudio, false);
}
self.startAudio = startAudio;
var pauseAudio = function(){
self.audio.pause();
self.audio.removeEventListener("play", self.pauseAudio, false);
}
self.pauseAudio = pauseAudio;
document.addEventListener("touchstart", self.startAudio, false);
self.audio.addEventListener("play", self.pauseAudio, false);
}

Categories