1

I'm trying to use the Audio API, and I can't play audio.

Here is a reproduction of the issue. If you open the js console, after triggering play/pause on the video, you'll see a message saying VM374:1MediaElementAudioSource outputs zeroes due to CORS access restrictions for https://s3.amazonaws.com/mettavr/dev/VfE_html5.mp4 and no audio is played. (it's not an error, but just an info log)

I've found a few SO questions like this one or this one. It sounds that the flag crossorigin should be set to anonymous and that the server permissions should allow cross origin.

I'm serving the file from a S3 bucket that seems to have opened enough permissions:

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
    <CORSRule>
        <AllowedOrigin>http://*</AllowedOrigin>
        <AllowedOrigin>https://*</AllowedOrigin>
        <AllowedMethod>POST</AllowedMethod>
        <AllowedMethod>GET</AllowedMethod>
        <AllowedMethod>HEAD</AllowedMethod>
        <MaxAgeSeconds>3000</MaxAgeSeconds>
        <ExposeHeader>Content-Range</ExposeHeader>
        <ExposeHeader>Content-Length</ExposeHeader>
        <AllowedHeader>*</AllowedHeader>
    </CORSRule>
</CORSConfiguration>

Still, I can't play my audio

======

Edit 1: clarify when the info message appears

Community
  • 1
  • 1
Guig
  • 9,891
  • 7
  • 64
  • 126

2 Answers2

2

If you do not want to stream your audio out to a peer using WebRTC for example, you don't need to use AudioContext.createMediaStreamDestination().

This function will create a MediaStreamAudioDestinationNode associated to a WebRTC MediaStream representing an audio stream which may be stored in a file or sent to another computer / browser. One common usage is to sent it to a remote peer using the RTCPeerConnection addStream() method.

In your case, if you just want to output the sound so it plays your audio, you can use the destination property of your AudioContext. It often represents an actual audio-rendering device such as your device's speakers.

var audioCtx = new AudioContext();
var source = audioCtx.createMediaElementSource(document.getElementById('video'));

var gainNode = audioCtx.createGain();
gainNode.gain.value = 0.5;
source.connect(gainNode);
gainNode.connect(audioCtx.destination);

You can check the result on this fiddle.

HiDeoo
  • 10,353
  • 8
  • 47
  • 47
2

You can request the resource as an ArrayBuffer or a Blob using fetch or XMLHttpRequest, and set both the <video> and AudioContext at the time, or load AudioContext from <video> src.

Use .decodeAudioData for ArrayBuffer or use URL.createObjectURL with Blob as parameter. This is a workaround for the issue described at Why aren't Safari or Firefox able to process audio data from MediaElementSource?? See this Answer. See also Getting Started with Web Audio API.

At approach below loaded both <video> and AudioContext using Blob, FileReader() to convert Blob to ArrayBuffer. Note also source.start(0) to start audio context playback.

Included <input type="range"> element to adjust gainNode value once AudioContext loaded.

TODO, progress handler and display while video and audio are loading.

<label>adjust audio gain<br>
<input type="range" min="0" max="5" value="2.5" step=".5" disabled /></label>
<video src="" id="video" controls="true" crossorigin="anonymous" />

var src = "https://s3.amazonaws.com/mettavr/dev/VfE_html5.mp4";
fetch(src)
.then(response => response.blob())
.then(blob => {
  video.src = URL.createObjectURL(blob);
  var audioCtx = new AudioContext();
  var reader = new FileReader();
  reader.onload = (e) => {
    audioCtx.decodeAudioData(e.target.result, (buffer) => {
      console.log(buffer); // `AudioBuffer`
        // creates a sound source
      var source = audioCtx.createBufferSource();
      source.buffer = buffer;
      gainNode = audioCtx.createGain();
      gainNode.gain.value = 2.5;
      // tell the source which sound to play
      source.connect(gainNode);
      // connect the gainNode to the context's destination
      // (the speakers)
      gainNode.connect(audioCtx.destination);
      source.start(0);
      console.log(source, audioCtx);
      range.removeAttribute("disabled")
    });
  }
  reader.readAsArrayBuffer(blob);
});

jsfiddle https://jsfiddle.net/m305au2d/2/

Community
  • 1
  • 1
guest271314
  • 1
  • 15
  • 104
  • 177