Fixes firefox issues. The firefox video is displayed in chrome.

This commit is contained in:
hristoterezov 2014-11-14 12:13:26 +02:00
parent 41fd416338
commit f5189d5cdc
9 changed files with 180 additions and 68 deletions

57
app.js
View File

@ -69,7 +69,7 @@ function init() {
obtainAudioAndVideoPermissions(function (stream) { obtainAudioAndVideoPermissions(function (stream) {
var audioStream, videoStream; var audioStream, videoStream;
if(document.webkitMediaStream) if(window.webkitMediaStream)
{ {
var audioStream = new webkitMediaStream(); var audioStream = new webkitMediaStream();
var videoStream = new webkitMediaStream(); var videoStream = new webkitMediaStream();
@ -90,7 +90,7 @@ function init() {
} }
else else
{ {
// VideoLayout.changeLocalAudio(stream); VideoLayout.changeLocalAudio(stream);
startLocalRtpStatsCollector(stream); startLocalRtpStatsCollector(stream);
@ -289,16 +289,19 @@ function waitForPresence(data, sid) {
var sess = connection.jingle.sessions[sid]; var sess = connection.jingle.sessions[sid];
var thessrc; var thessrc;
// look up an associated JID for a stream id // 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 // look only at a=ssrc: and _not_ at a=ssrc-group: lines
var ssrclines var ssrclines
= SDPUtil.find_lines(sess.peerconnection.remoteDescription.sdp, 'a=ssrc:'); = SDPUtil.find_lines(sess.peerconnection.remoteDescription.sdp, 'a=ssrc:');
ssrclines = ssrclines.filter(function (line) { ssrclines = ssrclines.filter(function (line) {
// NOTE(gp) previously we filtered on the mslabel, but that property // NOTE(gp) previously we filtered on the mslabel, but that property
// is not always present. // is not always present.
// return line.indexOf('mslabel:' + data.stream.label) !== -1; // 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) { if (ssrclines.length) {
thessrc = ssrclines[0].substring(7).split(' ')[0]; 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); var media = simulcast.parseMedia(sess.peerconnection.localDescription);
media.forEach(function (media) { media.forEach(function (media) {
// TODO(gp) maybe exclude FID streams? if(Object.keys(media.sources) > 0) {
Object.keys(media.sources).forEach(function(ssrc) { // 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({ newssrcs.push({
'ssrc': ssrc, 'ssrc': sess.localStreamsSSRC[media.type],
'type': media.type, 'type': media.type,
'direction': media.direction 'direction': media.direction
}); });
}); }
}); });
console.log('new ssrcs', newssrcs); console.log('new ssrcs', newssrcs);
// Have to clear presence map to get rid of removed streams // 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 = {}; var metadata = {};
metadata.setupTime = (new Date()).getTime() - session.timeChecking; metadata.setupTime = (new Date()).getTime() - session.timeChecking;
session.peerconnection.getStats(function (res) { session.peerconnection.getStats(function (res) {
res.result().forEach(function (report) { if(res && res.result) {
if (report.type == 'googCandidatePair' && report.stat('googActiveConnection') == 'true') { res.result().forEach(function (report) {
metadata.localCandidateType = report.stat('googLocalCandidateType'); if (report.type == 'googCandidatePair' && report.stat('googActiveConnection') == 'true') {
metadata.remoteCandidateType = report.stat('googRemoteCandidateType'); metadata.localCandidateType = report.stat('googLocalCandidateType');
metadata.remoteCandidateType = report.stat('googRemoteCandidateType');
// log pair as well so we can get nice pie charts // log pair as well so we can get nice pie charts
metadata.candidatePair = report.stat('googLocalCandidateType') + ';' + report.stat('googRemoteCandidateType'); metadata.candidatePair = report.stat('googLocalCandidateType') + ';' + report.stat('googRemoteCandidateType');
if (report.stat('googRemoteAddress').indexOf('[') === 0) { if (report.stat('googRemoteAddress').indexOf('[') === 0) {
metadata.ipv6 = true; metadata.ipv6 = true;
}
} }
} });
}); trackUsage('iceConnected', metadata);
trackUsage('iceConnected', metadata); }
}); });
} }
break; break;
@ -1328,6 +1345,8 @@ $(document).ready(function () {
VideoLayout.positionLarge(currentVideoWidth, currentVideoHeight); VideoLayout.positionLarge(currentVideoWidth, currentVideoHeight);
}); });
document.getElementById('largeVideo').volume = 0;
if (!$('#settings').is(':visible')) { if (!$('#settings').is(':visible')) {
console.log('init'); console.log('init');
init(); init();

View File

@ -453,6 +453,7 @@ ColibriFocus.prototype.createdConference = function (result) {
'a=rtpmap:100 VP8/90000\r\n' + 'a=rtpmap:100 VP8/90000\r\n' +
'a=rtcp-fb:100 ccm fir\r\n' + 'a=rtcp-fb:100 ccm fir\r\n' +
'a=rtcp-fb:100 nack\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=rtcp-fb:100 goog-remb\r\n' +
'a=rtpmap:116 red/90000\r\n' + 'a=rtpmap:116 red/90000\r\n' +
'a=rtpmap:117 ulpfec/90000\r\n' + 'a=rtpmap:117 ulpfec/90000\r\n' +

View File

@ -5,6 +5,7 @@ function TraceablePeerConnection(ice_config, constraints) {
this.updateLog = []; this.updateLog = [];
this.stats = {}; this.stats = {};
this.statsinterval = null; this.statsinterval = null;
this.originalRemoteDescription = null;
this.maxstats = 0; // limit to 300 values, i.e. 5 minutes; set to 0 to disable 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; var self = this;
description = simulcast.transformRemoteDescription(description); description = simulcast.transformRemoteDescription(description);
this.trace('setRemoteDescription', dumpSDP(description)); this.trace('setRemoteDescription', dumpSDP(description));
this.originalRemoteDescription = description;
this.peerconnection.setRemoteDescription(description, this.peerconnection.setRemoteDescription(description,
function () { function () {
self.trace('setRemoteDescriptionOnSuccess'); self.trace('setRemoteDescriptionOnSuccess');
@ -483,6 +485,11 @@ TraceablePeerConnection.prototype.addIceCandidate = function (candidate, success
TraceablePeerConnection.prototype.getStats = function(callback, errback) { TraceablePeerConnection.prototype.getStats = function(callback, errback) {
if (navigator.mozGetUserMedia) { if (navigator.mozGetUserMedia) {
// ignore for now... // ignore for now...
if(!errback)
errback = function () {
}
this.peerconnection.getStats(null,callback,errback);
} else { } else {
this.peerconnection.getStats(callback); this.peerconnection.getStats(callback);
} }
@ -511,6 +518,18 @@ function setupRTC() {
MediaStream.prototype.getAudioTracks = function () { return []; }; MediaStream.prototype.getAudioTracks = function () { return []; };
RTCSessionDescription = mozRTCSessionDescription; RTCSessionDescription = mozRTCSessionDescription;
RTCIceCandidate = mozRTCIceCandidate; 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) { } else if (navigator.webkitGetUserMedia) {
console.log('This appears to be Chrome'); console.log('This appears to be Chrome');
@ -537,6 +556,9 @@ function setupRTC() {
return this.audioTracks; return this.audioTracks;
}; };
} }
RTC.getLocalSSRC = function (session, callback) {
callback(null);
}
} }
if (RTC === null) { if (RTC === null) {
try { console.log('Browser does not appear to be WebRTC-capable'); } catch (e) { } try { console.log('Browser does not appear to be WebRTC-capable'); } catch (e) { }

View File

@ -84,7 +84,7 @@ Strophe.addConnectionPlugin('jingle', {
case 'session-initiate': case 'session-initiate':
sess = new JingleSession($(iq).attr('to'), $(iq).find('jingle').attr('sid'), this.connection); sess = new JingleSession($(iq).attr('to'), $(iq).find('jingle').attr('sid'), this.connection);
// configure session // configure session
if (this.localAudio) { if (this.localAudio && RTC.browser == "chrome") {
sess.localStreams.push(this.localAudio); sess.localStreams.push(this.localAudio);
} }
if (this.localVideo) { if (this.localVideo) {
@ -169,7 +169,7 @@ Strophe.addConnectionPlugin('jingle', {
Math.random().toString(36).substr(2, 12), // random string Math.random().toString(36).substr(2, 12), // random string
this.connection); this.connection);
// configure session // configure session
if (this.localAudio) { if (this.localAudio && RTC.browser == "chrome") {
sess.localStreams.push(this.localAudio); sess.localStreams.push(this.localAudio);
} }
if (this.localVideo) { if (this.localVideo) {

View File

@ -192,7 +192,8 @@ SDP.prototype.removeMediaLines = function(mediaindex, prefix) {
} }
// add content's to a jingle element // 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 i, j, k, mline, ssrc, rtpmap, tmp, line, lines;
var self = this; var self = this;
// new bundle plan // new bundle plan
@ -225,7 +226,12 @@ SDP.prototype.toJingle = function (elem, thecreator) {
if (SDPUtil.find_line(this.media[i], 'a=ssrc:')) { 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 ssrc = SDPUtil.find_line(this.media[i], 'a=ssrc:').substring(7).split(' ')[0]; // take the first
} else { } else {
ssrc = false; if(ssrcs && ssrcs[mline.media])
{
ssrc = ssrcs[mline.media];
}
else
ssrc = false;
} }
elem.c('content', {creator: thecreator, name: mline.media}); 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' }); elem.c('source', { ssrc: ssrc, xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0' });
// FIXME: group by ssrc and support multiple different ssrcs // FIXME: group by ssrc and support multiple different ssrcs
var ssrclines = SDPUtil.find_lines(this.media[i], 'a=ssrc:'); var ssrclines = SDPUtil.find_lines(this.media[i], 'a=ssrc:');
ssrclines.forEach(function(line) { if(ssrclines.length > 0) {
idx = line.indexOf(' '); ssrclines.forEach(function (line) {
var linessrc = line.substr(0, idx).substr(7); idx = line.indexOf(' ');
if (linessrc != ssrc) { 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(); 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();
}); }
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 // old proprietary mapping, to be removed at some point
tmp = SDPUtil.parse_ssrc(this.media[i]); tmp = SDPUtil.parse_ssrc(this.media[i]);

View File

@ -23,7 +23,7 @@ function JingleSession(me, sid, connection) {
this.ice_config = {}; this.ice_config = {};
this.drip_container = []; 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.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 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.reason = null;
this.wait = true; this.wait = true;
this.localStreamsSSRC = null;
} }
JingleSession.prototype.initiate = function (peerjid, isInitiator) { JingleSession.prototype.initiate = function (peerjid, isInitiator) {
@ -64,6 +65,7 @@ JingleSession.prototype.initiate = function (peerjid, isInitiator) {
}; };
this.peerconnection.onaddstream = function (event) { this.peerconnection.onaddstream = function (event) {
self.remoteStreams.push(event.stream); self.remoteStreams.push(event.stream);
console.log("REMOTE STREAM ADDED: " + event.stream + " - " + event.stream.id);
$(document).trigger('remotestreamadded.jingle', [event, self.sid]); $(document).trigger('remotestreamadded.jingle', [event, self.sid]);
}; };
this.peerconnection.onremovestream = function (event) { this.peerconnection.onremovestream = function (event) {
@ -105,6 +107,7 @@ JingleSession.prototype.accept = function () {
var pranswer = this.peerconnection.localDescription; var pranswer = this.peerconnection.localDescription;
if (!pranswer || pranswer.type != 'pranswer') { if (!pranswer || pranswer.type != 'pranswer') {
console.error("No local sdp set!");
return; return;
} }
console.log('going from pranswer to answer'); console.log('going from pranswer to answer');
@ -128,7 +131,7 @@ JingleSession.prototype.accept = function () {
initiator: this.initiator, initiator: this.initiator,
responder: this.responder, responder: this.responder,
sid: this.sid }); 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, this.connection.sendIQ(accept,
function () { function () {
var ack = {}; var ack = {};
@ -219,10 +222,10 @@ JingleSession.prototype.sendIceCandidate = function (candidate) {
}, 20); }, 20);
} }
this.drip_container.push(event.candidate); this.drip_container.push(candidate);
return; return;
} else { } else {
self.sendIceCandidate([event.candidate]); self.sendIceCandidate([candidate]);
} }
} }
} else { } else {
@ -236,25 +239,43 @@ JingleSession.prototype.sendIceCandidate = function (candidate) {
initiator: this.initiator, initiator: this.initiator,
sid: this.sid}); sid: this.sid});
this.localSDP = new SDP(this.peerconnection.localDescription.sdp); this.localSDP = new SDP(this.peerconnection.localDescription.sdp);
this.localSDP.toJingle(init, this.initiator == this.me ? 'initiator' : 'responder'); var self = this;
this.connection.sendIQ(init, var sendJingle = function (ssrc) {
function () { if(!ssrc)
//console.log('session initiate ack'); ssrc = {};
var ack = {}; self.localSDP.toJingle(init, self.initiator == self.me ? 'initiator' : 'responder', ssrc);
ack.source = 'offer'; self.connection.sendIQ(init,
$(document).trigger('ack.jingle', [self.sid, ack]); function () {
}, //console.log('session initiate ack');
function (stanza) { var ack = {};
self.state = 'error'; ack.source = 'offer';
self.peerconnection.close(); $(document).trigger('ack.jingle', [self.sid, ack]);
var error = ($(stanza).find('error').length) ? { },
code: $(stanza).find('error').attr('code'), function (stanza) {
reason: $(stanza).find('error :first')[0].tagName, self.state = 'error';
}:{}; self.peerconnection.close();
error.source = 'offer'; var error = ($(stanza).find('error').length) ? {
$(document).trigger('error.jingle', [self.sid, error]); code: $(stanza).find('error').attr('code'),
}, reason: $(stanza).find('error :first')[0].tagName,
10000); }:{};
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; this.lasticecandidate = true;
console.log('Have we encountered any srflx candidates? ' + this.hadstuncandidate); console.log('Have we encountered any srflx candidates? ' + this.hadstuncandidate);
@ -345,7 +366,7 @@ JingleSession.prototype.createdOffer = function (sdp) {
action: 'session-initiate', action: 'session-initiate',
initiator: this.initiator, initiator: this.initiator,
sid: this.sid}); 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, this.connection.sendIQ(init,
function () { function () {
var ack = {}; var ack = {};

View File

@ -89,7 +89,8 @@ SessionBase.prototype.switchStreams = function (new_stream, oldStream, success_c
self.connection.jingle.localVideo = new_stream; self.connection.jingle.localVideo = new_stream;
self.connection.jingle.localStreams = []; 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); self.connection.jingle.localStreams.push(self.connection.jingle.localVideo);
// Conference is not active // Conference is not active

View File

@ -174,6 +174,8 @@ StatsCollector.prototype.start = function ()
self.peerconnection.getStats( self.peerconnection.getStats(
function (report) function (report)
{ {
if(!report || !report.result || typeof report.result != 'function')
return;
var results = report.result(); var results = report.result();
//console.error("Got interval report", results); //console.error("Got interval report", results);
self.currentAudioLevelsReport = results; self.currentAudioLevelsReport = results;
@ -193,6 +195,8 @@ StatsCollector.prototype.start = function ()
self.peerconnection.getStats( self.peerconnection.getStats(
function (report) function (report)
{ {
if(!report || !report.result || typeof report.result != 'function')
return;
var results = report.result(); var results = report.result();
//console.error("Got interval report", results); //console.error("Got interval report", results);
self.currentStatsReport = results; self.currentStatsReport = results;

View File

@ -10,10 +10,13 @@ var VideoLayout = (function (my) {
my.changeLocalAudio = function(stream) { my.changeLocalAudio = function(stream) {
connection.jingle.localAudio = 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) { my.changeLocalVideo = function(stream, flipX) {