@@ -14,6 +14,8 @@ export default class InputAudioProcessor {
1414 private trackID : TrackIDType ;
1515 private ws : WebSocket ;
1616 private encoder : AudioEncoder | null = null ;
17+ private static bitrateList = [ 32_000 , 64_000 , 128_000 ] ;
18+ private encoders : Record < number , AudioEncoder > = { } ;
1719 private state : ProcessorStateType = ProcessorState . IDLE ;
1820 private audioConfig : AudioEncoderConfig | null = null ;
1921
@@ -58,32 +60,37 @@ export default class InputAudioProcessor {
5860 return ;
5961 }
6062
63+ for ( const bitrate of InputAudioProcessor . bitrateList ) {
64+ const encoder = new AudioEncoder ( {
65+ output : ( chunk : EncodedAudioChunk , metadata ?: EncodedAudioChunkMetadata ) => {
66+ this . handleMultipleEncoders ( chunk , bitrate , metadata ) ;
67+ } ,
68+ error : ( error ) => {
69+ console . error ( `${ bitrate } AudioEncoder error:` , error ) ;
70+ if ( this . state !== ProcessorState . STOPPING ) {
71+ delete this . encoders [ bitrate ] ;
72+ }
73+ } ,
74+ } ) ;
75+ const cfg = { ...config , bitrate } ;
76+ encoder . configure ( cfg ) ;
77+ this . encoders [ bitrate ] = encoder ;
78+ }
6179
62- this . encoder = new AudioEncoder ( {
63- output : this . handleEncodedChunk . bind ( this ) ,
64- error : ( error ) => {
65- console . error ( 'AudioEncoder error:' , error ) ;
66- // 只有在非停止状态时才重置编码器状态
67- if ( this . state !== ProcessorState . STOPPING ) {
68- this . state = ProcessorState . STOPPED ;
69- this . encoder = null ;
70- }
71- } ,
72- } ) ;
80+ // this.encoder = new AudioEncoder({
81+ // output: this.handleEncodedChunk.bind(this),
82+ // error: (error) => {
83+ // console.error('AudioEncoder error:', error);
84+ // // 只有在非停止状态时才重置编码器状态
85+ // if (this.state !== ProcessorState.STOPPING) {
86+ // this.state = ProcessorState.STOPPED;
87+ // this.encoder = null;
88+ // }
89+ // },
90+ // });
91+ // this.encoder.configure(config);
7392
74- this . encoder . configure ( config ) ;
7593 this . state = ProcessorState . RUNNING ;
76-
77- // 配置多个不同目标码率的opus,尝试同步
78- // let n = 0;
79- // setInterval(() => {
80- // this.encoder!.configure({
81- // ...config,
82- // bitrate: n % 2 === 0 ? 32_000 : 128_000,
83- // })
84- // console.log(`[audio encoder] Reconfigured encoder, bitrate: ${n % 2 === 0 ? 32_000 : 128_000}`);
85- // n++;
86- // }, 10 * 1000);
8794 } catch ( error ) {
8895 console . error ( '[audio encoder] Failed to initialize AudioEncoder:' , error ) ;
8996 this . state = ProcessorState . STOPPED ;
@@ -120,6 +127,38 @@ export default class InputAudioProcessor {
120127 }
121128 }
122129
130+ private handleMultipleEncoders ( chunk : EncodedAudioChunk , bitrate : number , metadata ?: EncodedAudioChunkMetadata ) {
131+ const buffer = new Uint8Array ( chunk . byteLength ) ;
132+ chunk . copyTo ( buffer ) ;
133+
134+ const headerSize = 1 + 8 + 4 ; // trackID + duration + bitrate
135+ const totalSize = headerSize + buffer . length ;
136+ const packet = new ArrayBuffer ( totalSize ) ;
137+ const view = new DataView ( packet ) ;
138+
139+ let offset = 0 ;
140+ view . setUint8 ( offset , this . trackID ) ; // 轨道ID
141+ offset += 1 ;
142+
143+ const duration = chunk . duration || 0 ;
144+ view . setBigUint64 ( offset , BigInt ( duration ) , true ) ; // duration
145+ offset += 8 ;
146+
147+ view . setUint32 ( offset , bitrate , true ) ; // 比特率
148+ offset += 4 ;
149+
150+ const dataView = new Uint8Array ( packet , offset ) ;
151+ dataView . set ( buffer ) ;
152+
153+ // 发送多比特率编码数据
154+ if ( this . ws . readyState === WebSocket . OPEN ) {
155+ this . ws . send ( packet ) ;
156+ } else {
157+ console . warn ( 'mediaWs is not open. Unable to send multi-bitrate audio data.' ) ;
158+ }
159+ }
160+
161+
123162
124163 private async encodeFromAudioTrack ( track : MediaStreamAudioTrack ) {
125164 if ( ! ( 'MediaStreamTrackProcessor' in window ) ) {
@@ -142,9 +181,13 @@ export default class InputAudioProcessor {
142181 await this . init ( value ) ;
143182 }
144183
145- if ( this . encoder && this . state === ProcessorState . RUNNING ) {
184+ if ( this . state === ProcessorState . RUNNING ) {
146185 try {
147- this . encoder . encode ( value ) ;
186+ // this.encoder.encode(value);
187+
188+ this . encoders && Object . values ( this . encoders ) . forEach ( enc => {
189+ enc . encode ( value ) ;
190+ } ) ;
148191 } catch ( error ) {
149192 console . error ( 'Error encoding frame:' , error ) ;
150193 }
@@ -165,23 +208,42 @@ export default class InputAudioProcessor {
165208 public stop ( ) {
166209 this . state = ProcessorState . STOPPING ;
167210
211+ // 停止主编码器
168212 if ( this . encoder ) {
169- // Flush any pending frames and close the encoder
170213 this . encoder . flush ( )
171214 . then ( ( ) => {
172215 this . encoder ?. close ( ) ;
173216 this . encoder = null ;
174- this . state = ProcessorState . STOPPED ;
175217 } )
176218 . catch ( error => {
177- console . error ( 'Error flushing encoder:' , error ) ;
178- this . state = ProcessorState . STOPPED ;
219+ console . error ( 'Error flushing main encoder:' , error ) ;
179220 } ) ;
180- } else {
181- this . state = ProcessorState . STOPPED ;
182221 }
183222
184- console . log ( 'Audio processing stopped' ) ;
223+ // 停止所有多比特率编码器
224+ const flushPromises = Object . entries ( this . encoders ) . map ( ( [ bitrate , encoder ] ) => {
225+ return encoder . flush ( )
226+ . then ( ( ) => {
227+ encoder . close ( ) ;
228+ console . log ( `Closed encoder for ${ bitrate } bps` ) ;
229+ } )
230+ . catch ( error => {
231+ console . error ( `Error flushing encoder ${ bitrate } bps:` , error ) ;
232+ } ) ;
233+ } ) ;
234+
235+ // 等待所有编码器完成
236+ Promise . all ( flushPromises )
237+ . then ( ( ) => {
238+ this . encoders = { } ;
239+ this . state = ProcessorState . STOPPED ;
240+ console . log ( 'All audio encoders stopped' ) ;
241+ } )
242+ . catch ( error => {
243+ console . error ( 'Error stopping audio encoders:' , error ) ;
244+ this . encoders = { } ;
245+ this . state = ProcessorState . STOPPED ;
246+ } ) ;
185247 }
186248}
187249
0 commit comments