@@ -16,6 +16,7 @@ limitations under the License.
1616
1717import * as Recorder from 'opus-recorder' ;
1818import encoderPath from 'opus-recorder/dist/encoderWorker.min.js' ;
19+ import mxVoiceWorkletPath from './mxVoiceWorklet' ;
1920import { MatrixClient } from "matrix-js-sdk/src/client" ;
2021import CallMediaHandler from "../CallMediaHandler" ;
2122import { SimpleObservable } from "matrix-widget-api" ;
@@ -36,7 +37,7 @@ export class VoiceRecorder {
3637 private recorderSource : MediaStreamAudioSourceNode ;
3738 private recorderStream : MediaStream ;
3839 private recorderFFT : AnalyserNode ;
39- private recorderProcessor : ScriptProcessorNode ;
40+ private recorderWorklet : AudioWorkletNode ;
4041 private buffer = new Uint8Array ( 0 ) ;
4142 private mxc : string ;
4243 private recording = false ;
@@ -70,18 +71,20 @@ export class VoiceRecorder {
7071 // it makes the time domain less than helpful.
7172 this . recorderFFT . fftSize = 64 ;
7273
73- // We use an audio processor to get accurate timing information.
74- // The size of the audio buffer largely decides how quickly we push timing/waveform data
75- // out of this class. Smaller buffers mean we update more frequently as we can't hold as
76- // many bytes. Larger buffers mean slower updates. For scale, 1024 gives us about 30Hz of
77- // updates and 2048 gives us about 20Hz. We use 1024 to get as close to perceived realtime
78- // as possible. Must be a power of 2.
79- this . recorderProcessor = this . recorderContext . createScriptProcessor ( 1024 , CHANNELS , CHANNELS ) ;
74+ await this . recorderContext . audioWorklet . addModule ( mxVoiceWorkletPath ) ;
75+ this . recorderWorklet = new AudioWorkletNode ( this . recorderContext , "mx-voice-worklet" ) ;
8076
8177 // Connect our inputs and outputs
8278 this . recorderSource . connect ( this . recorderFFT ) ;
83- this . recorderSource . connect ( this . recorderProcessor ) ;
84- this . recorderProcessor . connect ( this . recorderContext . destination ) ;
79+ this . recorderSource . connect ( this . recorderWorklet ) ;
80+ this . recorderWorklet . connect ( this . recorderContext . destination ) ;
81+
82+ // Dev note: we can't use `addEventListener` for some reason. It just doesn't work.
83+ this . recorderWorklet . port . onmessage = ( ev ) => {
84+ if ( ev . data [ 'ev' ] === 'proc' ) {
85+ this . tryUpdateLiveData ( ev . data [ 'timeMs' ] ) ;
86+ }
87+ } ;
8588
8689 this . recorder = new Recorder ( {
8790 encoderPath, // magic from webpack
@@ -128,7 +131,7 @@ export class VoiceRecorder {
128131 return this . mxc ;
129132 }
130133
131- private tryUpdateLiveData = ( ev : AudioProcessingEvent ) => {
134+ private tryUpdateLiveData = ( timeMillis : number ) => {
132135 if ( ! this . recording ) return ;
133136
134137 // The time domain is the input to the FFT, which means we use an array of the same
@@ -150,7 +153,7 @@ export class VoiceRecorder {
150153
151154 this . observable . update ( {
152155 waveform : translatedData ,
153- timeSeconds : ev . playbackTime ,
156+ timeSeconds : timeMillis / 1000 ,
154157 } ) ;
155158 } ;
156159
@@ -166,7 +169,6 @@ export class VoiceRecorder {
166169 }
167170 this . observable = new SimpleObservable < IRecordingUpdate > ( ) ;
168171 await this . makeRecorder ( ) ;
169- this . recorderProcessor . addEventListener ( "audioprocess" , this . tryUpdateLiveData ) ;
170172 await this . recorder . start ( ) ;
171173 this . recording = true ;
172174 }
@@ -178,6 +180,7 @@ export class VoiceRecorder {
178180
179181 // Disconnect the source early to start shutting down resources
180182 this . recorderSource . disconnect ( ) ;
183+ this . recorderWorklet . disconnect ( ) ;
181184 await this . recorder . stop ( ) ;
182185
183186 // close the context after the recorder so the recorder doesn't try to
@@ -189,7 +192,6 @@ export class VoiceRecorder {
189192
190193 // Finally do our post-processing and clean up
191194 this . recording = false ;
192- this . recorderProcessor . removeEventListener ( "audioprocess" , this . tryUpdateLiveData ) ;
193195 await this . recorder . close ( ) ;
194196
195197 return this . buffer ;
0 commit comments