Quellcode durchsuchen

feat: emit event when input device has no signal

dev1
Andrei Gavrilescu vor 6 Jahren
Ursprung
Commit
aa7b1eb5cb
3 geänderte Dateien mit 141 neuen und 0 gelöschten Zeilen
  1. 9
    0
      JitsiConference.js
  2. 5
    0
      JitsiConferenceEvents.js
  3. 127
    0
      modules/NoAudioSignalDetection.js

+ 9
- 0
JitsiConference.js Datei anzeigen

@@ -16,6 +16,7 @@ import authenticateAndUpgradeRole from './authenticateAndUpgradeRole';
16 16
 import P2PDominantSpeakerDetection from './modules/P2PDominantSpeakerDetection';
17 17
 import RTC from './modules/RTC/RTC';
18 18
 import TalkMutedDetection from './modules/TalkMutedDetection';
19
+import NoAudioSignalDetection from './modules/NoAudioSignalDetection';
19 20
 import browser from './modules/browser';
20 21
 import ConnectionQuality from './modules/connectivity/ConnectionQuality';
21 22
 import IceFailedNotification
@@ -379,6 +380,14 @@ JitsiConference.prototype._init = function(options = {}) {
379 380
                 this.eventEmitter.emit(JitsiConferenceEvents.TALK_WHILE_MUTED));
380 381
     }
381 382
 
383
+    // Generates events based on no audio input detector.
384
+    if (config.enableNoAudioDetection) {
385
+        // eslint-disable-next-line no-new
386
+        new NoAudioSignalDetection(this, () =>
387
+            this.eventEmitter.emit(JitsiConferenceEvents.NO_AUDIO_INPUT));
388
+    }
389
+
390
+
382 391
     if ('channelLastN' in config) {
383 392
         this.setLastN(config.channelLastN);
384 393
     }

+ 5
- 0
JitsiConferenceEvents.js Datei anzeigen

@@ -245,6 +245,11 @@ export const SUSPEND_DETECTED = 'conference.suspendDetected';
245 245
  */
246 246
 export const TALK_WHILE_MUTED = 'conference.talk_while_muted';
247 247
 
248
+/**
249
+ * Event indicates that the current selected input device has no signal
250
+ */
251
+export const NO_AUDIO_INPUT = 'conference.no_audio_input';
252
+
248 253
 /**
249 254
  * A new media track was added to the conference. The event provides the
250 255
  * following parameters to its listeners:

+ 127
- 0
modules/NoAudioSignalDetection.js Datei anzeigen

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

Laden…
Abbrechen
Speichern