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

Commit e0cae2c

Browse files
committed
Publish media data with WebTransport.
1 parent d1ef66b commit e0cae2c

File tree

4 files changed

+72
-18
lines changed

4 files changed

+72
-18
lines changed

src/sdk/base/publication.js

+16-4
Original file line numberDiff line numberDiff line change
@@ -195,17 +195,29 @@ export class PublishOptions {
195195
// eslint-disable-next-line require-jsdoc
196196
constructor(audio, video, transport) {
197197
/**
198-
* @member {?Array<Owt.Base.AudioEncodingParameters> | ?Array<RTCRtpEncodingParameters>} audio
198+
* @member {?Array<Owt.Base.AudioEncodingParameters> |
199+
* ?Array<RTCRtpEncodingParameters> | ?AudioEncoderConfig } audio
199200
* @instance
200201
* @memberof Owt.Base.PublishOptions
201-
* @desc Parameters for audio RtpSender. Publishing with RTCRtpEncodingParameters is an experimental feature. It is subject to change.
202+
* @desc Parameters for audio RtpSender when transport's type is 'webrtc' or
203+
* configuration of audio encoder when transport's type is 'quic'.
204+
* Publishing with RTCRtpEncodingParameters is an experimental feature. It
205+
* is subject to change.
206+
* @see {@link https://www.w3.org/TR/webrtc/#rtcrtpencodingparameters|RTCRtpEncodingParameters}
207+
* @see {@link https://w3c.github.io/webcodecs/#dictdef-audioencoderconfig|AudioEncoderConfig}
202208
*/
203209
this.audio = audio;
204210
/**
205-
* @member {?Array<Owt.Base.VideoEncodingParameters> | ?Array<RTCRtpEncodingParameters>} video
211+
* @member {?Array<Owt.Base.VideoEncodingParameters> |
212+
* ?Array<RTCRtpEncodingParameters> | ?VideoEncoderConfig } video
206213
* @instance
207214
* @memberof Owt.Base.PublishOptions
208-
* @desc Parameters for video RtpSender. Publishing with RTCRtpEncodingParameters is an experimental feature. It is subject to change.
215+
* @desc Parameters for video RtpSender when transport's type is 'webrtc' or
216+
* configuration of video encoder when transport's type is 'quic'.
217+
* Publishing with RTCRtpEncodingParameters is an experimental feature. It
218+
* is subject to change.
219+
* @see {@link https://www.w3.org/TR/webrtc/#rtcrtpencodingparameters|RTCRtpEncodingParameters}
220+
* @see {@link https://w3c.github.io/webcodecs/#dictdef-videoencoderconfig|VideoEncoderConfig}
209221
*/
210222
this.video = video;
211223
/**

src/sdk/base/transport.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,9 @@ export class TransportConstraints {
2929
* @member {Array.<Owt.Base.TransportType>} type
3030
* @instance
3131
* @memberof Owt.Base.TransportConstraints
32-
* @desc Transport type for publication and subscription.
32+
* @desc Transport type for publication and subscription. 'quic' is only
33+
* supported in conference mode when WebTransport is supported by client and
34+
* enabled at server side.
3335
*/
3436
this.type = type;
3537
/**

src/sdk/conference/client.js

+8-5
Original file line numberDiff line numberDiff line change
@@ -464,16 +464,16 @@ export const ConferenceClient = function(config, signalingImpl) {
464464
* @instance
465465
* @desc Publish a LocalStream to conference server. Other participants will be able to subscribe this stream when it is successfully published.
466466
* @param {Owt.Base.LocalStream} stream The stream to be published.
467-
* @param {(Owt.Base.PublishOptions|RTCRtpTransceiver[])} options If options is a PublishOptions, the stream will be published as options specified. If options is a list of RTCRtpTransceivers, each track in the first argument must have a corresponding RTCRtpTransceiver here, and the track will be published with the RTCRtpTransceiver associated with it.
467+
* @param {(Owt.Base.PublishOptions|RTCRtpTransceiver[])} options If options is a PublishOptions, the stream will be published as options specified. If options is a list of RTCRtpTransceivers, each track in the first argument must have a corresponding RTCRtpTransceiver here, and the track will be published with the RTCRtpTransceiver associated with it. If the type of transport is quic, PublishOptions.audio should be AudioEncoderConfig, and PublishOptions.video should be VideoEncoderConfig.
468468
* @param {string[]} videoCodecs Video codec names for publishing. Valid values are 'VP8', 'VP9' and 'H264'. This parameter only valid when the second argument is PublishOptions and options.video is RTCRtpEncodingParameters. Publishing with RTCRtpEncodingParameters is an experimental feature. This parameter is subject to change.
469469
* @return {Promise<Publication, Error>} Returned promise will be resolved with a newly created Publication once specific stream is successfully published, or rejected with a newly created Error if stream is invalid or options cannot be satisfied. Successfully published means PeerConnection is established and server is able to process media data.
470470
*/
471471
this.publish = function(stream, options, videoCodecs) {
472472
if (!(stream instanceof StreamModule.LocalStream)) {
473473
return Promise.reject(new ConferenceError('Invalid stream.'));
474474
}
475-
if (stream.source.data) {
476-
return quicTransportChannel.publish(stream);
475+
if (options?.transport?.type === 'quic') {
476+
return quicTransportChannel.publish(stream, options, videoCodecs);
477477
}
478478
if (publishChannels.has(stream.mediaStream.id)) {
479479
return Promise.reject(new ConferenceError(
@@ -501,13 +501,16 @@ export const ConferenceClient = function(config, signalingImpl) {
501501
'Invalid source info. A remote stream is either a data stream or ' +
502502
'a media stream.'));
503503
}
504+
}
505+
if (options?.transport?.type === 'quic') {
504506
if (quicTransportChannel) {
505-
return quicTransportChannel.subscribe(stream);
507+
return quicTransportChannel.subscribe(stream, options);
506508
} else {
507509
return Promise.reject(new TypeError('WebTransport is not supported.'));
508510
}
511+
} else {
512+
return peerConnectionChannel.subscribe(stream, options);
509513
}
510-
return peerConnectionChannel.subscribe(stream, options);
511514
};
512515

513516
/**

src/sdk/conference/quicconnection.js

+45-8
Original file line numberDiff line numberDiff line change
@@ -150,23 +150,23 @@ export class QuicConnection extends EventDispatcher {
150150
return quicStream;
151151
}
152152

153-
async publish(stream) {
153+
async publish(stream, options) {
154154
// TODO: Avoid a stream to be published twice. The first 16 bit data send to
155155
// server must be it's publication ID.
156156
// TODO: Potential failure because of publication stream is created faster
157157
// than signaling stream(created by the 1st call to initiatePublication).
158-
const publicationId = await this._initiatePublication();
158+
const publicationId = await this._initiatePublication(stream, options);
159159
const quicStream = stream.stream;
160160
const writer = quicStream.writable.getWriter();
161161
await writer.ready;
162162
writer.write(this._uuidToUint8Array(publicationId));
163163
writer.releaseLock();
164-
Logger.info('publish id');
165164
this._quicStreams.set(publicationId, quicStream);
166165
const publication = new Publication(publicationId, () => {
167166
this._signaling.sendSignalingMessage('unpublish', {id: publication})
168167
.catch((e) => {
169-
Logger.warning('MCU returns negative ack for unpublishing, ' + e);
168+
Logger.warning(
169+
'Server returns negative ack for unpublishing, ' + e);
170170
});
171171
} /* TODO: getStats, mute, unmute is not implemented */);
172172
return publication;
@@ -196,7 +196,7 @@ export class QuicConnection extends EventDispatcher {
196196
return s;
197197
}
198198

199-
subscribe(stream) {
199+
subscribe(stream, options) {
200200
const p = new Promise((resolve, reject) => {
201201
this._signaling
202202
.sendSignalingMessage('subscribe', {
@@ -231,10 +231,47 @@ export class QuicConnection extends EventDispatcher {
231231
});
232232
}
233233

234-
async _initiatePublication() {
234+
async _initiatePublication(stream, options) {
235+
const media = {tracks: []};
236+
if (stream.source.audio) {
237+
if (!options.audio) {
238+
throw new TypeError(
239+
'Options for audio is missing. Publish audio track with ' +
240+
'WebTransport must have AudioEncoderConfig specified.');
241+
}
242+
const track = {
243+
from: stream.id,
244+
source: stream.source.audio,
245+
type: 'audio',
246+
format: {
247+
codec: options.audio.codec,
248+
sampleRate: options.audio.sampleRate,
249+
channelNum: options.audio.numberOfChannels,
250+
},
251+
};
252+
media.tracks.push(track);
253+
}
254+
if (stream.source.video) {
255+
if (!options.video) {
256+
throw new TypeError(
257+
'Options for audio is missing. Publish video track with ' +
258+
'WebTransport must have VideoEncoderConfig specified.');
259+
}
260+
const track = {
261+
from: stream.id,
262+
source: stream.source.video,
263+
type: 'video',
264+
// TODO: convert from MIME type to the format required by server.
265+
format: {
266+
codec: 'h264',
267+
profile: 'B',
268+
},
269+
};
270+
media.tracks.push(track);
271+
}
235272
const data = await this._signaling.sendSignalingMessage('publish', {
236-
media: null,
237-
data: true,
273+
media: stream.source.data ? null : media,
274+
data: stream.source.data,
238275
transport: {type: 'quic', id: this._transportId},
239276
});
240277
if (this._transportId !== data.transportId) {

0 commit comments

Comments
 (0)