Search code examples
web-audio-apirecorder.js

Problems with WebAudio


I'm creating a research experiment that uses WebAudio API to record audio files spoken by the user. I came up with a solution for this using recorder.js and everything was working fine... until I tried it yesterday.

I am now getting this error in Chrome:

"The AudioContext was not allowed to start. It must be resumed (or created) after a user gesture on the page."

And it refers to this link: Web Audio API policy. This appears to be a consequence of Chrome's new policy outlined at the link above.

So I attempted to solve the problem by using resume() like this:

var gumStream; //stream from getUserMedia()
var rec; //Recorder.js object
var input; //MediaStreamAudioSourceNode we'll be recording

// shim for AudioContext when it's not avb. 
var AudioContext = window.AudioContext || window.webkitAudioContext;
var audioContext = new AudioContext; //new audio context to help us record

function startUserMedia() {
    var constraints = { audio: true, video:false };
    audioContext.resume().then(() => { // This is the new part
        console.log('context resumed successfully');
    });
    
    navigator.mediaDevices.getUserMedia(constraints).then(function(stream) {

        console.log("getUserMedia() success, stream created, initializing Recorder.js");
    gumStream = stream;
    input = audioContext.createMediaStreamSource(stream);
    rec = new Recorder(input, {numChannels:1});
    audio_recording_allowed = true;
    }).catch(function(err) {
        console.log("Error");
    });

}

Now in the console I'm getting:

Error

context resumed successfully

And the stream is not initializing. This happens in both Firefox and Chrome. What do I need to do?


Solution

  • I just had this exact same problem! And technically, you helped me to find this answer. My error message wasn't as complete as yours for some reason and the link to those policy changes had the answer :)

    Instead of resuming, it's best practise to create the audio context after the user interacted with the document (when I say best practise, if you have a look at padenot's first comment of 28 Sept 2018 on this thread, he mentions why in the first bullet point).

    So instead of this:

    var audioContext = new AudioContext; //new audio context to help us record
    
    function startUserMedia() {
        audioContext.resume().then(() => { // This is the new part
            console.log('context resumed successfully');
        });
    }
    

    Just set the audio context like this:

    var audioContext;
    
    function startUserMedia() {
        if(!audioContext){
          audioContext = new AudioContext;
        } 
    }
    

    This should work, as long as startUserMedia() is executed after some kind of user gesture.