Choose WebCams Via getusermedia - javascript

I am beginner with getusermedia, just got some codes from Google, and I'm able to work on those. But i have to show options on my webapp, from where a user can select WebCam from Primary (Laptop) or Secondary (Connected via USB).
Tried this, working for primary (Laptop WebCam), but when i am adding USB WebCam, it is auto select USB WebCam.
var canvas = document.getElementById("canvas"),
context = canvas.getContext("2d"),
video = document.getElementById("video"),
imagegrid = document.getElementById("imagegrid"),
videoObj = { "video": true },
errBack = function(error) {
console.log("Video capture error: ", error.code);
};
var video = document.querySelector("#video");
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia || navigator.oGetUserMedia;
if (navigator.getUserMedia) {      
navigator.getUserMedia({video: true}, handleVideo, videoError);
}
function handleVideo(stream) {
video.src = window.URL.createObjectURL(stream);
}
function videoError(e) {
// do something
}
// Trigger photo take
document.getElementById("video").addEventListener("click", function() {
draw(video, canvas, imagegrid);
});
Is it possible, i can show options for both webcams.
Thanks

The function navigator.getUserMedia() will only give you the default camera (with the exception of Firefox which gives you an option of which camera to share with the web application)
To avoid this problem you should use navigator.mediaDevices.enumerateDevices() and then navigator.mediaDevices.getUserMedia(constraints).
Example:
navigator.mediaDevices.enumerateDevices()
.then(gotDevices)
.catch(errorCallback);
...
function gotDevices(deviceInfos) {
...
for (var i = 0; i !== deviceInfos.length; ++i) {
var deviceInfo = deviceInfos[i];
var option = document.createElement('option');
option.value = deviceInfo.deviceId;
if (deviceInfo.kind === 'audioinput') {
option.text = deviceInfo.label ||
'Microphone ' + (audioInputSelect.length + 1);
audioInputSelect.appendChild(option);
} else if (deviceInfo.kind === 'audiooutput') {
option.text = deviceInfo.label || 'Speaker ' +
(audioOutputSelect.length + 1);
audioOutputSelect.appendChild(option);
} else if (deviceInfo.kind === 'videoinput') {
option.text = deviceInfo.label || 'Camera ' +
(videoSelect.length + 1);
videoSelect.appendChild(option);
}
...
}
navigator.mediaDevices.getUserMedia(constraints)
.then(function(stream) {
var videoTracks = stream.getVideoTracks();
console.log('Got stream with constraints:', constraints);
console.log('Using video device: ' + videoTracks[0].label);
stream.onended = function() {
console.log('Stream ended');
};
window.stream = stream; // make variable available to console
video.srcObject = stream;
})
.catch(function(error) {
// ...
}
The above functions use promises and require a more complex approach than yours. So you need to do some reading in order to adaptate this method. Have a look at the link below for some examples:
https://developers.google.com/web/updates/2015/10/media-devices

Related

Can't request audio/video IE11

I have a problem based on a code that I used to request audio/video , it works on chrome , mozilla firefox however in IE11 It doesn't work.
I've already read this one:
https://github.com/addyosmani/getUserMedia.js
and applied most of the changes to make it work on IE11 , however I don't get the results, what is wrong in my code that is not allowing me to get the video on that browser.
function initiateMedia(obj){
constraint="";
if(obj.video=="true" && obj.audio=="true"){
constraint={
audio:true,
video:{
width:{max:380},
height:{max:260}
}
}
//Set Video Element
$("#mediacontainer").html('<video id ="io-videocam" muted="muted"></video>');
mediactrl = document.querySelector('video');
mediaType="video/webm";
return "Audio and Video input found! You can now start recording!";
}else if(obj.video=="null" && obj.audio=="true"){ //audio input only
constraint={audio:true, video: false}
//Set Audio Element
$("#mediacontainer").html('<audio id ="io-audio" controls muted="muted"></audio>');
mediactrl = document.querySelector('audio');
mediaType="audio/mpeg";
return ("Audio input found! You can now start recording!");
}else if(obj.video=="null" && obj.audio=="null"){ //no audio or video input
console.log("No Audio or Video input found");
return false;
}
}
function listUserMedia(){
if (!navigator.mediaDevices || !navigator.mediaDevices.enumerateDevices) {
console.log("enumerateDevices() not supported.");
return;
}
var media = navigator.mediaDevices.enumerateDevices();
media.then(function(devices) {
var useVideo=null;
var useAudio=null;
devices.forEach(function(device) {
//console.log(device.kind + ": " + device.label + " id = " + device.deviceId);
if(device.kind=="audioinput"){
useAudio="true";
}
if(device.kind=="videoinput"){
useVideo="true";
}
});
if(typeof(Storage) !== "undefined") {
sessionStorage.setItem('useAudio', useAudio);
sessionStorage.setItem('useVideo', useVideo);
} else {
console.log("Unable to set SessionStorage");
}
});
media.catch(function(err) {
console.log(err.name + ": " + err.message);
});
if(typeof(Storage) !== "undefined") {
return {"audio":sessionStorage.getItem('useAudio'),"video":sessionStorage.getItem('useVideo')};
} else {
console.log("Unable to get SessionStorage");
}
return null;
}
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
function requestMedia(string){
if(typeof MediaRecorder === 'undefined' || !navigator.getUserMedia){
alert('MediaRecorder/getUserMedia no supported on your browser, kindly use Firefox 36+');
}else{
//initiateMedia(listUserMedia());
//navigator.getUserMedia(constraint, startRecording, errorCallback);
var media = navigator.mediaDevices.getUserMedia(constraint);
media.then(function(mediaStream){
stream=mediaStream;
var url = window.URL || window.webkitURL;
if(mediaType!=null){
if(mediaType=="video/webm"){
mediactrl.src = url ? url.createObjectURL(stream) : stream;
mediactrl.onloadedmetadata = function(e) {
mediactrl.play();
};
}else{
mediactrl.src = url ? url.createObjectURL(stream) : stream;
mediactrl.onloadedmetadata = function(e) {
mediactrl.play();
}
}
$("#requestmedia").addClass("btndisabled faded-effect");
$("#videocontrol").removeClass("btndisabled").prop("disabled",false);
$("#mediaerror").html(string).css({"display":"block","color":"#003666"});
}
});
media.catch(function(err){
errorCallback(err);
});
}
}
function startRecording(stream){
/*
if (typeof MediaRecorder.isTypeSupported == 'function'){
if (MediaRecorder.isTypeSupported('video/webm;codecs=vp9')) {
var options = {mimeType: 'video/webm;codecs=vp9'};
} else if (MediaRecorder.isTypeSupported('video/webm;codecs=vp8')) {
var options = {mimeType: 'video/webm;codecs=vp8'};
}
mediaRecorder = new MediaRecorder(stream, options);
}else{
mediaRecorder = new MediaRecorder(stream); //Default codec for browser
}
*/
mediaRecorder = new MediaRecorder(stream);
mediaRecorder.start(10);
mediaRecorder.ondataavailable = function(e){
chunks.push(e.data);
};
mediaRecorder.onerror = function(e){
console.log("Error: "+e)
};
mediaRecorder.onstop = function(){
var blob = new Blob(chunks, {type: mediaType});
chunks = [];
var mediaURL = (window.webkitURL || window.URL).createObjectURL(blob);
sendFileToServer(blob);
//console.log(mediaURL);
};
}
function errorCallback(error){
console.log('navigator.getUserMedia error: ', error);
}
function releaseDevice(){
if(stream && stream.stop){
//stream.stop();
if(mediaType=="video/webm"){
stream.getVideoTracks()[0].stop();
stream.getAudioTracks()[0].stop();
}else{
stream.getAudioTracks()[0].stop();
}
}
stream=null;
}

js+html5 getUserMedia conflicts with microphone (android) (mobile thinks phone call is active)

Edited - Update in bottom of post
I'm building a web based app for android using phonegap,
and i came across this problem,
after the initialization of getusermedia when i use the Volume down/up button the volume control is for call and not for speaker,
even if i didn't start a new recording...
in addition i noticed that the phone actually thinks its inside a phone call while the app is running for example:
i start my app , then i open whatsapp and try to record a voice message the message is being canceled.
I know that the next segment is the problem (i commented it and there was no problem)
/***recording audio block***/
function audioRecordingInit() {
navigator.getUserMedia = ( navigator.getUserMedia ||
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia ||
navigator.msGetUserMedia);
if (navigator.getUserMedia) {
console.log('getUserMedia supported.');
var constraints = {audio: true};
var chunks = [];
var onSuccess = function (stream) {
$.globals.mediaRecorder = new MediaRecorder(stream);
$.globals.mediaRecorder.onstop = function(e) {
console.log("data available after MediaRecorder.stop() called.");
var blob = new Blob(chunks, { 'type' : 'audio/ogg; codecs=opus' });
chunks = [];
if(!$("#recordBtn").hasClass("private"))
$.globals.lastRecorded.audio.src = window.URL.createObjectURL(blob);
else
$.globals.lastRecordedPrivate.audio.src = window.URL.createObjectURL(blob);
console.log("audio created");
};
$.globals.mediaRecorder.ondataavailable = function(e) {
chunks.push(e.data);
}
};
var onError = function (err) {
console.log('The following error occured: ' + err);
};
navigator.getUserMedia(constraints, onSuccess, onError);// I think this is the problem
}
else{
console.log('getUserMedia not supported on your browser!');
}
/***end of recording audio block***/
}
this function is called after device ready
and im adding also the start recording and stop recording functions below
function startRecording(event) {
document.getElementById("recordingTime").innerText = "00:00";
$.globals.mediaRecorder.start();
console.log($.globals.mediaRecorder.state);
console.log("recorder started");
$.globals.timerInterval = setInterval(function () {
$.globals.sec += 1;
if ($.globals.sec == 60) {
$.globals.min++;
$.globals.sec = 0;
}
if ($.globals.min < 10) {
if ($.globals.sec < 10)
$.globals.timeText = "0" + $.globals.min + ":0" + $.globals.sec;
else
$.globals.timeText = "0" + $.globals.min + ":" + $.globals.sec;
}
else if ($.globals.sec < 10)
$.globals.timeText = min + ":0" + $.globals.sec;
else
$.globals.timeText = min + ":" + $.globals.sec;
document.getElementById("recordingTime").innerText = $.globals.timeText;
}, 1000);
}
function stopRecording() {
if($(".circleNav").hasClass("recording"))
$(".circleNav").toggleClass("recording");
$.globals.currentState="Recorded";
console.log($.globals.mediaRecorder.state);
if($.globals.mediaRecorder.state=="inactive"){
$.globals.mediaRecorder.start();
}
$.globals.mediaRecorder.stop();
console.log("recorder stopped");
clearInterval($.globals.timerInterval);
}
startRecording starts when touchstarts on record button
stopRecording is called when touchend on record button
thank you for your help
Update:
the conflict was with the microphone because the stream was always live and not only when recording.
now it works fine but still needs to make the record button disabled while in a phone call otherwise it will conflict and possibly crash the app or diconnect the mic from the all or maybe even disconnect it.
ok,
so after alot of reading about MediaRecorder,MediaStream and MediaStreamTrack.
I found the problem, the stream of audio stayed active and was using the microphone and in so denied me access to phone calls and voice messages in whatsapp.
I will add my solution below:
function audioRecordingInit() {
navigator.mediaDevices.getUserMedia = ( navigator.getUserMedia ||
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia ||
navigator.msGetUserMedia);
if (navigator.getUserMedia) {
console.log('getUserMedia supported.');
navigator.getUserMedia({audio:true}, onSuccessMedia, onErrorMedia);
return true;
}
else{
console.log('getUserMedia not supported on your browser!');
return false;
}
}
notice that i made this function return a boolean value and i separated the success and error functions.
function onSuccessMedia(stream) {
var chunks = [];
$.globals.mediaStream=stream;
console.log(stream);
$.globals.mediaRecorder = new MediaRecorder(stream);
$.globals.mediaRecorder.onstop = function(e) {
console.log("data available after MediaRecorder.stop() called.");
var blob = new Blob(chunks, { 'type' : 'audio/mp3; codecs=opus' });
chunks = [];
if(!$("#recordBtn").hasClass("private"))
$.globals.lastRecorded.audio.src = window.URL.createObjectURL(blob);
else
$.globals.lastRecordedPrivate.audio.src = window.URL.createObjectURL(blob);
console.log("audio created");
};
$.globals.mediaRecorder.ondataavailable = function(e) {
chunks.push(e.data);
};
$.globals.mediaRecorder.start();
console.log("recording start");
}
function onErrorMedia(err) {
console.log('The following error occured: ' + err);
}
here i moved the mediaRecorder.start() to the onSuccess function instead inside of the start recording...
and finely I changed the start recording function to
function startRecording(event) {
if(audioRecordingInit()) {
//here is all of the visual changes
}
}
and that's it everything is working correctly

Mozilla doesn't trigger video tage events after attach video src

I have a problem with Mozilla, I need to fit video dimension to spread on whole div, I tried onloadedmetadata and onloadeddata and other events. all the previous events works perfect on chrome. If i use scaleToFill manually from Mozilla console, it works
This is the code
navigator.getUserMedia(constraints, handleUserMedia, handleUserMediaError);
function handleUserMedia(stream) {
localVideo = document.getElementById('localVideo');
sendButton.onclick = sendData
localStream = stream;
attachMediaStream(localVideo, stream);
localVideo.onloadedmetadata = function (e) {
scaleToFill(localVideo);
}
function scaleToFill(videoTag) {
var $video = $(videoTag),
videoRatio = videoTag.videoWidth / videoTag.videoHeight,
tagRatio = $video.width() / $video.height();
if (videoRatio < tagRatio) {
$video.css('-webkit-transform', 'scaleX(' + tagRatio / videoRatio + ')')
$video.css('-moz-transform', 'scaleX(' + tagRatio / videoRatio + ')')
} else if (tagRatio < videoRatio) {
$video.css('-webkit-transform', 'scaleY(' + videoRatio / tagRatio + ')')
$video.css('-moz-transform', 'scaleY(' + videoRatio / tagRatio + ')')
}
}
Thanks.
The event is fired for me.
You probably need to attach it before calling the attachMediaStream() function, however, the event could have fired before you attached it.
var video = document.createElement('video');
document.body.appendChild(video);
video.onloadedmetadata = function(){alert('metadata loaded');};
navigator.getUserMedia = (navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia);
if (!navigator.getUserMedia) {
alert('Your browser does not like GUM');
}
navigator.getUserMedia({
video: true,
audio: false,
},
function(stream) {
if (navigator.mozGetUserMedia) {
video.mozSrcObject = stream;
} else {
var URL = window.URL || window.webkitURL;
video.src = URL.createObjectURL(stream);
}
video.play();
},
function(err) {
console.log(err);
}
);

Setting drop down last item to selected but value does not change

Below is the code I am using to set a drop down list last item to be selected but for some reason the value is still of the first one can someone please help me. This is an application that will allow the user to open the rear camera as he gives permission to the browser. The problem is that although the drop down list is saying camera 2 it still open camera 1. I think the problem is the value is not changing
<body>
<div class='select'>
<label for='videoSource'>Video source: </label><select id='videoSource'></select>
</div>
<video muted autoplay style="width:100%; height:auto"></video>
</body>
</html>
<script type="text/javascript">
var videoElement = document.querySelector("video");
var videoSelect = document.querySelector("select#videoSource");
navigator.getUserMedia = navigator.getUserMedia ||
navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
function gotSources(sourceInfos) {
for (var i = 0; i != sourceInfos.length; ++i) {
var sourceInfo = sourceInfos[i];
var option = document.createElement("option");
option.value = sourceInfo.id;
if (sourceInfo.kind === 'video') {
option.text = sourceInfo.label || 'camera ' + (videoSelect.length + 1);
videoSelect.appendChild(option);
if( i == sourceInfos.length - 1 ) {
option.selected = true;
}
} else {
console.log('Some other kind of source: ', sourceInfo);
}
}
}
if (typeof MediaStreamTrack === 'undefined') {
alert('This browser does not support MediaStreamTrack.\n\nTry Chrome Canary.');
} else {
MediaStreamTrack.getSources(gotSources);
}
function successCallback(stream) {
window.stream = stream; // make stream available to console
videoElement.src = window.URL.createObjectURL(stream);
videoElement.play();
}
function errorCallback(error) {
console.log("navigator.getUserMedia error: ", error);
}
function start() {
if (!!window.stream) {
videoElement.src = null;
window.stream.stop();
}
var videoSource = videoSelect.value;
var constraints = {
video: {
optional: [{ sourceId: videoSource}]
}
};
navigator.getUserMedia(constraints , successCallback, errorCallback);
}
videoSelect.onchange = start;
start();
</script>

Specify webcam with sourceId in getUserMedia

I have two webcams and am trying to specify which one to show in my video tag. My HTML is simply <video autoplay></video>. Here is my javascript:
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
var constraints = {
video: {
optional: [{
sourceId: "64-character-alphanumeric-source-id-here"
}]
}
};
var video = document.querySelector("video");
function successCallback(stream) {
window.stream = stream; // stream available to console
if (window.URL) {
video.src = window.URL.createObjectURL(stream);
} else {
video.src = stream;
}
video.play();
}
function errorCallback(error) {
console.log("navigator.getUserMedia error: ", error);
}
navigator.getUserMedia(constraints, successCallback, errorCallback);
However, even when I change the sourceId to my second webcam, I can't get it to display that webcam. js.fiddle code
this code is working for me in mobile chrome: It tries to detect the back facing video stream.
MediaStreamTrack.getSources(function(sourceInfos) {
var videoSourceId;
for (var i = 0; i != sourceInfos.length; ++i) {
var sourceInfo = sourceInfos[i];
if(sourceInfo.kind == "video" && sourceInfo.facing == "environment") {
videoSourceId = sourceInfo.id;
}
}
var constraints = {
audio: false,
video: {
optional: [{sourceId: videoSourceId}]
}
};
....
});
note that there is no fallback in this code

Categories