modified lib-jitsi-meet dev repo
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.

NoAudioSignalDetection.js 4.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. import * as JitsiConferenceEvents from '../../JitsiConferenceEvents';
  2. // We wait a certain time interval for constant silence input from the current device to account for
  3. // potential abnormalities and for a better use experience i.e. don't generate event the instant
  4. // an audio track is added to the tcr.
  5. // Potential improvement - add this as a configurable parameter.
  6. const SILENCE_PERIOD_SEC = 4;
  7. /**
  8. * Detect if there is no audio input on the current TraceAblePeerConnection selected track. The no audio
  9. * state must be constant for a configured amount of time in order for the event to be triggered.
  10. */
  11. export default class NoAudioSignalDetection {
  12. /**
  13. * @param conference the JitsiConference instance that created us.
  14. * @param callback callback that notifies the conference when no audio event is triggered
  15. * @constructor
  16. */
  17. constructor(conference, callback) {
  18. this._conference = conference;
  19. this._callback = callback;
  20. this._firstSilentSignalDate = null;
  21. conference.statistics.addAudioLevelListener(this._audioLevel.bind(this));
  22. conference.on(JitsiConferenceEvents.TRACK_ADDED, this._trackAdded.bind(this));
  23. }
  24. /**
  25. * Checks if the configured period in which no audio was received has elapsed.
  26. *
  27. * @returns {boolean}
  28. */
  29. _hasSilencePeriodElapsed() {
  30. const currentDate = new Date();
  31. const elapsedSec = (currentDate.getTime() - this._firstSilentSignalDate.getTime()) / 1000;
  32. if (elapsedSec > SILENCE_PERIOD_SEC) {
  33. return true;
  34. }
  35. return false;
  36. }
  37. /**
  38. * Trigger the set callback for no audio input if expected conditions are met.
  39. */
  40. _triggerNoAudioCallback() {
  41. // In case this is the first time 0 audio level was detected initialize the interval check start
  42. // date
  43. if (!this._firstSilentSignalDate) {
  44. this._firstSilentSignalDate = new Date();
  45. // If the configured interval has elapsed trigger the callback
  46. } else if (this._hasSilencePeriodElapsed()) {
  47. this._eventFired = true;
  48. this._callback();
  49. }
  50. }
  51. /**
  52. * Receives audio level events for all send and receive streams on the current TraceablePeerConnection.
  53. *
  54. * @param {TraceablePeerConnection} tpc - TraceablePeerConnection of the owning conference.
  55. * @param {number} ssrc - The synchronization source identifier (SSRC) of the endpoint/participant/stream
  56. * being reported.
  57. * @param {number} audioLevel - The audio level of the ssrc.
  58. * @param {boolean} isLocal - true for local/send streams or false for remote/receive streams.
  59. */
  60. _audioLevel(tpc, ssrc, audioLevel, isLocal) {
  61. // We are interested in the local audio stream if the event was not triggered on this device.
  62. if (!isLocal || !this._audioTrack || this._eventFired) {
  63. return;
  64. }
  65. // Get currently active local tracks from the TraceablePeerConnection
  66. const localSSRCs = tpc.localSSRCs.get(this._audioTrack.rtcId);
  67. // Check that currently selected audio stream has ssrc in the TraceablePeerConnection
  68. if (!localSSRCs) {
  69. return;
  70. }
  71. // Only target the current active track in the tpc. For some reason audio levels for previous
  72. // devices are also picked up from the PeerConnection so we filter them out.
  73. const isCurrentTrack = localSSRCs.ssrcs.includes(ssrc);
  74. if (!isCurrentTrack) {
  75. return;
  76. }
  77. if (audioLevel === 0) {
  78. this._triggerNoAudioCallback();
  79. } else {
  80. // Reset the period start date in order to check for consistent silence over the configured
  81. // time interval.
  82. this._firstSilentSignalDate = null;
  83. }
  84. }
  85. /**
  86. * Determines if a specific JitsiTrack is a local audio track.
  87. *
  88. * @param {JitsiTrack} track - The JitsiTrack to be checked whether it represents a local audio track.
  89. * @return {boolean} - true if track represents a local audio track, false otherwise.
  90. */
  91. _isLocalAudioTrack(track) {
  92. return track.isAudioTrack() && track.isLocal();
  93. }
  94. /**
  95. * Notifies NoAudioSignalDetection that a JitsiTrack was added to the associated JitsiConference.
  96. * Only take into account local audio tracks.
  97. *
  98. * @param {JitsiTrack} track - The added JitsiTrack.
  99. */
  100. _trackAdded(track) {
  101. if (this._isLocalAudioTrack(track)) {
  102. // Reset state for the new track.
  103. this._firstSilentSignalDate = null;
  104. this._audioTrack = track;
  105. this._eventFired = false;
  106. }
  107. }
  108. }