I am using RTCMultiConnection v3.4.4
I want to run WebRTC on localhost. I chose XHR-Signaling because I want the project to be completely disabled. I do not want this to depend on the Internet, since everything is on the local host (it will be later deployed to the local network)
I turned on XHRConnection.js and set connection.setCustomSocketHandler(XHRConnection) . I also did an override of connection.openSignalingChannel...
However, when I open / start the room, my video shows, but the buttons that were disabled using disableInputButtons() still remain disabled. Chat is not working.
I did console.log while overriding connection.openSignalingChannel... to confirm if it was ever called, but it is not.
Please help how to implement XHR-Signaling on a local hosting.
Thanks.
the code:
File: Audio+Video+TextChat+FileSharing.html
<!DOCTYPE html> <html lang="en" dir="ltr"> <head> <meta charset="utf-8"> <title>Audio+Video+TextChat+FileSharing using RTCMultiConnection</title> <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0"> <link rel="shortcut icon" href="./logo.png"> <link rel="stylesheet" href="./stylesheet.css"> <script src="./menu.js"></script> </head> <body> <h1> Audio+Video+TextChat+FileSharing using RTCMultiConnection <p class="no-mobile"> Multi-user (many-to-many) video streaming + text chat + file sharing using mesh networking model. </p> </h1> <section class="make-center"> <input type="text" id="room-id" value="abcdef" autocorrect=off autocapitalize=off size=20> <button id="open-room">Open Room</button><button id="join-room">Join Room</button><button id="open-or-join-room">Auto Open Or Join Room</button> <br><br> <input type="text" id="input-text-chat" placeholder="Enter Text Chat" disabled> <button id="share-file" disabled>Share File</button> <br><br> <button id="btn-leave-room" disabled>Leave/or close the room</button> <div id="room-urls" style="text-align: center;display: none;background: #F1EDED;margin: 15px -10px;border: 1px solid rgb(189, 189, 189);border-left: 0;border-right: 0;"></div> <div id="chat-container"> <div id="file-container"></div> <div class="chat-output"></div> </div> <div id="videos-container"></div> </section> <script src="./RTCMultiConnection.min.js"></script> <script src="./adapter.js"></script> <script src="./XHRConnection.js"></script> <link rel="stylesheet" href="./getHTMLMediaElement.css"> <script src="./getHTMLMediaElement.js"></script> <script src="./FileBufferReader.js"></script> <script> </script> <footer> <small id="send-message"></small> </footer> <script src="common.js"></script> </body> </html>
XHRConnection.js
function XHRConnection(connection, connectCallback) { connection.socket = { send: function(data) { data = { message: data, sender: connection.userid }; // posting data to server // data is also JSON-ified. xhr('xhr-signalhandler-post.php', null, JSON.stringify(data)); } }; // this object is used to make sure identical messages are not used multiple times var messagesReceived = {}; function repeatedlyCheck() { xhr('xhr-signalhandler-get.php', function(data) { // if server says nothing; wait. if (data == false) return setTimeout(repeatedlyCheck, 400); // if already receied same message; skip. if (messagesReceived[data.ID]) return setTimeout(repeatedlyCheck, 400); messagesReceived[data.ID] = data.Message; // "Message" property is JSON-ified in "openSignalingChannel handler data = JSON.parse(data.Message); if (data.eventName === connection.socketMessageEvent) { onMessagesCallback(data.data); } if (data.eventName === 'presence') { data = data.data; if (data.userid === connection.userid) return; connection.onUserStatusChanged({ userid: data.userid, status: data.isOnline === true ? 'online' : 'offline', extra: connection.peers[data.userid] ? connection.peers[data.userid].extra : {} }); } // repeatedly check the database setTimeout(repeatedlyCheck, 1); }); } repeatedlyCheck(); setTimeout ( function() { if (connection.enableLogs) { console.info('XHR connection opened'); } connection.socket.emit('presence', { userid: connection.userid, isOnline: true }); if( connectCallback ) { console.log( 'Calling connectCallback...' ); connectCallback(connection.socket); console.log( 'Done' ); } }, 2000 ); connection.socket.emit = function(eventName, data, callback) { if (eventName === 'changed-uuid') return; if (data.message && data.message.shiftedModerationControl) return; connection.socket.send({ eventName: eventName, data: data }); if (callback) { callback(); } }; var mPeer = connection.multiPeersHandler; function onMessagesCallback(message) { if (message.remoteUserId != connection.userid) return; if (connection.peers[message.sender] && connection.peers[message.sender].extra != message.extra) { connection.peers[message.sender].extra = message.extra; connection.onExtraDataUpdated({ userid: message.sender, extra: message.extra }); } if (message.message.streamSyncNeeded && connection.peers[message.sender]) { var stream = connection.streamEvents[message.message.streamid]; if (!stream || !stream.stream) { return; } var action = message.message.action; if (action === 'ended' || action === 'stream-removed') { connection.onstreamended(stream); return; } var type = message.message.type != 'both' ? message.message.type : null; stream.stream[action](type); return; } if (message.message === 'connectWithAllParticipants') { if (connection.broadcasters.indexOf(message.sender) === -1) { connection.broadcasters.push(message.sender); } mPeer.onNegotiationNeeded({ allParticipants: connection.getAllParticipants(message.sender) }, message.sender); return; } if (message.message === 'removeFromBroadcastersList') { if (connection.broadcasters.indexOf(message.sender) !== -1) { delete connection.broadcasters[connection.broadcasters.indexOf(message.sender)]; connection.broadcasters = removeNullEntries(connection.broadcasters); } return; } if (message.message === 'dropPeerConnection') { connection.deletePeer(message.sender); return; } if (message.message.allParticipants) { if (message.message.allParticipants.indexOf(message.sender) === -1) { message.message.allParticipants.push(message.sender); } message.message.allParticipants.forEach(function(participant) { mPeer[!connection.peers[participant] ? 'createNewPeer' : 'renegotiatePeer'](participant, { localPeerSdpConstraints: { OfferToReceiveAudio: connection.sdpConstraints.mandatory.OfferToReceiveAudio, OfferToReceiveVideo: connection.sdpConstraints.mandatory.OfferToReceiveVideo }, remotePeerSdpConstraints: { OfferToReceiveAudio: connection.session.oneway ? !!connection.session.audio : connection.sdpConstraints.mandatory.OfferToReceiveAudio, OfferToReceiveVideo: connection.session.oneway ? !!connection.session.video || !!connection.session.screen : connection.sdpConstraints.mandatory.OfferToReceiveVideo }, isOneWay: !!connection.session.oneway || connection.direction === 'one-way', isDataOnly: isData(connection.session) }); }); return; } if (message.message.newParticipant) { if (message.message.newParticipant == connection.userid) return; if (!!connection.peers[message.message.newParticipant]) return; mPeer.createNewPeer(message.message.newParticipant, message.message.userPreferences || { localPeerSdpConstraints: { OfferToReceiveAudio: connection.sdpConstraints.mandatory.OfferToReceiveAudio, OfferToReceiveVideo: connection.sdpConstraints.mandatory.OfferToReceiveVideo }, remotePeerSdpConstraints: { OfferToReceiveAudio: connection.session.oneway ? !!connection.session.audio : connection.sdpConstraints.mandatory.OfferToReceiveAudio, OfferToReceiveVideo: connection.session.oneway ? !!connection.session.video || !!connection.session.screen : connection.sdpConstraints.mandatory.OfferToReceiveVideo }, isOneWay: !!connection.session.oneway || connection.direction === 'one-way', isDataOnly: isData(connection.session) }); return; } if (message.message.readyForOffer || message.message.addMeAsBroadcaster) { connection.addNewBroadcaster(message.sender); } if (message.message.newParticipationRequest && message.sender !== connection.userid) { if (connection.peers[message.sender]) { connection.deletePeer(message.sender); } var userPreferences = { extra: message.extra || {}, localPeerSdpConstraints: message.message.remotePeerSdpConstraints || { OfferToReceiveAudio: connection.sdpConstraints.mandatory.OfferToReceiveAudio, OfferToReceiveVideo: connection.sdpConstraints.mandatory.OfferToReceiveVideo }, remotePeerSdpConstraints: message.message.localPeerSdpConstraints || { OfferToReceiveAudio: connection.session.oneway ? !!connection.session.audio : connection.sdpConstraints.mandatory.OfferToReceiveAudio, OfferToReceiveVideo: connection.session.oneway ? !!connection.session.video || !!connection.session.screen : connection.sdpConstraints.mandatory.OfferToReceiveVideo }, isOneWay: typeof message.message.isOneWay !== 'undefined' ? message.message.isOneWay : !!connection.session.oneway || connection.direction === 'one-way', isDataOnly: typeof message.message.isDataOnly !== 'undefined' ? message.message.isDataOnly : isData(connection.session), dontGetRemoteStream: typeof message.message.isOneWay !== 'undefined' ? message.message.isOneWay : !!connection.session.oneway || connection.direction === 'one-way', dontAttachLocalStream: !!message.message.dontGetRemoteStream, connectionDescription: message, successCallback: function() { // if its oneway----- todo: THIS SEEMS NOT IMPORTANT. if (typeof message.message.isOneWay !== 'undefined' ? message.message.isOneWay : !!connection.session.oneway || connection.direction === 'one-way') { connection.addNewBroadcaster(message.sender, userPreferences); } if (!!connection.session.oneway || connection.direction === 'one-way' || isData(connection.session)) { connection.addNewBroadcaster(message.sender, userPreferences); } } }; connection.onNewParticipant(message.sender, userPreferences); return; } if (message.message.shiftedModerationControl) { connection.onShiftedModerationControl(message.sender, message.message.broadcasters); return; } if (message.message.changedUUID) { if (connection.peers[message.message.oldUUID]) { connection.peers[message.message.newUUID] = connection.peers[message.message.oldUUID]; delete connection.peers[message.message.oldUUID]; } } if (message.message.userLeft) { mPeer.onUserLeft(message.sender); if (!!message.message.autoCloseEntireSession) { connection.leave(); } return; } mPeer.addNegotiatedMessage(message.message, message.sender); } window.addEventListener('beforeunload', function() { connection.socket.emit('presence', { userid: connection.userid, isOnline: false }); }, false); } // a simple function to make XMLHttpRequests function xhr( url, callback, data ) { // if( data ) console.log('[' + url + '] sending: ' + JSON.stringify( data ) ); if (!window.XMLHttpRequest || !window.JSON){ console.log( 'No JSON and/or XMLHttpRequest support' ); return; } var request = new XMLHttpRequest(); request.onreadystatechange = function() { if (callback && request.readyState == 4 && request.status == 200) { // server MUST return JSON text if( request.responseText != 'false' ) console.log('Logging non-false data [from ' + url + ']: ' + request.responseText + "[...data POST'ed: " + JSON.stringify( data ) + "]" ); callback(JSON.parse(request.responseText)); } }; request.open( 'POST', url ); var formData = new FormData(); // you're passing "message" parameter formData.append( 'message', data ); request.send(formData); }
start-broadcast.php :
<?php require( "connection.inc.php" ); if( isset( $_POST['message'] ) ) { $data = json_decode( $_POST['message'] , true ); // Now, if someone initiates WebRTC session; you should make an XHR request to create a record in the room-table; and // set "Owner-id" equals to that user "user-id". //{"message":{"eventName":"presence","data":{"userid":"winey","isOnline":true}},"sender":"winey"} $query = " INSERT INTO active_broadcasts ( name ) VALUES ( '{$data['name']}' ) "; if( $mysqli->query( $query ) ) { $transport = json_encode( false ); exit( $transport ); } else exit( $mysqli->error ); } else exit( 'No data sent' ); ?>
XHR-signalhandler-post.php :
<?php require( "connection.inc.php" ); $response = array(); //{"message":{"eventName":"presence","data":{"userid":"winey","isOnline":true}},"sender":"winey"} // var_dump( $_POST ); // exit; if( isset( $_POST['message'] ) ) { $query = " INSERT INTO webrtc-messages ( name ) VALUES ( '{$_POST['name']}' ) "; if( $mysqli->query( $query ) ) { $transport = json_encode( false ); exit( $transport ); } else exit( $mysqli->error ); // Now, if someone else joins the room; you can update above record; and append his "user-id" in the "Participants-id" column. } if( @$_POST["message"] = "undefined" ) $response = false; $transport = json_encode( $response ); exit( $transport ); ?>
XHR-signalhandler-get.php :
<?php require( "connection.inc.php" ); $response = array(); // var_dump( $_POST ); if( isset( $_POST['message'] ) ) { $query = "SELECT id , message , channel , `sender-id` FROM `webrtc-messages` "; if( $mysqli->connect_errno ) exit ( "Failed to connect to MySQL: " . $mysqli->connect_error ); if( $res = $mysqli->query( $query ) ) { if( $res->num_rows > 0 ) { while( $value = mysqli_fetch_assoc( $res ) ) { // } } } else { echo "<center class='text-danger'>Server error</center>"; exit( $mysqli->error ); } } if( @$_POST["message"] = "undefined" ) $response = false; $transport = json_encode( $response ); exit( $transport ); ?>