because-why-not/awrtc_browser

How to change camera / audio?

aryeh-at-lls opened this issue · 4 comments

How can I switch the camera source?
After I get my own controlled (video source, controlled mute etc.) stream source with:
(build->callapp_js.html)

OnNetworkEvent(sender, args) {
  //User gave access to requested camera/ microphone
  if (args.Type === awrtc.CallEventType.ConfigurationComplete) {
    console.log("configuration complete");
  } else if (args.Type === awrtc.CallEventType.MediaUpdate) {
    const margs = args;
    const videoElement = margs.VideoElement;


//// my code starts here ///////
    if (this.mLocalVideo == null && margs.ConnectionId === awrtc.ConnectionId.INVALID) {
        const constraints = {
          'video': myOwnController && {deviceId: myOwnControlledSource},
          'audio':  myOwnAudioController && {deviceId: myOwnControlledAudioSource}
    };
    navigator.mediaDevices.getUserMedia(constraints).then(stream => {....});

I tried to manipulate by changing the following (inside the above "then" callback):

sender.mNetwork.mLocalStream.mVideoElement.srcObject = stream;

Or:

sender.mNetwork.mLocalStream.mStream = stream;

But on the other side of the call there wasn't effect

Note the current version still expects the connection to be restarted when video changes.

mLocalStream & mStream are references mostly used for local access of video (e.g. delivery into C# unity or Textures for WebGL apps). WebRTC has its own reference to the local video that is being created before the connection is established. This is done via the (now obsolete) addTrack method:
https://github.com/because-why-not/awrtc_browser/blob/master/src/awrtc/media_browser/MediaPeer.ts#L131

Most modern browsers can change the video track though: https://developer.mozilla.org/en-US/docs/Web/API/RTCRtpSender/replaceTrack

This will likely be added to awrtc_browser soon once I made sure all other supported platforms can handle this situation as well.

Here is a quick hacky way to use replaceTrack for changing the video you send e.g.:

//get a new video track
let stream = await navigator.mediaDevices.getUserMedia({video:true});
//replace the track of the first sender of each peer connection
Object.values(gCallApp.mCall.mNetwork.mIdToConnection).forEach((x)=>x.mPeer.getSenders()[0].replaceTrack(stream.getVideoTracks()[0]))

Pitfalls:

  • replaceTrack should be used with await
  • I use the first sender in the list here. If this sender is used for audio this might go wrong. Best to keep track of what sender you use for video and what for audio.

Thanks.

With your hint I found another place to change it that does not depend on remote peers

gCallApp.mCall.mNetwork.mLocalStream.mStream.getTracks().forEach(track => {
    gCallApp.mCall.mNetwork.mLocalStream.mStream.removeTrack(track);
});
gCallApp.mCall.mNetwork.mLocalStream.mStream.addTrack(myVideoTrack);
gCallApp.mCall.mNetwork.mLocalStream.mStream.addTrack(myAudioTrack);

I see. This should work as long as it is done before the other user connects.