33// SPDX-License-Identifier: Apache-2.0
44
55/* eslint-disable require-jsdoc */
6- /* global VideoEncoder, VideoDecoder, EncodedVideoChunk */
6+ /* global AudioEncoder, EncodedAudioChunk, VideoEncoder, VideoDecoder,
7+ * EncodedVideoChunk */
78
8- let bidirectionalStreamWritable , videoEncoder , frameBuffer , sendStreamWriter ,
9- mediaSession , datagramReceiver , videoDecoder ;
9+ let videoBidiStreamWritable , audioEncoder , videoEncoder , frameBuffer ,
10+ audioSendStreamWriter , videoSendStreamWriter , mediaSession ,
11+ datagramReceiver , videoDecoder ;
1012// 4 bytes for frame size before each frame. The 1st byte is reserved, always 0.
1113const sizePrefix = 4 ;
1214
1315onmessage = ( e ) => {
14- if ( e . data [ 0 ] === 'video-source' ) {
15- readVideoData ( e . data [ 1 ] ) ;
16- } else if ( e . data [ 0 ] === 'send-stream' ) {
17- bidirectionalStreamWritable = e . data [ 1 ] ;
18- sendStreamWriter = bidirectionalStreamWritable . getWriter ( ) ;
19- writeTrackId ( ) ;
20- // initVideoEncoder();
16+ if ( e . data [ 0 ] === 'audio-source' ) {
17+ readMediaData ( e . data [ 1 ] , 'audio' ) ;
18+ } else if ( e . data [ 0 ] === 'video-source' ) {
19+ readMediaData ( e . data [ 1 ] , 'video' ) ;
20+ } else if ( e . data [ 0 ] === 'send-stream-audio' ) {
21+ const audioBidiStreamWritable = e . data [ 1 ] ;
22+ audioSendStreamWriter = audioBidiStreamWritable . getWriter ( ) ;
23+ writeTrackId ( 'audio' , audioSendStreamWriter ) ;
24+ initAudioEncoder ( ) ;
25+ } else if ( e . data [ 0 ] === 'send-stream-video' ) {
26+ videoBidiStreamWritable = e . data [ 1 ] ;
27+ videoSendStreamWriter = videoBidiStreamWritable . getWriter ( ) ;
28+ writeTrackId ( 'video' , videoSendStreamWriter ) ;
29+ initVideoEncoder ( ) ;
2130 } else if ( e . data [ 0 ] === 'datagram-receiver' ) {
2231 datagramReceiver = e . data [ 1 ] ;
2332 } else if ( e . data [ 0 ] === 'encoded-video-frame' ) {
@@ -30,7 +39,8 @@ onmessage = (e) => {
3039} ;
3140
3241async function videoOutput ( chunk , metadata ) {
33- if ( bidirectionalStreamWritable ) {
42+ return ;
43+ if ( videoBidiStreamWritable ) {
3444 if ( ! frameBuffer ||
3545 frameBuffer . byteLength < chunk . byteLength + sizePrefix ) {
3646 frameBuffer = new ArrayBuffer ( chunk . byteLength + sizePrefix ) ;
@@ -40,21 +50,48 @@ async function videoOutput(chunk, metadata) {
4050 const dataView =
4151 new DataView ( frameBuffer , 0 , chunk . byteLength + sizePrefix ) ;
4252 dataView . setUint32 ( 0 , chunk . byteLength ) ;
43- await sendStreamWriter . ready ;
44- await sendStreamWriter . write ( dataView ) ;
45- console . log ( 'Write a frame.' ) ;
53+ await videoSendStreamWriter . ready ;
54+ await videoSendStreamWriter . write ( dataView ) ;
4655 }
4756}
4857
4958function videoError ( error ) {
50- console . log ( 'Encode error, ' + error ) ;
59+ console . log ( 'Video encode error, ' + error . message ) ;
5160}
5261
53- async function writeTrackId ( ) {
62+ async function audioOutput ( chunk , metadata ) {
63+ if ( audioSendStreamWriter ) {
64+ if ( ! frameBuffer ||
65+ frameBuffer . byteLength < chunk . byteLength + sizePrefix ) {
66+ frameBuffer = new ArrayBuffer ( chunk . byteLength + sizePrefix ) ;
67+ }
68+ const bufferView = new Uint8Array ( frameBuffer , sizePrefix ) ;
69+ chunk . copyTo ( bufferView ) ;
70+ const dataView =
71+ new DataView ( frameBuffer , 0 , chunk . byteLength + sizePrefix ) ;
72+ dataView . setUint32 ( 0 , chunk . byteLength ) ;
73+ await audioSendStreamWriter . ready ;
74+ await audioSendStreamWriter . write ( dataView ) ;
75+ console . log ( 'Wrote an audio frame. ' + chunk . byteLength ) ;
76+ }
77+ }
78+
79+ function audioError ( error ) {
80+ console . log ( `Audio encode error: ${ error . message } ` ) ;
81+ }
82+
83+ async function writeTrackId ( kind , writer ) {
5484 const id = new Uint8Array ( 16 ) ;
55- id [ 16 ] = 2 ;
56- await sendStreamWriter . ready ;
57- sendStreamWriter . write ( id ) ;
85+ id [ 15 ] = ( kind === 'audio' ? 1 : 2 ) ;
86+ await writer . ready ;
87+ writer . write ( id ) ;
88+ console . log ( 'Wrote track ID for ' + kind ) ;
89+ }
90+
91+ function initAudioEncoder ( ) {
92+ audioEncoder = new AudioEncoder ( { output : audioOutput , error : audioError } ) ;
93+ audioEncoder . configure (
94+ { codec : 'opus' , numberOfChannels : 1 , sampleRate : 48000 } ) ;
5895}
5996
6097function initVideoEncoder ( ) {
@@ -85,16 +122,20 @@ function webCodecsErrorCallback(error) {
85122 console . log ( 'error: ' + error . message ) ;
86123}
87124
88- // Read data from video track.
89- async function readVideoData ( readable ) {
125+ // Read data from media track.
126+ async function readMediaData ( readable , kind ) {
90127 const reader = readable . getReader ( ) ;
91128 while ( true ) {
92129 const { value, done} = await reader . read ( ) ;
93130 if ( done ) {
94131 console . log ( 'MediaStream ends.' ) ;
95132 break ;
96133 }
97- videoEncoder . encode ( value ) ;
134+ if ( kind === 'audio' ) {
135+ audioEncoder . encode ( value ) ;
136+ } else if ( kind === 'video' ) {
137+ videoEncoder . encode ( value ) ;
138+ }
98139 value . close ( ) ;
99140 }
100141}
0 commit comments