jiti-meet/modules/RTC/RTCUtils.js

334 lines
12 KiB
JavaScript

//This should be uncommented when app.js supports require
//var RTCBrowserType = require("../../service/RTC/RTCBrowserType.js");
function setResolutionConstraints(constraints, resolution, isAndroid)
{
if (resolution && !constraints.video || isAndroid) {
constraints.video = { mandatory: {}, optional: [] };// 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':
constraints.video.mandatory.minWidth = 1920;
constraints.video.mandatory.minHeight = 1080;
break;
case '720':
case 'hd':
constraints.video.mandatory.minWidth = 1280;
constraints.video.mandatory.minHeight = 720;
break;
case '360':
constraints.video.mandatory.minWidth = 640;
constraints.video.mandatory.minHeight = 360;
break;
case '180':
constraints.video.mandatory.minWidth = 320;
constraints.video.mandatory.minHeight = 180;
break;
// 4:3
case '960':
constraints.video.mandatory.minWidth = 960;
constraints.video.mandatory.minHeight = 720;
break;
case '640':
case 'vga':
constraints.video.mandatory.minWidth = 640;
constraints.video.mandatory.minHeight = 480;
break;
case '320':
constraints.video.mandatory.minWidth = 320;
constraints.video.mandatory.minHeight = 240;
break;
default:
if (isAndroid) {
constraints.video.mandatory.minWidth = 320;
constraints.video.mandatory.minHeight = 240;
constraints.video.mandatory.maxFrameRate = 15;
}
break;
}
if (constraints.video.mandatory.minWidth)
constraints.video.mandatory.maxWidth = constraints.video.mandatory.minWidth;
if (constraints.video.mandatory.minHeight)
constraints.video.mandatory.maxHeight = constraints.video.mandatory.minHeight;
}
function getConstraints(um, resolution, bandwidth, fps, desktopStream, isAndroid)
{
var constraints = {audio: false, video: false};
if (um.indexOf('video') >= 0) {
constraints.video = { mandatory: {}, optional: [] };// same behaviour as true
}
if (um.indexOf('audio') >= 0) {
constraints.audio = { mandatory: {}, optional: []};// same behaviour as true
}
if (um.indexOf('screen') >= 0) {
constraints.video = {
mandatory: {
chromeMediaSource: "screen",
googLeakyBucket: true,
maxWidth: window.screen.width,
maxHeight: window.screen.height,
maxFrameRate: 3
},
optional: []
};
}
if (um.indexOf('desktop') >= 0) {
constraints.video = {
mandatory: {
chromeMediaSource: "desktop",
chromeMediaSourceId: desktopStream,
googLeakyBucket: true,
maxWidth: window.screen.width,
maxHeight: window.screen.height,
maxFrameRate: 3
},
optional: []
};
}
if (constraints.audio) {
// if it is good enough for hangouts...
constraints.audio.optional.push(
{googEchoCancellation: true},
{googAutoGainControl: true},
{googNoiseSupression: true},
{googHighpassFilter: true},
{googNoisesuppression2: true},
{googEchoCancellation2: true},
{googAutoGainControl2: true}
);
}
if (constraints.video) {
constraints.video.optional.push(
{googNoiseReduction: false} // chrome 37 workaround for issue 3807, reenable in M38
);
if (um.indexOf('video') >= 0) {
constraints.video.optional.push(
{googLeakyBucket: true}
);
}
}
setResolutionConstraints(constraints, resolution, isAndroid);
if (bandwidth) { // doesn't work currently, see webrtc issue 1846
if (!constraints.video) constraints.video = {mandatory: {}, optional: []};//same behaviour as true
constraints.video.optional.push({bandwidth: bandwidth});
}
if (fps) { // for some cameras it might be necessary to request 30fps
// so they choose 30fps mjpg over 10fps yuy2
if (!constraints.video) constraints.video = {mandatory: {}, optional: []};// same behaviour as true;
constraints.video.mandatory.minFrameRate = fps;
}
return constraints;
}
function RTCUtils(RTCService)
{
this.service = RTCService;
if (navigator.mozGetUserMedia) {
console.log('This appears to be Firefox');
var version = parseInt(navigator.userAgent.match(/Firefox\/([0-9]+)\./)[1], 10);
if (version >= 22) {
this.peerconnection = mozRTCPeerConnection;
this.browser = RTCBrowserType.RTC_BROWSER_FIREFOX;
this.getUserMedia = navigator.mozGetUserMedia.bind(navigator);
this.pc_constraints = {};
this.attachMediaStream = function (element, stream) {
element[0].mozSrcObject = stream;
element[0].play();
};
this.getStreamID = function (stream) {
var tracks = stream.getVideoTracks();
if(!tracks || tracks.length == 0)
{
tracks = stream.getAudioTracks();
}
return tracks[0].id.replace(/[\{,\}]/g,"");
};
this.getVideoSrc = function (element) {
return element.mozSrcObject;
};
this.setVideoSrc = function (element, src) {
element.mozSrcObject = src;
};
RTCSessionDescription = mozRTCSessionDescription;
RTCIceCandidate = mozRTCIceCandidate;
}
} else if (navigator.webkitGetUserMedia) {
console.log('This appears to be Chrome');
this.peerconnection = webkitRTCPeerConnection;
this.browser = RTCBrowserType.RTC_BROWSER_CHROME;
this.getUserMedia = navigator.webkitGetUserMedia.bind(navigator);
this.attachMediaStream = function (element, stream) {
element.attr('src', webkitURL.createObjectURL(stream));
};
this.getStreamID = function (stream) {
// streams from FF endpoints have the characters '{' and '}'
// that make jQuery choke.
return stream.id.replace(/[\{,\}]/g,"");
};
this.getVideoSrc = function (element) {
return element.getAttribute("src");
};
this.setVideoSrc = function (element, src) {
element.setAttribute("src", src);
};
// DTLS should now be enabled by default but..
this.pc_constraints = {'optional': [{'DtlsSrtpKeyAgreement': 'true'}]};
if (navigator.userAgent.indexOf('Android') != -1) {
this.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;
};
}
}
else
{
try { console.log('Browser does not appear to be WebRTC-capable'); } catch (e) { }
window.location.href = 'webrtcrequired.html';
return;
}
if (this.browser !== RTCBrowserType.RTC_BROWSER_CHROME &&
config.enableFirefoxSupport !== true) {
window.location.href = 'chromeonly.html';
return;
}
}
RTCUtils.prototype.getUserMediaWithConstraints = function(
um, success_callback, failure_callback, resolution,bandwidth, fps,
desktopStream)
{
// Check if we are running on Android device
var isAndroid = navigator.userAgent.indexOf('Android') != -1;
var constraints = getConstraints(
um, resolution, bandwidth, fps, desktopStream, isAndroid);
var isFF = navigator.userAgent.toLowerCase().indexOf('firefox') > -1;
try {
if (config.enableSimulcast
&& constraints.video
&& constraints.video.chromeMediaSource !== 'screen'
&& constraints.video.chromeMediaSource !== 'desktop'
&& !isAndroid
// We currently do not support FF, as it doesn't have multistream support.
&& !isFF) {
simulcast.getUserMedia(constraints, function (stream) {
console.log('onUserMediaSuccess');
success_callback(stream);
},
function (error) {
console.warn('Failed to get access to local media. Error ', error);
if (failure_callback) {
failure_callback(error);
}
});
} else {
this.getUserMedia(constraints,
function (stream) {
console.log('onUserMediaSuccess');
success_callback(stream);
},
function (error) {
console.warn('Failed to get access to local media. Error ',
error, constraints);
if (failure_callback) {
failure_callback(error);
}
});
}
} catch (e) {
console.error('GUM failed: ', e);
if(failure_callback) {
failure_callback(e);
}
}
};
/**
* We ask for audio and video combined stream in order to get permissions and
* not to ask twice.
*/
RTCUtils.prototype.obtainAudioAndVideoPermissions = function() {
var self = this;
// Get AV
var cb = function (stream) {
console.log('got', stream, stream.getAudioTracks().length, stream.getVideoTracks().length);
self.handleLocalStream(stream);
};
var self = this;
this.getUserMediaWithConstraints(
['audio', 'video'],
cb,
function (error) {
console.error('failed to obtain audio/video stream - trying audio only', error);
self.getUserMediaWithConstraints(
['audio'],
cb,
function (error) {
console.error('failed to obtain audio/video stream - stop', error);
UI.messageHandler.showError("Error",
"Failed to obtain permissions to use the local microphone" +
"and/or camera.");
}
);
},
config.resolution || '360');
}
RTCUtils.prototype.handleLocalStream = function(stream)
{
if(window.webkitMediaStream)
{
var audioStream = new webkitMediaStream();
var videoStream = new webkitMediaStream();
var audioTracks = stream.getAudioTracks();
var videoTracks = stream.getVideoTracks();
for (var i = 0; i < audioTracks.length; i++) {
audioStream.addTrack(audioTracks[i]);
}
this.service.createLocalStream(audioStream, "audio");
for (i = 0; i < videoTracks.length; i++) {
videoStream.addTrack(videoTracks[i]);
}
this.service.createLocalStream(videoStream, "video");
}
else
{//firefox
this.service.createLocalStream(stream, "stream");
}
};
module.exports = RTCUtils;