Search code examples
javascriptpythonpyaudio

Uncaught (in promise) DOMException: Unable to decode audio data from pyAudio to JavaScript


I have a python app that gets the audio from the microphone, sends it to the server, which in turn sends it to a javascript app.

I have checked and the data sent by the python app is the same as the one received by the javascript one.

In the console, in the javascript app, the following message appears: Uncaught (in promise) DOMException: Unable to decode audio data.

I think the problem is because the data sent is the raw one, without the '.wav' headers, but I also tried writing the data to a file using wave and reading it, the same error appears.

The data is sent/ received as binary data, using websockets.

Python code:

# self data in init
self.sampleRate = 44100
self.duration = 1 / 30
self.channels = 2
self.chunk = 1024
self.format = pyaudio.paInt16

# code
pyAudio = pyaudio.PyAudio()
frames = []
stream = pyAudio.open(
    format=self.format,
    channels=self.channels,
    rate=self.sampleRate,
    input=True,
    output=True,
    frames_per_buffer=self.chunk
)

data = stream.read(int(44100 / self.chunk * self.duration))
frames.append(data)
recording = data

stream.stop_stream()
stream.close()
pyAudio.terminate()
  1. The recording data is the one sent to the javascript app.
  2. I know I should record multiple frames, but I've done it this way as it is easier for testing.

JavaScript code:

function playByteArray(byteArray) {
    var arrayBuffer = new ArrayBuffer(byteArray.length);
    var bufferView = new Uint8Array(arrayBuffer);
    for (i = 0; i < byteArray.length; i++) {
      bufferView[i] = byteArray[i];
    }
    context.decodeAudioData(arrayBuffer, function(buffer) {
        buf = buffer;
        play();
    });
}

function play() {
    var source = context.createBufferSource();
    source.buffer = buf;
    source.connect(context.destination);
    source.start(0);
}

I've also tried it with the sounddevice python module, but I was getting the same error (the normal method, I couldn't get the Stream callback method to work).

Thank you.


Solution

  • I solved it changing the playByteArray to the following function:

    function playByteArray(byteArray) {
        audio = new Audio();
        var blob = new Blob([byteArray], { type: 'audio/wav; codecs=0' });
        var url = window.URL.createObjectURL(blob);     
        audio.src = url;
        audio.oncanplaythrough = (event) => {
            var playedPromise = audio.play();
            if (playedPromise) {
                playedPromise.catch((e) => {
                    console.log(e);
                    if (e.name === 'NotAllowedError' || e.name === 'NotSupportedError') {
                        console.log(e.name);
                    }
                }).then(() => {
    
                });
            }
        };
    }