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.

AudioMixerEffect.js 3.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. // @flow
  2. import JitsiMeetJS from '../../base/lib-jitsi-meet';
  3. import { MEDIA_TYPE } from '../../base/media';
  4. /**
  5. * Class Implementing the effect interface expected by a JitsiLocalTrack.
  6. * The AudioMixerEffect, as the name implies, mixes two JitsiLocalTracks containing a audio track. First track is
  7. * provided at the moment of creation, second is provided through the effect interface.
  8. */
  9. export class AudioMixerEffect {
  10. /**
  11. * JitsiLocalTrack that is going to be mixed into the track that uses this effect.
  12. */
  13. _mixAudio: Object;
  14. /**
  15. * MediaStream resulted from mixing.
  16. */
  17. _mixedMediaStream: Object;
  18. /**
  19. * MediaStreamTrack obtained from mixed stream.
  20. */
  21. _mixedMediaTrack: Object;
  22. /**
  23. * Original MediaStream from the JitsiLocalTrack that uses this effect.
  24. */
  25. _originalStream: Object;
  26. /**
  27. * MediaStreamTrack obtained from the original MediaStream.
  28. */
  29. _originalTrack: Object;
  30. /**
  31. * lib-jitsi-meet AudioMixer.
  32. */
  33. _audioMixer: Object;
  34. /**
  35. * Creates AudioMixerEffect.
  36. *
  37. * @param {JitsiLocalTrack} mixAudio - JitsiLocalTrack which will be mixed with the original track.
  38. */
  39. constructor(mixAudio: Object) {
  40. if (mixAudio.getType() !== MEDIA_TYPE.AUDIO) {
  41. throw new Error('AudioMixerEffect only supports audio JitsiLocalTracks; effect will not work!');
  42. }
  43. this._mixAudio = mixAudio;
  44. }
  45. /**
  46. * Checks if the JitsiLocalTrack supports this effect.
  47. *
  48. * @param {JitsiLocalTrack} sourceLocalTrack - Track to which the effect will be applied.
  49. * @returns {boolean} - Returns true if this effect can run on the specified track, false otherwise.
  50. */
  51. isEnabled(sourceLocalTrack: Object) {
  52. // Both JitsiLocalTracks need to be audio i.e. contain an audio MediaStreamTrack
  53. return sourceLocalTrack.isAudioTrack() && this._mixAudio.isAudioTrack();
  54. }
  55. /**
  56. * Effect interface called by source JitsiLocalTrack, At this point a WebAudio ChannelMergerNode is created
  57. * and and the two associated MediaStreams are connected to it; the resulting mixed MediaStream is returned.
  58. *
  59. * @param {MediaStream} audioStream - Audio stream which will be mixed with _mixAudio.
  60. * @returns {MediaStream} - MediaStream containing both audio tracks mixed together.
  61. */
  62. startEffect(audioStream: MediaStream) {
  63. this._originalStream = audioStream;
  64. this._originalTrack = audioStream.getTracks()[0];
  65. this._audioMixer = JitsiMeetJS.createAudioMixer();
  66. this._audioMixer.addMediaStream(this._mixAudio.getOriginalStream());
  67. this._audioMixer.addMediaStream(this._originalStream);
  68. this._mixedMediaStream = this._audioMixer.start();
  69. this._mixedMediaTrack = this._mixedMediaStream.getTracks()[0];
  70. // Sync the resulting mixed track enabled state with that of the track using the effect.
  71. this.setMuted(!this._originalTrack.enabled);
  72. this._originalTrack.enabled = true;
  73. return this._mixedMediaStream;
  74. }
  75. /**
  76. * Reset the AudioMixer stopping it in the process.
  77. *
  78. * @returns {void}
  79. */
  80. stopEffect() {
  81. // Match state of the original track with that of the mixer track, not doing so can
  82. // result in an inconsistent state e.g. redux state is muted yet track is enabled.
  83. this._originalTrack.enabled = this._mixedMediaTrack.enabled;
  84. this._audioMixer.reset();
  85. }
  86. /**
  87. * Change the muted state of the effect.
  88. *
  89. * @param {boolean} muted - Should effect be muted or not.
  90. * @returns {void}
  91. */
  92. setMuted(muted: boolean) {
  93. this._mixedMediaTrack.enabled = !muted;
  94. }
  95. /**
  96. * Check whether or not this effect is muted.
  97. *
  98. * @returns {boolean}
  99. */
  100. isMuted() {
  101. return !this._mixedMediaTrack.enabled;
  102. }
  103. }