added functions to retrieve devices list and check if that's possible

This commit is contained in:
isymchych 2015-11-12 19:18:23 +02:00
parent 503db36efd
commit 015492e8da
3 changed files with 177 additions and 7 deletions

View File

@ -3,6 +3,7 @@ var JitsiConferenceEvents = require("./JitsiConferenceEvents");
var JitsiConnectionEvents = require("./JitsiConnectionEvents");
var JitsiConnectionErrors = require("./JitsiConnectionErrors");
var JitsiConferenceErrors = require("./JitsiConferenceErrors");
var RTC = require("./modules/RTC/RTC");
/**
* Namespace for the interface of Jitsi Meet Library.
@ -19,10 +20,15 @@ var LibJitsiMeet = {
connection: JitsiConnectionErrors
},
init: function (options) {
require("./modules/RTC/RTC").init(options || {});
RTC.init(options || {});
},
isDeviceListAvailable: function () {
return RTC.isDeviceListAvailable();
},
enumerateDevices: function (callback) {
RTC.enumerateDevices(callback);
}
}
};
//Setups the promise object.
window.Promise = window.Promise || require("es6-promise").polyfill();

View File

@ -211,6 +211,18 @@ RTC.getVideoSrc = function (element) {
return RTCUtils.getVideoSrc(element);
};
RTC.isDeviceListAvailable = function () {
return RTCUtils.isDeviceListAvailable();
};
/**
* Allows to receive list of available cameras/microphones.
* @param {function} callback would receive array of devices as an argument
*/
RTC.enumerateDevices = function (callback) {
RTCUtils.enumerateDevices(callback);
};
RTC.setVideoSrc = function (element, src) {
RTCUtils.setVideoSrc(element, src);
};

View File

