Mandy Lastra
Mandy Lastra

Reputation: 181

Can I send a video stream even if the user does not have a webcam?

I am working on a video conference and I am using connection.waitUntilRemoteStreamStartsFlowing = true; before I do something else. It works fine except when a user does not have a webcam. Is there any way I could still send a video stream from that user with no Webcam?

Upvotes: 3

Views: 1345

Answers (1)

jib
jib

Reputation: 42500

That would be a waste of good bandwidth. I'm not familiar with the library you're using, but with plain WebRTC, like in this textbook WebRTC sample which uses adapter.js, you can do this:

Call navigator.mediaDevices.enumerateDevices() to learn how many cameras and microphones the user has:

navigator.mediaDevices.enumerateDevices()
.then(function(devices) {
  var hasCam = devices.some(function(d) { return d.kind == "videoinput"; });
  var hasMic = devices.some(function(d) { return d.kind == "audioinput"; });
  ...
})

Armed with this info, skip asking the user for their camera if they don't have one:

var constraints = { video: hasCam, audio: hasMic };

navigator.mediaDevices.getUserMedia(constraints)
.then(function(stream) {
  myPeerConnection.addStream(stream);
})

Lastly, if you don't send video, then the default is not to receive video either (silly default), so in case the other party has a camera, use RTCOfferOptions:

var options = { offerToReceiveAudio: true, offerToReceiveVideo: true };

myPeerConnection.createOffer(options)
.then(function(offer) { ... })

In Chrome you'll need adapter.js for all but the last bit, but in the latest Firefox it should just work (note: uses arrow-functions):

var pc1 = new mozRTCPeerConnection(), pc2 = new mozRTCPeerConnection();

navigator.mediaDevices.enumerateDevices()
.then(devices => navigator.mediaDevices.getUserMedia({
  video: devices.some(device => device.kind == "videoinput"),
  audio: devices.some(device => device.kind == "audioinput")
}))
.then(stream => pc1.addStream(v1.mozSrcObject = stream))
.then(() => pc1.createOffer({ offerToReceiveAudio: true,
                              offerToReceiveVideo: true }))
.then(offer => pc1.setLocalDescription(offer))
.then(() => pc2.setRemoteDescription(pc1.localDescription))
.then(() => pc2.createAnswer())
.then(answer => pc2.setLocalDescription(answer))
.then(() => pc1.setRemoteDescription(pc2.localDescription))
.then(() => log("Connected!"))
.catch(failed);

pc1.onicecandidate = e => !e.candidate ||
    pc2.addIceCandidate(e.candidate).catch(failed);
pc2.onicecandidate = e => !e.candidate ||
    pc1.addIceCandidate(e.candidate).catch(failed);
pc2.onaddstream = e => v2.mozSrcObject = e.stream;

var log = msg => div.innerHTML += msg + "<br>";
var failed = e => log(e.toString() +", line "+ e.lineNumber);
<video id="v1" height="120" width="160" autoplay></video>
<video id="v2" height="120" width="160" autoplay></video>
<br><div id="div"></div>

Parts of this is brand new, so I'm not sure how well it integrates with the library you are using just yet, but it should over time.

Chrome has an older version of this API which I wont mention here since it is not standard.

Upvotes: 6

Related Questions