Search code examples
javascriptweb-audio-api

PizzicatoJS play to specified device (SinkId)


I've been using this library called Pizzicato and I want to know how I could potentially play it to a specific audio output device. I've done it before with the web audio API like this.

navigator.getUserMedia({audio: true}, function(stream) {
    var ac = new AudioContext();
    var audio = new Audio();
    var microphone = ac.createMediaStreamSource(stream);
    var dest = ac.createMediaStreamDestination();
    microphone.connect(dest);

    audio.srcObject = dest.stream;

    audio.setSinkId(settings.output);
    audio.play();
}, function (){console.warn("Error getting audio stream from getUserMedia")});

But in the example below, it plays nothing. I've tried removing the setSinkId and it still doesn't work.

var voice = new Pizzicato.Sound({ source: 'input' }, (err) => {
    var dest = voice.getRawSourceNode().context.createMediaStreamDestination();
    var audio = new Audio();
    voice.connect(dest);
    audio.srcObject = dest.stream;
    audio.setSinkId(id);
    audio.play();
});

Solution

  • Pizzicato.js has an internal GainNode to which it connects everything. Luckily there is a getter which allows us to modify that GainNode from the outside.

    To achieve the desired result we have to disconnect that GainNode from the destination of the AudioContext to which it is connected by default. Afterwards we can connect it to the newly created MediaStreamAudioDestinationNode.

    const voice = new Pizzicato.Sound({ source: 'input' });
    
    // Disconnect the masterGainNode from the default destination.
    Pizzicato.masterGainNode.disconnect(Pizzicato.context.destination);
    
    const dest = Pizzicato.context.createMediaStreamDestination();
    
    // Connect the masterGainNode to the new destination.
    Pizzicato.masterGainNode.connect(dest);
    
    const audio = new Audio();
    
    audio.srcObject = dest.stream;
    audio.setSinkId(id);
    audio.play();