Skip to content

Commit

Permalink
Do not clone MediaStreamTrack in Chrome (#713)
Browse files Browse the repository at this point in the history
  • Loading branch information
timmydoza authored Jun 28, 2022
1 parent d4c418c commit f92e4ed
Showing 1 changed file with 11 additions and 4 deletions.
15 changes: 11 additions & 4 deletions src/components/AudioLevelIndicator/AudioLevelIndicator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ export function initializeAnalyser(stream: MediaStream) {
return analyser;
}

const isIOS = /iPhone|iPad/.test(navigator.userAgent);

function AudioLevelIndicator({ audioTrack, color = 'white' }: { audioTrack?: AudioTrack; color?: string }) {
const SVGRectRef = useRef<SVGRectElement>(null);
const [analyser, setAnalyser] = useState<AnalyserNode>();
Expand All @@ -41,22 +43,27 @@ function AudioLevelIndicator({ audioTrack, color = 'white' }: { audioTrack?: Aud
if (audioTrack && mediaStreamTrack && isTrackEnabled) {
// Here we create a new MediaStream from a clone of the mediaStreamTrack.
// A clone is created to allow multiple instances of this component for a single
// AudioTrack on iOS Safari.
let newMediaStream = new MediaStream([mediaStreamTrack.clone()]);
// AudioTrack on iOS Safari. We only clone the mediaStreamTrack on iOS.
let newMediaStream = new MediaStream([isIOS ? mediaStreamTrack.clone() : mediaStreamTrack]);

// Here we listen for the 'stopped' event on the audioTrack. When the audioTrack is stopped,
// we stop the cloned track that is stored in 'newMediaStream'. It is important that we stop
// all tracks when they are not in use. Browsers like Firefox don't let you create a new stream
// from a new audio device while the active audio device still has active tracks.
const stopAllMediaStreamTracks = () => {
newMediaStream.getTracks().forEach(track => track.stop());
if (isIOS) {
// If we are on iOS, then we want to stop the MediaStreamTrack that we have previously cloned.
// If we are not on iOS, then we do not stop the MediaStreamTrack since it is the original and still in use.
newMediaStream.getTracks().forEach(track => track.stop());
}
newMediaStream.dispatchEvent(new Event('cleanup')); // Stop the audioContext
};
audioTrack.on('stopped', stopAllMediaStreamTracks);

const reinitializeAnalyser = () => {
stopAllMediaStreamTracks();
newMediaStream = new MediaStream([mediaStreamTrack.clone()]);
// We only clone the mediaStreamTrack on iOS.
newMediaStream = new MediaStream([isIOS ? mediaStreamTrack.clone() : mediaStreamTrack]);
setAnalyser(initializeAnalyser(newMediaStream));
};

Expand Down

0 comments on commit f92e4ed

Please sign in to comment.