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.4KB

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