@ -1,4 +1,5 @@
/* global config, require, attachMediaStream, getUserMedia */
/* global config, require, attachMediaStream, getUserMedia,
MediaStreamTrack, mozRTCPeerConnection */
var RTCBrowserType = require("./RTCBrowserType");
var Resolutions = require("../../service/RTC/Resolutions");
var AdapterJS = require("./adapter.screenshare");
@ -141,6 +142,131 @@ function getConstraints(um, resolution, bandwidth, fps, desktopStream) {
return constraints;
}
/**
* Apply function with arguments if function exists.
* Do nothing if function not provided.
* @param {function} [fn] function to apply
* @param {Array} [args=[]] arguments for function
*/
function maybeApply(fn, args) {
if (fn) {
fn.apply(null, args || []);
}
}
var getUserMediaStatus = {
initialized: false,
callbacks: []
};
/**
* Wrap `getUserMedia` to allow others to know if it was executed at least
* once or not. Wrapper function uses `getUserMediaStatus` object.
* @param {Function} getUserMedia native function
* @returns {Function} wrapped function
*/
function wrapGetUserMedia(getUserMedia) {
return function (constraints, successCallback, errorCallback) {
getUserMedia(constraints, function (stream) {
maybeApply(successCallback, [stream]);
if (!getUserMediaStatus.initialized) {
getUserMediaStatus.initialized = true;
getUserMediaStatus.callbacks.forEach(function (callback) {
callback();
});
getUserMediaStatus.callbacks.length = 0;
}
}, function (error) {
maybeApply(errorCallback, [error]);
});
};
}
/**
* Create stub device which equals to auto selected device.
* @param {string} kind if that should be `audio` or `video` device
* @returns {Object} stub device description in `enumerateDevices` format
*/
function createAutoDeviceInfo(kind) {
return {
facing: null,
label: 'Auto',
kind: kind,
deviceId: '',
groupId: null
};
}
/**
* Execute function after getUserMedia was executed at least once.
* @param {Function} callback function to execute after getUserMedia
*/
function afterUserMediaInitialized(callback) {
if (getUserMediaStatus.initialized) {
callback();
} else {
getUserMediaStatus.callbacks.push(callback);
}
}
/**
* Wrapper function which makes enumerateDevices to wait
* until someone executes getUserMedia first time.
* @param {Function} enumerateDevices native function
* @returns {Funtion} wrapped function
*/
function wrapEnumerateDevices(enumerateDevices) {
return function (callback) {
// enumerate devices only after initial getUserMedia
afterUserMediaInitialized(function () {
enumerateDevices().then(function (devices) {
//add auto devices
devices.unshift(
createAutoDeviceInfo('audioinput'),
createAutoDeviceInfo('videoinput')
);
callback(devices);
}, function (err) {
console.error('cannot enumerate devices: ', err);
// return only auto devices
callback([createAutoDeviceInfo('audioInput'),
createAutoDeviceInfo('videoinput')]);
});
});
};
}
/**
* Use old MediaStreamTrack to get devices list and
* convert it to enumerateDevices format.
* @param {Function} callback function to call when received devices list.
*/
function enumerateDevicesThroughMediaStreamTrack (callback) {
MediaStreamTrack.getSources(function (sources) {
var devices = sources.map(function (source) {
var kind = (source.kind || '').toLowerCase();
return {
facing: source.facing || null,
label: source.label,
kind: kind ? kind + 'input': null,
deviceId: source.id,
groupId: source.groupId || null
};
});
//add auto devices
devices.unshift(
createAutoDeviceInfo('audioinput'),
createAutoDeviceInfo('videoinput')
);
callback(devices);
});
}
//Options parameter is to pass config options. Currently uses only "useIPv6".
var RTCUtils = {
eventEmitter: new EventEmitter(),
@ -150,7 +276,10 @@ var RTCUtils = {
var FFversion = RTCBrowserType.getFirefoxVersion();
if (FFversion >= 40) {
this.peerconnection = mozRTCPeerConnection;
this.getUserMedia = navigator.mozGetUserMedia.bind(navigator);
this.getUserMedia = wrapGetUserMedia(navigator.mozGetUserMedia.bind(navigator));
this.enumerateDevices = wrapEnumerateDevices(
navigator.mediaDevices.enumerateDevices.bind(navigator.mediaDevices)
);
this.pc_constraints = {};
this.attachMediaStream = function (element, stream) {
// srcObject is being standardized and FF will eventually
@ -196,7 +325,16 @@ var RTCUtils = {
} else if (RTCBrowserType.isChrome() || RTCBrowserType.isOpera()) {
this.peerconnection = webkitRTCPeerConnection;
this.getUserMedia = navigator.webkitGetUserMedia.bind(navigator);
var getUserMedia = navigator.webkitGetUserMedia.bind(navigator);
if (navigator.mediaDevices) {
this.getUserMedia = wrapGetUserMedia(getUserMedia);
this.enumerateDevices = wrapEnumerateDevices(
navigator.mediaDevices.enumerateDevices.bind(navigator.mediaDevices)
);
} else {
this.getUserMedia = getUserMedia;
this.enumerateDevices = enumerateDevicesThroughMediaStreamTrack;
}
this.attachMediaStream = function (element, stream) {
element.attr('src', webkitURL.createObjectURL(stream));
};
@ -246,6 +384,7 @@ var RTCUtils = {
self.peerconnection = RTCPeerConnection;
self.getUserMedia = getUserMedia;
self.enumerateDevices = enumerateDevicesThroughMediaStreamTrack;
self.attachMediaStream = function (elSel, stream) {
if (stream.id === "dummyAudio" || stream.id === "dummyVideo") {
@ -585,7 +724,20 @@ var RTCUtils = {
}
return newStream;
},
/**
* Checks if its possible to enumerate available cameras/micropones.
* @returns {boolean} true if available, false otherwise.
*/
isDeviceListAvailable: function () {
var isEnumerateDevicesAvailable = navigator.mediaDevices && navigator.mediaDevices.enumerateDevices;
if (isEnumerateDevicesAvailable) {
return true;
}
return MediaStreamTrack && MediaStreamTrack.getSources;
}
}
};
module.exports = RTCUtils;