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.

JitsiLocalTrack.js 7.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. /* global Promise */
  2. var JitsiTrack = require("./JitsiTrack");
  3. var RTCBrowserType = require("./RTCBrowserType");
  4. var JitsiTrackEvents = require('../../JitsiTrackEvents');
  5. var RTCUtils = require("./RTCUtils");
  6. /**
  7. * Represents a single media track (either audio or video).
  8. * @constructor
  9. */
  10. function JitsiLocalTrack(stream, videoType,
  11. resolution, deviceId)
  12. {
  13. this.videoType = videoType;
  14. this.dontFireRemoveEvent = false;
  15. this.resolution = resolution;
  16. this.deviceId = deviceId;
  17. this.startMuted = false;
  18. this.ssrc = null;
  19. this.disposed = false;
  20. //FIXME: This dependacy is not necessary.
  21. this.conference = null;
  22. JitsiTrack.call(this, null, stream,
  23. function () {
  24. if(!this.dontFireRemoveEvent)
  25. this.eventEmitter.emit(
  26. JitsiTrackEvents.LOCAL_TRACK_STOPPED);
  27. this.dontFireRemoveEvent = false;
  28. }.bind(this));
  29. this.initialMSID = this.getMSID();
  30. }
  31. JitsiLocalTrack.prototype = Object.create(JitsiTrack.prototype);
  32. JitsiLocalTrack.prototype.constructor = JitsiLocalTrack;
  33. /**
  34. * Mutes / unmutes the track.
  35. * @param mute {boolean} if true the track will be muted. Otherwise the track will be unmuted.
  36. */
  37. JitsiLocalTrack.prototype._setMute = function (mute) {
  38. if (this.isMuted() === mute) {
  39. return;
  40. }
  41. if(!this.rtc) {
  42. this.startMuted = mute;
  43. return;
  44. }
  45. var isAudio = this.type === JitsiTrack.AUDIO;
  46. this.dontFireRemoveEvent = false;
  47. if ((window.location.protocol != "https:") ||
  48. (isAudio) || this.videoType === "desktop" ||
  49. // FIXME FF does not support 'removeStream' method used to mute
  50. RTCBrowserType.isFirefox()) {
  51. var tracks = this._getTracks();
  52. for (var idx = 0; idx < tracks.length; idx++) {
  53. tracks[idx].enabled = !mute;
  54. }
  55. if(isAudio)
  56. this.rtc.room.setAudioMute(mute);
  57. else
  58. this.rtc.room.setVideoMute(mute);
  59. this.eventEmitter.emit(JitsiTrackEvents.TRACK_MUTE_CHANGED);
  60. } else {
  61. if (mute) {
  62. this.dontFireRemoveEvent = true;
  63. this.rtc.room.removeStream(this.stream, function () {},
  64. {mtype: this.type, type: "mute", ssrc: this.ssrc});
  65. RTCUtils.stopMediaStream(this.stream);
  66. if(isAudio)
  67. this.rtc.room.setAudioMute(mute);
  68. else
  69. this.rtc.room.setVideoMute(mute);
  70. this.stream = null;
  71. this.eventEmitter.emit(JitsiTrackEvents.TRACK_MUTE_CHANGED);
  72. //FIXME: Maybe here we should set the SRC for the containers to something
  73. } else {
  74. var self = this;
  75. var streamOptions = {
  76. devices: (isAudio ? ["audio"] : ["video"]),
  77. resolution: self.resolution
  78. };
  79. if (isAudio) {
  80. streamOptions['micDeviceId'] = self.deviceId;
  81. } else if(self.videoType === 'camera') {
  82. streamOptions['cameraDeviceId'] = self.deviceId;
  83. }
  84. RTCUtils.obtainAudioAndVideoPermissions(streamOptions)
  85. .then(function (streams) {
  86. var stream = null;
  87. for(var i = 0; i < streams.length; i++) {
  88. stream = streams[i];
  89. if(stream.type === self.type) {
  90. self.stream = stream.stream;
  91. self.videoType = stream.videoType;
  92. break;
  93. }
  94. }
  95. if(!stream)
  96. return;
  97. for(var i = 0; i < self.containers.length; i++)
  98. {
  99. self.containers[i]
  100. = RTCUtils.attachMediaStream(
  101. self.containers[i], self.stream);
  102. }
  103. self.rtc.room.addStream(self.stream,
  104. function () {
  105. if(isAudio)
  106. self.rtc.room.setAudioMute(mute);
  107. else
  108. self.rtc.room.setVideoMute(mute);
  109. self.eventEmitter.emit(
  110. JitsiTrackEvents.TRACK_MUTE_CHANGED);
  111. }, {
  112. mtype: self.type,
  113. type: "unmute",
  114. ssrc: self.ssrc,
  115. msid: self.getMSID()});
  116. });
  117. }
  118. }
  119. }
  120. /**
  121. * Stops sending the media track. And removes it from the HTML.
  122. * NOTE: Works for local tracks only.
  123. * @returns {Promise}
  124. */
  125. JitsiLocalTrack.prototype.dispose = function () {
  126. var promise = Promise.resolve();
  127. if (this.conference){
  128. promise = this.conference.removeTrack(this);
  129. }
  130. if (this.stream) {
  131. RTCUtils.stopMediaStream(this.stream);
  132. this.detach();
  133. }
  134. this.disposed = true;
  135. return promise;
  136. };
  137. /**
  138. * Returns <tt>true</tt> - if the stream is muted
  139. * and <tt>false</tt> otherwise.
  140. * @returns {boolean} <tt>true</tt> - if the stream is muted
  141. * and <tt>false</tt> otherwise.
  142. */
  143. JitsiLocalTrack.prototype.isMuted = function () {
  144. if (!this.stream)
  145. return true;
  146. var tracks = [];
  147. var isAudio = this.type === JitsiTrack.AUDIO;
  148. if (isAudio) {
  149. tracks = this.stream.getAudioTracks();
  150. } else {
  151. if (!this.isActive())
  152. return true;
  153. tracks = this.stream.getVideoTracks();
  154. }
  155. for (var idx = 0; idx < tracks.length; idx++) {
  156. if(tracks[idx].enabled)
  157. return false;
  158. }
  159. return true;
  160. };
  161. /**
  162. * Private method. Updates rtc property of the track.
  163. * @param rtc the rtc instance.
  164. */
  165. JitsiLocalTrack.prototype._setRTC = function (rtc) {
  166. this.rtc = rtc;
  167. // We want to keep up with postponed events which should have been fired
  168. // on "attach" call, but for local track we not always have the conference
  169. // before attaching. However this may result in duplicated events if they
  170. // have been triggered on "attach" already.
  171. for(var i = 0; i < this.containers.length; i++)
  172. {
  173. this._maybeFireTrackAttached(this.containers[i]);
  174. }
  175. };
  176. /**
  177. * Updates the SSRC associated with the MediaStream in JitsiLocalTrack object.
  178. * @ssrc the new ssrc
  179. */
  180. JitsiLocalTrack.prototype._setSSRC = function (ssrc) {
  181. this.ssrc = ssrc;
  182. }
  183. //FIXME: This dependacy is not necessary. This is quick fix.
  184. /**
  185. * Sets the JitsiConference object associated with the track. This is temp
  186. * solution.
  187. * @param conference the JitsiConference object
  188. */
  189. JitsiLocalTrack.prototype._setConference = function(conference) {
  190. this.conference = conference;
  191. }
  192. /**
  193. * Gets the SSRC of this local track if it's available already or <tt>null</tt>
  194. * otherwise. That's because we don't know the SSRC until local description is
  195. * created.
  196. * In case of video and simulcast returns the the primarySSRC.
  197. * @returns {string} or {null}
  198. */
  199. JitsiLocalTrack.prototype.getSSRC = function () {
  200. if(this.ssrc && this.ssrc.groups && this.ssrc.groups.length)
  201. return this.ssrc.groups[0].primarySSRC;
  202. else if(this.ssrc && this.ssrc.ssrcs && this.ssrc.ssrcs.length)
  203. return this.ssrc.ssrcs[0];
  204. else
  205. return null;
  206. };
  207. /**
  208. * Return true;
  209. */
  210. JitsiLocalTrack.prototype.isLocal = function () {
  211. return true;
  212. }
  213. module.exports = JitsiLocalTrack;