WebRTC/getUserMedia: How to properly mute local video?

13,493

Solution 1

Today

track.stop() works just fine in Firefox. Chrome's behind. Spec way to end a track (https fiddle):

navigator.mediaDevices.getUserMedia({video: true, audio: true})
  .then(stream => video.srcObject = stream)
  .catch(e => log(e.name + ": "+ e.message));

let stop = k => video.srcObject.getTracks().map(t => t.kind == k && t.stop());
<video id="video" width="160" height="120" autoplay></video><br>
<button onclick="stop('video')">Stop Video</button>
<button onclick="stop('audio')">Stop Audio</button>

This gives you a way to turn off video while keeping audio, without permission re-prompt in Firefox. You still get prompted when turning video back on, so it's not perfect, but 50% better.

Until Chrome catches up, your other answer (drop and re-gUM each time) should work there, since they never re-prompt.

By browser-detecting and combining these answers, it should be possible to come up with something that works well in more than one browser, until browsers catch up.

Long term

The spec has recently addressed this by allowing browsers to turn off the camera light during temporal mute (e.g. track.enabled == false), provided a camera access indicator remains on:

"The User Agent is encouraged to provide ongoing indication of the current state of anyAccessible.

The User Agent is encouraged to provide ongoing indication of the current state of anyLive and to make any generic hardware device indicator light match."

Stronger language precedes these statements in the spec, making indicators a requirement.

Currently, browsers do not implement this correctly. Chrome is close, with a tiny camera access indicator inside the url bar on the right after recent access, but it fails to appear on page load to warn that persistent access was granted on a previous visit; the site can turn the camera on at any time.

Solution 2

I think you can make two requests for getuser media : http://codepen.io/anon/pen/gjtpu . Then you can really stop a stream. You will also have to use mutiple peer connection between user since renegociation (adding or removing stream during to an existing peer connection) is not supported by firefox

Share:
13,493
jamix
Author by

jamix

Passionate about Natural Language Processing. Founder of a VC-backed video conferencing startup. Drupal developer and equity sales in the past. Jazz piano and DJing aficionado. Father of three.

Updated on July 14, 2022

Comments

  • jamix
    jamix almost 2 years

    I'm trying to implement the functionality for muting the local video MediaStreamTrack in my WebRTC application. Here's how I'm approaching this:

    function muteVideo() {
      if (this._localStream && this._localStream.getVideoTracks().length > 0) {
        this._localStream.getVideoTracks()[0].enabled = false;
      }
    }
    

    In Firefox, the <video> element to which the local stream is attached correctly renders blackness on mute. In Chrome, blackness is not rendered but the picture freezes. However, in both browsers, the camera's green light stays on, which is clearly undesired behavior. (I want my users to see that the application actually disconnects from the camera on video mute.)

    The camera's light goes off if I do this._localStream.stop(), but then the audio goes off, too.

    The current draft of the Media Capture spec mentions the MediaStreamTrack.stop() method but it currently seems unimplemented in Chrome and Firefox.

    So is there a way to mute local video while:

    1. Making the camera's light go off
    2. Not losing the audio track?
  • jamix
    jamix over 10 years
    Thank you. But as per the WebRTC draft, MediaStreamTracks don't necessarily have to be synchronized if they belong to different MediaStreams. I'm afraid this could lead to audio/video syncing issues.
  • flo850
    flo850 over 10 years
    And you are right, it will lead to sync issues. But the only way to turn off the light is to really stop the stream (so you'll have to ask again for permission before restarting)
  • jamix
    jamix over 7 years
    The point of the question was to find a solution that works today regardless of what the spec says. 3 years later, the spec way of doing things doesn't work.
  • jib
    jib over 7 years
    @jamix I gave you a way to turn off video while keeping audio, without re-prompting for permission in Firefox today. That beats your self-answer which would re-prompt twice in Firefox (once when video goes away, and again when it comes back on). By browser detecting and combining these answers, you should be able to come up with something that works well in more than one browser, until browsers catch up. Hardly deserving of a down-vote.
  • jib
    jib over 7 years
    You should be able to use stream.addTrack and stream.removeTrack, or even new MediaStream([videoTrack, audioTrack]) (spec and Firefox, behind a flag in Chrome today), to combine tracks into a new stream. At least in theory that should re-sync them, but I haven't tried. A bug if it doesn't.
  • jamix
    jamix over 7 years
    Yes, browser-dependent behavior would indeed make the UX better in Firefox, thanks for suggesting that. I can no longer cancel the downvote but I will be able to if you edit the answer (accordingly?).