Commit b5e771e9 authored by Dele Olajide's avatar Dele Olajide Committed by dele

Jitsi Videobridge - Fixed broken screen share

git-svn-id: http://svn.igniterealtime.org/svn/repos/openfire/trunk@14005 b35dd754-fafc-0310-a699-88a17e54d16e
parent 93daa5f9
......@@ -10,7 +10,8 @@
<script src="js/base64.js"></script>
<script src="js/strophe.js"></script>
<script src="js/muc.js"></script>
<script src="js/webrtc.sdp.js"></script>
<script src="js/strophe.jingle.sdp.js"></script>
<script src="js/strophe.jingle.sdp.util.js"></script>
<script src="js/strophe-openfire.js"></script>
<script src="js/main.js"></script>
<script src="js/util.js"></script>
......
......@@ -4,6 +4,7 @@ var nickname = null;
var roomUrl = null;
var sharedKey = '';
var screenShare = false;
var screenToVideo = false;
var pdfShare = null;
var pdfFrame = null;
var pdfPage = "1";
......@@ -129,7 +130,7 @@ $(document).ready(function ()
getConstraints(['audio', 'video'], config.resolution);
$("#screen").removeClass("fa-border");
}
//showToolbar();
showToolbar();
updateRoomUrl(window.location.href);
getUserMedia();
......@@ -399,6 +400,7 @@ function getConstraints(um, resolution, bandwidth, fps)
if (um.indexOf('audio') >= 0) {
window.RTC.rayo.constraints.audio = {};// same behaviour as true
}
if (um.indexOf('screen') >= 0) {
window.RTC.rayo.constraints.video = {
"mandatory": {
......@@ -408,7 +410,8 @@ function getConstraints(um, resolution, bandwidth, fps)
"maxFrameRate": "3"
}
};
}
} else
if (resolution && window.RTC.rayo.constraints.video)
{
......@@ -542,10 +545,11 @@ function resizeLarge()
function getAvailableVideoWidth()
{
var chatspaceWidth = $('#chatspace').is(":visible") ? $('#chatspace').width() : 0;
var chatspaceWidth = $('#chatspace').css("opacity") == 1 ? $('#chatspace').width() : 0;
return window.innerWidth - chatspaceWidth;
};
function resizeThumbnails()
{
// Calculate the available height, which is the inner window height minus
......@@ -655,14 +659,13 @@ function doJoin() {
$('#nickname').css({visibility:"hidden"});
$('#ofmeet').css({visibility:'visible'});
$('#usermsg').css({visibility:'visible'});
openChat();
}
}
function rayoCallback(presence)
{
console.log("rayoCallback", presence);
console.log("rayoCallback start", presence);
var from = $(presence).attr('from');
......@@ -692,6 +695,8 @@ function rayoCallback(presence)
$("#invite").removeClass("fa-spin");
});
console.log("rayoCallback end", presence);
return true;
};
......@@ -707,31 +712,32 @@ function removeSSRC(from, removesource)
$(removesource).find('content').each(function()
{
var name = $(this).attr('name');
var name = $(this).attr('name');
var ssrc = null;
$(this).find('source').each(function()
{
{
ssrc = $(this).attr('ssrc');
});
if (ssrc != null)
{
var idx = (name == "audio" ? 0 : 1);
sdp.removeMediaLines(idx, 'a=ssrc:' + ssrc);
{
var idx = (name == "audio" ? 0 : 1);
if (!screenToVideo) sdp.removeMediaLines(idx, 'a=ssrc:' + ssrc);
}
});
});
sdp.raw = sdp.session + sdp.media.join('');
//console.log("removeSSRC modified SDP", sdp.raw);
window.RTC.rayo.pc[videobridge].setRemoteDescription(new RTCSessionDescription({type: 'offer', sdp: sdp.raw}
), function() {
), function() {
console.log('removeSSRC modify ok');
}, function(error) {
console.log('removeSSRC modify failed');
});
};
......@@ -791,9 +797,9 @@ function handleOffer (from, offer)
{
console.log("handleOffer", offer);
//var bridgeSDP = new SDP('v=0\r\no=- 5151055458874951233 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\nm=audio 1 RTP/SAVPF 111 0 126\r\nc=IN IP4 0.0.0.0\r\na=rtcp:1 IN IP4 0.0.0.0\r\na=mid:audio\r\na=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\na=sendrecv\r\na=rtpmap:111 opus/48000/2\r\na=fmtp:111 minptime=10\r\na=rtpmap:0 PCMU/8000\r\na=rtpmap:126 telephone-event/8000\r\na=maxptime:60\r\nm=video 1 RTP/SAVPF 100 116 117\r\nc=IN IP4 0.0.0.0\r\na=rtcp:1 IN IP4 0.0.0.0\r\na=mid:video\r\na=extmap:2 urn:ietf:params:rtp-hdrext:toffset\r\na=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\na=sendrecv\r\na=rtpmap:100 VP8/90000\r\na=rtcp-fb:100 ccm fir\r\na=rtcp-fb:100 nack\r\na=rtcp-fb:100 goog-remb\r\na=rtpmap:116 red/90000\r\na=rtpmap:117 ulpfec/90000\r\n');
//var bridgeSDP = new SDP('v=0\r\no=- 5151055458874951233 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\nm=audio 1 RTP/SAVPF 111 0 126\r\nc=IN IP4 0.0.0.0\r\na=rtcp:1 IN IP4 0.0.0.0\r\na=mid:audio\r\na=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\na=sendrecv\r\na=rtpmap:111 opus/48000/2\r\na=fmtp:111 minptime=10\r\na=rtpmap:0 PCMU/8000\r\na=rtpmap:126 telephone-event/8000\r\na=maxptime:60\r\nm=video 1 RTP/SAVPF 100 116 117\r\nc=IN IP4 0.0.0.0\r\na=rtcp:1 IN IP4 0.0.0.0\r\na=mid:video\r\na=extmap:2 urn:ietf:params:rtp-hdrext:toffset\r\na=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\na=sendrecv\r\na=rtpmap:100 VP8/90000\r\na=rtcp-fb:100 ccm fir\r\na=rtcp-fb:100 nack\r\na=rtcp-fb:100 goog-remb\r\na=rtpmap:116 red/90000\r\na=rtpmap:117 ulpfec/90000\r\n');
var bridgeSDP = new SDP('v=0\r\no=- 5151055458874951233 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\nm=audio 1 RTP/SAVPF 111 0 126\r\nc=IN IP4 0.0.0.0\r\na=rtcp:1 IN IP4 0.0.0.0\r\na=mid:audio\r\na=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\na=sendrecv\r\na=rtpmap:111 opus/48000/2\r\na=fmtp:111 minptime=10\r\na=rtpmap:0 PCMU/8000\r\na=rtpmap:126 telephone-event/8000\r\na=maxptime:60\r\nm=video 1 RTP/SAVPF 100 116 117\r\nc=IN IP4 0.0.0.0\r\na=rtcp:1 IN IP4 0.0.0.0\r\na=mid:video\r\na=extmap:2 urn:ietf:params:rtp-hdrext:toffset\r\na=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\na=sendrecv\r\na=rtpmap:100 VP8/90000\r\na=rtcp-fb:100 ccm fir\r\na=rtcp-fb:100 nack\r\na=rtcp-fb:100 goog-remb\r\n');
var muc = $(offer).attr('muc');
var nick = $(offer).attr('nickname');
var participant = $(offer).attr('participant');
......@@ -1041,13 +1047,22 @@ function registerRayoEvents()
);
}
function unregisterRayoEvents()
{
window.RTC.rayo.localStream.stop();
function unregisterRayoEvents(constraints, resolution)
{
connection.sendIQ($iq({to: connection.domain, type: 'set'}).c('colibri', {xmlns: 'urn:xmpp:rayo:colibri:1', action: 'expire', muc: roomjid}),
function (res) {
console.log('rayo colibri unregister set ok');
window.RTC.rayo.localStream.stop();
if (constraints)
{
setTimeout(function()
{
screenToVideo = false;
getConstraints(constraints, resolution);
getUserMedia();
}, 1000);
}
},
function (err) {
......@@ -1064,16 +1079,14 @@ function toggleScreenShare()
if (screenShare)
{
var screenDIV = document.getElementById("screenshare");
screenDIV.parentElement.removeChild(screenDIV);
screenToVideo = true;
unregisterRayoEvents(['audio', 'video'], config.resolution);
$("#screen").removeClass("fa-border");
} else {
var url = "publish.html?r=" + videobridge + "&screen=true";
$("body").append("<div id='screenshare'><iframe style='display:none' src='" + url + "'></iframe></div>");
unregisterRayoEvents(['screen']);
$("#screen").addClass("fa-border");
}
}
screenShare = !screenShare;
}
......@@ -1315,6 +1328,9 @@ function openChat() {
videospace.animate({right:chatspaceWidth, width:"80%"}, "slow");
}
resizeLarge();
positionLarge();
// Request the focus in the nickname field or the chat input field.
if ($('#nickinput').is(':visible'))
$('#nickinput').focus();
......@@ -1339,7 +1355,7 @@ function hideToolbar()
$('#header').hide("slide", { direction: "up", duration: 300});
}
else {
toolbarTimeout = setTimeout(hideToolbar, 2000);
toolbarTimeout = setTimeout(hideToolbar, 5000);
}
};
......@@ -1353,7 +1369,7 @@ function showToolbar()
clearTimeout(toolbarTimeout);
toolbarTimeout = null;
}
toolbarTimeout = setTimeout(hideToolbar, 2000);
toolbarTimeout = setTimeout(hideToolbar, 5000);
}
}
......@@ -1373,7 +1389,7 @@ function dockToolbar(isDock) {
showToolbar();
}
else {
toolbarTimeout = setTimeout(hideToolbar, 2000);
toolbarTimeout = setTimeout(hideToolbar, 5000);
}
}
}
......
var connection = null;
var roomjid;
var nickname = null;
var roomUrl = null;
var sharedKey = '';
var screenShare = false;
$(document).ready(function ()
{
var storedDisplayName = window.localStorage.displayname;
if (storedDisplayName) {
nickname = unescape(storedDisplayName);
}
window.RTC = setupRTC();
if (window.RTC === null) {
return;
} else if (window.RTC.browser != 'chrome') {
return;
}
RTCPeerconnection = RTC.peerconnection;
if (config.useWebsockets)
connection = new Openfire.Connection(config.bosh);
else
connection = new Strophe.Connection(config.bosh);
connection.resource = Math.random().toString(36).substr(2, 20);
/*
connection.rawInput = function (data) { console.log('RECV: ' + data); };
connection.rawOutput = function (data) { console.log('SEND: ' + data); };
*/
var jid = config.hosts.domain;
connection.connect(jid, null, function (status)
{
if (status == Strophe.Status.CONNECTED)
{
console.log('connected');
connection.send($pres());
doJoin();
getConstraints(['screen']);
getUserMedia();
} else {
console.log('status', status);
}
});
});
$(window).bind('beforeunload', function ()
{
if (connection && connection.connected) {
unregisterRayoEvents();
connection.disconnect();
}
});
$(document).bind('mediaready.rayo', function(event, stream)
{
console.log("mediaready.rayo");
window.RTC.rayo.localStream = stream;
registerRayoEvents();
});
$(document).bind('mediafailure.rayo', function(error) {
console.error('mediafailure.rayo ' + error);
});
function setupRTC()
{
var RTC = null;
if (navigator.mozGetUserMedia) {
console.log('This appears to be Firefox');
var version = parseInt(navigator.userAgent.match(/Firefox\/([0-9]+)\./)[1], 10);
if (version >= 22) {
RTC = {
rayo: {
channels: {},
confid: {},
pc: {},
addssrc: {},
localStream: null,
constraints: {audio: false, video: false}
},
peerconnection: mozRTCPeerConnection,
browser: 'firefox',
getUserMedia: navigator.mozGetUserMedia.bind(navigator),
attachMediaStream: function (element, stream) {
element[0].mozSrcObject = stream;
element[0].play();
},
pc_constraints: {}
};
if (!MediaStream.prototype.getVideoTracks)
MediaStream.prototype.getVideoTracks = function () { return []; };
if (!MediaStream.prototype.getAudioTracks)
MediaStream.prototype.getAudioTracks = function () { return []; };
RTCSessionDescription = mozRTCSessionDescription;
RTCIceCandidate = mozRTCIceCandidate;
}
} else if (navigator.webkitGetUserMedia) {
console.log('This appears to be Chrome');
RTC = {
rayo: {
channels: {},
confid: {},
pc: {},
addssrc: {},
localStream: null,
constraints: {audio: false, video: false}
},
peerconnection: webkitRTCPeerConnection,
browser: 'chrome',
getUserMedia: navigator.webkitGetUserMedia.bind(navigator),
attachMediaStream: function (element, stream) {
element.attr('src', webkitURL.createObjectURL(stream));
},
pc_constraints: {'optional': [{'DtlsSrtpKeyAgreement': 'true'}]} // enable dtls support in canary
};
if (navigator.userAgent.indexOf('Android') != -1) {
RTC.pc_constraints = {}; // disable DTLS on Android
}
if (!webkitMediaStream.prototype.getVideoTracks) {
webkitMediaStream.prototype.getVideoTracks = function () {
return this.videoTracks;
};
}
if (!webkitMediaStream.prototype.getAudioTracks) {
webkitMediaStream.prototype.getAudioTracks = function () {
return this.audioTracks;
};
}
}
if (RTC === null) {
try { console.log('Browser does not appear to be WebRTC-capable'); } catch (e) { }
}
return RTC;
}
function getUserMedia()
{
console.log("getUserMedia", window.RTC.rayo.constraints);
try {
window.RTC.getUserMedia(window.RTC.rayo.constraints,
function (stream) {
console.log('onUserMediaSuccess');
$(document).trigger('mediaready.rayo', [stream]);
},
function (error) {
console.warn('Failed to get access to local media. Error ', error);
$(document).trigger('mediafailure.rayo');
});
} catch (e) {
console.error('GUM failed: ', e);
$(document).trigger('mediafailure.rayo');
}
};
function getConstraints(um, resolution, bandwidth, fps)
{
console.log("getConstraints", um, resolution, bandwidth, fps);
window.RTC.rayo.constraints = {audio: false, video: false};
if (um.indexOf('video') >= 0) {
window.RTC.rayo.constraints.video = {mandatory: {}};// same behaviour as true
}
if (um.indexOf('audio') >= 0) {
window.RTC.rayo.constraints.audio = {};// same behaviour as true
}
if (um.indexOf('screen') >= 0) {
window.RTC.rayo.constraints.video = {
"mandatory": {
"chromeMediaSource": "screen",
"maxWidth": window.screen.width,
"maxHeight": window.screen.height,
"maxFrameRate": "3"
}
};
}
if (resolution && window.RTC.rayo.constraints.video)
{
window.RTC.rayo.constraints.video = {mandatory: {}};// same behaviour as true
// see https://code.google.com/p/chromium/issues/detail?id=143631#c9 for list of supported resolutions
switch (resolution) {
// 16:9 first
case '1080':
case 'fullhd':
window.RTC.rayo.constraints.video.mandatory.minWidth = 1920;
window.RTC.rayo.constraints.video.mandatory.minHeight = 1080;
window.RTC.rayo.constraints.video.mandatory.minAspectRatio = 1.77;
break;
case '720':
case 'hd':
window.RTC.rayo.constraints.video.mandatory.minWidth = 1280;
window.RTC.rayo.constraints.video.mandatory.minHeight = 720;
window.RTC.rayo.constraints.video.mandatory.minAspectRatio = 1.77;
break;
case '360':
window.RTC.rayo.constraints.video.mandatory.minWidth = 640;
window.RTC.rayo.constraints.video.mandatory.minHeight = 360;
window.RTC.rayo.constraints.video.mandatory.minAspectRatio = 1.77;
break;
case '180':
window.RTC.rayo.constraints.video.mandatory.minWidth = 320;
window.RTC.rayo.constraints.video.mandatory.minHeight = 180;
window.RTC.rayo.constraints.video.mandatory.minAspectRatio = 1.77;
break;
// 4:3
case '960':
window.RTC.rayo.constraints.video.mandatory.minWidth = 960;
window.RTC.rayo.constraints.video.mandatory.minHeight = 720;
break;
case '640':
case 'vga':
window.RTC.rayo.constraints.video.mandatory.minWidth = 640;
window.RTC.rayo.constraints.video.mandatory.minHeight = 480;
break;
case '320':
window.RTC.rayo.constraints.video.mandatory.minWidth = 320;
window.RTC.rayo.constraints.video.mandatory.minHeight = 240;
break;
default:
if (navigator.userAgent.indexOf('Android') != -1) {
window.RTC.rayo.constraints.video.mandatory.minWidth = 320;
window.RTC.rayo.constraints.video.mandatory.minHeight = 240;
window.RTC.rayo.constraints.video.mandatory.maxFrameRate = 15;
}
break;
}
}
if (bandwidth) { // doesn't work currently, see webrtc issue 1846
if (!window.RTC.rayo.constraints.video) window.RTC.rayo.constraints.video = {mandatory: {}};//same behaviour as true
window.RTC.rayo.constraints.video.optional = [{bandwidth: bandwidth}];
}
if (fps) { // for some cameras it might be necessary to request 30fps
// so they choose 30fps mjpg over 10fps yuy2
if (!window.RTC.rayo.constraints.video) window.RTC.rayo.constraints.video = {mandatory: {}};// same behaviour as tru;
window.RTC.rayo.constraints.video.mandatory.minFrameRate = fps;
}
}
function urlParam(name)
{
var results = new RegExp('[\\?&]' + name + '=([^&#]*)').exec(window.location.href);
if (!results) { return undefined; }
return results[1] || undefined;
}
function doJoin() {
var roomnode = urlParam("r");
if (urlParam("n"))
{
nickname = unescape(urlParam("n"));
}
console.log("doJoin", roomnode);
if (!roomnode) {
roomnode = Math.random().toString(36).substr(2, 20);
window.history.pushState('VideoChat', 'Room: ' + roomnode, window.location.pathname + "?r=" + roomnode);
}
roomjid = roomnode + '@' + config.hosts.muc;
var myroomjid = roomjid;
if (!nickname) nickname = Strophe.getNodeFromJid(connection.jid);
myroomjid += '/' + nickname + "(Desktop)";
connection.addHandler(rayoCallback, 'urn:xmpp:rayo:colibri:1');
connection.emuc.doJoin(myroomjid);
}
function rayoCallback(presence)
{
console.log("rayoCallback", presence);
var from = $(presence).attr('from');
$(presence).find('offer').each(function()
{
handleOffer(from, this);
});
return true;
};
function handleOffer (from, offer)
{
console.log("handleOffer", offer);
var bridgeSDP = new SDP('v=0\r\no=- 5151055458874951233 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\nm=audio 1 RTP/SAVPF 111 0 126\r\nc=IN IP4 0.0.0.0\r\na=rtcp:1 IN IP4 0.0.0.0\r\na=mid:audio\r\na=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\na=sendrecv\r\na=rtpmap:111 opus/48000/2\r\na=fmtp:111 minptime=10\r\na=rtpmap:0 PCMU/8000\r\na=rtpmap:126 telephone-event/8000\r\na=maxptime:60\r\nm=video 1 RTP/SAVPF 100 116 117\r\nc=IN IP4 0.0.0.0\r\na=rtcp:1 IN IP4 0.0.0.0\r\na=mid:video\r\na=extmap:2 urn:ietf:params:rtp-hdrext:toffset\r\na=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\na=sendrecv\r\na=rtpmap:100 VP8/90000\r\na=rtcp-fb:100 ccm fir\r\na=rtcp-fb:100 nack\r\na=rtcp-fb:100 goog-remb\r\na=rtpmap:116 red/90000\r\na=rtpmap:117 ulpfec/90000\r\n');
var muc = $(offer).attr('muc');
var nick = $(offer).attr('nickname');
var participant = $(offer).attr('participant');
var videobridge = $(offer).attr('videobridge');
var confid = null;
var channelId = [];
window.RTC.rayo.channels = {}
window.RTC.rayo.addssrc = false;
$(offer).find('conference').each(function()
{
confid = $(this).attr('id');
window.RTC.rayo.channels.id = confid;
$(this).find('content').each(function()
{
var name = $(this).attr('name');
var channel = name == "audio" ? 0 : 1;
if ((window.RTC.rayo.localStream.getVideoTracks().length > 0 && name == "video") || (window.RTC.rayo.localStream.getAudioTracks().length > 0 && name == "audio"))
{
console.log("handleOffer track", name);
$(this).find('channel').each(function()
{
channelId[channel] = $(this).attr('id');
$(this).find('source').each(function()
{
var ssrc = $(this).attr('ssrc');
if (ssrc)
{
bridgeSDP.media[channel] += 'a=ssrc:' + ssrc + ' ' + 'cname:mixed' + '\r\n';
bridgeSDP.media[channel] += 'a=ssrc:' + ssrc + ' ' + 'label:mixedlabela0' + '\r\n';
bridgeSDP.media[channel] += 'a=ssrc:' + ssrc + ' ' + 'msid:mixedmslabela0 mixedlabela0' + '\r\n';
bridgeSDP.media[channel] += 'a=ssrc:' + ssrc + ' ' + 'mslabel:mixedmslabela0' + '\r\n';
} else {
// make chrome happy... '3735928559' == 0xDEADBEEF
bridgeSDP.media[channel] += 'a=ssrc:' + '3735928559' + ' ' + 'cname:mixed' + '\r\n';
bridgeSDP.media[channel] += 'a=ssrc:' + '3735928559' + ' ' + 'label:mixedlabelv0' + '\r\n';
bridgeSDP.media[channel] += 'a=ssrc:' + '3735928559' + ' ' + 'msid:mixedmslabelv0 mixedlabelv0' + '\r\n';
bridgeSDP.media[channel] += 'a=ssrc:' + '3735928559' + ' ' + 'mslabel:mixedmslabelv0' + '\r\n';
}
});
$(this).find('transport').each(function()
{
var pwd = $(this).attr('pwd');
var ufrag = $(this).attr('ufrag');
if (ufrag) bridgeSDP.media[channel] += 'a=ice-ufrag:' + ufrag + '\r\n';
if (pwd) bridgeSDP.media[channel] += 'a=ice-pwd:' + pwd + '\r\n';
$(this).find('candidate').each(function()
{
bridgeSDP.media[channel] += SDPUtil.candidateFromJingle(this);
});
$(this).find('fingerprint').each(function()
{
var hash = $(this).attr('hash');
var setup = $(this).attr('setup');
var fingerprint = $(this).text();
if (hash && fingerprint) bridgeSDP.media[channel] += 'a=fingerprint:' + hash + ' ' + fingerprint + '\r\n';
if (setup) bridgeSDP.media[channel] += 'a=setup:' + setup + '\r\n';
});
});
});
} else {
bridgeSDP.media[channel] = null;
}
});
});
bridgeSDP.raw = bridgeSDP.session + bridgeSDP.media.join('');
window.RTC.rayo.channels.sdp = bridgeSDP.raw;
//console.log("bridgeSDP.raw", bridgeSDP.raw);
window.RTC.rayo.pc[videobridge] = new window.RTC.peerconnection(null, {'optional': [{'DtlsSrtpKeyAgreement': 'true'}]});
window.RTC.rayo.pc[videobridge].onicecandidate = function(event)
{
//console.log('candidate', event.candidate);
if (!event.candidate)
{
sendAnswer(from, videobridge, confid, channelId);
}
}
window.RTC.rayo.pc[videobridge].onaddstream = function(e)
{
console.log("onstream", e, window.RTC.rayo.addssrc);
if (window.RTC.rayo.pc[videobridge].signalingState == "have-remote-offer")
$(document).trigger('remotestreamadded.rayo', [e, nick]);
window.RTC.rayo.pc[videobridge].createAnswer(function(desc)
{
if (!window.RTC.rayo.addssrc)
window.RTC.rayo.pc[videobridge].setLocalDescription(desc);
});
};
window.RTC.rayo.pc[videobridge].addStream(window.RTC.rayo.localStream);
window.RTC.rayo.pc[videobridge].setRemoteDescription(new RTCSessionDescription({type: "offer", sdp : bridgeSDP.raw}));
};
function sendAnswer(from, videobridge, confid, channelId)
{
console.log("sendAnswer");
var remoteSDP = new SDP(window.RTC.rayo.pc[videobridge].localDescription.sdp);
//console.log("remoteSDP ", window.RTC.rayo.pc[videobridge].localDescription.sdp);
var change = $iq({to: from, type: 'set'});
change.c('colibri', {xmlns: 'urn:xmpp:rayo:colibri:1', videobridge: videobridge});
change.c('conference', {xmlns: 'http://jitsi.org/protocol/colibri', id: confid});
for (channel = 0; channel < 2; channel++)
{
if (remoteSDP.media[channel])
{
change.c('content', {name: remoteSDP.media[channel].indexOf('m=audio') > -1 ? 'audio' : 'video'});
change.c('channel', {id: remoteSDP.media[channel].indexOf('m=audio') > -1 ? channelId[0] : channelId[1]});
tmp = SDPUtil.find_lines(remoteSDP.media[channel], 'a=ssrc:');
change.c('source', { xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0' });
tmp.forEach(function (line) {
var idx = line.indexOf(' ');
var linessrc = line.substr(0, idx).substr(7);
change.attrs({ssrc: linessrc});
var kv = line.substr(idx + 1);
change.c('parameter');
if (kv.indexOf(':') == -1) {
change.attrs({ name: kv });
} else {
change.attrs({ name: kv.split(':', 2)[0] });
change.attrs({ value: kv.split(':', 2)[1] });
}
change.up();
});
change.up(); // end of source
var rtpmap = SDPUtil.find_lines(remoteSDP.media[channel], 'a=rtpmap:');
rtpmap.forEach(function (val) {
var rtpmap = SDPUtil.parse_rtpmap(val);
change.c('payload-type', rtpmap);
change.up();
});
change.c('transport', {xmlns: 'urn:xmpp:jingle:transports:ice-udp:1'});
var fingerprints = SDPUtil.find_lines(remoteSDP.media[channel], 'a=fingerprint:', remoteSDP.session);
fingerprints.forEach(function (line)
{
var tmp = SDPUtil.parse_fingerprint(line);
tmp.xmlns = 'urn:xmpp:jingle:apps:dtls:0';
change.c('fingerprint').t(tmp.fingerprint);
delete tmp.fingerprint;
var line = SDPUtil.find_line(remoteSDP.media[channel], 'a=setup:', remoteSDP.session);
if (line) {
tmp.setup = line.substr(8);
}
change.attrs(tmp);
change.up();
});
var candidates = SDPUtil.find_lines(remoteSDP.media[channel], 'a=candidate:', remoteSDP.session);
candidates.forEach(function (line) {
var tmp = SDPUtil.candidateToJingle(line);
change.c('candidate', tmp).up();
});
tmp = SDPUtil.iceparams(remoteSDP.media[channel], remoteSDP.session);
if (tmp) {
change.attrs(tmp);
}
change.up(); // end of transport
change.up(); // end of channel
change.up(); // end of content
}
}
connection.sendIQ(change,
function (res) {
console.log('rayo colibri answer set ok', window.RTC.rayo.pc[videobridge].signalingState);
},
function (err) {
console.log('rayo colibri answer got error ' + err);
}
);
};
function registerRayoEvents()
{
connection.sendIQ($iq({to: connection.domain, type: 'set'}).c('colibri', {xmlns: 'urn:xmpp:rayo:colibri:1', action: 'offer', muc: roomjid}),
function (res) {
console.log('rayo colibri register set ok');
},
function (err) {
console.log('rayo colibri register got error', err);
}
);
}
function unregisterRayoEvents()
{
window.RTC.rayo.localStream.stop();
connection.sendIQ($iq({to: connection.domain, type: 'set'}).c('colibri', {xmlns: 'urn:xmpp:rayo:colibri:1', action: 'expire', muc: roomjid}),
function (res) {
console.log('rayo colibri unregister set ok');
},
function (err) {
console.log('rayo colibri unregister got error', err);
}
);
}
/* jshint -W117 */
// SDP STUFF
function SDP(sdp) {
this.media = sdp.split('\r\nm=');
for (var i = 1; i < this.media.length; i++) {
......@@ -10,7 +11,75 @@ function SDP(sdp) {
this.session = this.media.shift() + '\r\n';
this.raw = this.session + this.media.join('');
}
/**
* Returns map of MediaChannel mapped per channel idx.
*/
SDP.prototype.getMediaSsrcMap = function() {
var self = this;
var media_ssrcs = {};
for (channelNum = 0; channelNum < self.media.length; channelNum++) {
modified = true;
tmp = SDPUtil.find_lines(self.media[channelNum], 'a=ssrc:');
var type = SDPUtil.parse_mid(SDPUtil.find_line(self.media[channelNum], 'a=mid:'));
var channel = new MediaChannel(channelNum, type);
media_ssrcs[channelNum] = channel;
tmp.forEach(function (line) {
var linessrc = line.substring(7).split(' ')[0];
// allocate new ChannelSsrc
if(!channel.ssrcs[linessrc]) {
channel.ssrcs[linessrc] = new ChannelSsrc(linessrc, type);
}
channel.ssrcs[linessrc].lines.push(line);
});
}
return media_ssrcs;
}
/**
* Returns <tt>true</tt> if this SDP contains given SSRC.
* @param ssrc the ssrc to check.
* @returns {boolean} <tt>true</tt> if this SDP contains given SSRC.
*/
SDP.prototype.containsSSRC = function(ssrc) {
var channels = this.getMediaSsrcMap();
var contains = false;
Object.keys(channels).forEach(function(chNumber){
var channel = channels[chNumber];
//console.log("Check", channel, ssrc);
if(Object.keys(channel.ssrcs).indexOf(ssrc) != -1){
contains = true;
}
});
return contains;
}
/**
* Returns map of MediaChannel that contains only media not contained in <tt>otherSdp</tt>. Mapped by channel idx.
* @param otherSdp the other SDP to check ssrc with.
*/
SDP.prototype.getNewMedia = function(otherSdp) {
var myMedia = this.getMediaSsrcMap();
var othersMedia = otherSdp.getMediaSsrcMap();
var newMedia = {};
Object.keys(othersMedia).forEach(function(channelNum) {
var myChannel = myMedia[channelNum];
var othersChannel = othersMedia[channelNum];
if(!myChannel && othersChannel) {
// Add whole channel
newMedia[channelNum] = othersChannel;
return;
}
// Look for new ssrcs accross the channel
Object.keys(othersChannel.ssrcs).forEach(function(ssrc) {
if(Object.keys(myChannel.ssrcs).indexOf(ssrc) === -1) {
// Allocate channel if we've found ssrc that doesn't exist in our channel
if(!newMedia[channelNum]){
newMedia[channelNum] = new MediaChannel(othersChannel.chNumber, othersChannel.mediaType);
}
newMedia[channelNum].ssrcs[ssrc] = othersChannel.ssrcs[ssrc];
}
})
});
return newMedia;
}
// remove iSAC and CN from SDP
SDP.prototype.mangle = function () {
var i, j, mline, lines, rtpmap, newdesc;
......@@ -41,10 +110,10 @@ SDP.prototype.mangle = function () {
// remove lines matching prefix from session section
SDP.prototype.removeSessionLines = function(prefix) {
var ob = this;
var self = this;
var lines = SDPUtil.find_lines(this.session, prefix);
lines.forEach(function(line) {
ob.session = ob.session.replace(line + '\r\n', '');
self.session = self.session.replace(line + '\r\n', '');
});
this.raw = this.session + this.media.join('');
return lines;
......@@ -52,10 +121,10 @@ SDP.prototype.removeSessionLines = function(prefix) {
// remove lines matching prefix from a media section specified by mediaindex
// TODO: non-numeric mediaindex could match mid
SDP.prototype.removeMediaLines = function(mediaindex, prefix) {
var ob = this;
var self = this;
var lines = SDPUtil.find_lines(this.media[mediaindex], prefix);
lines.forEach(function(line) {
ob.media[mediaindex] = ob.media[mediaindex].replace(line + '\r\n', '');
self.media[mediaindex] = self.media[mediaindex].replace(line + '\r\n', '');
});
this.raw = this.session + this.media.join('');
return lines;
......@@ -64,22 +133,14 @@ SDP.prototype.removeMediaLines = function(mediaindex, prefix) {
// add content's to a jingle element
SDP.prototype.toJingle = function (elem, thecreator) {
var i, j, k, mline, ssrc, rtpmap, tmp, line, lines;
var ob = this;
var self = this;
// new bundle plan
if (SDPUtil.find_line(this.session, 'a=group:')) {
lines = SDPUtil.find_lines(this.session, 'a=group:');
for (i = 0; i < lines.length; i++) {
tmp = lines[i].split(' ');
var semantics = tmp.shift().substr(8);
// new plan
elem.c('group', {xmlns: 'urn:xmpp:jingle:apps:grouping:0', type: semantics, semantics:semantics});
for (j = 0; j < tmp.length; j++) {
elem.c('content', {name: tmp[j]}).up();
}
elem.up();
// temporary plan, to be removed
elem.c('group', {xmlns: 'urn:ietf:rfc:5888', type: semantics});
elem.c('group', {xmlns: 'urn:xmpp:jingle:apps:grouping:0', semantics:semantics});
for (j = 0; j < tmp.length; j++) {
elem.c('content', {name: tmp[j]}).up();
}
......@@ -117,8 +178,8 @@ SDP.prototype.toJingle = function (elem, thecreator) {
}
if (SDPUtil.find_line(this.media[i], 'a=rtpmap:').length) {
elem.c('description',
{xmlns: 'urn:xmpp:jingle:apps:rtp:1',
media: mline.media });
{xmlns: 'urn:xmpp:jingle:apps:rtp:1',
media: mline.media });
if (ssrc) {
elem.attrs({ssrc: ssrc});
}
......@@ -132,7 +193,7 @@ SDP.prototype.toJingle = function (elem, thecreator) {
elem.c('parameter', tmp[k]).up();
}
}
this.RtcpFbToJingle(this.media[i], elem, mline.fmt[j]); // XEP-0293 -- map a=rtcp-fb
this.RtcpFbToJingle(i, elem, mline.fmt[j]); // XEP-0293 -- map a=rtcp-fb
elem.up();
}
......@@ -182,7 +243,7 @@ SDP.prototype.toJingle = function (elem, thecreator) {
}
// XEP-0293 -- map a=rtcp-fb:*
this.RtcpFbToJingle(this.media[i], elem, '*');
this.RtcpFbToJingle(i, elem, '*');
// XEP-0294
if (SDPUtil.find_line(this.media[i], 'a=extmap:')) {
......@@ -190,22 +251,22 @@ SDP.prototype.toJingle = function (elem, thecreator) {
for (j = 0; j < lines.length; j++) {
tmp = SDPUtil.parse_extmap(lines[j]);
elem.c('rtp-hdrext', { xmlns: 'urn:xmpp:jingle:apps:rtp:rtp-hdrext:0',
uri: tmp.uri,
id: tmp.value });
uri: tmp.uri,
id: tmp.value });
if (tmp.hasOwnProperty('direction')) {
switch (tmp.direction) {
case 'sendonly':
elem.attrs({senders: 'responder'});
break;
case 'recvonly':
elem.attrs({senders: 'initiator'});
break;
case 'sendrecv':
elem.attrs({senders: 'both'});
break;
case 'inactive':
elem.attrs({senders: 'none'});
break;
case 'sendonly':
elem.attrs({senders: 'responder'});
break;
case 'recvonly':
elem.attrs({senders: 'initiator'});
break;
case 'sendrecv':
elem.attrs({senders: 'both'});
break;
case 'inactive':
elem.attrs({senders: 'none'});
break;
}
}
// TODO: handle params
......@@ -215,35 +276,8 @@ SDP.prototype.toJingle = function (elem, thecreator) {
elem.up(); // end of description
}
elem.c('transport', {xmlns: 'urn:xmpp:jingle:transports:ice-udp:1'});
// XEP-0320
var fingerprints = SDPUtil.find_lines(this.media[i], 'a=fingerprint:', this.session);
fingerprints.forEach(function(line) {
tmp = SDPUtil.parse_fingerprint(line);
tmp.xmlns = 'urn:xmpp:tmp:jingle:apps:dtls:0';
// tmp.xmlns = 'urn:xmpp:jingle:apps:dtls:0'; -- FIXME: update receivers first
elem.c('fingerprint').t(tmp.fingerprint);
delete tmp.fingerprint;
line = SDPUtil.find_line(ob.media[i], 'a=setup:', ob.session);
if (line) {
tmp.setup = line.substr(8);
}
elem.attrs(tmp);
elem.up();
});
tmp = SDPUtil.iceparams(this.media[i], this.session);
if (tmp) {
elem.attrs(tmp);
// XEP-0176
if (SDPUtil.find_line(this.media[i], 'a=candidate:', this.session)) { // add any a=candidate lines
lines = SDPUtil.find_lines(this.media[i], 'a=candidate:', this.session);
for (j = 0; j < lines.length; j++) {
tmp = SDPUtil.candidateToJingle(lines[j]);
elem.c('candidate', tmp).up();
}
}
elem.up(); // end of transport
}
// map ice-ufrag/pwd, dtls fingerprint, candidates
this.TransportToJingle(i, elem);
if (SDPUtil.find_line(this.media[i], 'a=sendrecv', this.session)) {
elem.attrs({senders: 'both'});
......@@ -264,10 +298,46 @@ SDP.prototype.toJingle = function (elem, thecreator) {
return elem;
};
SDP.prototype.RtcpFbToJingle = function (sdp, elem, payloadtype) { // XEP-0293
var lines = SDPUtil.find_lines(sdp, 'a=rtcp-fb:' + payloadtype);
for (var i = 0; i < lines.length; i++) {
var tmp = SDPUtil.parse_rtcpfb(lines[i]);
SDP.prototype.TransportToJingle = function (mediaindex, elem) {
var i = mediaindex;
var tmp;
var self = this;
elem.c('transport');
// XEP-0320
var fingerprints = SDPUtil.find_lines(this.media[mediaindex], 'a=fingerprint:', this.session);
fingerprints.forEach(function(line) {
tmp = SDPUtil.parse_fingerprint(line);
tmp.xmlns = 'urn:xmpp:tmp:jingle:apps:dtls:0';
// tmp.xmlns = 'urn:xmpp:jingle:apps:dtls:0'; -- FIXME: update receivers first
elem.c('fingerprint').t(tmp.fingerprint);
delete tmp.fingerprint;
line = SDPUtil.find_line(self.media[mediaindex], 'a=setup:', self.session);
if (line) {
tmp.setup = line.substr(8);
}
elem.attrs(tmp);
elem.up(); // end of fingerprint
});
tmp = SDPUtil.iceparams(this.media[mediaindex], this.session);
if (tmp) {
tmp.xmlns = 'urn:xmpp:jingle:transports:ice-udp:1';
elem.attrs(tmp);
// XEP-0176
if (SDPUtil.find_line(this.media[mediaindex], 'a=candidate:', this.session)) { // add any a=candidate lines
var lines = SDPUtil.find_lines(this.media[mediaindex], 'a=candidate:', this.session);
lines.forEach(function (line) {
elem.c('candidate', SDPUtil.candidateToJingle(line)).up();
});
}
}
elem.up(); // end of transport
}
SDP.prototype.RtcpFbToJingle = function (mediaindex, elem, payloadtype) { // XEP-0293
var lines = SDPUtil.find_lines(this.media[mediaindex], 'a=rtcp-fb:' + payloadtype);
lines.forEach(function (line) {
var tmp = SDPUtil.parse_rtcpfb(line);
if (tmp.type == 'trr-int') {
elem.c('rtcp-fb-trr-int', {xmlns: 'urn:xmpp:jingle:apps:rtp:rtcp-fb:0', value: tmp.params[0]});
elem.up();
......@@ -278,7 +348,7 @@ SDP.prototype.RtcpFbToJingle = function (sdp, elem, payloadtype) { // XEP-0293
}
elem.up();
}
}
});
};
SDP.prototype.RtcpFbFromJingle = function (elem, payloadtype) { // XEP-0293
......@@ -306,31 +376,29 @@ SDP.prototype.RtcpFbFromJingle = function (elem, payloadtype) { // XEP-0293
// construct an SDP from a jingle stanza
SDP.prototype.fromJingle = function (jingle) {
var obj = this;
var self = this;
this.raw = 'v=0\r\n' +
'o=- ' + '1923518516' + ' 2 IN IP4 0.0.0.0\r\n' +// FIXME
's=-\r\n' +
't=0 0\r\n';
// http://tools.ietf.org/html/draft-ietf-mmusic-sdp-bundle-negotiation-04#section-8
if ($(jingle).find('>group[xmlns="urn:xmpp:jingle:apps:grouping:0"]').length) {
try {
$(jingle).find('>group[xmlns="urn:xmpp:jingle:apps:grouping:0"]').each(function (idx, group) {
var contents = $(group).find('>content').map(function (idx, content) {
return $(content).attr('name');
return content.getAttribute('name');
}).get();
if (contents.length > 0) {
obj.raw += 'a=group:' + ($(group).attr('semantics') || $(group).attr('type')) + ' ' + contents.join(' ') + '\r\n';
self.raw += 'a=group:' + (group.getAttribute('semantics') || group.getAttribute('type')) + ' ' + contents.join(' ') + '\r\n';
}
});
} catch (e) { console.error(e.toString()); }
} else if ($(jingle).find('>group[xmlns="urn:ietf:rfc:5888"]').length) {
// temporary namespace, not to be used. to be removed soon.
$(jingle).find('>group[xmlns="urn:ietf:rfc:5888"]').each(function (idx, group) {
var contents = $(group).find('>content').map(function (idx, content) {
return $(content).attr('name');
return content.getAttribute('name');
}).get();
if ($(group).attr('type') !== null && contents.length > 0) {
obj.raw += 'a=group:' + $(group).attr('type') + ' ' + contents.join(' ') + '\r\n';
if (group.getAttribute('type') !== null && contents.length > 0) {
self.raw += 'a=group:' + group.getAttribute('type') + ' ' + contents.join(' ') + '\r\n';
}
});
} else {
......@@ -340,8 +408,8 @@ SDP.prototype.fromJingle = function (jingle) {
//elem.c('bundle', {xmlns:'http://estos.de/ns/bundle'});
return $(content).find('>bundle').length > 0;
}).map(function (idx, content) {
return $(content).attr('name');
}).get();
return content.getAttribute('name');
}).get();
if (bundle.length) {
this.raw += 'a=group:BUNDLE ' + bundle.join(' ') + '\r\n';
}
......@@ -349,17 +417,17 @@ SDP.prototype.fromJingle = function (jingle) {
this.session = this.raw;
jingle.find('>content').each(function () {
var m = obj.jingle2media($(this));
obj.media.push(m);
var m = self.jingle2media($(this));
self.media.push(m);
});
// reconstruct msid-semantic -- apparently not necessary
/*
var msid = SDPUtil.parse_ssrc(this.raw);
if (msid.hasOwnProperty('mslabel')) {
this.session += "a=msid-semantic: WMS " + msid.mslabel + "\r\n";
}
*/
var msid = SDPUtil.parse_ssrc(this.raw);
if (msid.hasOwnProperty('mslabel')) {
this.session += "a=msid-semantic: WMS " + msid.mslabel + "\r\n";
}
*/
this.raw = this.session + this.media.join('');
};
......@@ -383,7 +451,7 @@ SDP.prototype.jingle2media = function (content) {
} else {
tmp.proto = 'RTP/AVPF';
}
tmp.fmt = desc.find('payload-type').map(function () { return $(this).attr('id'); }).get();
tmp.fmt = desc.find('payload-type').map(function () { return this.getAttribute('id'); }).get();
media += SDPUtil.build_mline(tmp) + '\r\n';
media += 'c=IN IP4 0.0.0.0\r\n';
media += 'a=rtcp:1 IN IP4 0.0.0.0\r\n';
......@@ -397,27 +465,27 @@ SDP.prototype.jingle2media = function (content) {
}
tmp.find('>fingerprint').each(function () {
// FIXME: check namespace at some point
media += 'a=fingerprint:' + $(this).attr('hash');
media += 'a=fingerprint:' + this.getAttribute('hash');
media += ' ' + $(this).text();
media += '\r\n';
if ($(this).attr('setup')) {
media += 'a=setup:' + $(this).attr('setup') + '\r\n';
if (this.getAttribute('setup')) {
media += 'a=setup:' + this.getAttribute('setup') + '\r\n';
}
});
}
switch (content.attr('senders')) {
case 'initiator':
media += 'a=sendonly\r\n';
break;
case 'responder':
media += 'a=recvonly\r\n';
break;
case 'none':
media += 'a=inactive\r\n';
break;
case 'both':
media += 'a=sendrecv\r\n';
break;
case 'initiator':
media += 'a=sendonly\r\n';
break;
case 'responder':
media += 'a=recvonly\r\n';
break;
case 'none':
media += 'a=inactive\r\n';
break;
case 'both':
media += 'a=sendrecv\r\n';
break;
}
media += 'a=mid:' + content.attr('name') + '\r\n';
......@@ -430,11 +498,11 @@ SDP.prototype.jingle2media = function (content) {
if (desc.find('encryption').length) {
desc.find('encryption>crypto').each(function () {
media += 'a=crypto:' + $(this).attr('tag');
media += ' ' + $(this).attr('crypto-suite');
media += ' ' + $(this).attr('key-params');
if ($(this).attr('session-params')) {
media += ' ' + $(this).attr('session-params');
media += 'a=crypto:' + this.getAttribute('tag');
media += ' ' + this.getAttribute('crypto-suite');
media += ' ' + this.getAttribute('key-params');
if (this.getAttribute('session-params')) {
media += ' ' + this.getAttribute('session-params');
}
media += '\r\n';
});
......@@ -442,12 +510,12 @@ SDP.prototype.jingle2media = function (content) {
desc.find('payload-type').each(function () {
media += SDPUtil.build_rtpmap(this) + '\r\n';
if ($(this).find('>parameter').length) {
media += 'a=fmtp:' + $(this).attr('id') + ' ';
media += $(this).find('parameter').map(function () { return ($(this).attr('name') ? ($(this).attr('name') + '=') : '') + $(this).attr('value'); }).get().join(';');
media += 'a=fmtp:' + this.getAttribute('id') + ' ';
media += $(this).find('parameter').map(function () { return (this.getAttribute('name') ? (this.getAttribute('name') + '=') : '') + this.getAttribute('value'); }).get().join(';');
media += '\r\n';
}
// xep-0293
media += self.RtcpFbFromJingle($(this), $(this).attr('id'));
media += self.RtcpFbFromJingle($(this), this.getAttribute('id'));
});
// xep-0293
......@@ -456,7 +524,7 @@ SDP.prototype.jingle2media = function (content) {
// xep-0294
tmp = desc.find('>rtp-hdrext[xmlns="urn:xmpp:jingle:apps:rtp:rtp-hdrext:0"]');
tmp.each(function () {
media += 'a=extmap:' + $(this).attr('id') + ' ' + $(this).attr('uri') + '\r\n';
media += 'a=extmap:' + this.getAttribute('id') + ' ' + this.getAttribute('uri') + '\r\n';
});
content.find('>transport[xmlns="urn:xmpp:jingle:transports:ice-udp:1"]>candidate').each(function () {
......@@ -465,11 +533,11 @@ SDP.prototype.jingle2media = function (content) {
tmp = content.find('description>source[xmlns="urn:xmpp:jingle:apps:rtp:ssma:0"]');
tmp.each(function () {
var ssrc = $(this).attr('ssrc');
var ssrc = this.getAttribute('ssrc');
$(this).find('>parameter').each(function () {
media += 'a=ssrc:' + ssrc + ' ' + $(this).attr('name');
if ($(this).attr('value') && $(this).attr('value').length)
media += ':' + $(this).attr('value');
media += 'a=ssrc:' + ssrc + ' ' + this.getAttribute('name');
if (this.getAttribute('value') && this.getAttribute('value').length)
media += ':' + this.getAttribute('value');
media += '\r\n';
});
});
......@@ -485,317 +553,4 @@ SDP.prototype.jingle2media = function (content) {
}
}
return media;
};
SDPUtil = {
iceparams: function (mediadesc, sessiondesc) {
var data = null;
if (SDPUtil.find_line(mediadesc, 'a=ice-ufrag:', sessiondesc) &&
SDPUtil.find_line(mediadesc, 'a=ice-pwd:', sessiondesc)) {
data = {
ufrag: SDPUtil.parse_iceufrag(SDPUtil.find_line(mediadesc, 'a=ice-ufrag:', sessiondesc)),
pwd: SDPUtil.parse_icepwd(SDPUtil.find_line(mediadesc, 'a=ice-pwd:', sessiondesc))
};
}
return data;
},
parse_iceufrag: function (line) {
return line.substring(12);
},
build_iceufrag: function (frag) {
return 'a=ice-ufrag:' + frag;
},
parse_icepwd: function (line) {
return line.substring(10);
},
build_icepwd: function (pwd) {
return 'a=ice-pwd:' + pwd;
},
parse_mid: function (line) {
return line.substring(6);
},
parse_mline: function (line) {
var parts = line.substring(2).split(' '),
data = {};
data.media = parts.shift();
data.port = parts.shift();
data.proto = parts.shift();
if (parts[parts.length - 1] === '') { // trailing whitespace
parts.pop();
}
data.fmt = parts;
return data;
},
build_mline: function (mline) {
return 'm=' + mline.media + ' ' + mline.port + ' ' + mline.proto + ' ' + mline.fmt.join(' ');
},
parse_rtpmap: function (line) {
var parts = line.substring(9).split(' '),
data = {};
data.id = parts.shift();
parts = parts[0].split('/');
data.name = parts.shift();
data.clockrate = parts.shift();
data.channels = parts.length ? parts.shift() : '1';
return data;
},
build_rtpmap: function (el) {
var line = 'a=rtpmap:' + el.getAttribute('id') + ' ' + el.getAttribute('name') + '/' + el.getAttribute('clockrate');
if (el.getAttribute('channels') && el.getAttribute('channels') != '1') {
line += '/' + el.getAttribute('channels');
}
return line;
},
parse_crypto: function (line) {
var parts = line.substring(9).split(' '),
data = {};
data.tag = parts.shift();
data['crypto-suite'] = parts.shift();
data['key-params'] = parts.shift();
if (parts.length) {
data['session-params'] = parts.join(' ');
}
return data;
},
parse_fingerprint: function (line) { // RFC 4572
var parts = line.substring(14).split(' '),
data = {};
data.hash = parts.shift();
data.fingerprint = parts.shift();
// TODO assert that fingerprint satisfies 2UHEX *(":" 2UHEX) ?
return data;
},
parse_fmtp: function (line) {
var parts = line.split(' '),
i, key, value,
data = [];
parts.shift();
parts = parts.join(' ').split(';');
for (i = 0; i < parts.length; i++) {
key = parts[i].split('=')[0];
while (key.length && key[0] == ' ') {
key = key.substring(1);
}
value = parts[i].split('=')[1];
if (key && value) {
data.push({name: key, value: value});
} else if (key) {
// rfc 4733 (DTMF) style stuff
data.push({name: '', value: key});
}
}
return data;
},
parse_icecandidate: function (line) {
var candidate = {},
elems = line.split(' ');
candidate.foundation = elems[0].substring(12);
candidate.component = elems[1];
candidate.protocol = elems[2].toLowerCase();
candidate.priority = elems[3];
candidate.ip = elems[4];
candidate.port = elems[5];
// elems[6] => "typ"
candidate.type = elems[7];
candidate.generation = 0; // default value, may be overwritten below
for (var i = 8; i < elems.length; i += 2) {
switch (elems[i]) {
case 'raddr':
candidate['rel-addr'] = elems[i + 1];
break;
case 'rport':
candidate['rel-port'] = elems[i + 1];
break;
case 'generation':
candidate.generation = elems[i + 1];
break;
default: // TODO
console.log('parse_icecandidate not translating "' + elems[i] + '" = "' + elems[i + 1] + '"');
}
}
candidate.network = '1';
candidate.id = Math.random().toString(36).substr(2, 10); // not applicable to SDP -- FIXME: should be unique, not just random
return candidate;
},
build_icecandidate: function (cand) {
var line = ['a=candidate:' + cand.foundation, cand.component, cand.protocol, cand.priority, cand.ip, cand.port, 'typ', cand.type].join(' ');
line += ' ';
switch (cand.type) {
case 'srflx':
case 'prflx':
case 'relay':
if (cand.hasOwnAttribute('rel-addr') && cand.hasOwnAttribute('rel-port')) {
line += 'raddr';
line += ' ';
line += cand['rel-addr'];
line += ' ';
line += 'rport';
line += ' ';
line += cand['rel-port'];
line += ' ';
}
break;
}
line += 'generation';
line += ' ';
line += cand.hasOwnAttribute('generation') ? cand.generation : '0';
return line;
},
parse_ssrc: function (desc) {
// proprietary mapping of a=ssrc lines
// TODO: see "Jingle RTP Source Description" by Juberti and P. Thatcher on google docs
// and parse according to that
var lines = desc.split('\r\n'),
data = {};
for (var i = 0; i < lines.length; i++) {
if (lines[i].substring(0, 7) == 'a=ssrc:') {
var idx = lines[i].indexOf(' ');
data[lines[i].substr(idx + 1).split(':', 2)[0]] = lines[i].substr(idx + 1).split(':', 2)[1];
}
}
return data;
},
parse_rtcpfb: function (line) {
var parts = line.substr(10).split(' ');
var data = {};
data.pt = parts.shift();
data.type = parts.shift();
data.params = parts;
return data;
},
parse_extmap: function (line) {
var parts = line.substr(9).split(' ');
var data = {};
data.value = parts.shift();
if (data.value.indexOf('/') != -1) {
data.direction = data.value.substr(data.value.indexOf('/') + 1);
data.value = data.value.substr(0, data.value.indexOf('/'));
} else {
data.direction = 'both';
}
data.uri = parts.shift();
data.params = parts;
return data;
},
find_line: function (haystack, needle, sessionpart) {
var lines = haystack.split('\r\n');
for (var i = 0; i < lines.length; i++) {
if (lines[i].substring(0, needle.length) == needle) {
return lines[i];
}
}
if (!sessionpart) {
return false;
}
// search session part
lines = sessionpart.split('\r\n');
for (var j = 0; j < lines.length; j++) {
if (lines[j].substring(0, needle.length) == needle) {
return lines[j];
}
}
return false;
},
find_lines: function (haystack, needle, sessionpart) {
var lines = haystack.split('\r\n'),
needles = [];
for (var i = 0; i < lines.length; i++) {
if (lines[i].substring(0, needle.length) == needle)
needles.push(lines[i]);
}
if (needles.length || !sessionpart) {
return needles;
}
// search session part
lines = sessionpart.split('\r\n');
for (var j = 0; j < lines.length; j++) {
if (lines[j].substring(0, needle.length) == needle) {
needles.push(lines[j]);
}
}
return needles;
},
candidateToJingle: function (line) {
// a=candidate:2979166662 1 udp 2113937151 192.168.2.100 57698 typ host generation 0
// <candidate component=... foundation=... generation=... id=... ip=... network=... port=... priority=... protocol=... type=.../>
if (line.substring(0, 12) != 'a=candidate:') {
console.log('parseCandidate called with a line that is not a candidate line');
console.log(line);
return null;
}
if (line.substring(line.length - 2) == '\r\n') // chomp it
line = line.substring(0, line.length - 2);
var candidate = {},
elems = line.split(' '),
i;
if (elems[6] != 'typ') {
console.log('did not find typ in the right place');
console.log(line);
return null;
}
candidate.foundation = elems[0].substring(12);
candidate.component = elems[1];
candidate.protocol = elems[2].toLowerCase();
candidate.priority = elems[3];
candidate.ip = elems[4];
candidate.port = elems[5];
// elems[6] => "typ"
candidate.type = elems[7];
for (i = 8; i < elems.length; i += 2) {
switch (elems[i]) {
case 'raddr':
candidate['rel-addr'] = elems[i + 1];
break;
case 'rport':
candidate['rel-port'] = elems[i + 1];
break;
case 'generation':
candidate.generation = elems[i + 1];
break;
default: // TODO
console.log('not translating "' + elems[i] + '" = "' + elems[i + 1] + '"');
}
}
candidate.network = '1';
candidate.id = Math.random().toString(36).substr(2, 10); // not applicable to SDP -- FIXME: should be unique, not just random
return candidate;
},
candidateFromJingle: function (cand) {
var line = 'a=candidate:';
line += cand.getAttribute('foundation');
line += ' ';
line += cand.getAttribute('component');
line += ' ';
line += cand.getAttribute('protocol'); //.toUpperCase(); // chrome M23 doesn't like this
line += ' ';
line += cand.getAttribute('priority');
line += ' ';
line += cand.getAttribute('ip');
line += ' ';
line += cand.getAttribute('port');
line += ' ';
line += 'typ';
line += ' ' + cand.getAttribute('type');
line += ' ';
switch (cand.getAttribute('type')) {
case 'srflx':
case 'prflx':
case 'relay':
if (cand.getAttribute('rel-addr') && cand.getAttribute('rel-port')) {
line += 'raddr';
line += ' ';
line += cand.getAttribute('rel-addr');
line += ' ';
line += 'rport';
line += ' ';
line += cand.getAttribute('rel-port');
line += ' ';
}
break;
}
line += 'generation';
line += ' ';
line += cand.getAttribute('generation') || '0';
return line + '\r\n';
}
};
\ No newline at end of file
/**
* Contains utility classes used in SDP class.
*
*/
/**
* Class holds a=ssrc lines and media type a=mid
* @param ssrc synchronization source identifier number(a=ssrc lines from SDP)
* @param type media type eg. "audio" or "video"(a=mid frm SDP)
* @constructor
*/
function ChannelSsrc(ssrc, type) {
this.ssrc = ssrc;
this.type = type;
this.lines = [];
}
/**
* Helper class represents media channel. Is a container for ChannelSsrc, holds channel idx and media type.
* @param channelNumber channel idx in SDP media array.
* @param mediaType media type(a=mid)
* @constructor
*/
function MediaChannel(channelNumber, mediaType) {
/**
* SDP channel number
* @type {*}
*/
this.chNumber = channelNumber;
/**
* Channel media type(a=mid)
* @type {*}
*/
this.mediaType = mediaType;
/**
* The maps of ssrc numbers to ChannelSsrc objects.
*/
this.ssrcs = {};
}
SDPUtil = {
iceparams: function (mediadesc, sessiondesc) {
var data = null;
if (SDPUtil.find_line(mediadesc, 'a=ice-ufrag:', sessiondesc) &&
SDPUtil.find_line(mediadesc, 'a=ice-pwd:', sessiondesc)) {
data = {
ufrag: SDPUtil.parse_iceufrag(SDPUtil.find_line(mediadesc, 'a=ice-ufrag:', sessiondesc)),
pwd: SDPUtil.parse_icepwd(SDPUtil.find_line(mediadesc, 'a=ice-pwd:', sessiondesc))
};
}
return data;
},
parse_iceufrag: function (line) {
return line.substring(12);
},
build_iceufrag: function (frag) {
return 'a=ice-ufrag:' + frag;
},
parse_icepwd: function (line) {
return line.substring(10);
},
build_icepwd: function (pwd) {
return 'a=ice-pwd:' + pwd;
},
parse_mid: function (line) {
return line.substring(6);
},
parse_mline: function (line) {
var parts = line.substring(2).split(' '),
data = {};
data.media = parts.shift();
data.port = parts.shift();
data.proto = parts.shift();
if (parts[parts.length - 1] === '') { // trailing whitespace
parts.pop();
}
data.fmt = parts;
return data;
},
build_mline: function (mline) {
return 'm=' + mline.media + ' ' + mline.port + ' ' + mline.proto + ' ' + mline.fmt.join(' ');
},
parse_rtpmap: function (line) {
var parts = line.substring(9).split(' '),
data = {};
data.id = parts.shift();
parts = parts[0].split('/');
data.name = parts.shift();
data.clockrate = parts.shift();
data.channels = parts.length ? parts.shift() : '1';
return data;
},
build_rtpmap: function (el) {
var line = 'a=rtpmap:' + el.getAttribute('id') + ' ' + el.getAttribute('name') + '/' + el.getAttribute('clockrate');
if (el.getAttribute('channels') && el.getAttribute('channels') != '1') {
line += '/' + el.getAttribute('channels');
}
return line;
},
parse_crypto: function (line) {
var parts = line.substring(9).split(' '),
data = {};
data.tag = parts.shift();
data['crypto-suite'] = parts.shift();
data['key-params'] = parts.shift();
if (parts.length) {
data['session-params'] = parts.join(' ');
}
return data;
},
parse_fingerprint: function (line) { // RFC 4572
var parts = line.substring(14).split(' '),
data = {};
data.hash = parts.shift();
data.fingerprint = parts.shift();
// TODO assert that fingerprint satisfies 2UHEX *(":" 2UHEX) ?
return data;
},
parse_fmtp: function (line) {
var parts = line.split(' '),
i, key, value,
data = [];
parts.shift();
parts = parts.join(' ').split(';');
for (i = 0; i < parts.length; i++) {
key = parts[i].split('=')[0];
while (key.length && key[0] == ' ') {
key = key.substring(1);
}
value = parts[i].split('=')[1];
if (key && value) {
data.push({name: key, value: value});
} else if (key) {
// rfc 4733 (DTMF) style stuff
data.push({name: '', value: key});
}
}
return data;
},
parse_icecandidate: function (line) {
var candidate = {},
elems = line.split(' ');
candidate.foundation = elems[0].substring(12);
candidate.component = elems[1];
candidate.protocol = elems[2].toLowerCase();
candidate.priority = elems[3];
candidate.ip = elems[4];
candidate.port = elems[5];
// elems[6] => "typ"
candidate.type = elems[7];
candidate.generation = 0; // default value, may be overwritten below
for (var i = 8; i < elems.length; i += 2) {
switch (elems[i]) {
case 'raddr':
candidate['rel-addr'] = elems[i + 1];
break;
case 'rport':
candidate['rel-port'] = elems[i + 1];
break;
case 'generation':
candidate.generation = elems[i + 1];
break;
default: // TODO
console.log('parse_icecandidate not translating "' + elems[i] + '" = "' + elems[i + 1] + '"');
}
}
candidate.network = '1';
candidate.id = Math.random().toString(36).substr(2, 10); // not applicable to SDP -- FIXME: should be unique, not just random
return candidate;
},
build_icecandidate: function (cand) {
var line = ['a=candidate:' + cand.foundation, cand.component, cand.protocol, cand.priority, cand.ip, cand.port, 'typ', cand.type].join(' ');
line += ' ';
switch (cand.type) {
case 'srflx':
case 'prflx':
case 'relay':
if (cand.hasOwnAttribute('rel-addr') && cand.hasOwnAttribute('rel-port')) {
line += 'raddr';
line += ' ';
line += cand['rel-addr'];
line += ' ';
line += 'rport';
line += ' ';
line += cand['rel-port'];
line += ' ';
}
break;
}
line += 'generation';
line += ' ';
line += cand.hasOwnAttribute('generation') ? cand.generation : '0';
return line;
},
parse_ssrc: function (desc) {
// proprietary mapping of a=ssrc lines
// TODO: see "Jingle RTP Source Description" by Juberti and P. Thatcher on google docs
// and parse according to that
var lines = desc.split('\r\n'),
data = {};
for (var i = 0; i < lines.length; i++) {
if (lines[i].substring(0, 7) == 'a=ssrc:') {
var idx = lines[i].indexOf(' ');
data[lines[i].substr(idx + 1).split(':', 2)[0]] = lines[i].substr(idx + 1).split(':', 2)[1];
}
}
return data;
},
parse_rtcpfb: function (line) {
var parts = line.substr(10).split(' ');
var data = {};
data.pt = parts.shift();
data.type = parts.shift();
data.params = parts;
return data;
},
parse_extmap: function (line) {
var parts = line.substr(9).split(' ');
var data = {};
data.value = parts.shift();
if (data.value.indexOf('/') != -1) {
data.direction = data.value.substr(data.value.indexOf('/') + 1);
data.value = data.value.substr(0, data.value.indexOf('/'));
} else {
data.direction = 'both';
}
data.uri = parts.shift();
data.params = parts;
return data;
},
find_line: function (haystack, needle, sessionpart) {
var lines = haystack.split('\r\n');
for (var i = 0; i < lines.length; i++) {
if (lines[i].substring(0, needle.length) == needle) {
return lines[i];
}
}
if (!sessionpart) {
return false;
}
// search session part
lines = sessionpart.split('\r\n');
for (var j = 0; j < lines.length; j++) {
if (lines[j].substring(0, needle.length) == needle) {
return lines[j];
}
}
return false;
},
find_lines: function (haystack, needle, sessionpart) {
var lines = haystack.split('\r\n'),
needles = [];
for (var i = 0; i < lines.length; i++) {
if (lines[i].substring(0, needle.length) == needle)
needles.push(lines[i]);
}
if (needles.length || !sessionpart) {
return needles;
}
// search session part
lines = sessionpart.split('\r\n');
for (var j = 0; j < lines.length; j++) {
if (lines[j].substring(0, needle.length) == needle) {
needles.push(lines[j]);
}
}
return needles;
},
candidateToJingle: function (line) {
// a=candidate:2979166662 1 udp 2113937151 192.168.2.100 57698 typ host generation 0
// <candidate component=... foundation=... generation=... id=... ip=... network=... port=... priority=... protocol=... type=.../>
if (line.substring(0, 12) != 'a=candidate:') {
console.log('parseCandidate called with a line that is not a candidate line');
console.log(line);
return null;
}
if (line.substring(line.length - 2) == '\r\n') // chomp it
line = line.substring(0, line.length - 2);
var candidate = {},
elems = line.split(' '),
i;
if (elems[6] != 'typ') {
console.log('did not find typ in the right place');
console.log(line);
return null;
}
candidate.foundation = elems[0].substring(12);
candidate.component = elems[1];
candidate.protocol = elems[2].toLowerCase();
candidate.priority = elems[3];
candidate.ip = elems[4];
candidate.port = elems[5];
// elems[6] => "typ"
candidate.type = elems[7];
for (i = 8; i < elems.length; i += 2) {
switch (elems[i]) {
case 'raddr':
candidate['rel-addr'] = elems[i + 1];
break;
case 'rport':
candidate['rel-port'] = elems[i + 1];
break;
case 'generation':
candidate.generation = elems[i + 1];
break;
default: // TODO
console.log('not translating "' + elems[i] + '" = "' + elems[i + 1] + '"');
}
}
candidate.network = '1';
candidate.id = Math.random().toString(36).substr(2, 10); // not applicable to SDP -- FIXME: should be unique, not just random
return candidate;
},
candidateFromJingle: function (cand) {
var line = 'a=candidate:';
line += cand.getAttribute('foundation');
line += ' ';
line += cand.getAttribute('component');
line += ' ';
line += cand.getAttribute('protocol'); //.toUpperCase(); // chrome M23 doesn't like this
line += ' ';
line += cand.getAttribute('priority');
line += ' ';
line += cand.getAttribute('ip');
line += ' ';
line += cand.getAttribute('port');
line += ' ';
line += 'typ';
line += ' ' + cand.getAttribute('type');
line += ' ';
switch (cand.getAttribute('type')) {
case 'srflx':
case 'prflx':
case 'relay':
if (cand.getAttribute('rel-addr') && cand.getAttribute('rel-port')) {
line += 'raddr';
line += ' ';
line += cand.getAttribute('rel-addr');
line += ' ';
line += 'rport';
line += ' ';
line += cand.getAttribute('rel-port');
line += ' ';
}
break;
}
line += 'generation';
line += ' ';
line += cand.getAttribute('generation') || '0';
return line + '\r\n';
}
};
<html>
<head>
<title>Openfire Meet</title>
<script src="js/jquery.min.js"></script>
<script src="js/md5.js"></script>
<script src="js/base64.js"></script>
<script src="js/strophe.js"></script>
<script src="js/muc.js"></script>
<script src="js/config.js"></script>
<script src="js/webrtc.sdp.js"></script>
<script src="js/strophe-openfire.js"></script>
<script src="js/publish.js"></script>
<link rel="shortcut icon" href="favicon.ico"/>
</head>
<body>
</body>
</html>
......@@ -255,7 +255,7 @@ public class PluginImpl implements Plugin, PropertyEventListener
if (username != null && "".equals(username) == false)
{
context.setSecurityHandler(basicAuth(username, password, "Private!"));
context.setSecurityHandler(basicAuth(username, password, "Videobridge"));
}
createIQHandlers();
......@@ -350,7 +350,7 @@ public class PluginImpl implements Plugin, PropertyEventListener
ConstraintSecurityHandler csh = new ConstraintSecurityHandler();
csh.setAuthenticator(new BasicAuthenticator());
csh.setRealmName("myrealm");
csh.setRealmName(realm);
csh.addConstraintMapping(cm);
csh.setLoginService(l);
......@@ -1017,6 +1017,7 @@ public class PluginImpl implements Plugin, PropertyEventListener
private int lastseqnum = -1;
private Participant me = this;
private int snapshot = 0;
private boolean isKeyframe = false;
/**
*
*
......@@ -1052,7 +1053,7 @@ public class PluginImpl implements Plugin, PropertyEventListener
*/
public void recordData(RawPacket packet)
{
if (snapshot < 10) Log.info("transferData " + packet.getPayloadLength() + " " + packet.getHeaderLength() + " " + packet.getExtensionLength());
if (snapshot < 1) Log.info("transferData " + packet.getPayloadLength() + " " + packet.getHeaderLength() + " " + packet.getExtensionLength());
try {
......@@ -1069,7 +1070,7 @@ public class PluginImpl implements Plugin, PropertyEventListener
partial = new byte[0];
}
if (snapshot < 10) Log.info("expecting X R N S PartID");
if (snapshot < 1) Log.info("expecting X R N S PartID");
byte x = rtp[payloadOffset]; //X R N S PartID
......@@ -1078,34 +1079,34 @@ public class PluginImpl implements Plugin, PropertyEventListener
if ((x & 0x80) != 0) // extened bits
{
if (snapshot < 10) Log.info("found I L T RSV-A");
if (snapshot < 1) Log.info("found I L T RSV-A");
byte ilt = rtp[payloadOffset]; //I L T RSV-A
payloadOffset++;
vp8Length--;
if ((ilt & 0x80) != 0) { //picture ID
if (snapshot < 10) Log.info("found picture ID 1");
byte m = rtp[payloadOffset]; //picture ID
if (snapshot < 1) Log.info("found picture ID 1");
payloadOffset++;
vp8Length--;
byte m = rtp[payloadOffset]; //picture ID
if ((m & 0x80) != 0)
{
if (snapshot < 10) Log.info("found picture ID 2");
if (snapshot < 1) Log.info("found picture ID 2");
payloadOffset++;
vp8Length--;
}
}
if ((ilt & 0x40) != 0) { //TL0PICIDX
if (snapshot < 10) Log.info("found TL0PICIDX");
if (snapshot < 1) Log.info("found TL0PICIDX");
payloadOffset++;
vp8Length--;
}
if ((ilt & 0x20) != 0 || (ilt & 0x10) != 0) { //TID RSV-B
if (snapshot < 10) Log.info("found TID RSV-B or keyframe index");
if (snapshot < 1) Log.info("found TID RSV-B or keyframe index");
payloadOffset++;
vp8Length--;
}
......@@ -1113,12 +1114,11 @@ public class PluginImpl implements Plugin, PropertyEventListener
if ((x & 0x10) != 0 && (x & 0x0f) == 0 && vp8Length >= 3) // start of partition
{
if (snapshot < 10) Log.info("found start of partition " + x);
if (snapshot < 1) Log.info("found start of partition " + x);
partial = new byte[0];
isKeyframe = (rtp[payloadOffset] & 0x1) == 0;
}
boolean isKeyframe = (rtp[payloadOffset] & 0x1) == 0;
int partialLength = partial.length;
partial = Arrays.copyOf(partial, partial.length + vp8Length);
System.arraycopy(rtp, payloadOffset, partial, partialLength, vp8Length);
......@@ -1126,7 +1126,7 @@ public class PluginImpl implements Plugin, PropertyEventListener
int thisseqnum = packet.getSequenceNumber();
if (lastseqnum != -1 && thisseqnum != lastseqnum + 1) {
if (snapshot < 10) Log.info("VP8:Received packet out of order, discarding frame.");
if (snapshot < 1) Log.info("VP8:Received packet out of order, discarding frame.");
partial = null;
lastseqnum = -1;
return;
......@@ -1138,19 +1138,19 @@ public class PluginImpl implements Plugin, PropertyEventListener
if (recorder != null && partial != null)
{
byte[] full = Arrays.copyOf(partial, partial.length);
if (snapshot < 10) Log.info("recordData " + " " + packet.getPayloadType() + " " + full + " " + packet.getSequenceNumber() + " " + isKeyframe);
if (snapshot < 1) Log.info("recordData " + " " + packet.getPayloadType() + " " + full + " " + packet.getSequenceNumber() + " " + isKeyframe);
recorder.write(full, 0, full.length, isKeyframe, packet.getTimestamp());
if (isKeyframe && snapshot < 10)
if (isKeyframe && snapshot < 1)
{
recorder.writeWebPImage(full, 0, full.length, packet.getTimestamp());
snapshot++;
}
}
partial = null;
lastseqnum = -1;
partial = null;
lastseqnum = -1;
}
} else {
Log.error("record video cannot parse packet data " + packet);
......@@ -1397,7 +1397,7 @@ public class PluginImpl implements Plugin, PropertyEventListener
if (videoChannel != null)
{
// webm file creation not working yet
//participant.addMediaStream(videoChannel.getMediaStream());
participant.addMediaStream(videoChannel.getMediaStream());
}
}
}
......@@ -1456,10 +1456,10 @@ public class PluginImpl implements Plugin, PropertyEventListener
}
Element audioContent = conferenceIq.addElement("content").addAttribute("name", "audio");
audioContent.addElement("channel").addAttribute("initiator", "true").addAttribute("expire", "15").addAttribute("rtp-level-relay-type", "mixer");
audioContent.addElement("channel").addAttribute("initiator", "true").addAttribute("expire", "15").addAttribute("rtp-level-relay-type", "mixer").addAttribute("endpoint", nickname);
Element videoContent = conferenceIq.addElement("content").addAttribute("name", "video");
videoContent.addElement("channel").addAttribute("initiator", "true").addAttribute("expire", "15");
videoContent.addElement("channel").addAttribute("initiator", "true").addAttribute("expire", "15").addAttribute("endpoint", nickname);
router.route(iq);
}
......
......@@ -130,7 +130,7 @@ public class Recorder extends Thread
track.CodecID = "V_VP8";
track.DefaultDuration = 0;
track.Video_PixelWidth = 640;
track.Video_PixelHeight = 360;
track.Video_PixelHeight = 480;
track.CodecPrivate = new byte[0];
mFW.TrackList.add(track);
......@@ -433,11 +433,11 @@ public class Recorder extends Thread
{
if (lastTimecode != 0)
{
//Log.info("writeData end cluster " + d.data);
Log.info("writeData end cluster " + d.data);
duration = d.timestamp - lastTimecode;
mFW.endCluster();
}
//Log.info("writeData start cluster " + d.timestamp);
Log.info("writeData start cluster " + d.timestamp);
mFW.startCluster(d.timestamp);
}
......
......@@ -140,7 +140,7 @@
</td>
<td align="left">
<input name="username" type="text" maxlength="16" size="16"
value="<%=JiveGlobals.getProperty(PluginImpl.USERNAME_PROPERTY_NAME, "jitsi")%>"/>
value="<%=JiveGlobals.getProperty(PluginImpl.USERNAME_PROPERTY_NAME, "")%>"/>
</td>
</tr>
<tr>
......@@ -148,7 +148,7 @@
</td>
<td align="left">
<input name="password" type="password" maxlength="16" size="16"
value="<%=JiveGlobals.getProperty(PluginImpl.PASSWORD_PROPERTY_NAME, "jitsi")%>"/>
value="<%=JiveGlobals.getProperty(PluginImpl.PASSWORD_PROPERTY_NAME, "")%>"/>
</td>
</tr>
</tbody>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment