-
Notifications
You must be signed in to change notification settings - Fork 4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How to detect if user has camera #180
Comments
I'm using MultiConnection. |
Remember, we can't check presence of a webcam without making a RTCMultiConnection Docs has // is WebRTC compatible browser?
console.log( connection.caniuse.RTCPeerConnection );
// getUserMedia API exists?
console.log( connection.caniuse.getUserMedia );
// have WebAudio support?
console.log( connection.caniuse.AudioContext );
// chrome screen capturing support
console.log( connection.caniuse.ScreenSharing );
// chrome RTP data channels support
console.log( connection.caniuse.RtpDataChannels );
// chrome SCTP data channels support
console.log( connection.caniuse.SctpDataChannels );
// to verify if flag "chrome://flags/#enable-usermedia-screen-capture" is enabled
connection.caniuse.checkIfScreenSharingFlagEnabled(function (isFlagEnabled, warning) {
if (isFlagEnabled) {
console.error('Multi-capturing of screen is not allowed. Capturing process is denied. Try chrome >= M31.');
}
if (warning) console.error(warning);
else if (!isFlagEnabled) {
console.error('It seems that "Enable screen capture support in getUserMedia" flag is not enabled.');
}
});
Subsequent The EVENT var session = {
audio: true
};
connection.captureUserMedia(function (mediaStream) {
// if it is second invocation
// pass "streamObject" over "onstream"
var streamObject = connection.streams[mediaStream.streamid].streamObject;
connection.onstream(streamObject);
}, session); If previously you captured only audio; and now you captured both audio and video; then We can't fire |
Hey muaz-khan, Thanks for the help, you fixed my problem of detecting whether the user has webcam or not. The app seems to be working fine now, but there seems to be quite some lag (then again, I'm testing this on my old laptop). Could you please look at the code bellow and see if I'm making any big mystakes? <script> //Initialize RTCMultiConnection var connection = new RTCMultiConnection(); var socket; connection.session = { audio: true, video: false }; connection.openSignalingChannel = function (config) { var SIGNALING_SERVER = 'http://192.168.1.67:8888/'; var channel = config.channel || this.channel; var sender = Math.round(Math.random() * 60535) + 5000; socket = io.connect(SIGNALING_SERVER); socket.channel = channel; socket.on('connect', function () { if (config.callback) config.callback(socket); }); socket.on('test', function (message) { console.log("DIDIT"); }); //On signaling server finding peers socket.on('conference', function (session) { connection = new RTCMultiConnection(session.channel); connection.userid = session.userID; connection.session = { audio: false, video: true }; connection.onCustomMessage = function (message) { console.log(message); }; //On new stream connection.onstream = function (stream) { if (stream.type === 'local') { var video = getVideo(stream.mediaElement); document.body.appendChild(video); } if (stream.type === 'remote') { var video = getVideo(stream.mediaElement, stream.extra); document.body.appendChild(video); } }; function getVideo(video, extra) { var div = document.createElement('div'); div.className = 'video-container'; div.appendChild(video); if (extra) { var h2 = document.createElement('h2'); h2.innerHTML = extra.username; div.appendChild(h2); } return div; }; //On host creating the session connection.onNewSession = function (session) { connection.join(session); }; //Connecting to the channel received by signaling server connection.connect(); //If host, then open the channel if (session.host == true) { connection.open(); } }); }; //Connect to the signaling server connection.connect(); connection.captureUserMedia(function (mediaStream) { mediaStream.stop(); }); //Tell server the client is ready to find peers $("#init").click(function () { socket.emit('start'); }); </script>Thank you so much. |
|
Unfortunately I'm unable to understand the logic behind your code. If you're planning to get full control over signaling or you wanted to use existing 3rd party implementations like SingalMaster or PeerServer then simply understand how openSignalingChannel method works.
aButton.onclick = function () {
connection.dontAttackStream = false;
connection.captureUserMedia(function (stream) {
connection.dontAttackStream = true;
someButton.disabled = true;
});
};
anotherButton.onclick = function() {
connection.open();
};
var room;
connection.onNewSession = function(session) {
if(!room) room = session;
};
btnJoinRoom.onclick = function() {
if(room) room.join();
};
|
Yes, my plan is to fully control the channels and conversations by signalling. The idea is to have clients joining a queue, while the server connects 8 peers into each conversation. Did I mess up openSignallingChannel? Should I use captureUserMedia with dontAttachStreams = true for testing the webcam, and then attach the stream later? I had this in mind, but the problem is that it seems that if I do this, when the user joins the conference the client didn't go through onStream for his peers. |
Ok, I think the peer's stream not attaching was just a bug in my code, the code is now working with only 1 captureUserMedia, as you advised. Still wondering about the signalling part though, am I doing it wrong? |
You should open single socket; as explained here. You can set default channel like this: connection.channel = 'default-channel'; This is the same thing passed over the constructor. First Step: Initialize a global array-like objectThis array-like object will store var onMessageCallbacks = {}; Second Step: Initialize Signaling Servervar websocket = new WebSocket('wss://something:port/');
var socket = io.connect('https://domain:port/');
var firebase = new Firebase('https://user.firebaseio.com/' + connection.channel); For socket.io; you can pass default channel as URL parameter: var socket = io.connect('https://domain:port/?channel=' + connection.channel); 3rd Step: Subscribe to server messagesCapture server messages: websocket.onmessage = function (event) {
onMessageCallBack(event.data);
};
socket.on('message', function (data) {
onMessageCallBack(data);
});
firebase.on('child_added', function (snap) {
onMessageCallBack(snap.val());
snap.ref().remove(); // for socket.io live behaviour
}); and function onMessageCallBack(data) {
data = JSON.parse(e.data);
if (data.sender == connection.userid) return;
if (onMessageCallbacks[data.channel]) {
onMessageCallbacks[data.channel](data.message);
};
} 4th and final Step: Override
|
I see what you are saying, but if do everything on the default channel, having in mind that my signalling server must select 8 users from the queue and connect them togheter in the same room, how can I make make these 8 users join the same session? My current implementation was making use of onNewSession, the idea was to connect the 8 users to a different room, make the host create the session and then have all the users join it via onNewSession. I guess there is an easier way to join the session, I only did it this way because I was having trouble joining sessions outside of onNewSession. Is there a way to send the session object via the signalling server? or can I join the session via session id somehow? (When I pass session-id to join I get an error). |
Hey again, I fixed most problems you pointed out, the only current problem is that the code only works if I dont override openSignallingChannel, which makes me question what it does. (I'm able to communicate with node, to change channels and to connect with peers on the same session). My code is bellow. var connection = new RTCMultiConnection('default');
connection.captureUserMedia(function (mediaStream) {
|
You can use default socket like this: defaultSocket.on('message', function (data) {
onMessageCallBack(data);
});
function onMessageCallBack(data) {
if (data.userid == connection.userid) return;
if (data.RTCMultiConnectionPrivateMessage && onMessageCallbacks[data.channel]) {
onMessageCallbacks[data.channel](data.message);
};
// here you can add your custom code
if (!data.RTCMultiConnectionPrivateMessage) {
yourCustomCallBack(data);
}
}
connection.openSignalingChannel = function (config) {
var channel = config.channel || this.channel;
onMessageCallbacks[channel] = config.onmessage;
if (config.onopen) setTimeout(config.onopen, 1000);
return {
send: function (message) {
defaultSocket.emit('message', {
userid: connection.userid,
channel: channel,
message: message,
RTCMultiConnectionPrivateMessage: true // ------------- see this line!
});
},
channel: channel
};
};
// and here you can initialize "yourCustomCallBack"
function yourCustomCallBack(data) {
if (data.newRoomFound) {
connection.join(data.roomDetails);
}
if (data.whoisthere) {
defaultSocket.emit('message', {
userid: connection.userid, // sender userid
iamhere: true // boolean
});
}
if (connection.iamhere) {
defaultSocket.emit('message', {
userid: connection.userid, // sender userid
canyouchat: true // boolean
});
}
if (connection.canyouchat) {
defaultSocket.emit('message', {
userid: connection.userid, // sender userid
yes_icanchat: true // boolean
});
}
if (connection.yes_icanchat) {
alert('wow!');
}
}
// your button which can be clicked to open room; and emit socketio message
customButton.onclick = function () {
var roomDetails = {
sessionid: connection.sessionid,
userid: connection.userid,
session: connection.session,
extra: connection.extra
};
defaultSocket.emit('message', {
roomFound: true, // boolean
userid: connection.userid, // message sender
roomDetails: roomDetails // room details that can be passed over "join" method!
});
// www.rtcmulticonnection.org/docs/transmitRoomOnce/
connection.transmitRoomOnce = true;
connection.open();
};
// another button that can be clicked to check existnig users
anotherButton.onclick = function () {
defaultSocket.emit('message', {
userid: connection.userid, // message sender
whoisthere: true // boolean
});
}; You can see that you can use default socket for custom messages transmission as well! You can even manually share "room-details" object that can be passed directly over "join" method. Don't forget calling "connect" method before invoking "join"! Above all custom scenarios can be implemented using |
Thank you so much, I changed the code as you said and it's now working. Just one last question, my plan was to make it cross platform between mobile and web, and I would like to start working on an android version as soon as I finish my web version. So far I have found a few git projects for libjingle singnalling, but have yet to find a good project with built-in socket.io support for android. I guess it's possible to use libjingle supported projects and use a socket.io lib for android to take care of the signaling, right? How harder would it be to work with appRTC itself instead of an abstraction, like your project? Thank you so much for your support so far! |
It works on Chrome+Firefox+Opera both on desktop and android. I don't know much about 3rd party services; however if your plan to support IE/Safari or native applications then you need to clone chromium code and use in your c++ applications; same as node-webkit do (behind the scene). You may like to try crosswalk to compile js for android or node-webkit-hipster-seed to compile on desktop! |
Thanks again, your suggestions helped me find a solution. Just out of curiosity, how does the built in signalling system work? |
I'm trying to detect if the user has camera.
The idea behind this is to make sure the user has a camera before starting my web app.
Also facing a problem on starting captureUserMedia before joining a channel, whenever I try to call it again after switching channels it never goes through onStream again.
The text was updated successfully, but these errors were encountered: