浏览代码

feat(AudioTrack): retries for play()

master
Hristo Terezov 3 年前
父节点
当前提交
574994607c
共有 2 个文件被更改,包括 89 次插入8 次删除
  1. 30
    0
      react/features/analytics/AnalyticsEvents.js
  2. 59
    8
      react/features/base/media/components/web/AudioTrack.js

+ 30
- 0
react/features/analytics/AnalyticsEvents.js 查看文件

696
     };
696
     };
697
 }
697
 }
698
 
698
 
699
+/**
700
+ * Creates an event which indicates that HTMLAudioElement.play has failed.
701
+ *
702
+ * @param {sting} elementID - The ID of the HTMLAudioElement.
703
+ * @returns {Object} The event in a format suitable for sending via sendAnalytics.
704
+ */
705
+export function createAudioPlayErrorEvent(elementID) {
706
+    return {
707
+        action: 'audio.play.error',
708
+        attributes: {
709
+            elementID
710
+        }
711
+    };
712
+}
713
+
714
+/**
715
+ * Creates an event which indicates that HTMLAudioElement.play has succeded after a prior failure.
716
+ *
717
+ * @param {sting} elementID - The ID of the HTMLAudioElement.
718
+ * @returns {Object} The event in a format suitable for sending via sendAnalytics.
719
+ */
720
+export function createAudioPlaySuccessEvent(elementID) {
721
+    return {
722
+        action: 'audio.play.success',
723
+        attributes: {
724
+            elementID
725
+        }
726
+    };
727
+}
728
+
699
 /**
729
 /**
700
  * Creates an event which indicates the "start muted" configuration.
730
  * Creates an event which indicates the "start muted" configuration.
701
  *
731
  *

+ 59
- 8
react/features/base/media/components/web/AudioTrack.js 查看文件

2
 
2
 
3
 import React, { Component } from 'react';
3
 import React, { Component } from 'react';
4
 
4
 
5
+import { createAudioPlayErrorEvent, createAudioPlaySuccessEvent, sendAnalytics } from '../../../../analytics';
6
+import logger from '../../logger';
7
+
5
 /**
8
 /**
6
  * The type of the React {@code Component} props of {@link AudioTrack}.
9
  * The type of the React {@code Component} props of {@link AudioTrack}.
7
  */
10
  */
50
      */
53
      */
51
     _ref: ?HTMLAudioElement;
54
     _ref: ?HTMLAudioElement;
52
 
55
 
56
+    /**
57
+     * The current timeout ID for play() retries.
58
+     */
59
+    _playTimeout: ?TimeoutID;
60
+
53
     /**
61
     /**
54
      * Default values for {@code AudioTrack} component's properties.
62
      * Default values for {@code AudioTrack} component's properties.
55
      *
63
      *
72
 
80
 
73
         // Bind event handlers so they are only bound once for every instance.
81
         // Bind event handlers so they are only bound once for every instance.
74
         this._setRef = this._setRef.bind(this);
82
         this._setRef = this._setRef.bind(this);
83
+        this._play = this._play.bind(this);
75
     }
84
     }
76
 
85
 
77
 
86
 
85
         this._attachTrack(this.props.audioTrack);
94
         this._attachTrack(this.props.audioTrack);
86
 
95
 
87
         if (this._ref) {
96
         if (this._ref) {
88
-            const { autoPlay, muted, volume } = this.props;
89
-
90
-            if (autoPlay) {
91
-                // Ensure the audio gets play() called on it. This may be necessary in the
92
-                // case where the local video container was moved and re-attached, in which
93
-                // case the audio may not autoplay.
94
-                this._ref.play();
95
-            }
97
+            const { muted, volume } = this.props;
96
 
98
 
97
             if (typeof volume === 'number') {
99
             if (typeof volume === 'number') {
98
                 this._ref.volume = volume;
100
                 this._ref.volume = volume;
181
         }
183
         }
182
 
184
 
183
         track.jitsiTrack.attach(this._ref);
185
         track.jitsiTrack.attach(this._ref);
186
+        this._play();
184
     }
187
     }
185
 
188
 
186
     /**
189
     /**
193
      */
196
      */
194
     _detachTrack(track) {
197
     _detachTrack(track) {
195
         if (this._ref && track && track.jitsiTrack) {
198
         if (this._ref && track && track.jitsiTrack) {
199
+            clearTimeout(this._playTimeout);
200
+            this._playTimeout = undefined;
196
             track.jitsiTrack.detach(this._ref);
201
             track.jitsiTrack.detach(this._ref);
197
         }
202
         }
198
     }
203
     }
199
 
204
 
205
+    _play: ?number => void;
206
+
207
+    /**
208
+     * Plays the uderlying HTMLAudioElement.
209
+     *
210
+     * @param {number} retries - The number of previously failed retries.
211
+     * @returns {void}
212
+     */
213
+    _play(retries = 0) {
214
+        if (!this._ref) {
215
+            // nothing to play.
216
+
217
+            return;
218
+        }
219
+        const { autoPlay, id } = this.props;
220
+
221
+        if (autoPlay) {
222
+            // Ensure the audio gets play() called on it. This may be necessary in the
223
+            // case where the local video container was moved and re-attached, in which
224
+            // case the audio may not autoplay.
225
+            this._ref.play()
226
+            .then(() => {
227
+                if (retries !== 0) {
228
+                    // success after some failures
229
+                    this._playTimeout = undefined;
230
+                    sendAnalytics(createAudioPlaySuccessEvent(id));
231
+                    logger.info(`Successfully played audio track! retries: ${retries}`);
232
+                }
233
+            })
234
+            .catch(e => {
235
+                logger.error(`Failed to play audio track! retry: ${retries} ; Error: ${e}`);
236
+
237
+                if (retries < 3) {
238
+                    this._playTimeout = setTimeout(() => this._play(retries + 1), 1000);
239
+
240
+                    if (retries === 0) {
241
+                        // send only 1 error event.
242
+                        sendAnalytics(createAudioPlayErrorEvent(id));
243
+                    }
244
+                } else {
245
+                    this._playTimeout = undefined;
246
+                }
247
+            });
248
+        }
249
+    }
250
+
200
     _setRef: (?HTMLAudioElement) => void;
251
     _setRef: (?HTMLAudioElement) => void;
201
 
252
 
202
     /**
253
     /**

正在加载...
取消
保存