File: source/room-connection.js

  1. /**
  2. * These are the list of platform signaling system actions that Skylink would be given with.
  3. * - Upon receiving from the signaling, the application has to reflect the
  4. * relevant actions given.
  5. * - You may refer to {{#crossLink "Skylink/SYSTEM_ACTION_REASON:attribute"}}SYSTEM_ACTION_REASON{{/crossLink}}
  6. * for the types of system action reasons that would be given.
  7. * @attribute SYSTEM_ACTION
  8. * @type JSON
  9. * @param {String} WARNING <small>Value <code>"warning"</code></small>
  10. * This action serves a warning to self. Usually if
  11. * warning is not heeded, it may result in an <code>REJECT</code> action.
  12. * @param {String} REJECT <small>Value <code>"reject"</code></small>
  13. * This action means that self has been kicked out
  14. * of the current signaling room connection, and subsequent Peer connections
  15. * would be disconnected.
  16. * @readOnly
  17. * @component Room
  18. * @for Skylink
  19. * @since 0.5.1
  20. */
  21. Skylink.prototype.SYSTEM_ACTION = {
  22. WARNING: 'warning',
  23. REJECT: 'reject'
  24. };
  25.  
  26. /**
  27. * These are the list of Skylink platform signaling codes as the reason
  28. * for the system action given by the platform signaling that Skylink would receive.
  29. * - You may refer to {{#crossLink "Skylink/SYSTEM_ACTION:attribute"}}SYSTEM_ACTION{{/crossLink}}
  30. * for the types of system actions that would be given.
  31. * - Reason codes like <code>FAST_MESSAGE</code>, <code>ROOM_FULL</code>, <code>VERIFICATION</code> and
  32. * <code>OVER_SEAT_LIMIT</code> has been removed as they are no longer supported.
  33. * @attribute SYSTEM_ACTION_REASON
  34. * @type JSON
  35. * @param {String} ROOM_LOCKED <small>Value <code>"locked"</code> | Action ties with <code>REJECT</code></small>
  36. * The reason code when room is locked and self is rejected from joining the room.
  37. * @param {String} DUPLICATED_LOGIN <small>Value <code>"duplicatedLogin"</code> | Action ties with <code>REJECT</code></small>
  38. * The reason code when the credentials given is already in use, which the platform signaling
  39. * throws an exception for this error.<br>
  40. * This rarely occurs as Skylink handles this issue, and it's recommended to report this issue if this occurs.
  41. * @param {String} SERVER_ERROR <small>Value <code>"serverError"</code> | Action ties with <code>REJECT</code></small>
  42. * The reason code when the connection with the platform signaling has an exception with self.<br>
  43. * This rarely (and should not) occur and it's recommended to report this issue if this occurs.
  44. * @param {String} EXPIRED <small>Value <code>"expired"</code> | Action ties with <code>REJECT</code></small>
  45. * The reason code when the persistent room meeting has expired so self is unable to join the room as
  46. * the end time of the meeting has ended.<br>
  47. * Depending on other meeting timings available for this room, the persistent room will appear expired.<br>
  48. * This relates to the persistent room feature configured in the Application Key.
  49. * @param {String} ROOM_CLOSED <small>Value <code>"roomclose"</code> | Action ties with <code>REJECT</code></small>
  50. * The reason code when the persistent room meeting has ended and has been rendered expired so self is rejected
  51. * from the room as the meeting is over.<br>
  52. * This relates to the persistent room feature configured in the Application Key.
  53. * @param {String} ROOM_CLOSING <small>Value <code>"toclose"</code> | Action ties with <code>WARNING</code></small>
  54. * The reason code when the persistent room meeting is going to end soon, so this warning is given to inform
  55. * users before self is rejected from the room.<br>
  56. * This relates to the persistent room feature configured in the Application Key.
  57. * @readOnly
  58. * @component Room
  59. * @for Skylink
  60. * @since 0.5.2
  61. */
  62. Skylink.prototype.SYSTEM_ACTION_REASON = {
  63. //FAST_MESSAGE: 'fastmsg',
  64. ROOM_LOCKED: 'locked',
  65. //ROOM_FULL: 'roomfull',
  66. DUPLICATED_LOGIN: 'duplicatedLogin',
  67. SERVER_ERROR: 'serverError',
  68. //VERIFICATION: 'verification',
  69. EXPIRED: 'expired',
  70. ROOM_CLOSED: 'roomclose',
  71. ROOM_CLOSING: 'toclose'
  72. };
  73.  
  74. /**
  75. * Stores the current room self is joined to.
  76. * The selected room will be usually defaulted to
  77. * {{#crossLink "Skylink/_defaultRoom:attribute"}}_defaultRoom{{/crossLink}}
  78. * if there is no selected room in
  79. * {{#crossLink "Skylink/joinRoom:method"}}joinRoom(){{/crossLink}}.
  80. * @attribute _selectedRoom
  81. * @type String
  82. * @default Skylink._defaultRoom
  83. * @private
  84. * @component Room
  85. * @for Skylink
  86. * @since 0.3.0
  87. */
  88. Skylink.prototype._selectedRoom = null;
  89.  
  90. /**
  91. * The flag that indicates if the currently joined room is locked.
  92. * @attribute _roomLocked
  93. * @type Boolean
  94. * @private
  95. * @component Room
  96. * @for Skylink
  97. * @since 0.5.2
  98. */
  99. Skylink.prototype._roomLocked = false;
  100.  
  101. /**
  102. * The flag that indicates if self is currently joined in a room.
  103. * @attribute _inRoom
  104. * @type Boolean
  105. * @private
  106. * @component Room
  107. * @for Skylink
  108. * @since 0.4.0
  109. */
  110. Skylink.prototype._inRoom = false;
  111.  
  112. /**
  113. * Connects self to the selected room.
  114. * By default, if room parameter is not provided, it will
  115. * connect to the default room provided in
  116. * {{#crossLink "Skylink/init:method"}}init() <code>defaultRoom</code> settings{{/crossLink}}.
  117. * If any existing user media streams attached in Skylink, like for an example, calling
  118. * {{#crossLink "Skylink/getUserMedia:method"}}getUserMedia(){{/crossLink}} or
  119. * {{#crossLink "Skylink/sendStream:method"}}sendStream(){{/crossLink}} before
  120. * <code>joinRoom()</code>, self would actually send the current attached user media stream
  121. * attached. To stop the current attached Stream, please invoke
  122. * {{#crossLink "Skylink/stopStream:method"}}stopStream(){{/crossLink}} before
  123. * <code>joinRoom()</code> is invoked.
  124. * @method joinRoom
  125. * @param {String} [room] The room for
  126. * self to join to. If room is not provided, the room
  127. * would default to the the <code>defaultRoom</code> option set
  128. * in {{#crossLink "Skylink/init:method"}}init() settings{{/crossLink}}.
  129. * @param {JSON} [options] The connection settings for self connection in the
  130. * room. If both audio and video
  131. * option is <code>false</code>, there should be no audio and video stream
  132. * sending from self connection.
  133. * @param {String|JSON} [options.userData] The custom user data
  134. * information set by developer. This custom user data can also
  135. * be set in {{#crossLink "Skylink/setUserData:method"}}setUserData(){{/crossLink}}.
  136. * @param {Boolean|JSON} [options.audio=false] The self Stream streaming audio settings.
  137. * If <code>false</code>, it means that audio streaming is disabled in
  138. * the self Stream. If this option is set to <code>true</code> or is defined with
  139. * settings, {{#crossLink "Skylink/getUserMedia:method"}}getUserMedia(){{/crossLink}}
  140. * will be invoked. Self will not connect to the room unless the Stream audio
  141. * user media access is given.
  142. * @param {Boolean} [options.audio.stereo] The flag that indicates if
  143. * stereo should be enabled in self connection Stream
  144. * audio streaming.
  145. * @param {Boolean} [options.audio.mute=false] The flag that
  146. * indicates if the self Stream object audio streaming is muted.
  147. * @param {Array} [options.audio.optional] The optional constraints for audio streaming
  148. * in self user media Stream object. This follows the <code>optional</code>
  149. * setting in the <code>MediaStreamConstraints</code> when <code>getUserMedia()</code> is invoked.
  150. * Tampering this may cause errors in retrieval of self user media Stream object.
  151. * Refer to this [site for more reference](http://www.sitepoint.com/introduction-getusermedia-api/).
  152. * @param {Boolean|JSON} [options.video=false] The self Stream streaming video settings.
  153. * If <code>false</code>, it means that video streaming is disabled in
  154. * the self Stream. If this option is set to <code>true</code> or is defined with
  155. * settings, {{#crossLink "Skylink/getUserMedia:method"}}getUserMedia(){{/crossLink}}
  156. * will be invoked. Self will not connect to the room unless the Stream video
  157. * user media access is given.
  158. * @param {Boolean} [options.video.mute=false] The flag that
  159. * indicates if the self Stream object video streaming is muted.
  160. * @param {Array} [options.video.optional] The optional constraints for video streaming
  161. * in self user media Stream object. This follows the <code>optional</code>
  162. * setting in the <code>MediaStreamConstraints</code> when <code>getUserMedia()</code> is invoked.
  163. * Tampering this may cause errors in retrieval of self user media Stream object.
  164. * Refer to this [site for more reference](http://www.sitepoint.com/introduction-getusermedia-api/).
  165. * @param {JSON} [options.video.resolution] The self Stream streaming video
  166. * resolution settings. Setting the resolution may
  167. * not force set the resolution provided as it depends on the how the
  168. * browser handles the resolution. [Rel: Skylink.VIDEO_RESOLUTION]
  169. * @param {Number} [options.video.resolution.width] The self
  170. * Stream streaming video resolution width.
  171. * @param {Number} [options.video.resolution.height] The self
  172. * Stream streaming video resolution height.
  173. * @param {Number} [options.video.frameRate=50] The self
  174. * Stream streaming video maximum frameRate.
  175. * @param {String} [options.bandwidth] The self
  176. * streaming bandwidth settings. Setting the bandwidth flags may not
  177. * force set the bandwidth for each connection stream channels as it depends
  178. * on how the browser handles the bandwidth bitrate. Values are configured
  179. * in <var>kb/s</var>.
  180. * @param {String} [options.bandwidth.audio=50] The configured
  181. * audio stream channel for the self Stream object bandwidth
  182. * that audio streaming should use in <var>kb/s</var>.
  183. * @param {String} [options.bandwidth.video=256] The configured
  184. * video stream channel for the self Stream object bandwidth
  185. * that video streaming should use in <var>kb/s</var>.
  186. * @param {String} [options.bandwidth.data=1638400] The configured
  187. * datachannel channel for the DataChannel connection bandwidth
  188. * that datachannel connection per packet should be able use in <var>kb/s</var>.
  189. * @param {Boolean} [options.manualGetUserMedia] The flag that indicates if
  190. * <code>joinRoom()</code> should not invoke
  191. * {{#crossLink "Skylink/getUserMedia:method"}}getUserMedia(){{/crossLink}}
  192. * automatically but allow the developer's application to invoke
  193. * {{#crossLink "Skylink/getUserMedia:method"}}getUserMedia(){{/crossLink}}
  194. * manually in the application. When user media access is required, the
  195. * event {{#crossLink "Skylink/mediaAccessRequired:event"}}mediaAccessRequired{{/crossLink}}
  196. * will be triggered.
  197. * @param {Function} [callback] The callback fired after self has
  198. * joined the room successfully with the provided media settings or
  199. * have met with an exception.
  200. * The callback signature is <code>function (error, success)</code>.
  201. * @param {JSON} callback.error The error object received in the callback.
  202. * If received as <code>null</code>, it means that there is no errors.
  203. * @param {Array} callback.error.error The exception thrown that caused the failure
  204. * for joining the room.
  205. * @param {JSON} callback.error.errorCode The
  206. * <a href="#attr_READY_STATE_CHANGE_ERROR">READY_STATE_CHANGE_ERROR</a>
  207. * if there is an <a href="#event_readyStateChange">readyStateChange</a>
  208. * event error that caused the failure for joining the room.
  209. * [Rel: Skylink.READY_STATE_CHANGE_ERROR]
  210. * @param {Object|String} callback.error.room The selected room that self is
  211. * trying to join to.
  212. * @param {JSON} callback.success The success object received in the callback.
  213. * If received as <code>null</code>, it means that there are errors.
  214. * @param {Array} callback.success.room The selected room that self has
  215. * succesfully joined to.
  216. * @param {String} callback.success.peerId The self Peer ID that
  217. * would be reflected remotely to peers in the room.
  218. * @param {JSON} callback.success.peerInfo The connection settings for self connection in the
  219. * room. If both audio and video option is <code>false</code>,
  220. * there should be no audio and video stream sending from self connection.
  221. * @param {String|JSON} callback.success.peerInfo.userData The custom user data
  222. * information set by developer. This custom user data can also
  223. * be set in <a href="#method_setUserData">setUserData()</a>.
  224. * @param {Boolean|JSON} [callback.success.peerInfo.audio=false] The self Stream
  225. * streaming audio settings. If <code>false</code>, it means that audio
  226. * streaming is disabled in the self Stream. If this option is set to
  227. * <code>true</code> or is defined with settings,
  228. * <a href="#method_getUserMedia">getUserMedia()</a>
  229. * will be invoked. Self will not connect to the room unless the Stream audio
  230. * user media access is given.
  231. * @param {Boolean} [callback.success.peerInfo.audio.stereo] The flag that indicates if
  232. * stereo should be enabled in self connection Stream
  233. * audio streaming.
  234. * @param {Boolean|JSON} [callback.success.peerInfo.video=false] The self Stream
  235. * streaming video settings. If <code>false</code>, it means that video
  236. * streaming is disabled in the self Stream. If this option is set to
  237. * <code>true</code> or is defined with settings,
  238. * <a href="#method_getUserMedia">getUserMedia()</a>
  239. * will be invoked. Self will not connect to the room unless the Stream video
  240. * user media access is given.
  241. * @param {JSON} [callback.success.peerInfo.video.resolution] The self Stream streaming video
  242. * resolution settings. Setting the resolution may
  243. * not force set the resolution provided as it depends on the how the
  244. * browser handles the resolution. [Rel: Skylink.VIDEO_RESOLUTION]
  245. * @param {Number} [callback.success.peerInfo.video.resolution.width] The self
  246. * Stream streaming video resolution width.
  247. * @param {Number} [callback.success.peerInfo.video.resolution.height] The self
  248. * Stream streaming video resolution height.
  249. * @param {Number} [callback.success.peerInfo.video.frameRate=50] The self
  250. * Stream streaming video maximum frameRate.
  251. * @param {Boolean} [callback.success.peerInfo.video.screenshare=false] The flag
  252. * that indicates if the self connection Stream object sent
  253. * is a screensharing stream or not.
  254. * @param {String} [callback.success.peerInfo.bandwidth] The self
  255. * streaming bandwidth settings. Setting the bandwidth flags may not
  256. * force set the bandwidth for each connection stream channels as it depends
  257. * on how the browser handles the bandwidth bitrate. Values are configured
  258. * in <var>kb/s</var>.
  259. * @param {String} [callback.success.peerInfo.bandwidth.audio=50] The configured
  260. * audio stream channel for the self Stream object bandwidth
  261. * that audio streaming should use in <var>kb/s</var>.
  262. * @param {String} [callback.success.peerInfo.bandwidth.video=256] The configured
  263. * video stream channel for the self Stream object bandwidth
  264. * that video streaming should use in <var>kb/s</var>.
  265. * @param {String} [callback.success.peerInfo.bandwidth.data=1638400] The configured
  266. * datachannel channel for the DataChannel connection bandwidth
  267. * that datachannel connection per packet should be able use in <var>kb/s</var>.
  268. * @param {JSON} callback.success.peerInfo.mediaStatus The self Stream mute
  269. * settings for both audio and video streamings.
  270. * @param {Boolean} [callback.success.peerInfo.mediaStatus.audioMuted=true] The flag that
  271. * indicates if the self Stream object audio streaming is muted. If
  272. * there is no audio streaming enabled for the self, by default,
  273. * it is set to <code>true</code>.
  274. * @param {Boolean} [callback.success.peerInfo.mediaStatus.videoMuted=true] The flag that
  275. * indicates if the self Stream object video streaming is muted. If
  276. * there is no video streaming enabled for the Peer connection, by default,
  277. * it is set to <code>true</code>.
  278. * @param {JSON} callback.success.peerInfo.agent The self platform agent information.
  279. * @param {String} callback.success.peerInfo.agent.name The self platform browser or agent name.
  280. * @param {Number} callback.success.peerInfo.agent.version The self platform browser or agent version.
  281. * @param {Number} callback.success.peerInfo.agent.os The self platform name.
  282. * @param {String} callback.success.peerInfo.room The current room that the self is in.
  283. * @example
  284. * // To just join the default room without any video or audio
  285. * // Note that calling joinRoom without any parameters
  286. * // still sends any available existing MediaStreams allowed.
  287. * // See Examples 2, 3, 4 and 5 etc to prevent video or audio stream
  288. * SkylinkDemo.joinRoom();
  289. *
  290. * // To just join the default room with bandwidth settings
  291. * SkylinkDemo.joinRoom({
  292. * bandwidth: {
  293. * data: 14440
  294. * }
  295. * });
  296. *
  297. * // Example 1: To call getUserMedia and joinRoom seperately
  298. * SkylinkDemo.getUserMedia();
  299. * SkylinkDemo.on("mediaAccessSuccess", function (stream)) {
  300. * attachMediaStream($(".localVideo")[0], stream);
  301. * SkylinkDemo.joinRoom();
  302. * });
  303. *
  304. * // Example 2: Join a room without any video or audio
  305. * SkylinkDemo.joinRoom("room_a");
  306. *
  307. * // Example 3: Join a room with audio only
  308. * SkylinkDemo.joinRoom("room_b", {
  309. * audio: true,
  310. * video: false
  311. * });
  312. *
  313. * // Example 4: Join a room with prefixed video width and height settings
  314. * SkylinkDemo.joinRoom("room_c", {
  315. * audio: true,
  316. * video: {
  317. * resolution: {
  318. * width: 640,
  319. * height: 320
  320. * }
  321. * }
  322. * });
  323. *
  324. * // Example 5: Join a room with userData and settings with audio, video
  325. * // and bandwidth
  326. * SkylinkDemo.joinRoom({
  327. * userData: {
  328. * item1: "My custom data",
  329. * item2: "Put whatever, string or JSON or array"
  330. * },
  331. * audio: {
  332. * stereo: true
  333. * },
  334. * video: {
  335. * resolution: SkylinkDemo.VIDEO_RESOLUTION.VGA,
  336. * frameRate: 50
  337. * },
  338. * bandwidth: {
  339. * audio: 48,
  340. * video: 256,
  341. * data: 14480
  342. * }
  343. * });
  344. *
  345. * //Example 6: joinRoom with callback
  346. * SkylinkDemo.joinRoom(function(error, success){
  347. * if (error){
  348. * console.log("Error happened. Can not join room");
  349. * }
  350. * else{
  351. * console.log("Successfully joined room");
  352. * }
  353. * });
  354. * @trigger readyStateChange, peerJoined, mediaAccessRequired
  355. * @component Room
  356. * @for Skylink
  357. * @since 0.5.5
  358. */
  359.  
  360. Skylink.prototype.joinRoom = function(room, mediaOptions, callback) {
  361. var self = this;
  362. var error;
  363. var stopStream = false;
  364. var previousRoom = self._selectedRoom;
  365.  
  366. if (room === null) {
  367. error = 'Invalid room name is provided';
  368. log.error(error, room);
  369.  
  370. if (typeof mediaOptions === 'function') {
  371. callback = mediaOptions;
  372. mediaOptions = undefined;
  373. }
  374.  
  375. if (typeof callback === 'function') {
  376. callback({
  377. room: room,
  378. errorCode: self._readyState,
  379. error: new Error(error)
  380. }, null);
  381. }
  382. return;
  383. }
  384. else if (typeof room === 'string') {
  385. //joinRoom(room+); - skip
  386.  
  387. //joinRoom(room+,mediaOptions+) - skip
  388.  
  389. // joinRoom(room+,callback+)
  390. if (typeof mediaOptions === 'function') {
  391. callback = mediaOptions;
  392. mediaOptions = undefined;
  393.  
  394. // joinRoom(room+, mediaOptions-)
  395. } else if (typeof mediaOptions !== 'undefined') {
  396. if (mediaOptions === null || typeof mediaOptions !== 'object') {
  397. error = 'Invalid mediaOptions is provided';
  398. log.error(error, mediaOptions);
  399.  
  400. // joinRoom(room+,mediaOptions-,callback+)
  401. if (typeof callback === 'function') {
  402. callback({
  403. room: room,
  404. errorCode: self._readyState,
  405. error: new Error(error)
  406. }, null);
  407. }
  408. return;
  409. }
  410. }
  411.  
  412. } else if (typeof room === 'object') {
  413. //joinRoom(mediaOptions+, callback);
  414. if (typeof mediaOptions === 'function') {
  415. callback = mediaOptions;
  416. }
  417.  
  418. //joinRoom(mediaOptions);
  419. mediaOptions = room;
  420. room = undefined;
  421.  
  422. } else if (typeof room === 'function') {
  423. //joinRoom(callback);
  424. callback = room;
  425. room = undefined;
  426. mediaOptions = undefined;
  427.  
  428. } else if (typeof room !== 'undefined') {
  429. //joinRoom(mediaOptions-,callback?);
  430. error = 'Invalid mediaOptions is provided';
  431. log.error(error, mediaOptions);
  432.  
  433. if (typeof mediaOptions === 'function') {
  434. callback = mediaOptions;
  435. mediaOptions = undefined;
  436. }
  437.  
  438. if (typeof callback === 'function') {
  439. callback({
  440. room: self._defaultRoom,
  441. errorCode: self._readyState,
  442. error: new Error(error)
  443. }, null);
  444. return;
  445. }
  446. }
  447.  
  448. // If no room provided, join the default room
  449. if (!room) {
  450. room = self._defaultRoom;
  451. }
  452.  
  453. //if none of the above is true --> joinRoom()
  454. var channelCallback = function (error, success) {
  455. if (error) {
  456. if (typeof callback === 'function') {
  457. callback({
  458. error: error,
  459. errorCode: null,
  460. room: self._selectedRoom
  461. }, null);
  462. }
  463. } else {
  464. if (typeof callback === 'function') {
  465. self.once('peerJoined', function(peerId, peerInfo, isSelf) {
  466. // keep returning _inRoom false, so do a wait
  467. self._wait(function () {
  468. log.log([null, 'Socket', self._selectedRoom, 'Peer joined. Firing callback. ' +
  469. 'PeerId ->'
  470. ], peerId);
  471. callback(null, {
  472. room: self._selectedRoom,
  473. peerId: peerId,
  474. peerInfo: peerInfo
  475. });
  476. }, function () {
  477. return self._inRoom;
  478. }, false);
  479. }, function(peerId, peerInfo, isSelf) {
  480. return isSelf;
  481. }, false);
  482. }
  483.  
  484. self._sendChannelMessage({
  485. type: self._SIG_MESSAGE_TYPE.JOIN_ROOM,
  486. uid: self._user.uid,
  487. cid: self._key,
  488. rid: self._room.id,
  489. userCred: self._user.token,
  490. timeStamp: self._user.timeStamp,
  491. apiOwner: self._appKeyOwner,
  492. roomCred: self._room.token,
  493. start: self._room.startDateTime,
  494. len: self._room.duration,
  495. isPrivileged: self._isPrivileged === true, // Default to false if undefined
  496. autoIntroduce: self._autoIntroduce!== false // Default to true if undefined
  497. });
  498. }
  499. };
  500.  
  501. if (self._inRoom) {
  502. if (typeof mediaOptions === 'object') {
  503. if (mediaOptions.audio === false && mediaOptions.video === false) {
  504. stopStream = true;
  505. log.warn([null, 'MediaStream', self._selectedRoom, 'Stopping current MediaStream ' +
  506. 'as provided settings for audio and video is false (' + stopStream + ')'], mediaOptions);
  507. }
  508. }
  509.  
  510. log.log([null, 'Socket', previousRoom, 'Leaving room before joining new room'], self._selectedRoom);
  511.  
  512. self.leaveRoom(stopStream, function(error, success) {
  513. log.log([null, 'Socket', previousRoom, 'Leave room callback result'], {
  514. error: error,
  515. success: success
  516. });
  517. log.log([null, 'Socket', self._selectedRoom, 'Joining room. Media options:'], mediaOptions);
  518. if (typeof room === 'string' ? room !== self._selectedRoom : false) {
  519. self._initSelectedRoom(room, function(errorObj) {
  520. if (errorObj) {
  521. if (typeof callback === 'function') {
  522. callback({
  523. room: self._selectedRoom,
  524. errorCode: self._readyState,
  525. error: new Error(errorObj)
  526. }, null);
  527. }
  528. } else {
  529. self._waitForOpenChannel(mediaOptions, channelCallback);
  530. }
  531. });
  532. } else {
  533. self._waitForOpenChannel(mediaOptions, channelCallback);
  534. }
  535. });
  536.  
  537. } else {
  538. log.log([null, 'Socket', self._selectedRoom, 'Joining room. Media options:'],
  539. mediaOptions);
  540.  
  541. var isNotSameRoom = typeof room === 'string' ? room !== self._selectedRoom : false;
  542.  
  543. if (isNotSameRoom) {
  544. self._initSelectedRoom(room, function(errorObj) {
  545. if (errorObj) {
  546. if (typeof callback === 'function') {
  547. callback({
  548. room: self._selectedRoom,
  549. errorCode: self._readyState,
  550. error: new Error(errorObj)
  551. }, null);
  552. }
  553. } else {
  554. self._waitForOpenChannel(mediaOptions, channelCallback);
  555. }
  556. });
  557. } else {
  558. self._waitForOpenChannel(mediaOptions, channelCallback);
  559. }
  560. }
  561. };
  562.  
  563. /**
  564. * Waits for the signaling socket channel connection to be ready before
  565. * starting the room connection with the Skylink signaling platform.
  566. * @method _waitForOpenChannel
  567. * @param {JSON} [options] The connection settings for self connection in the
  568. * room. If both audio and video
  569. * option is <code>false</code>, there should be no audio and video stream
  570. * sending from self connection.
  571. * @param {String|JSON} [options.userData] The custom user data
  572. * information set by developer. This custom user data can also
  573. * be set in {{#crossLink "Skylink/setUserData:method"}}setUserData(){{/crossLink}}.
  574. * @param {Boolean|JSON} [options.audio=false] The self Stream streaming audio settings.
  575. * If <code>false</code>, it means that audio streaming is disabled in
  576. * the self Stream. If this option is set to <code>true</code> or is defined with
  577. * settings, {{#crossLink "Skylink/getUserMedia:method"}}getUserMedia(){{/crossLink}}
  578. * will be invoked. Self will not connect to the room unless the Stream audio
  579. * user media access is given.
  580. * @param {Boolean} [options.audio.stereo] The flag that indicates if
  581. * stereo should be enabled in self connection Stream
  582. * audio streaming.
  583. * @param {Boolean} [options.audio.mute=false] The flag that
  584. * indicates if the self Stream object audio streaming is muted.
  585. * @param {Boolean|JSON} [options.video=false] The self Stream streaming video settings.
  586. * If <code>false</code>, it means that video streaming is disabled in
  587. * the self Stream. If this option is set to <code>true</code> or is defined with
  588. * settings, {{#crossLink "Skylink/getUserMedia:method"}}getUserMedia(){{/crossLink}}
  589. * will be invoked. Self will not connect to the room unless the Stream video
  590. * user media access is given.
  591. * @param {Boolean} [options.video.mute=false] The flag that
  592. * indicates if the self Stream object video streaming is muted.
  593. * @param {JSON} [options.video.resolution] The self Stream streaming video
  594. * resolution settings. Setting the resolution may
  595. * not force set the resolution provided as it depends on the how the
  596. * browser handles the resolution. [Rel: Skylink.VIDEO_RESOLUTION]
  597. * @param {Number} [options.video.resolution.width] The self
  598. * Stream streaming video resolution width.
  599. * @param {Number} [options.video.resolution.height] The self
  600. * Stream streaming video resolution height.
  601. * @param {Number} [options.video.frameRate=50] The self
  602. * Stream streaming video maximum frameRate.
  603. * @param {String} [options.bandwidth] The self
  604. * streaming bandwidth settings. Setting the bandwidth flags may not
  605. * force set the bandwidth for each connection stream channels as it depends
  606. * on how the browser handles the bandwidth bitrate. Values are configured
  607. * in <var>kb/s</var>.
  608. * @param {String} [options.bandwidth.audio=50] The configured
  609. * audio stream channel for the self Stream object bandwidth
  610. * that audio streaming should use in <var>kb/s</var>.
  611. * @param {String} [options.bandwidth.video=256] The configured
  612. * video stream channel for the self Stream object bandwidth
  613. * that video streaming should use in <var>kb/s</var>.
  614. * @param {String} [options.bandwidth.data=1638400] The configured
  615. * datachannel channel for the DataChannel connection bandwidth
  616. * that datachannel connection per packet should be able use in <var>kb/s</var>.
  617. * @param {Boolean} [options.manualGetUserMedia] The flag that indicates if
  618. * <code>joinRoom()</code> should not invoke
  619. * {{#crossLink "Skylink/getUserMedia:method"}}getUserMedia(){{/crossLink}}
  620. * automatically but allow the developer's application to invoke
  621. * {{#crossLink "Skylink/getUserMedia:method"}}getUserMedia(){{/crossLink}}
  622. * manually in the application. When user media access is required, the
  623. * event {{#crossLink "Skylink/mediaAccessRequired:event"}}mediaAccessRequired{{/crossLink}}
  624. * will be triggered.
  625. * @param {Function} callback The callback fired after signaling socket channel connection
  626. * has opened successfully with relevant user media being available according to the
  627. * settings or met with an exception. The callback signature is <code>function (error)</code>.
  628. * @param {Object} callback.error The error object received in the callback.
  629. * If received as <code>undefined</code>, it means that there is no errors.
  630. * @trigger peerJoined, incomingStream, mediaAccessRequired
  631. * @private
  632. * @component Room
  633. * @for Skylink
  634. * @since 0.5.5
  635. */
  636. Skylink.prototype._waitForOpenChannel = function(mediaOptions, callback) {
  637. var self = this;
  638. // when reopening room, it should stay as 0
  639. self._socketCurrentReconnectionAttempt = 0;
  640.  
  641. // wait for ready state before opening
  642. self._wait(function() {
  643. self._condition('channelOpen', function() {
  644. mediaOptions = mediaOptions || {};
  645.  
  646. // parse user data settings
  647. self._parseUserData(mediaOptions.userData || self._userData);
  648. self._parseBandwidthSettings(mediaOptions.bandwidth);
  649.  
  650. // wait for local mediastream
  651. self._waitForLocalMediaStream(callback, mediaOptions);
  652. }, function() { // open channel first if it's not opened
  653.  
  654. if (!self._channelOpen) {
  655. self._openChannel();
  656. }
  657. return self._channelOpen;
  658. }, function(state) {
  659. return true;
  660. });
  661. }, function() {
  662. return self._readyState === self.READY_STATE_CHANGE.COMPLETED;
  663. });
  664.  
  665. };
  666.  
  667. /**
  668. * Disconnects self from current connected room.
  669. * @method leaveRoom
  670. * @param {Boolean|JSON} [stopMediaOptions=true] The stop attached Stream options for
  671. * Skylink when leaving the room. If provided options is a
  672. * <var>typeof</var> <code>boolean</code>, it will be interpreted as both
  673. * <code>userMedia</code> and <code>screenshare</code> Streams would be stopped.
  674. * @param {Boolean} [stopMediaOptions.userMedia=true] The flag that indicates if leaving the room
  675. * should automatically stop and clear the existing user media stream attached to skylink.
  676. * This would trigger <code>mediaAccessStopped</code> for this Stream if available.
  677. * @param {Boolean} [stopMediaOptions.screenshare=true] The flag that indicates if leaving the room
  678. * should automatically stop and clear the existing screensharing stream attached to skylink.
  679. * This would trigger <code>mediaAccessStopped</code> for this Stream if available.
  680. * @param {Function} [callback] The callback fired after self has
  681. * left the room successfully or have met with an exception.
  682. * The callback signature is <code>function (error, success)</code>.
  683. * @param {Object} callback.error The error object received in the callback.
  684. * If received as <code>null</code>, it means that there is no errors.
  685. * @param {JSON} callback.success The success object received in the callback.
  686. * If received as <code>null</code>, it means that there are errors.
  687. * @param {String} callback.success.peerId The assigned previous Peer ID
  688. * to self given when self was still connected to the room.
  689. * @param {String} callback.success.previousRoom The room self was disconnected
  690. * from.
  691. * @example
  692. * //Example 1: Just leaveRoom
  693. * SkylinkDemo.leaveRoom();
  694. *
  695. * //Example 2: leaveRoom with callback
  696. * SkylinkDemo.leaveRoom(function(error, success){
  697. * if (error){
  698. * console.log("Error happened");
  699. * }
  700. * else{
  701. * console.log("Successfully left room");
  702. * }
  703. * });
  704. * @trigger peerLeft, channelClose, streamEnded
  705. * @component Room
  706. * @for Skylink
  707. * @since 0.5.5
  708. */
  709. Skylink.prototype.leaveRoom = function(stopMediaOptions, callback) {
  710. var self = this;
  711. var error; // j-shint !!!
  712. var stopUserMedia = true;
  713. var stopScreenshare = true;
  714.  
  715. // shift parameters
  716. if (typeof stopMediaOptions === 'function') {
  717. callback = stopMediaOptions;
  718. stopMediaOptions = true;
  719. } else if (typeof stopMediaOptions === 'undefined') {
  720. stopMediaOptions = true;
  721. }
  722.  
  723. // stopMediaOptions === null or {} ?
  724. if (typeof stopMediaOptions === 'object' && stopMediaOptions !== null) {
  725. stopUserMedia = stopMediaOptions.userMedia !== false;
  726. stopScreenshare = stopMediaOptions.screenshare !== false;
  727.  
  728. } else if (typeof stopMediaOptions !== 'boolean') {
  729. error = 'stopMediaOptions parameter provided is not a boolean or valid object';
  730. log.error(error, stopMediaOptions);
  731. if (typeof callback === 'function') {
  732. log.log([null, 'Socket', self._selectedRoom, 'Error occurred. ' +
  733. 'Firing callback with error -> '
  734. ], error);
  735. callback(new Error(error), null);
  736. }
  737. return;
  738.  
  739. } else if (stopMediaOptions === false) {
  740. stopUserMedia = false;
  741. stopScreenshare = false;
  742. }
  743.  
  744. if (!self._inRoom) {
  745. error = 'Unable to leave room as user is not in any room';
  746. log.error(error);
  747. if (typeof callback === 'function') {
  748. log.log([null, 'Socket', self._selectedRoom, 'Error occurred. ' +
  749. 'Firing callback with error -> '
  750. ], error);
  751. callback(new Error(error), null);
  752. }
  753. return;
  754. }
  755.  
  756. // NOTE: ENTER/WELCOME made but no peerconnection...
  757. // which may result in peerLeft not triggered..
  758. // WHY? but to ensure clear all
  759. var peers = Object.keys(self._peerInformations);
  760. var conns = Object.keys(self._peerConnections);
  761. var i;
  762. for (i = 0; i < conns.length; i++) {
  763. if (peers.indexOf(conns[i]) === -1) {
  764. peers.push(conns[i]);
  765. }
  766. }
  767. for (i = 0; i < peers.length; i++) {
  768. self._removePeer(peers[i]);
  769. }
  770. self._inRoom = false;
  771. self._closeChannel();
  772.  
  773. self._stopLocalMediaStreams({
  774. userMedia: stopUserMedia,
  775. screenshare: stopScreenshare
  776. });
  777.  
  778. self._wait(function() {
  779. log.log([null, 'Socket', self._selectedRoom, 'User left the room. Callback fired.']);
  780. self._trigger('peerLeft', self._user.sid, self.getPeerInfo(), true);
  781.  
  782. if (typeof callback === 'function') {
  783. callback(null, {
  784. peerId: self._user.sid,
  785. previousRoom: self._selectedRoom
  786. });
  787. }
  788. }, function() {
  789. return (Object.keys(self._peerConnections).length === 0 &&
  790. self._channelOpen === false); // &&
  791. //self._readyState === self.READY_STATE_CHANGE.COMPLETED);
  792. }, false);
  793. };
  794.  
  795. /**
  796. * Locks the currently connected room to prevent other peers
  797. * from joining the room.
  798. * @method lockRoom
  799. * @example
  800. * SkylinkDemo.lockRoom();
  801. * @trigger roomLock
  802. * @component Room
  803. * @for Skylink
  804. * @since 0.5.0
  805. */
  806. Skylink.prototype.lockRoom = function() {
  807. log.log('Update to isRoomLocked status ->', true);
  808. this._sendChannelMessage({
  809. type: this._SIG_MESSAGE_TYPE.ROOM_LOCK,
  810. mid: this._user.sid,
  811. rid: this._room.id,
  812. lock: true
  813. });
  814. this._roomLocked = true;
  815. this._trigger('roomLock', true, this._user.sid,
  816. this.getPeerInfo(), true);
  817. };
  818.  
  819. /**
  820. * Unlocks the currently connected room to allow other peers
  821. * to join the room.
  822. * @method unlockRoom
  823. * @example
  824. * SkylinkDemo.unlockRoom();
  825. * @trigger roomLock
  826. * @component Room
  827. * @for Skylink
  828. * @since 0.5.0
  829. */
  830. Skylink.prototype.unlockRoom = function() {
  831. log.log('Update to isRoomLocked status ->', false);
  832. this._sendChannelMessage({
  833. type: this._SIG_MESSAGE_TYPE.ROOM_LOCK,
  834. mid: this._user.sid,
  835. rid: this._room.id,
  836. lock: false
  837. });
  838. this._roomLocked = false;
  839. this._trigger('roomLock', false, this._user.sid,
  840. this.getPeerInfo(), true);
  841. };