You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

JitsiMeetJS.js 9.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. var logger = require("jitsi-meet-logger").getLogger(__filename);
  2. var JitsiConnection = require("./JitsiConnection");
  3. var JitsiMediaDevices = require("./JitsiMediaDevices");
  4. var JitsiConferenceEvents = require("./JitsiConferenceEvents");
  5. var JitsiConnectionEvents = require("./JitsiConnectionEvents");
  6. var JitsiMediaDevicesEvents = require('./JitsiMediaDevicesEvents');
  7. var JitsiConnectionErrors = require("./JitsiConnectionErrors");
  8. var JitsiConferenceErrors = require("./JitsiConferenceErrors");
  9. var JitsiTrackEvents = require("./JitsiTrackEvents");
  10. var JitsiTrackErrors = require("./JitsiTrackErrors");
  11. var JitsiRecorderErrors = require("./JitsiRecorderErrors");
  12. var Logger = require("jitsi-meet-logger");
  13. var MediaType = require("./service/RTC/MediaType");
  14. var RTC = require("./modules/RTC/RTC");
  15. var RTCUIHelper = require("./modules/RTC/RTCUIHelper");
  16. var Statistics = require("./modules/statistics/statistics");
  17. var Resolutions = require("./service/RTC/Resolutions");
  18. var ScriptUtil = require("./modules/util/ScriptUtil");
  19. function getLowerResolution(resolution) {
  20. if(!Resolutions[resolution])
  21. return null;
  22. var order = Resolutions[resolution].order;
  23. var res = null;
  24. var resName = null;
  25. for(var i in Resolutions) {
  26. var tmp = Resolutions[i];
  27. if (!res || (res.order < tmp.order && tmp.order < order)) {
  28. resName = i;
  29. res = tmp;
  30. }
  31. }
  32. return resName;
  33. }
  34. /**
  35. * Namespace for the interface of Jitsi Meet Library.
  36. */
  37. var LibJitsiMeet = {
  38. version: '{#COMMIT_HASH#}',
  39. events: {
  40. conference: JitsiConferenceEvents,
  41. connection: JitsiConnectionEvents,
  42. track: JitsiTrackEvents,
  43. mediaDevices: JitsiMediaDevicesEvents
  44. },
  45. errors: {
  46. conference: JitsiConferenceErrors,
  47. connection: JitsiConnectionErrors,
  48. recorder: JitsiRecorderErrors,
  49. track: JitsiTrackErrors
  50. },
  51. logLevels: Logger.levels,
  52. mediaDevices: JitsiMediaDevices,
  53. /**
  54. * Array of functions that will receive the GUM error.
  55. */
  56. _gumFailedHandler: [],
  57. init: function (options) {
  58. Statistics.audioLevelsEnabled = !options.disableAudioLevels;
  59. if (options.enableWindowOnErrorHandler) {
  60. // if an old handler exists also fire its events
  61. var oldOnErrorHandler = window.onerror;
  62. window.onerror = function (message, source, lineno, colno, error) {
  63. this.getGlobalOnErrorHandler(
  64. message, source, lineno, colno, error);
  65. if (oldOnErrorHandler)
  66. oldOnErrorHandler(message, source, lineno, colno, error);
  67. }.bind(this);
  68. // if an old handler exists also fire its events
  69. var oldOnUnhandledRejection = window.onunhandledrejection;
  70. window.onunhandledrejection = function(event) {
  71. this.getGlobalOnErrorHandler(
  72. null, null, null, null, event.reason);
  73. if(oldOnUnhandledRejection)
  74. oldOnUnhandledRejection(event);
  75. }.bind(this);
  76. }
  77. return RTC.init(options || {});
  78. },
  79. /**
  80. * Returns whether the desktop sharing is enabled or not.
  81. * @returns {boolean}
  82. */
  83. isDesktopSharingEnabled: function () {
  84. return RTC.isDesktopSharingEnabled();
  85. },
  86. setLogLevel: function (level) {
  87. Logger.setLogLevel(level);
  88. },
  89. /**
  90. * Creates the media tracks and returns them trough the callback.
  91. * @param options Object with properties / settings specifying the tracks which should be created.
  92. * should be created or some additional configurations about resolution for example.
  93. * @param {Array} options.devices the devices that will be requested
  94. * @param {string} options.resolution resolution constraints
  95. * @param {bool} options.dontCreateJitsiTrack if <tt>true</tt> objects with the following structure {stream: the Media Stream,
  96. * type: "audio" or "video", videoType: "camera" or "desktop"}
  97. * will be returned trough the Promise, otherwise JitsiTrack objects will be returned.
  98. * @param {string} options.cameraDeviceId
  99. * @param {string} options.micDeviceId
  100. * @returns {Promise.<{Array.<JitsiTrack>}, JitsiConferenceError>}
  101. * A promise that returns an array of created JitsiTracks if resolved,
  102. * or a JitsiConferenceError if rejected.
  103. */
  104. createLocalTracks: function (options) {
  105. return RTC.obtainAudioAndVideoPermissions(options || {}).then(
  106. function(tracks) {
  107. if(!RTC.options.disableAudioLevels)
  108. for(var i = 0; i < tracks.length; i++) {
  109. var track = tracks[i];
  110. var mStream = track.getOriginalStream();
  111. if(track.getType() === MediaType.AUDIO){
  112. Statistics.startLocalStats(mStream,
  113. track.setAudioLevel.bind(track));
  114. track.addEventListener(
  115. JitsiTrackEvents.LOCAL_TRACK_STOPPED,
  116. function(){
  117. Statistics.stopLocalStats(mStream);
  118. });
  119. }
  120. }
  121. return tracks;
  122. }).catch(function (error) {
  123. this._gumFailedHandler.forEach(function (handler) {
  124. handler(error);
  125. });
  126. if(!this._gumFailedHandler.length)
  127. Statistics.sendGetUserMediaFailed(error);
  128. if(error === JitsiTrackErrors.UNSUPPORTED_RESOLUTION) {
  129. var oldResolution = options.resolution || '360';
  130. var newResolution = getLowerResolution(oldResolution);
  131. if(newResolution === null)
  132. return Promise.reject(error);
  133. options.resolution = newResolution;
  134. logger.debug("Retry createLocalTracks with resolution",
  135. newResolution);
  136. return LibJitsiMeet.createLocalTracks(options);
  137. }
  138. return Promise.reject(error);
  139. }.bind(this));
  140. },
  141. /**
  142. * Checks if its possible to enumerate available cameras/micropones.
  143. * @returns {boolean} true if available, false otherwise.
  144. * @deprecated use JitsiMeetJS.mediaDevices.isDeviceListAvailable instead
  145. */
  146. isDeviceListAvailable: function () {
  147. logger.warn('This method is deprecated, use ' +
  148. 'JitsiMeetJS.mediaDevices.isDeviceListAvailable instead');
  149. return this.mediaDevices.isDeviceListAvailable();
  150. },
  151. /**
  152. * Returns true if changing the input (camera / microphone) or output
  153. * (audio) device is supported and false if not.
  154. * @params {string} [deviceType] - type of device to change. Default is
  155. * undefined or 'input', 'output' - for audio output device change.
  156. * @returns {boolean} true if available, false otherwise.
  157. * @deprecated use JitsiMeetJS.mediaDevices.isDeviceChangeAvailable instead
  158. */
  159. isDeviceChangeAvailable: function (deviceType) {
  160. logger.warn('This method is deprecated, use ' +
  161. 'JitsiMeetJS.mediaDevices.isDeviceChangeAvailable instead');
  162. return this.mediaDevices.isDeviceChangeAvailable(deviceType);
  163. },
  164. /**
  165. * Executes callback with list of media devices connected.
  166. * @param {function} callback
  167. * @deprecated use JitsiMeetJS.mediaDevices.enumerateDevices instead
  168. */
  169. enumerateDevices: function (callback) {
  170. logger.warn('This method is deprecated, use ' +
  171. 'JitsiMeetJS.mediaDevices.enumerateDevices instead');
  172. this.mediaDevices.enumerateDevices(callback);
  173. },
  174. /**
  175. * Array of functions that will receive the unhandled errors.
  176. */
  177. _globalOnErrorHandler: [],
  178. /**
  179. * @returns function that can be used to be attached to window.onerror and
  180. * if options.enableWindowOnErrorHandler is enabled returns
  181. * the function used by the lib.
  182. * (function(message, source, lineno, colno, error)).
  183. */
  184. getGlobalOnErrorHandler: function (message, source, lineno, colno, error) {
  185. logger.error(
  186. 'UnhandledError: ' + message,
  187. 'Script: ' + source,
  188. 'Line: ' + lineno,
  189. 'Column: ' + colno,
  190. 'StackTrace: ', error);
  191. var globalOnErrorHandler = this._globalOnErrorHandler;
  192. if (globalOnErrorHandler.length) {
  193. globalOnErrorHandler.forEach(function (handler) {
  194. handler(error);
  195. });
  196. } else {
  197. Statistics.sendUnhandledError(error);
  198. }
  199. },
  200. /**
  201. * Represents a hub/namespace for utility functionality which may be of
  202. * interest to LibJitsiMeet clients.
  203. */
  204. util: {
  205. ScriptUtil: ScriptUtil,
  206. RTCUIHelper: RTCUIHelper
  207. }
  208. };
  209. // XXX JitsiConnection or the instances it initializes and is associated with
  210. // (e.g. JitsiConference) may need a reference to LibJitsiMeet (aka
  211. // JitsiMeetJS). An approach could be to declare LibJitsiMeet global (which is
  212. // what we do in Jitsi Meet) but that could be seen as not such a cool decision
  213. // certainly looks even worse within the lib-jitsi-meet library itself. That's
  214. // why the decision is to provide LibJitsiMeet as a parameter of
  215. // JitsiConnection.
  216. LibJitsiMeet.JitsiConnection = JitsiConnection.bind(null, LibJitsiMeet);
  217. //Setups the promise object.
  218. window.Promise = window.Promise || require("es6-promise").Promise;
  219. module.exports = LibJitsiMeet;