您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

VADTalkMutedDetection.js 4.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. import { EventEmitter } from 'events';
  2. import { calculateAverage } from '../util/MathUtil';
  3. import { DETECTOR_STATE_CHANGE, VAD_TALK_WHILE_MUTED } from './DetectionEvents';
  4. /**
  5. * The threshold which the average VAD values for a span of time needs to exceed to trigger an event.
  6. * @type {number}
  7. */
  8. const VAD_AVG_THRESHOLD = 0.6;
  9. /**
  10. * The VAD score needed to trigger the processing algorithm, i.e. if a sample has the VAD score >= VAD_VOICE_LEVEL
  11. * we start processing all scores for a time span defined by const PROCESS_TIME_FRAME_SPAN_MS.
  12. * @type {number}
  13. */
  14. const VAD_VOICE_LEVEL = 0.9;
  15. /**
  16. * Sample rate of TrackVADEmitter, it defines how many audio samples are processed at a time.
  17. * @type {number}
  18. */
  19. /**
  20. * Time span over which we calculate an average score used to determine if we trigger the event.
  21. * @type {number}
  22. */
  23. const PROCESS_TIME_FRAME_SPAN_MS = 700;
  24. /**
  25. * Detect if provided VAD score which is generated on a muted device is voice and fires an event.
  26. */
  27. export default class VADTalkMutedDetection extends EventEmitter {
  28. /**
  29. * Creates <tt>VADTalkMutedDetection</tt>
  30. * @constructor
  31. */
  32. constructor() {
  33. super();
  34. /**
  35. * Flag which denotes the current state of the detection service i.e.if there is already a processing operation
  36. * ongoing.
  37. */
  38. this._processing = false;
  39. /**
  40. * Buffer that keeps the VAD scores for a period of time.
  41. */
  42. this._scoreArray = [];
  43. /**
  44. * Current mute state of the audio track being monitored.
  45. */
  46. this._active = false;
  47. this._calculateVADScore = this._calculateVADScore.bind(this);
  48. }
  49. /**
  50. * Compute cumulative VAD score function called once the PROCESS_TIME_FRAME_SPAN_MS timeout has elapsed.
  51. * @returns {void}
  52. * @fires VAD_TALK_WHILE_MUTED
  53. */
  54. _calculateVADScore() {
  55. const score = calculateAverage(this._scoreArray);
  56. if (score > VAD_AVG_THRESHOLD) {
  57. this.emit(VAD_TALK_WHILE_MUTED);
  58. // Event was fired. Stop event emitter and remove listeners so no residue events kick off after this point
  59. // and a single VAD_TALK_WHILE_MUTED is generated per mic muted state.
  60. this._setActiveState(false);
  61. }
  62. // We reset the context in case a new process phase needs to be triggered.
  63. this.reset();
  64. }
  65. /**
  66. * Set the active state of the detection service and notify any listeners.
  67. *
  68. * @param {boolean} active
  69. * @fires DETECTOR_STATE_CHANGE
  70. */
  71. _setActiveState(active) {
  72. this._active = active;
  73. this.emit(DETECTOR_STATE_CHANGE, this._active);
  74. }
  75. /**
  76. * Change the state according to the muted status of the tracked device.
  77. *
  78. * @param {boolean} isMuted - Is the device muted or not.
  79. */
  80. changeMuteState(isMuted) {
  81. // This service only needs to run when the microphone is muted.
  82. this._setActiveState(isMuted);
  83. this.reset();
  84. }
  85. /**
  86. * Check whether or not the service is active or not.
  87. *
  88. * @returns {boolean}
  89. */
  90. isActive() {
  91. return this._active;
  92. }
  93. /**
  94. * Listens for {@link TrackVADEmitter} events and processes them.
  95. *
  96. * @param {Object} vadScore -VAD score emitted by {@link TrackVADEmitter}
  97. * @param {Date} vadScore.timestamp - Exact time at which processed PCM sample was generated.
  98. * @param {number} vadScore.score - VAD score on a scale from 0 to 1 (i.e. 0.7)
  99. * @param {string} vadScore.deviceId - Device id of the associated track.
  100. * @listens VAD_SCORE_PUBLISHED
  101. */
  102. processVADScore(vadScore) {
  103. if (!this._active) {
  104. return;
  105. }
  106. // There is a processing phase on going, add score to buffer array.
  107. if (this._processing) {
  108. this._scoreArray.push(vadScore.score);
  109. return;
  110. }
  111. // Because we remove all listeners on the vadEmitter once the main event is triggered,
  112. // there is no need to check for rogue events.
  113. if (vadScore.score > VAD_VOICE_LEVEL) {
  114. this._processing = true;
  115. this._scoreArray.push(vadScore.score);
  116. // Start gathering VAD scores for the configured period of time.
  117. this._processTimeout = setTimeout(this._calculateVADScore, PROCESS_TIME_FRAME_SPAN_MS);
  118. }
  119. }
  120. /**
  121. * Reset the processing context, clear buffer, cancel the timeout trigger.
  122. *
  123. * @returns {void}
  124. */
  125. reset() {
  126. this._processing = false;
  127. this._scoreArray = [];
  128. clearTimeout(this._processTimeout);
  129. }
  130. }