3
3
// SPDX-License-Identifier: Apache-2.0
4
4
5
5
/* eslint-disable require-jsdoc */
6
- /* global VideoEncoder, VideoDecoder, EncodedVideoChunk */
6
+ /* global AudioEncoder, EncodedAudioChunk, VideoEncoder, VideoDecoder,
7
+ * EncodedVideoChunk */
7
8
8
- let bidirectionalStreamWritable , videoEncoder , frameBuffer , sendStreamWriter ,
9
- mediaSession , datagramReceiver , videoDecoder ;
9
+ let videoBidiStreamWritable , audioEncoder , videoEncoder , frameBuffer ,
10
+ audioSendStreamWriter , videoSendStreamWriter , mediaSession ,
11
+ datagramReceiver , videoDecoder ;
10
12
// 4 bytes for frame size before each frame. The 1st byte is reserved, always 0.
11
13
const sizePrefix = 4 ;
12
14
13
15
onmessage = ( 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 ( ) ;
21
30
} else if ( e . data [ 0 ] === 'datagram-receiver' ) {
22
31
datagramReceiver = e . data [ 1 ] ;
23
32
} else if ( e . data [ 0 ] === 'encoded-video-frame' ) {
@@ -30,7 +39,8 @@ onmessage = (e) => {
30
39
} ;
31
40
32
41
async function videoOutput ( chunk , metadata ) {
33
- if ( bidirectionalStreamWritable ) {
42
+ return ;
43
+ if ( videoBidiStreamWritable ) {
34
44
if ( ! frameBuffer ||
35
45
frameBuffer . byteLength < chunk . byteLength + sizePrefix ) {
36
46
frameBuffer = new ArrayBuffer ( chunk . byteLength + sizePrefix ) ;
@@ -40,21 +50,48 @@ async function videoOutput(chunk, metadata) {
40
50
const dataView =
41
51
new DataView ( frameBuffer , 0 , chunk . byteLength + sizePrefix ) ;
42
52
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 ) ;
46
55
}
47
56
}
48
57
49
58
function videoError ( error ) {
50
- console . log ( 'Encode error, ' + error ) ;
59
+ console . log ( 'Video encode error, ' + error . message ) ;
51
60
}
52
61
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 ) {
54
84
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 } ) ;
58
95
}
59
96
60
97
function initVideoEncoder ( ) {
@@ -85,16 +122,20 @@ function webCodecsErrorCallback(error) {
85
122
console . log ( 'error: ' + error . message ) ;
86
123
}
87
124
88
- // Read data from video track.
89
- async function readVideoData ( readable ) {
125
+ // Read data from media track.
126
+ async function readMediaData ( readable , kind ) {
90
127
const reader = readable . getReader ( ) ;
91
128
while ( true ) {
92
129
const { value, done} = await reader . read ( ) ;
93
130
if ( done ) {
94
131
console . log ( 'MediaStream ends.' ) ;
95
132
break ;
96
133
}
97
- videoEncoder . encode ( value ) ;
134
+ if ( kind === 'audio' ) {
135
+ audioEncoder . encode ( value ) ;
136
+ } else if ( kind === 'video' ) {
137
+ videoEncoder . encode ( value ) ;
138
+ }
98
139
value . close ( ) ;
99
140
}
100
141
}
0 commit comments