Skip to content
This repository was archived by the owner on Oct 25, 2024. It is now read-only.

Commit c531a97

Browse files
committed
Send audio over WebTransport streams.
1 parent e7ab0c6 commit c531a97

File tree

2 files changed

+96
-40
lines changed

2 files changed

+96
-40
lines changed

src/samples/conference/public/scripts/media-worker.js

+63-22
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,30 @@
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.
1113
const sizePrefix = 4;
1214

1315
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();
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

3241
async 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

4958
function 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

6097
function 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
}

src/samples/conference/public/scripts/quic.js

+33-18
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
let quicChannel = null;
1010
let bidirectionalStream = null;
11+
let bidiAudioStream = null;
1112
let writeTask, mediaStream, mediaWorker, conferenceId, myId, mixedStream, generatorWriter;
1213

1314
window.Module={};
@@ -114,18 +115,22 @@ async function attachReader(stream) {
114115
}
115116

116117
async function createSendChannel() {
117-
bidirectionalStream = await conference.createSendStream();
118+
//bidirectionalStream = await conference.createSendStream();
119+
bidiAudioStream = await conference.createSendStream();
120+
const localStream = new Owt.Base.LocalStream(
121+
bidiAudioStream,
122+
new Owt.Base.StreamSourceInfo('mic', undefined, undefined));
123+
attachReader(bidiAudioStream);
124+
const publication = await conference.publish(localStream, {
125+
audio: {codec: 'opus', numberOfChannels: 2, sampleRate: 48000},
126+
video: false,
127+
transport: {type: 'quic'},
128+
});
118129
// const localStream = new Owt.Base.LocalStream(
119130
// bidirectionalStream,
120-
// new Owt.Base.StreamSourceInfo(undefined, 'camera', undefined));
121-
// attachReader(bidirectionalStream);
131+
// new Owt.Base.StreamSourceInfo(undefined, undefined, true));
122132
// const publication = await conference.publish(
123-
// localStream, {video: {codec: 'h264'}, transport: {type: 'quic'}});
124-
const localStream = new Owt.Base.LocalStream(
125-
bidirectionalStream,
126-
new Owt.Base.StreamSourceInfo(undefined, undefined, true));
127-
const publication = await conference.publish(
128-
localStream, {transport: {type: 'quic'}});
133+
// localStream, {transport: {type: 'quic'}});
129134
console.log(publication);
130135
updateConferenceStatus('Created send channel.');
131136
}
@@ -146,13 +151,23 @@ async function writeUuid() {
146151
return;
147152
}
148153

149-
async function writeVideoData() {
150-
mediaStream = await navigator.mediaDevices.getUserMedia({video: true});
151-
const track = new MediaStreamTrackProcessor(mediaStream.getVideoTracks()[0]);
152-
mediaWorker.postMessage(['video-source', track.readable], [track.readable]);
154+
async function writeMediaData() {
155+
mediaStream =
156+
await navigator.mediaDevices.getUserMedia({audio: true, video: true});
157+
const audioTrack =
158+
new MediaStreamTrackProcessor(mediaStream.getAudioTracks()[0]);
159+
mediaWorker.postMessage(
160+
['audio-source', audioTrack.readable], [audioTrack.readable]);
153161
mediaWorker.postMessage(
154-
['send-stream', bidirectionalStream.writable],
155-
[bidirectionalStream.writable]);
162+
['send-stream-audio', bidiAudioStream.writable],
163+
[bidiAudioStream.writable]);
164+
// const videoTrack =
165+
// new MediaStreamTrackProcessor(mediaStream.getVideoTracks()[0]);
166+
// mediaWorker.postMessage(
167+
// ['video-source', videoTrack.readable], [videoTrack.readable]);
168+
// mediaWorker.postMessage(
169+
// ['send-stream-video', bidirectionalStream.writable],
170+
// [bidirectionalStream.writable]);
156171
}
157172

158173
async function writeData() {
@@ -173,12 +188,12 @@ window.addEventListener('load', () => {
173188
});
174189

175190
document.getElementById('start-sending').addEventListener('click', async () => {
176-
if (!bidirectionalStream) {
191+
if (!bidiAudioStream) {
177192
updateConferenceStatus('Stream is not created.');
178193
return;
179194
}
180-
//writeVideoData();
181-
writeTask = setInterval(writeData, 200);
195+
writeMediaData();
196+
//writeTask = setInterval(writeData, 200);
182197
updateConferenceStatus('Started sending.');
183198
});
184199

0 commit comments

Comments
 (0)