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

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