Преглед на файлове

Implements audio problems detection

master
hristoterezov преди 9 години
родител
ревизия
36078b0e66
променени са 6 файла, в които са добавени 121 реда и са изтрити 12 реда
  1. 63
    0
      JitsiConference.js
  2. 19
    12
      modules/RTC/RTC.js
  3. 12
    0
      modules/statistics/CallStats.js
  4. 5
    0
      modules/statistics/RTPStatsCollector.js
  5. 18
    0
      modules/statistics/statistics.js
  6. 4
    0
      service/statistics/Events.js

+ 63
- 0
JitsiConference.js Целия файл

@@ -68,6 +68,7 @@ function JitsiConference(options) {
68 68
         video: undefined
69 69
     };
70 70
     this.isMutedByFocus = false;
71
+    this.reportedAudioSSRCs = {};
71 72
 }
72 73
 
73 74
 /**
@@ -922,6 +923,63 @@ JitsiConference.prototype.isCallstatsEnabled = function () {
922 923
     return this.statistics.isCallstatsEnabled();
923 924
 }
924 925
 
926
+/**
927
+ * Reports detected audio problem with the media stream related to the passed
928
+ * ssrc.
929
+ * @param ssrc {string} the ssrc
930
+ */
931
+JitsiConference.prototype._reportAudioProblem = function (ssrc) {
932
+    if(this.reportedAudioSSRCs[ssrc])
933
+        return;
934
+    var track = this.rtc.getRemoteTrackBySSRC(ssrc);
935
+    if(!track || !track.isAudioTrack())
936
+        return;
937
+
938
+    this.reportedAudioSSRCs[ssrc] = true;
939
+    var errorContent = {
940
+        errMsg: "The audio is received but not played",
941
+        ssrc: ssrc
942
+    };
943
+
944
+    var mstream = track.stream, mtrack = track.track;
945
+    if(mstream) {
946
+        errorContent.MediaStream = {
947
+            active: mstream.active,
948
+            id: mstream.id
949
+        }
950
+    }
951
+
952
+    if(mtrack) {
953
+        errorContent.MediaStreamTrack = {
954
+            enabled: mtrack.enabled,
955
+            id: mtrack.id,
956
+            label: mtrack.label,
957
+            muted: mtrack.muted
958
+        }
959
+    }
960
+
961
+    if(track.containers) {
962
+        errorContent.containers = [];
963
+        track.containers.forEach(function (container) {
964
+            errorContent.containers.push({
965
+                autoplay: container.autoplay,
966
+                muted: container.muted,
967
+                src: container.src,
968
+                volume: container.volume,
969
+                id: container.id,
970
+                ended: container.ended,
971
+                paused: container.paused,
972
+                readyState: container.readyState
973
+            });
974
+        });
975
+    }
976
+
977
+    this.statistics.sendDetectedAudioProblem(
978
+        new Error(JSON.stringify(errorContent)));
979
+    logger.error("Audio problem detected. The audio is received but not played",
980
+        errorContent);
981
+}
982
+
925 983
 /**
926 984
  * Setups the listeners needed for the conference.
927 985
  * @param conference the conference
@@ -1277,6 +1335,11 @@ function setupListeners(conference) {
1277 1335
 
1278 1336
             conference.rtc.setAudioLevel(resource, level);
1279 1337
         });
1338
+
1339
+        conference.statistics.addAudioProblemListener(function (ssrc) {
1340
+            conference._reportAudioProblem(ssrc)
1341
+        });
1342
+
1280 1343
         conference.statistics.addConnectionStatsListener(function (stats) {
1281 1344
             var ssrc2resolution = stats.resolution;
1282 1345
 

+ 19
- 12
modules/RTC/RTC.js Целия файл

@@ -447,19 +447,26 @@ RTC.prototype.getResourceBySSRC = function (ssrc) {
447 447
         return Strophe.getResourceFromJid(this.room.myroomjid);
448 448
     }
449 449
 
450
-    var self = this;
451
-    var resultResource = null;
452
-    Object.keys(this.remoteTracks).some(function (resource) {
453
-        var audioTrack = self.getRemoteAudioTrack(resource);
454
-        var videoTrack = self.getRemoteVideoTrack(resource);
455
-        if((audioTrack && audioTrack.getSSRC() == ssrc) ||
456
-            (videoTrack && videoTrack.getSSRC() == ssrc)) {
457
-            resultResource = resource;
458
-            return true;
459
-        }
460
-    });
450
+    var track = this.getRemoteTrackBySSRC(ssrc);
451
+    return track? track.getParticipantId() : null;
452
+};
461 453
 
462
-    return resultResource;
454
+/**
455
+ * Searches in remoteTracks for the ssrc and returns the corresponding track.
456
+ * @param ssrc the ssrc to check.
457
+ */
458
+RTC.prototype.getRemoteTrackBySSRC = function (ssrc) {
459
+    for (var resource in this.remoteTracks) {
460
+        var track = this.getRemoteAudioTrack(resource);
461
+        if(track && track.getSSRC() == ssrc) {
462
+            return track;
463
+        }
464
+        track = this.getRemoteVideoTrack(resource);
465
+        if(track && track.getSSRC() == ssrc) {
466
+            return track;
467
+        }
468
+    }
469
+    return null;
463 470
 };
