Hello I am getting an exception when playing audio in Chrome.
Here is my function to play the audio
$(document).ready(function ()
{
generateAlarm();
});
function generateAlarm()
{
alarm_1 = new Audio();
alarm_1.src = '/Content/assets/sounds/alarm_1.mp3';
const playPromise = alarm_1.play();
if (playPromise !== null)
{
playPromise.catch(() => {
const btn = $('#playAlarm');
btn.click();
});
}
}
document.getElementById('playAlarm').addEventListener("click", handlePlayButton, false);
function handlePlayButton()
{
if (alarm_1.paused) {
generateAlarm();
}
else {
alarm_1.pause();
}
}
Can anyone tell me what is wrong with the above code?
Thank you in advance.
Autoplaying audio is no longer allowed because it's obnoxious and is frequently abused. You have to wait for the user to interact with the page first. You can check out this guide by google on how to use the new AudioContext api: https://developers.google.com/web/updates/2018/11/web-audio-autoplay
The only solution i could find so far was to change the chrome autoplay policies like this:
chrome://flags/#autoplay-policy
and set it to
No user gesture is required
i don't if it is the right way to solve the problem, but i am not getting anymore exception. I would appreciate if anyone has a better idea.
Related
I've been wondering how can I stop the audio stream even if the user checks the audio checkbox in the sharescreen Chrome pop-up. Is there any setting, any flag that I can tick as false that won't share the audio?
The sharescreen popup
I was jumping between chime-sdk, and chime-sdk-react-components documentations and wasn't able to find the thing I am looking for.
This is the function I'm currently using and I suppose that if there is any way of stopping the audio stream I would put it right here.
const createSession = async () => {
try {
const contentShareStream = await meetingSession.audioVideo!.startContentShareFromScreenCapture();
meetingSession.audioVideo!.addContentShareObserver(observer);
} catch (e) {
console.log(e);
}
};
I've been trying to think on some ideas on what I could make with JavaScript using Web Audio API. I know that depending on the user's browser I know that sometimes it won't let you play audio without a user gesture of some sort. I been doing some research on how to do it and they are pretty useful ways but the problem is that some developers found different ways to do it. For example:
Using a audioContext.resume() and audioContext.suspend() methods to unlock web audio by changing it's state:
function unlockAudioContext(context) {
if (context.state !== "suspended") return;
const b = document.body;
const events = ["touchstart", "touchend", "mousedown", "keydown"];
events.forEach(e => b.addEventListener(e, unlock, false));
function unlock() {context.resume().then(clean);}
function clean() {events.forEach(e => b.removeEventListener(e, unlock));}
}
creating an empty buffer and play it to unlock web audio.
var unlocked = false;
var context = new (window.AudioContext || window.webkitAudioContext)();
function init(e) {
if (unlocked) return;
// create empty buffer and play it
var buffer = context.createBuffer(1, 1, 22050);
var source = context.createBufferSource();
source.buffer = buffer;
source.connect(context.destination);
/*
Phonograph.js use this method to start it
source.start(context.currentTime);
paulbakaus.com suggest to use this method to start it
source.noteOn(0);
*/
source.start(context.currentTime) || source.noteOn(0);
setTimeout(function() {
if (!unlocked) {
if (source.playbackState === source.PLAYING_STATE || source.playbackState === source.FINISHED_STATE) {
unlocked = true;
window.removeEventListener("touchend", init, false);
}
}
}, 0);
}
window.addEventListener("touchend", init, false);
I know mostly how both of these methods work but
my question is what is going on here, what is the difference and which method is better etc?
And can someone please explain to me about this source.playbackState from an AudioBufferSourceNode Please? I never heard about that property on there before. It even doesn't have an article or get mentioned in the Mozilla MDN Website.
Also as a bonus question (which you don't have to answer), If both of these methods are useful then could it be possible to put them together as one if you know what I mean?
Sorry if that is a lot to ask. Thanks :)
resources:
https://paulbakaus.com/tutorials/html5/web-audio-on-ios/
https://github.com/Rich-Harris/phonograph/blob/master/src/init.ts
https://www.mattmontag.com/web/unlock-web-audio-in-safari-for-ios-and-macos
Both methods work, but I find the first (resume context in a user gesture) to be cleaner. The AudioBufferSource method is a kind of gross hack for backward compatibility with old sites that started playing buffers in a user gesture. This method doesn't work if you don't start the buffer from a gesture. (I think.)
Which one you want to use is up to you.
I've been using AngularAudioRecorder (AngularJS) for the last 4 years and with the last Chrome update I'm getting the following error:
The AudioContext was not allowed to start. It must be resumed (or created) after a user gesture on the page.
init # angular-audio-recorder.js: 861
Code:
getPermission: function () {
navigator.getUserMedia({
"audio": true
}, html5HandlerConfig.gotStream, html5HandlerConfig.failStream);
},
init: function () {
service.isHtml5 = true;
var AudioContext = window.AudioContext || window.webkitAudioContext;
if (AudioContext && !html5AudioProps.audioContext) {
html5AudioProps.audioContext = new AudioContext();
}
if (localStorage.getItem("permission") !== null) {
//to get permission from browser cache for returning user
html5HandlerConfig.getPermission();
}
}
};
Please find the full code here: Angular Audio Recorder
Thank you for any help you can offer
do it when user press any key or touch any button
if(audio_context.state !== 'running') {
audio_context.resume();
}
I solved the problem. Finally resumed the paused AudioContext with:
html5AudioProps.audioContext.resume().then(() => {
var audioContext = html5AudioProps.audioContext;
})
Inside the function that starts the recording.
This issue is nothing which only applies to Angular; it's much more general, and has to do with the fact that modern browsers have disabled auto-playing sounds (until user has interacted 'enough') so that you're not annoyed by sounds of some web page which you just opened.
see this old question here.
I was getting the exact same 'not allowed to start' message, and I'm not using Angular; I was just trying to have JavaScript play a sound (programmatically) before 'enough' user interaction. What I did to fix it was to take care that ... = new AudioContext() is executed only after the user has pressed a button or interacted with a (native) slider. The accepted answer to above old question suggests essentially the same strategy.
Good to see that you already solved the problem. Probably (caution: not tested) an alternative solution would be to just delay the loading and/or initialization of the recorder code until the user has pressed some button or so.
I solved my problem with:
setTimeout(() => {
context.close();
}, timenotification);
I am trying to play a beep sound a minute after user has come on the page of my website. I found the solution here https://stackoverflow.com/a/18628124/912359
Here's my code:
$(document).ready(function(){
setTimeout(function () {
try{
if(!$(".facebook-chat").hasClass("active")){
$(".facebook-chat").addClass("active");
var audio = new Audio("/sound/chat.mp3");
audio.play();
}
}catch(e){
}
}, 60000);
}):
This throws an exception:
Uncaught (in promise) DOMException
Strangely, once I load the sound file separately in my browser and come back to the page, it works perfectly. Any ideas how I can fix it.
[Edit]
The issue is that user has to interact with the browser before the sound can be played. So I put the same code under click event of the body and it works. But the same doesn't work on scroll event either. I guess chrome doesn't consider scroll a user interaction. Can anyone add what other interactions can be used to trigger this?
Also, how is it working if I load the audio file in a separate window and come back to my page.
You can try loading the audio when the document is ready and then play it later only if the resource is loaded (for this check you can register a callback on onloadeddata). Otherwise, if resource is not loaded, you can try loading it again.
$(document).ready(function()
{
let aud = new Audio('https://dl.dropboxusercontent.com/s/1cdwpm3gca9mlo0/kick.mp3');
let canPlay = false;
aud.onloadeddata = () => (console.log("audio loaded"), canPlay = true);
setInterval(function()
{
if (canPlay)
aud.play();
else
aud = new Audio('https://dl.dropboxusercontent.com/s/1cdwpm3gca9mlo0/kick.mp3');
}, 3000);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Best solution I could come up with when I tried the same was:
const playPromise = audio.play();
if (playPromise !== null){
playPromise.catch(function() { audio.play(); })
}
But sometimes (One out of ten) the second audio.play() where also uncaught and the audio did not play either. I suggest you made a loop that stops only when the Promise is finally caught.
I'm trying to get an alert sound to play when a certain condition is met. This condition is being met when I test with an alert() in place of the sound. Code snippet:
if ($scope.incomplete > $scope.incomplete_old) {
$scope.playAudio = function() {
var audio = new Audio("{% static 'ping.mp3' %}");
audio.play();
}
}
Am I missing something here? I don't understand why the sound isn't playing. I'm testing the site locally in Chrome. Is there some other configuration I overlooked?
according to your code example $scope.playAudio method is never called. Therefor your audio.play() will never be executed. To play the sound you have to call the $scope.playAudio method.
basically you can do either
$scope.playAudio()
of you let the function invoke itself
$scope.playAudio = function() {
var audio = new Audio("{% static 'ping.mp3' %}");
audio.play();
}()
further reading: https://www.w3schools.com/js/js_functions.asp