'How to select destination output device using Web Audio Api

I have been using web audio api and have created a context, and populated a source buffer with data. It plays fine over the default output device, but i don't understand how to choose the destination. In an old w3 spec you were able to pass in the correct deviceId to the audio context constructor, but i can't figure out how to do it now without using a media element. Any suggestions?

source = context.createBufferSource()
source.loop = true;
source.buffer = globalAudioBuffer;
source.connect(context.destination);
context.resume();
source.start(0);


Solution 1:[1]

Unfortunately, setting the destination audio device of a webaudio graph isn't yet implemented, and the api for this is not yet finalized.

What you can do for now, is connect the webaudio graph to an HTML element, and set the sinkid of the element (currently works on Chrome only)

Here is a simple example:

var ac = new AudioContext();
var audio = new Audio();
var o = ac.createOscillator();
o.start();
var dest = ac.createMediaStreamDestination();
o.connect(dest);
audio.src = URL.createObjectURL(dest.stream);
audio.play();

Now your oscillator will play through the audio element and you can now call audio.setSinkId() with the deviceId of a connected output device.

Solution 2:[2]

Complete example that works in Chrome 100, but not in Firefox 98.

Posting this here since the other answer at https://stackoverflow.com/a/43069474/1005419 doesn't work here (the call to createObjectURL is invalid) and because the other answer doesn't show the setSinkId() usage.

The snippet below plays the audio on the 3rd audio output device found on the system (audioDevices[2]).

Try it out at JSFiddle.

async function playAudio() {
  await navigator.mediaDevices.getUserMedia({
    audio: { deviceId: undefined },
    video: false
  });
  const devices = await navigator.mediaDevices.enumerateDevices();
  const audioDevices = devices.filter((device) => {
    return (
      device.kind === "audiooutput"
    );
  });
  const audioDevice = audioDevices[2];

  var audioContext = new AudioContext();
  var audioElement = new Audio();
  await audioElement.setSinkId(audioDevice.deviceId);
  var oscillator = audioContext.createOscillator();
  var mediaStreamDestination = audioContext.createMediaStreamDestination();
  oscillator.connect(mediaStreamDestination);
  audioElement.srcObject = mediaStreamDestination.stream;

  oscillator.start();
  audioElement.play();
  await new Promise((r) => setTimeout(r, 2000));
  oscillator.stop();
}

playAudio();

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Asher
Solution 2