From f5189d5cdcd032778c240b00ae8e6be576aaf975 Mon Sep 17 00:00:00 2001 From: hristoterezov Date: Fri, 14 Nov 2014 12:13:26 +0200 Subject: [PATCH] Fixes firefox issues. The firefox video is displayed in chrome. --- app.js | 57 ++++++++++------ libs/colibri/colibri.focus.js | 1 + libs/strophe/strophe.jingle.adapter.js | 22 ++++++ libs/strophe/strophe.jingle.js | 4 +- libs/strophe/strophe.jingle.sdp.js | 79 ++++++++++++++++------ libs/strophe/strophe.jingle.session.js | 69 ++++++++++++------- libs/strophe/strophe.jingle.sessionbase.js | 3 +- rtp_sts.js | 4 ++ videolayout.js | 9 ++- 9 files changed, 180 insertions(+), 68 deletions(-) diff --git a/app.js b/app.js index 5a98ed10b..252eaa49f 100644 --- a/app.js +++ b/app.js @@ -69,7 +69,7 @@ function init() { obtainAudioAndVideoPermissions(function (stream) { var audioStream, videoStream; - if(document.webkitMediaStream) + if(window.webkitMediaStream) { var audioStream = new webkitMediaStream(); var videoStream = new webkitMediaStream(); @@ -90,7 +90,7 @@ function init() { } else { -// VideoLayout.changeLocalAudio(stream); + VideoLayout.changeLocalAudio(stream); startLocalRtpStatsCollector(stream); @@ -289,16 +289,19 @@ function waitForPresence(data, sid) { var sess = connection.jingle.sessions[sid]; var thessrc; + // look up an associated JID for a stream id - if (!data.stream.id || data.stream.id.indexOf('mixedmslabel') === -1) { + if (data.stream.id && data.stream.id.indexOf('mixedmslabel') === -1) { // look only at a=ssrc: and _not_ at a=ssrc-group: lines + var ssrclines = SDPUtil.find_lines(sess.peerconnection.remoteDescription.sdp, 'a=ssrc:'); ssrclines = ssrclines.filter(function (line) { // NOTE(gp) previously we filtered on the mslabel, but that property // is not always present. // return line.indexOf('mslabel:' + data.stream.label) !== -1; - return (!data.stream.id? false : (line.indexOf('msid:' + data.stream.id) !== -1)); + + return ((line.indexOf('msid:' + data.stream.id) !== -1)); }); if (ssrclines.length) { thessrc = ssrclines[0].substring(7).split(' ')[0]; @@ -606,15 +609,27 @@ $(document).bind('setLocalDescription.jingle', function (event, sid) { var media = simulcast.parseMedia(sess.peerconnection.localDescription); media.forEach(function (media) { - // TODO(gp) maybe exclude FID streams? - Object.keys(media.sources).forEach(function(ssrc) { + if(Object.keys(media.sources) > 0) { + // TODO(gp) maybe exclude FID streams? + Object.keys(media.sources).forEach(function (ssrc) { + newssrcs.push({ + 'ssrc': ssrc, + 'type': media.type, + 'direction': media.direction + }); + }); + } + else if(sess.localStreamsSSRC && sess.localStreamsSSRC[media.type]) + { newssrcs.push({ - 'ssrc': ssrc, + 'ssrc': sess.localStreamsSSRC[media.type], 'type': media.type, 'direction': media.direction }); - }); + } + }); + console.log('new ssrcs', newssrcs); // Have to clear presence map to get rid of removed streams @@ -647,20 +662,22 @@ $(document).bind('iceconnectionstatechange.jingle', function (event, sid, sessio var metadata = {}; metadata.setupTime = (new Date()).getTime() - session.timeChecking; session.peerconnection.getStats(function (res) { - res.result().forEach(function (report) { - if (report.type == 'googCandidatePair' && report.stat('googActiveConnection') == 'true') { - metadata.localCandidateType = report.stat('googLocalCandidateType'); - metadata.remoteCandidateType = report.stat('googRemoteCandidateType'); + if(res && res.result) { + res.result().forEach(function (report) { + if (report.type == 'googCandidatePair' && report.stat('googActiveConnection') == 'true') { + metadata.localCandidateType = report.stat('googLocalCandidateType'); + metadata.remoteCandidateType = report.stat('googRemoteCandidateType'); - // log pair as well so we can get nice pie charts - metadata.candidatePair = report.stat('googLocalCandidateType') + ';' + report.stat('googRemoteCandidateType'); + // log pair as well so we can get nice pie charts + metadata.candidatePair = report.stat('googLocalCandidateType') + ';' + report.stat('googRemoteCandidateType'); - if (report.stat('googRemoteAddress').indexOf('[') === 0) { - metadata.ipv6 = true; + if (report.stat('googRemoteAddress').indexOf('[') === 0) { + metadata.ipv6 = true; + } } - } - }); - trackUsage('iceConnected', metadata); + }); + trackUsage('iceConnected', metadata); + } }); } break; @@ -1328,6 +1345,8 @@ $(document).ready(function () { VideoLayout.positionLarge(currentVideoWidth, currentVideoHeight); }); + document.getElementById('largeVideo').volume = 0; + if (!$('#settings').is(':visible')) { console.log('init'); init(); diff --git a/libs/colibri/colibri.focus.js b/libs/colibri/colibri.focus.js index 87b92ab1b..4695e6320 100644 --- a/libs/colibri/colibri.focus.js +++ b/libs/colibri/colibri.focus.js @@ -453,6 +453,7 @@ ColibriFocus.prototype.createdConference = function (result) { 'a=rtpmap:100 VP8/90000\r\n' + 'a=rtcp-fb:100 ccm fir\r\n' + 'a=rtcp-fb:100 nack\r\n' + + 'a=rtcp-fb:100 nack pli\r\n' + 'a=rtcp-fb:100 goog-remb\r\n' + 'a=rtpmap:116 red/90000\r\n' + 'a=rtpmap:117 ulpfec/90000\r\n' + diff --git a/libs/strophe/strophe.jingle.adapter.js b/libs/strophe/strophe.jingle.adapter.js index 8ef3b219b..b825db7ef 100644 --- a/libs/strophe/strophe.jingle.adapter.js +++ b/libs/strophe/strophe.jingle.adapter.js @@ -5,6 +5,7 @@ function TraceablePeerConnection(ice_config, constraints) { this.updateLog = []; this.stats = {}; this.statsinterval = null; + this.originalRemoteDescription = null; this.maxstats = 0; // limit to 300 values, i.e. 5 minutes; set to 0 to disable /** @@ -187,6 +188,7 @@ TraceablePeerConnection.prototype.setRemoteDescription = function (description, var self = this; description = simulcast.transformRemoteDescription(description); this.trace('setRemoteDescription', dumpSDP(description)); + this.originalRemoteDescription = description; this.peerconnection.setRemoteDescription(description, function () { self.trace('setRemoteDescriptionOnSuccess'); @@ -483,6 +485,11 @@ TraceablePeerConnection.prototype.addIceCandidate = function (candidate, success TraceablePeerConnection.prototype.getStats = function(callback, errback) { if (navigator.mozGetUserMedia) { // ignore for now... + if(!errback) + errback = function () { + + } + this.peerconnection.getStats(null,callback,errback); } else { this.peerconnection.getStats(callback); } @@ -511,6 +518,18 @@ function setupRTC() { MediaStream.prototype.getAudioTracks = function () { return []; }; RTCSessionDescription = mozRTCSessionDescription; RTCIceCandidate = mozRTCIceCandidate; + RTC.getLocalSSRC = function (session, callback) { + session.peerconnection.getStats(function (s) { + session.localStreamsSSRC = { + "audio": s['outbound_rtp_audio_0'].ssrc, + "video": s['outbound_rtp_video_1'].ssrc + }; + callback(session.localStreamsSSRC); + }, + function () { + callback(null); + }); + }; } } else if (navigator.webkitGetUserMedia) { console.log('This appears to be Chrome'); @@ -537,6 +556,9 @@ function setupRTC() { return this.audioTracks; }; } + RTC.getLocalSSRC = function (session, callback) { + callback(null); + } } if (RTC === null) { try { console.log('Browser does not appear to be WebRTC-capable'); } catch (e) { } diff --git a/libs/strophe/strophe.jingle.js b/libs/strophe/strophe.jingle.js index b15702411..98f54b7df 100644 --- a/libs/strophe/strophe.jingle.js +++ b/libs/strophe/strophe.jingle.js @@ -84,7 +84,7 @@ Strophe.addConnectionPlugin('jingle', { case 'session-initiate': sess = new JingleSession($(iq).attr('to'), $(iq).find('jingle').attr('sid'), this.connection); // configure session - if (this.localAudio) { + if (this.localAudio && RTC.browser == "chrome") { sess.localStreams.push(this.localAudio); } if (this.localVideo) { @@ -169,7 +169,7 @@ Strophe.addConnectionPlugin('jingle', { Math.random().toString(36).substr(2, 12), // random string this.connection); // configure session - if (this.localAudio) { + if (this.localAudio && RTC.browser == "chrome") { sess.localStreams.push(this.localAudio); } if (this.localVideo) { diff --git a/libs/strophe/strophe.jingle.sdp.js b/libs/strophe/strophe.jingle.sdp.js index af99e30e2..0800be4b8 100644 --- a/libs/strophe/strophe.jingle.sdp.js +++ b/libs/strophe/strophe.jingle.sdp.js @@ -192,7 +192,8 @@ SDP.prototype.removeMediaLines = function(mediaindex, prefix) { } // add content's to a jingle element -SDP.prototype.toJingle = function (elem, thecreator) { +SDP.prototype.toJingle = function (elem, thecreator, ssrcs) { +// console.log("SSRC" + ssrcs["audio"] + " - " + ssrcs["video"]); var i, j, k, mline, ssrc, rtpmap, tmp, line, lines; var self = this; // new bundle plan @@ -225,7 +226,12 @@ SDP.prototype.toJingle = function (elem, thecreator) { if (SDPUtil.find_line(this.media[i], 'a=ssrc:')) { ssrc = SDPUtil.find_line(this.media[i], 'a=ssrc:').substring(7).split(' ')[0]; // take the first } else { - ssrc = false; + if(ssrcs && ssrcs[mline.media]) + { + ssrc = ssrcs[mline.media]; + } + else + ssrc = false; } elem.c('content', {creator: thecreator, name: mline.media}); @@ -277,25 +283,60 @@ SDP.prototype.toJingle = function (elem, thecreator) { elem.c('source', { ssrc: ssrc, xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0' }); // FIXME: group by ssrc and support multiple different ssrcs var ssrclines = SDPUtil.find_lines(this.media[i], 'a=ssrc:'); - ssrclines.forEach(function(line) { - idx = line.indexOf(' '); - var linessrc = line.substr(0, idx).substr(7); - if (linessrc != ssrc) { + if(ssrclines.length > 0) { + ssrclines.forEach(function (line) { + idx = line.indexOf(' '); + var linessrc = line.substr(0, idx).substr(7); + if (linessrc != ssrc) { + elem.up(); + ssrc = linessrc; + elem.c('source', { ssrc: ssrc, xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0' }); + } + var kv = line.substr(idx + 1); + elem.c('parameter'); + if (kv.indexOf(':') == -1) { + elem.attrs({ name: kv }); + } else { + elem.attrs({ name: kv.split(':', 2)[0] }); + elem.attrs({ value: kv.split(':', 2)[1] }); + } elem.up(); - ssrc = linessrc; - elem.c('source', { ssrc: ssrc, xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0' }); - } - var kv = line.substr(idx + 1); - elem.c('parameter'); - if (kv.indexOf(':') == -1) { - elem.attrs({ name: kv }); - } else { - elem.attrs({ name: kv.split(':', 2)[0] }); - elem.attrs({ value: kv.split(':', 2)[1] }); - } + }); elem.up(); - }); - elem.up(); + } + else + { + elem.up(); + elem.c('source', { ssrc: ssrc, xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0' }); + elem.c('parameter'); + elem.attrs({name: "cname", value:Math.random().toString(36).substring(7)}); + elem.up(); + var msid = null; + if(mline.media == "audio") + { + msid = connection.jingle.localAudio.getAudioTracks()[0].id; + } + else + { + msid = connection.jingle.localVideo.getVideoTracks()[0].id; + } + if(msid != null) + { + msid = msid.replace(/[\{,\}]/g,""); + elem.c('parameter'); + elem.attrs({name: "msid", value:msid}); + elem.up(); + elem.c('parameter'); + elem.attrs({name: "mslabel", value:msid}); + elem.up(); + elem.c('parameter'); + elem.attrs({name: "label", value:msid}); + elem.up(); + elem.up(); + } + + + } // old proprietary mapping, to be removed at some point tmp = SDPUtil.parse_ssrc(this.media[i]); diff --git a/libs/strophe/strophe.jingle.session.js b/libs/strophe/strophe.jingle.session.js index 3b8515b20..97734ebda 100644 --- a/libs/strophe/strophe.jingle.session.js +++ b/libs/strophe/strophe.jingle.session.js @@ -23,7 +23,7 @@ function JingleSession(me, sid, connection) { this.ice_config = {}; this.drip_container = []; - this.usetrickle = true; + this.usetrickle = false; this.usepranswer = false; // early transport warmup -- mind you, this might fail. depends on webrtc issue 1718 this.usedrip = false; // dripping is sending trickle candidates not one-by-one @@ -36,6 +36,7 @@ function JingleSession(me, sid, connection) { this.reason = null; this.wait = true; + this.localStreamsSSRC = null; } JingleSession.prototype.initiate = function (peerjid, isInitiator) { @@ -64,6 +65,7 @@ JingleSession.prototype.initiate = function (peerjid, isInitiator) { }; this.peerconnection.onaddstream = function (event) { self.remoteStreams.push(event.stream); + console.log("REMOTE STREAM ADDED: " + event.stream + " - " + event.stream.id); $(document).trigger('remotestreamadded.jingle', [event, self.sid]); }; this.peerconnection.onremovestream = function (event) { @@ -105,6 +107,7 @@ JingleSession.prototype.accept = function () { var pranswer = this.peerconnection.localDescription; if (!pranswer || pranswer.type != 'pranswer') { + console.error("No local sdp set!"); return; } console.log('going from pranswer to answer'); @@ -128,7 +131,7 @@ JingleSession.prototype.accept = function () { initiator: this.initiator, responder: this.responder, sid: this.sid }); - prsdp.toJingle(accept, this.initiator == this.me ? 'initiator' : 'responder'); + prsdp.toJingle(accept, this.initiator == this.me ? 'initiator' : 'responder', this.localStreamsSSRC); this.connection.sendIQ(accept, function () { var ack = {}; @@ -219,10 +222,10 @@ JingleSession.prototype.sendIceCandidate = function (candidate) { }, 20); } - this.drip_container.push(event.candidate); + this.drip_container.push(candidate); return; } else { - self.sendIceCandidate([event.candidate]); + self.sendIceCandidate([candidate]); } } } else { @@ -236,25 +239,43 @@ JingleSession.prototype.sendIceCandidate = function (candidate) { initiator: this.initiator, sid: this.sid}); this.localSDP = new SDP(this.peerconnection.localDescription.sdp); - this.localSDP.toJingle(init, this.initiator == this.me ? 'initiator' : 'responder'); - this.connection.sendIQ(init, - function () { - //console.log('session initiate ack'); - var ack = {}; - ack.source = 'offer'; - $(document).trigger('ack.jingle', [self.sid, ack]); - }, - function (stanza) { - self.state = 'error'; - self.peerconnection.close(); - var error = ($(stanza).find('error').length) ? { - code: $(stanza).find('error').attr('code'), - reason: $(stanza).find('error :first')[0].tagName, - }:{}; - error.source = 'offer'; - $(document).trigger('error.jingle', [self.sid, error]); - }, - 10000); + var self = this; + var sendJingle = function (ssrc) { + if(!ssrc) + ssrc = {}; + self.localSDP.toJingle(init, self.initiator == self.me ? 'initiator' : 'responder', ssrc); + self.connection.sendIQ(init, + function () { + //console.log('session initiate ack'); + var ack = {}; + ack.source = 'offer'; + $(document).trigger('ack.jingle', [self.sid, ack]); + }, + function (stanza) { + self.state = 'error'; + self.peerconnection.close(); + var error = ($(stanza).find('error').length) ? { + code: $(stanza).find('error').attr('code'), + reason: $(stanza).find('error :first')[0].tagName, + }:{}; + error.source = 'offer'; + $(document).trigger('error.jingle', [self.sid, error]); + }, + 10000); + } + + RTC.getLocalSSRC(this, function (ssrcs) { + if(ssrcs) + { + sendJingle(ssrcs); + $(document).trigger("setLocalDescription.jingle", [self.sid]); + } + else + { + sendJingle(); + } + }); + } this.lasticecandidate = true; console.log('Have we encountered any srflx candidates? ' + this.hadstuncandidate); @@ -345,7 +366,7 @@ JingleSession.prototype.createdOffer = function (sdp) { action: 'session-initiate', initiator: this.initiator, sid: this.sid}); - this.localSDP.toJingle(init, this.initiator == this.me ? 'initiator' : 'responder'); + this.localSDP.toJingle(init, this.initiator == this.me ? 'initiator' : 'responder', this.localStreamsSSRC); this.connection.sendIQ(init, function () { var ack = {}; diff --git a/libs/strophe/strophe.jingle.sessionbase.js b/libs/strophe/strophe.jingle.sessionbase.js index b2dcb4bf8..eb6a78327 100644 --- a/libs/strophe/strophe.jingle.sessionbase.js +++ b/libs/strophe/strophe.jingle.sessionbase.js @@ -89,7 +89,8 @@ SessionBase.prototype.switchStreams = function (new_stream, oldStream, success_c self.connection.jingle.localVideo = new_stream; self.connection.jingle.localStreams = []; - self.connection.jingle.localStreams.push(self.connection.jingle.localAudio); + if(RTC.browser == "chrome") + self.connection.jingle.localStreams.push(self.connection.jingle.localAudio); self.connection.jingle.localStreams.push(self.connection.jingle.localVideo); // Conference is not active diff --git a/rtp_sts.js b/rtp_sts.js index 7cb0439b7..c04f4b3d8 100644 --- a/rtp_sts.js +++ b/rtp_sts.js @@ -174,6 +174,8 @@ StatsCollector.prototype.start = function () self.peerconnection.getStats( function (report) { + if(!report || !report.result || typeof report.result != 'function') + return; var results = report.result(); //console.error("Got interval report", results); self.currentAudioLevelsReport = results; @@ -193,6 +195,8 @@ StatsCollector.prototype.start = function () self.peerconnection.getStats( function (report) { + if(!report || !report.result || typeof report.result != 'function') + return; var results = report.result(); //console.error("Got interval report", results); self.currentStatsReport = results; diff --git a/videolayout.js b/videolayout.js index ae539d82c..c42a79ee7 100644 --- a/videolayout.js +++ b/videolayout.js @@ -10,10 +10,13 @@ var VideoLayout = (function (my) { my.changeLocalAudio = function(stream) { connection.jingle.localAudio = stream; + if(RTC.browser == "chrome") + { + RTC.attachMediaStream($('#localAudio'), stream); + document.getElementById('localAudio').autoplay = true; + document.getElementById('localAudio').volume = 0; + } - RTC.attachMediaStream($('#localAudio'), stream); - document.getElementById('localAudio').autoplay = true; - document.getElementById('localAudio').volume = 0; }; my.changeLocalVideo = function(stream, flipX) {