Safari and iOS 15 to 14 have rendered the Javascript audio context unusable

Recently, I noticed that the IOS/Safari upgrade has caused some issues with the web audio API.

Check out this simple code that used to work on IOS and Safari before the upgrade, but now it doesn't work anymore. Interestingly, it still works on Firefox, Edge, and Chrome.

    var url  = 'https://www.mylooper.com/static/btf_10_loop1.aac';
    var context = new AudioContext();
    var source = context.createBufferSource();
    
    //connect it to the destination so you can hear it.
    source.connect(context.destination);
    /* --- load buffer ---  */
    var request = new XMLHttpRequest();
    //open the request
    request.open('GET', url, true); 
    //webaudio paramaters
    request.responseType = 'arraybuffer';
    request.onload = function() {
        context.decodeAudioData(request.response, function(response) {
            /* --- play the sound AFTER the buffer loaded --- */
            //set the buffer to the response we just received.
            source.buffer = response;
            source.start(0);
            source.loop = true;
        }, function () { console.error('The request failed.'); } );
    }
    //Now that the request has been defined, actually make the request. (send it)
    request.send();
</script>

Many libraries are affected, such as Howler.js and Tuna.js, but I'm unsure if this issue will be fixed in the future.

By the way, how should one create a perfect audio loop with JS on Safari / IOS now?

Thank you so much, this problem is really frustrating...

Answer №1

When you refer to something as "broken", what exactly do you mean?
If it indicates that the audio is not starting with this warning, then you need to execute source.start(0) after a user gesture.

The AudioContext was not permitted to start. It must be resumed (or created) following a user's action on the page.

For instance, trigger request.send() within an onclick function of a button.
Alternatively, encapsulate all your code within an onclick function of a button.

const button = document.getElementbyId("foo");
button.onclick = () => {
    var url = 'https://www.mylooper.com/static/btf_10_loop1.aac';
    var context = new AudioContext();
    var source = context.createBufferSource();
    
    // Connect it to the destination for audible playback.
    source.connect(context.destination);
    /* --- Load buffer --- */
    var request = new XMLHttpRequest();
    // Open the request
    request.open('GET', url, true); 
    // WebAudio parameters
    request.responseType = 'arraybuffer';
    request.onload = function() {
        context.decodeAudioData(request.response, function(response) {
            /* --- Play the sound AFTER the buffer has loaded --- */
            // Set the buffer to the response received.
            source.buffer = response;
            source.start(0);
            source.loop = true;
        }, function () { console.error('The request failed.'); } );
    }
    // Now that the request has been defined, actually make the request by sending it.
    request.send();
}

This is a described feature found here: https://developer.chrome.com/blog/autoplay/#webaudio
Therefore, it will not be resolved.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Tips for choosing all elements in a form that have a specific class assigned

I am attempting to target all fields in a form with a specific class name and then select all the remaining fields. This is my form: <form style="margin:20px 0" id="myform_2"> <p> Query Name : <input i ...

Error in custom class using vanilla JavaScript: "Error: Unable to assign innerHTML to an undefined property"

Apologies for the ambiguous title, but I am struggling to pinpoint the exact issue at hand... I'm essentially guessing my way through this problem. This marks my initial venture into creating a reusable Javascript class. Below is a simplified version ...

Is there a way to adjust the height of one div based on the height of another div in Bootstrap?

I am experimenting with a Bootstrap example featuring a table in the left column and 4 columns in 2 rows in the right column. Check out the code below: <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css ...

Is there any difference in loading speed when using an async function in the createConnection method of promise-mysql?

