phtrivier
phtrivier

Reputation: 13361

Can a MediaStream be used immediately after getUserMedia() returns?

I'm trying to capture the audio from a website user's phone, and transmit it to a remote RTCPeerConnection.

Assume that I have a function to get the local MediaStream:

function getLocalAudioStream(): Promise<*> {
  const devices = navigator.mediaDevices;
  if (!devices) {
    return Promise.reject(new Error('[webrtc] Audio is not supported'));
  } else {
    return devices
      .getUserMedia({
        audio: true,
        video: false,
      })
      .then(function(stream) {
        return stream;
      });
  }
}

The following code works fine:

// variable is in 'global' scope
var LOCAL_STREAM: any = null;
// At application startup: 
getLocalAudioStream().then(function(stream) {
  LOCAL_STREAM = stream;
});
...
// Later, when the peer connection has been established:
// `pc` is an RTCPeerConnection
LOCAL_STREAM.getTracks().forEach(function(track) {
        pc.addTrack(track, LOCAL_STREAM);
      });

However, I don't want to have to keep a MediaStream open, and I would like to delay fetching the stream later, so I tried this:

getLocalAudioStream().then(function(localStream) {
    localStream.getTracks().forEach(function(track) {
      pc.addTrack(track, localStream);
    });
});

This does not work (the other end does not receive the sound.) I tried keeping the global variable around, in case of a weird scoping / garbage collection issue:

// variable is in 'global' scope
var LOCAL_STREAM: any = null;

 getLocalAudioStream().then(function(localStream) {
    LOCAL_STREAM = localStream;
    localStream.getTracks().forEach(function(track) {
       pc.addTrack(track, localStream);
    });
});

What am I missing here ?

Is there a delay to wait between the moment the getUserMedia promise is returned, and the moment it can be added to an RTCPeerConnection ? Or can I wait for a specific event ?

-- EDIT --

As @kontrollanten suggested, I made it work under Chrome by resetting my local description of the RTCPeerConnection:

getLocalAudioStream().then(function(localStream) {
    localStream.getTracks().forEach(function(track) {
      pc.addTrack(track, localStream);
    });

    pc
      .createOffer({
        voiceActivityDetection: false,
      })
      .then(offer => {
        return pc.setLocalDescription(offer);
      })
  });

However:

I tried stopping with:

  getLocalAudioStream().then(stream => {
    stream.getTracks().forEach(track => {
      track.stop();
    });
  });

Upvotes: 0

Views: 889

Answers (1)

kontrollanten
kontrollanten

Reputation: 2829

No, there's no such delay. As soon as you have the media returned, you can send it to the RTCPeerConnection.

In your example

getLocalAudioStream().then(function(localStream) {
    pc.addTrack(track, localStream);
});

It's unclear how stream is defined. Can it be that it's undefined?

Why can't you go with the following?

getLocalAudioStream()
  .then(function (stream) {
    stream
      .getTracks()
      .forEach(function(track) {
        pc.addTrack(track, stream);
      });
  });

Upvotes: 2

Related Questions