Asher
Asher

Reputation: 1267

Chrome: Wrong sound when changing the audio source for Audio element and MediaStreamAudioDestinationNode

I have a app where I play different code-generated sounds. I place these sounds in a AudioBufferSourceNode. I allow the the user to choose what output device to play the sound through, so I use a MediaStreamAudioDestinationNode with its stream used as the source for an Audio Element. This way when the user chooses an audio output to play the sound to, I set the Sink Id of the Audio element to the requested audio output.

So I have AudioBufferSourceNode -> some Audio Graph (gain nodes, etc) -> MediaStreamAudioDestinationNode -> Audio element.

When I Play the first sound, it sound fine. But when I create a new source and connect it to the same MediaStreamAudioDestinationNode, the sound is played with the wrong pitch.

I created a Fiddle that shows the problem.

Is this a bug, or am I doing something wrong?

Upvotes: 3

Views: 688

Answers (2)

agfline
agfline

Reputation: 1

The problem was identified based on the OP Chrome Ticket.

It seems to come from the lack of sync between AudioElement and its source AudioNode (AudioBufferSourceNode, OscillatorNode, etc.) when you pause the source and play it back again.

The solution is to always call AudioElement.pause() and AudioElement.start() alongside your source stop and start.

https://jsfiddle.net/k1r7o0xj/3/

Upvotes: 0

MarijnS95
MarijnS95

Reputation: 4793

It's possible to dynamically change your graph layout by using .connect() and .disconnect(), even when audio is playing or sent through a stream (which could even be streamed over WebRTC). I couldn't find a reference in the spec, so I'm pretty sure this is taken for granted.

For example, if you have two AudioBufferSourceNodes bufferSource1 and bufferSource2, and a MediaStreamAudioDestinationNode streamDestination:

bufferSource1.connect(streamDestination);

//do some other things here, and after some time, switch to bufferSource2:

//(streamDestination doesn't need to be explicitly specified here)
bufferSource1.disconnect(streamDestination); 
bufferSource2.connect(streamDestination);

Example in action.


Edit 1:

Proper implementation:

According to the Editors Draft on the Audio Output API, it is planned/will be possible to choose a custom audio output device for the AudioContext as well (by means of new AudioContext({ sinkId: requestedSinkId });). I couldn't find any info on the progress, and even found a related discussion which the asker apparently read already. According to this and (many) other references, it doesn't seem te be an easy task, but it's planned for WA V1.

Edit: That section has been removed from the API Draft, but you can still find it in an older version.

Current workaround:

I played around with your workaround (using a MediaStreamAudioDestinationNode and Audio object), and it seems to be related to nothing being connected. I modified my example to toggle a single buffer (similar to your example but with an AudioBufferSourceNode), and observed a similar frequency drop. However, when using a GainNode inbetween and setting it's gain.value to either 0 or 1, the frequency drops disappeared (this isn't gonna be the solution if you want to create and connect new AudioBuffers dynamically).

Upvotes: -1

Related Questions