464 471
 
465 472
 module.exports = RTC;

+ 12
- 0
modules/statistics/CallStats.js Целия файл

@@ -270,6 +270,18 @@ CallStats.prototype.sendTerminateEvent = _try_catch(function () {
270 270
         callStats.fabricEvent.fabricTerminated, this.confID);
271 271
 });
272 272
 
273
+/**
274
+ * Notifies CallStats that audio problems are detected.
275
+ *
276
+ * @param {Error} e error to send
277
+ * @param {CallStats} cs callstats instance related to the error (optional)
278
+ */
279
+CallStats.prototype.sendDetectedAudioProblem = _try_catch(function (e) {
280
+    CallStats._reportError.call(this, wrtcFuncNames.signalingError, e,
281
+        this.peerconnection);
282
+});
283
+
284
+
273 285
 /**
274 286
  * Notifies CallStats for ice connection failed
275 287
  * @param {RTCPeerConnection} pc connection on which failure occured.

+ 5
- 0
modules/statistics/RTPStatsCollector.js Целия файл

@@ -639,6 +639,11 @@ StatsCollector.prototype.processStatsReport = function () {
639 639
             bytesSent = Math.round(((bytesSent * 8) / time) / 1000);
640 640
         }
641 641
 
642
+        //detect audio issues (receiving data but audioLevel == 0)
643
+        if(bytesReceived > 10 && ssrcStats.ssrc2AudioLevel === 0) {
644
+            this.eventEmitter.emit(StatisticsEvents.AUDIO_NOT_WORKING, ssrc);
645
+        }
646
+
642 647
         ssrcStats.setSsrcBitrate({
643 648
             "download": bytesReceived,
644 649
             "upload": bytesSent

+ 18
- 0
modules/statistics/statistics.js Целия файл

@@ -139,6 +139,14 @@ Statistics.prototype.addConnectionStatsListener = function (listener) {
139 139
     this.eventEmitter.on(StatisticsEvents.CONNECTION_STATS, listener);
140 140
 };
141 141
 
142
+/**
143
+ * Adds listener for detected audio problems.
144
+ * @param listener the listener.
145
+ */
146
+Statistics.prototype.addAudioProblemListener = function (listener) {
147
+    this.eventEmitter.on(StatisticsEvents.AUDIO_NOT_WORKING, listener);
148
+};
149
+
142 150
 Statistics.prototype.removeConnectionStatsListener = function (listener) {
143 151
     this.eventEmitter.removeListener(StatisticsEvents.CONNECTION_STATS, listener);
144 152
 };
@@ -349,6 +357,16 @@ Statistics.prototype.sendAddIceCandidateFailed = function (e, pc) {
349 357
         CallStats.sendAddIceCandidateFailed(e, pc, this.callstats);
350 358
 };
351 359
 
360
+/**
361
+ * Notifies CallStats that audio problems are detected.
362
+ *
363
+ * @param {Error} e error to send
364
+ */
365
+Statistics.prototype.sendDetectedAudioProblem = function (e) {
366
+    if(this.callstats)
367
+        this.callstats.sendDetectedAudioProblem(e);
368
+};
369
+
352 370
 /**
353 371
  * Notifies CallStats that there is unhandled exception.
354 372
  *

+ 4
- 0
service/statistics/Events.js Целия файл

@@ -7,4 +7,8 @@ module.exports = {
7 7
      * FIXME: needs documentation.
8 8
      */
9 9
     AUDIO_LEVEL: "statistics.audioLevel",
10
+    /**
11
+     * Notifies about audio problem with remote participant.
12
+     */
13
+    AUDIO_NOT_WORKING: "statistics.audio_not_working"
10 14
 };

Loading…
Отказ
Запис