Is it more efficient to use asynchronous createConnection or not? Does this impact the loading speed in any way? I am working with express, ReactJS, and promise-mysql. Which approach is preferable? Option 1: async connect () { try{ ...

How to Retrieve the Current div's ID in VueJS

When using the v-for directive to dynamically generate an id for my div, I need to pass this unique id to a specific function. <div v-for="(item, index) in items" :key="index" :id="'form' + index" > ...

Retrieving journal web addresses using the CORE API

I am currently working on pulling journal data from the CORE API in React, specifically focusing on obtaining the title and URL of each journal. My goal is to create clickable links that direct users to the specified URLs. { "identifiers": [ ...

How to avoid the need to wrap all setState calls with #act in React 18?

One issue I encountered was when upgrading from React 17 to 18, ReactDom render became asynchronous. To handle this, I needed to use #act to wrap the ReactDom render. However, React also required that all setState calls be wrapped with #act. If not done, ...

Newbie in PHP: Techniques for transferring PHP variables between different sections of PHP code

In my project, I have a file named index.php which is responsible for uploading files to the server and setting PHP variables such as $target_folder_and_file_name. This index.php file also includes the following line (originally it was in an index.html fi ...

The Angular UI Bootstrap Datepicker fails to appear on top of the Bootstrap Modal

I'm currently working on an Angular app that utilizes UI Bootstrap. Within my app, I have a modal containing a Datepicker at the bottom. However, I've encountered an issue where the Datepicker remains confined within the modal when expanded. I at ...

Setting properties on functions and defining their prototype

My task involves working on the following block of code: function Vector(x, y) { this.x = x || 0; this.y = y || 0; } Vector.add = function(a, b) { return new Vector(a.x + b.x, a.y + b.y); }; Vector.sub = function(a, b) { return new Vecto ...

Guide to retrieving the second value variable in an array based on the selected dropdown option within a controller

In my controller, I am trying to extract the second value in an array list that a user selects from a dropdown so that I can perform mathematical operations on it. $scope.dropdown = [ {name:'Name', value:'123'}] When a user chooses "N ...

Tips for extracting the values of multiple input fields in JavaScript and displaying them on a webpage

I want to collect all the values from input fields and display them on the website. Check out my code snippet below: var button = document.querySelector("button"); button.addEventListener("click", function() { var inputs = document.querySelectorAll( ...

Preserve the Redux state when transitioning from a popup to the main window

My authentication process involves using auth0 to authenticate users. After selecting a provider, a popup opens for the user to choose an account to sign in with. With the help of the Auth0 sdk, I am able to retrieve user information such as email and nam ...

How to enhance a jQuery tab control by implementing custom JavaScript forward and back arrows?

Although there are other questions related to this topic, mine is unique. I have a scrolling jQuery feature that utilizes tabs for selection and is automated. Modifying the layout is challenging because it is dynamic and depends on the number of items in t ...

What is the process for transforming a string into a Cairo felt (field element)?

In order to work with Cairo, all data must be represented as a felt. Learn more here Is there a way to convert a string into a felt using JavaScript? ...

Delete the placeholder image from a div once live content has been inserted into it

If I have a container div that displays an image when empty, but I want to remove the image when content is dynamically added to the container, what would be the most effective way to do this with jQuery? The usual method of checking if the container' ...

When incorporating conditional statements into your code, make sure to utilize the tags <script> along with

I have some script tags as shown below: <script src="cordova-2.5.0.js"></script> <script src="js/jquery-1.7.2.min.js"></script> <script src="js/jquery.mobile-1.1.1.min.js"></script> <script src="js/jquery.xdomainajax ...

The value of useEffect does not change even after it is defined in ReactJS

I am working on a component where I need to fetch data from an API after it has been rendered, and store the response in a useState value. However, when attempting to set the state using the useEffect callback after fetching the API, nothing seems to be w ...

Why is it that a JSX element can take a method with parentheses or without as its child?

Why is it that when I attempt to pass a method without parentheses into a React component as a child of one of the JSX elements, an error appears in the console? However, simply adding parentheses resolves the issue. What's the deal? For example: ran ...

Utilizing a try/catch block for validating a JSON file is ineffective

I'm attempting to verify if a received string is JSON and I experimented with the code below: try { JSON.parse(-10); // Also tried with "-10" }catch(e) { console.log('inside catch'); } Surprisingly, the code never enters the catch ...