Przeglądaj źródła

refactor: remove ensureInitialized

master
Radium Zheng 7 lat temu
rodzic
commit
ce308eaa8b

+ 2
- 2
react/features/local-recording/components/LocalRecordingInfoDialog.js Wyświetl plik

@@ -95,11 +95,11 @@ class LocalRecordingInfoDialog extends Component<Props, State> {
95 95
     }
96 96
 
97 97
     /**
98
-     * Implements React's {@link Component#componentWillMount()}.
98
+     * Implements React's {@link Component#componentDidMount()}.
99 99
      *
100 100
      * @returns {void}
101 101
      */
102
-    componentWillMount() {
102
+    componentDidMount() {
103 103
         this._timer = setInterval(
104 104
             () => {
105 105
                 this.setState((_prevState, props) => {

+ 1
- 2
react/features/local-recording/controller/RecordingController.js Wyświetl plik

@@ -398,8 +398,7 @@ class RecordingController {
398 398
             this._state = ControllerState.RECORDING;
399 399
             const delegate = this._adapters[this._currentSessionToken];
400 400
 
401
-            delegate.ensureInitialized()
402
-            .then(() => delegate.start())
401
+            delegate.start()
403 402
             .then(() => {
404 403
                 logger.log('Local recording engaged.');
405 404
                 const message = i18next.t('localRecording.messages.engaged');

+ 41
- 36
react/features/local-recording/recording/OggAdapter.js Wyświetl plik

@@ -4,8 +4,8 @@ import { downloadBlob, timestampString } from './Utils';
4 4
 const logger = require('jitsi-meet-logger').getLogger(__filename);
5 5
 
6 6
 /**
7
- * RecordingAdapter implementation that uses MediaRecorder
8
- * (default browser encoding with Opus codec)
7
+ * Recording adapter that uses {@code MediaRecorder} (default browser encoding
8
+ * with Opus codec).
9 9
  */
10 10
 export class OggAdapter extends RecordingAdapter {
11 11
 
@@ -15,35 +15,9 @@ export class OggAdapter extends RecordingAdapter {
15 15
     _mediaRecorder = null;
16 16
 
17 17
     /**
18
-     * Implements {@link RecordingAdapter#ensureInitialized()}.
19
-     *
20
-     * @inheritdoc
18
+     * Initialization promise.
21 19
      */
22
-    ensureInitialized() {
23
-        let p = null;
24
-
25
-        if (this._mediaRecorder === null) {
26
-            p = new Promise((resolve, error) => {
27
-                this._getAudioStream(0)
28
-                .then(stream => {
29
-                    this._mediaRecorder = new MediaRecorder(stream);
30
-                    this._mediaRecorder.ondataavailable
31
-                        = e => this._saveMediaData(e.data);
32
-                    resolve();
33
-                })
34
-                .catch(err => {
35
-                    logger.error(`Error calling getUserMedia(): ${err}`);
36
-                    error();
37
-                });
38
-            });
39
-        } else {
40
-            p = new Promise(resolve => {
41
-                resolve();
42
-            });
43
-        }
44
-
45
-        return p;
46
-    }
20
+    _initPromise = null;
47 21
 
48 22
     /**
49 23
      * Implements {@link RecordingAdapter#start()}.
@@ -51,10 +25,16 @@ export class OggAdapter extends RecordingAdapter {
51 25
      * @inheritdoc
52 26
      */
53 27
     start() {
54
-        return new Promise(resolve => {
55
-            this._mediaRecorder.start();
56
-            resolve();
57
-        });
28
+        if (!this._initPromise) {
29
+            this._initPromise = this._initialize();
30
+        }
31
+
32
+        return this._initPromise.then(() =>
33
+            new Promise(resolve => {
34
+                this._mediaRecorder.start();
35
+                resolve();
36
+            })
37
+        );
58 38
     }
59 39
 
60 40
     /**
@@ -82,14 +62,39 @@ export class OggAdapter extends RecordingAdapter {
82 62
 
83 63
             downloadBlob(audioURL, `recording${timestampString()}.ogg`);
84 64
         }
65
+    }
66
+
67
+    /**
68
+     * Initialize the adapter.
69
+     *
70
+     * @private
71
+     * @returns {Promise}
72
+     */
73
+    _initialize() {
74
+        if (this._mediaRecorder) {
75
+            return Promise.resolve();
76
+        }
85 77
 
78
+        return new Promise((resolve, error) => {
79
+            this._getAudioStream(0)
80
+            .then(stream => {
81
+                this._mediaRecorder = new MediaRecorder(stream);
82
+                this._mediaRecorder.ondataavailable
83
+                    = e => this._saveMediaData(e.data);
84
+                resolve();
85
+            })
86
+            .catch(err => {
87
+                logger.error(`Error calling getUserMedia(): ${err}`);
88
+                error();
89
+            });
90
+        });
86 91
     }
87 92
 
88 93
     /**
89
-     * Callback for encoded data.
94
+     * Callback for storing the encoded data.
90 95
      *
91 96
      * @private
92
-     * @param {*} data - Encoded data.
97
+     * @param {Blob} data - Encoded data.
93 98
      * @returns {void}
94 99
      */
95 100
     _saveMediaData(data) {

+ 0
- 9
react/features/local-recording/recording/RecordingAdapter.js Wyświetl plik

@@ -5,15 +5,6 @@ import JitsiMeetJS from '../../base/lib-jitsi-meet';
5 5
  */
6 6
 export class RecordingAdapter {
7 7
 
8
-    /**
9
-     * Initialize the recording backend.
10
-     *
11
-     * @returns {Promise}
12
-     */
13
-    ensureInitialized() {
14
-        throw new Error('Not implemented');
15
-    }
16
-
17 8
     /**
18 9
      * Starts recording.
19 10
      *

+ 73
- 40
react/features/local-recording/recording/WavAdapter.js Wyświetl plik

@@ -11,17 +11,43 @@ const WAV_SAMPLE_RATE = 44100;
11 11
  */
12 12
 export class WavAdapter extends RecordingAdapter {
13 13
 
14
+    /**
15
+     * {@code AudioContext} instance.
16
+     */
14 17
     _audioContext = null;
18
+
19
+    /**
20
+     * {@code ScriptProcessorNode} instance, which receives the raw PCM bits.
21
+     */
15 22
     _audioProcessingNode = null;
23
+
24
+    /**
25
+     * {@code MediaStreamAudioSourceNode} instance, which represents the mic.
26
+     */
16 27
     _audioSource = null;
17 28
 
29
+    /**
30
+     * Length of the WAVE file, in units of {@code sizeof(Float32)}.
31
+     */
18 32
     _wavLength = 0;
33
+
34
+    /**
35
+     * The {@code ArrayBuffer}s that stores the PCM bits.
36
+     */
19 37
     _wavBuffers = [];
38
+
39
+    /**
40
+     * Whether or not the {@code WavAdapter} is in a ready state.
41
+     */
20 42
     _isInitialized = false;
21 43
 
44
+    /**
45
+     * Initialization promise.
46
+     */
47
+    _initPromise = null;
48
+
22 49
     /**
23 50
      * Constructor.
24
-     *
25 51
      */
26 52
     constructor() {
27 53
         super();
@@ -29,50 +55,16 @@ export class WavAdapter extends RecordingAdapter {
29 55
         this._saveWavPCM = this._saveWavPCM.bind(this);
30 56
     }
31 57
 
32
-    /**
33
-     * Implements {@link RecordingAdapter#ensureInitialized()}.
34
-     *
35
-     * @inheritdoc
36
-     */
37
-    ensureInitialized() {
38
-        if (this._isInitialized) {
39
-            return Promise.resolve();
40
-        }
41
-
42
-        const p = new Promise((resolve, reject) => {
43
-            this._getAudioStream(0)
44
-            .then(stream => {
45
-                this._audioContext = new AudioContext();
46
-                this._audioSource
47
-                    = this._audioContext.createMediaStreamSource(stream);
48
-                this._audioProcessingNode
49
-                    = this._audioContext.createScriptProcessor(4096, 1, 1);
50
-                this._audioProcessingNode.onaudioprocess = e => {
51
-                    const channelLeft = e.inputBuffer.getChannelData(0);
52
-
53
-                    // https://developer.mozilla.org/en-US/docs/
54
-                    // Web/API/AudioBuffer/getChannelData
55
-                    // the returned value is an Float32Array
56
-                    this._saveWavPCM(channelLeft);
57
-                };
58
-                this._isInitialized = true;
59
-                resolve();
60
-            })
61
-            .catch(err => {
62
-                logger.error(`Error calling getUserMedia(): ${err}`);
63
-                reject();
64
-            });
65
-        });
66
-
67
-        return p;
68
-    }
69
-
70 58
     /**
71 59
      * Implements {@link RecordingAdapter#start()}.
72 60
      *
73 61
      * @inheritdoc
74 62
      */
75 63
     start() {
64
+        if (!this._initPromise) {
65
+            this._initPromise = this._initialize();
66
+        }
67
+
76 68
         return new Promise(
77 69
             (resolve, /* eslint-disable */_reject/* eslint-enable */) => {
78 70
                 this._wavBuffers = [];
@@ -95,6 +87,10 @@ export class WavAdapter extends RecordingAdapter {
95 87
         this._audioProcessingNode.disconnect();
96 88
         this._audioSource.disconnect();
97 89
         this._data = this._exportMonoWAV(this._wavBuffers, this._wavLength);
90
+        this._audioContext = null;
91
+        this._audioProcessingNode = null;
92
+        this._audioSource = null;
93
+        this._isInitialized = false;
98 94
 
99 95
         return Promise.resolve();
100 96
     }
@@ -110,7 +106,6 @@ export class WavAdapter extends RecordingAdapter {
110 106
 
111 107
             downloadBlob(audioURL, `recording${timestampString()}.wav`);
112 108
         }
113
-
114 109
     }
115 110
 
116 111
     /**
@@ -167,6 +162,44 @@ export class WavAdapter extends RecordingAdapter {
167 162
         return new Uint8Array(buffer);
168 163
     }
169 164
 
165
+    /**
166
+     * Initialize the adapter.
167
+     *
168
+     * @private
169
+     * @returns {Promise}
170
+     */
171
+    _initialize() {
172
+        if (this._isInitialized) {
173
+            return Promise.resolve();
174
+        }
175
+
176
+        const p = new Promise((resolve, reject) => {
177
+            this._getAudioStream(0)
178
+            .then(stream => {
179
+                this._audioContext = new AudioContext();
180
+                this._audioSource
181
+                    = this._audioContext.createMediaStreamSource(stream);
182
+                this._audioProcessingNode
183
+                    = this._audioContext.createScriptProcessor(4096, 1, 1);
184
+                this._audioProcessingNode.onaudioprocess = e => {
185
+                    const channelLeft = e.inputBuffer.getChannelData(0);
186
+
187
+                    // https://developer.mozilla.org/en-US/docs/
188
+                    // Web/API/AudioBuffer/getChannelData
189
+                    // the returned value is an Float32Array
190
+                    this._saveWavPCM(channelLeft);
191
+                };
192
+                this._isInitialized = true;
193
+                resolve();
194
+            })
195
+            .catch(err => {
196
+                logger.error(`Error calling getUserMedia(): ${err}`);
197
+                reject();
198
+            });
199
+        });
200
+
201
+        return p;
202
+    }
170 203
 
171 204
     /**
172 205
      * Callback function that saves the PCM bits.

+ 89
- 52
react/features/local-recording/recording/flac/FlacAdapter.js Wyświetl plik

@@ -21,35 +21,86 @@ export class FlacAdapter extends RecordingAdapter {
21 21
     _audioProcessingNode = null;
22 22
     _audioSource = null;
23 23
 
24
+    /**
25
+     * Resolve function of the promise returned by {@code stop()}.
26
+     * This is called after the WebWorker sends back {@code WORKER_BLOB_READY}.
27
+     */
24 28
     _stopPromiseResolver = null;
25 29
 
26 30
     /**
27
-     * Implements {@link RecordingAdapter#ensureInitialized}.
31
+     * Initialization promise.
32
+     */
33
+    _initPromise = null;
34
+
35
+    /**
36
+     * Implements {@link RecordingAdapter#start()}.
37
+     *
38
+     * @inheritdoc
39
+     */
40
+    start() {
41
+        if (!this._initPromise) {
42
+            this._initPromise = this._initialize();
43
+        }
44
+
45
+        return this._initPromise.then(() => {
46
+            this._audioSource.connect(this._audioProcessingNode);
47
+            this._audioProcessingNode.connect(this._audioContext.destination);
48
+        });
49
+    }
50
+
51
+    /**
52
+     * Implements {@link RecordingAdapter#stop()}.
28 53
      *
29 54
      * @inheritdoc
30 55
      */
31
-    ensureInitialized() {
56
+    stop() {
57
+        if (!this._encoder) {
58
+            logger.error('Attempting to stop but has nothing to stop.');
59
+
60
+            return Promise.reject();
61
+        }
62
+
63
+        return new Promise(resolve => {
64
+            this._initPromise = null;
65
+            this._audioProcessingNode.onaudioprocess = undefined;
66
+            this._audioProcessingNode.disconnect();
67
+            this._audioSource.disconnect();
68
+            this._stopPromiseResolver = resolve;
69
+            this._encoder.postMessage({
70
+                command: MAIN_THREAD_FINISH
71
+            });
72
+        });
73
+    }
74
+
75
+    /**
76
+     * Implements {@link RecordingAdapter#download()}.
77
+     *
78
+     * @inheritdoc
79
+     */
80
+    download() {
81
+        if (this._data !== null) {
82
+            const audioURL = window.URL.createObjectURL(this._data);
83
+
84
+            downloadBlob(audioURL, `recording${timestampString()}.flac`);
85
+        }
86
+    }
87
+
88
+    /**
89
+     * Initialize the adapter.
90
+     *
91
+     * @private
92
+     * @returns {Promise}
93
+     */
94
+    _initialize() {
32 95
         if (this._encoder !== null) {
33 96
             return Promise.resolve();
34 97
         }
35 98
 
36 99
         const promiseInitWorker = new Promise((resolve, reject) => {
37
-            // FIXME: workaround for different file names in development/
38
-            // production environments.
39
-            // We cannot import flacEncodeWorker as a webpack module,
40
-            // because it is in a different bundle and should be lazy-loaded
41
-            // only when flac recording is in use.
42 100
             try {
43
-                // try load the minified version first
44
-                this._encoder = new Worker('/libs/flacEncodeWorker.min.js');
45
-            } catch (exception1) {
46
-                // if failed, try unminified version
47
-                try {
48
-                    this._encoder = new Worker('/libs/flacEncodeWorker.js');
49
-                } catch (exception2) {
50
-                    logger.error('Failed to load flacEncodeWorker.');
51
-                    reject();
52
-                }
101
+                this._loadWebWorker();
102
+            } catch (e) {
103
+                reject();
53 104
             }
54 105
 
55 106
             // set up listen for messages from the WebWorker
@@ -60,6 +111,8 @@ export class FlacAdapter extends RecordingAdapter {
60 111
                     if (this._stopPromiseResolver !== null) {
61 112
                         this._stopPromiseResolver();
62 113
                         this._stopPromiseResolver = null;
114
+                        this._encoder.terminate();
115
+                        this._encoder = null;
63 116
                     }
64 117
                 } else if (e.data.command === DEBUG) {
65 118
                     logger.log(e.data);
@@ -116,43 +169,27 @@ export class FlacAdapter extends RecordingAdapter {
116 169
     }
117 170
 
118 171
     /**
119
-     * Implements {@link RecordingAdapter#start()}.
120
-     *
121
-     * @inheritdoc
122
-     */
123
-    start() {
124
-        this._audioSource.connect(this._audioProcessingNode);
125
-        this._audioProcessingNode.connect(this._audioContext.destination);
126
-    }
127
-
128
-    /**
129
-     * Implements {@link RecordingAdapter#stop()}.
130
-     *
131
-     * @inheritdoc
132
-     */
133
-    stop() {
134
-        return new Promise(resolve => {
135
-            this._audioProcessingNode.onaudioprocess = undefined;
136
-            this._audioProcessingNode.disconnect();
137
-            this._audioSource.disconnect();
138
-            this._stopPromiseResolver = resolve;
139
-            this._encoder.postMessage({
140
-                command: MAIN_THREAD_FINISH
141
-            });
142
-        });
143
-    }
144
-
145
-    /**
146
-     * Implements {@link RecordingAdapter#download()}.
172
+     * Loads the WebWorker.
147 173
      *
148
-     * @inheritdoc
174
+     * @private
175
+     * @returns {void}
149 176
      */
150
-    download() {
151
-        if (this._data !== null) {
152
-            const audioURL = window.URL.createObjectURL(this._data);
153
-
154
-            downloadBlob(audioURL, `recording${timestampString()}.flac`);
177
+    _loadWebWorker() {
178
+        // FIXME: workaround for different file names in development/
179
+        // production environments.
180
+        // We cannot import flacEncodeWorker as a webpack module,
181
+        // because it is in a different bundle and should be lazy-loaded
182
+        // only when flac recording is in use.
183
+        try {
184
+            // try load the minified version first
185
+            this._encoder = new Worker('/libs/flacEncodeWorker.min.js');
186
+        } catch (exception1) {
187
+            // if failed, try unminified version
188
+            try {
189
+                this._encoder = new Worker('/libs/flacEncodeWorker.js');
190
+            } catch (exception2) {
191
+                throw new Error('Failed to load flacEncodeWorker.');
192
+            }
155 193
         }
156
-
157 194
     }
158 195
 }

+ 3
- 3
react/features/local-recording/recording/flac/flacEncodeWorker.js Wyświetl plik

@@ -19,10 +19,10 @@ importScripts('/libs/libflac3-1.3.2.min.js');
19 19
 // So we disable the ESLint rule `new-cap` in this file.
20 20
 /* eslint-disable new-cap */
21 21
 
22
-// Flow will complain about the number keys in `FLAC_ERRORS,
22
+// Flow will complain about the number keys in `FLAC_ERRORS`,
23 23
 // ESLint will complain about the `declare` statement.
24 24
 // As the current workaround, add an exception for eslint.
25
-/* eslint-disable flowtype/no-types-missing-file-annotation*/
25
+/* eslint-disable flowtype/no-types-missing-file-annotation */
26 26
 declare var Flac: Object;
27 27
 
28 28
 const FLAC_ERRORS = {
@@ -151,7 +151,7 @@ class Encoder {
151 151
     _state = EncoderState.UNINTIALIZED;
152 152
 
153 153
     /**
154
-     * The ready-for-grab downloadable blob.
154
+     * The ready-for-grab downloadable Blob.
155 155
      */
156 156
     _data = null;
157 157
 

Ładowanie…
Anuluj
Zapisz