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

Commit 105f24c

Browse files
committed
Update QuicTransport APIs for conference SDK.
It follows the design in docs\webtransport.md.
1 parent 95b37a8 commit 105f24c

File tree

6 files changed

+92
-50
lines changed

6 files changed

+92
-50
lines changed

docs/design/webtransport.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ JavaScript SDK creates a QuicTransport with a QUIC agent when QUIC agent is enab
2424

2525
```
2626
const sendStream = conferenceClient.createSendStream();
27-
const publication = await conferenceClient.publish(sendStream);
27+
const localStream = new LocalStream(sendStream, new StreamSourceInfo(undefined, undefined, true));
28+
const publication = await conferenceClient.publish(localStream);
2829
sendStream.stream.write(somethingToWrite);
2930
```
3031

docs/mdfiles/changelog.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
Change Log
22
==========
3+
# 4.4
4+
* `LocalStream`'s property `mediaStream` is renamed to `stream`. It could also be a `SendStream` or `BidirectionalStream`.
5+
36
# 4.3
47
* The type of `conferenceClient.publish` method's option is changed from `AudioEncodingParameters` and `VideoEncodingParameters` to `RTCRtpSendParameters`.
58
* `audio` and `video` of `PublicationSettings` is changed from `AudioPublicationSettings` and `VideoPublicationSettings` to `AudioPublicationSettings` array and `VideoPublicationSettings` array.

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,13 +63,15 @@ function createRandomContentSessionId() {
6363
}
6464

6565
async function createSendChannel() {
66-
bidirectionalStream = await quicChannel.createSendStream();
66+
bidirectionalStream = await conference.createSendStream();
67+
const localStream=new Owt.Base.LocalStream(bidirectionalStream, new Owt.Base.StreamSourceInfo(undefined, undefined,true));
68+
const publication = await conference.publish(localStream);
69+
console.log(publication);
6770
updateConferenceStatus('Created send channel.');
6871
}
6972

7073
async function windowOnLoad() {
7174
await joinConference();
72-
await createQuicTransport();
7375
await createSendChannel();
7476
}
7577

src/sdk/base/stream.js

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//
33
// SPDX-License-Identifier: Apache-2.0
44

5-
/* global MediaStream */
5+
/* global MediaStream, SendStream, BidirectionalStream */
66

77
'use strict';
88
import * as Utils from './utils.js';
@@ -55,21 +55,39 @@ export class Stream extends EventDispatcher {
5555
// eslint-disable-next-line require-jsdoc
5656
constructor(stream, sourceInfo, attributes) {
5757
super();
58-
if ((stream && !(stream instanceof MediaStream)) || (typeof sourceInfo !==
59-
'object')) {
58+
if ((stream && !(stream instanceof MediaStream) &&
59+
!(stream instanceof SendStream) &&
60+
!(stream instanceof BidirectionalStream)) ||
61+
(typeof sourceInfo !== 'object')) {
6062
throw new TypeError('Invalid stream or sourceInfo.');
6163
}
62-
if (stream && ((stream.getAudioTracks().length > 0 && !sourceInfo.audio) ||
63-
stream.getVideoTracks().length > 0 && !sourceInfo.video)) {
64+
if (stream && (stream instanceof MediaStream) &&
65+
((stream.getAudioTracks().length > 0 && !sourceInfo.audio) ||
66+
stream.getVideoTracks().length > 0 && !sourceInfo.video)) {
6467
throw new TypeError('Missing audio source info or video source info.');
6568
}
6669
/**
6770
* @member {?MediaStream} mediaStream
6871
* @instance
6972
* @memberof Owt.Base.Stream
7073
* @see {@link https://www.w3.org/TR/mediacapture-streams/#mediastream|MediaStream API of Media Capture and Streams}.
74+
* @desc This property is deprecated, please use stream instead.
7175
*/
72-
Object.defineProperty(this, 'mediaStream', {
76+
if (stream instanceof MediaStream) {
77+
Object.defineProperty(this, 'mediaStream', {
78+
configurable: false,
79+
writable: true,
80+
value: stream,
81+
});
82+
}
83+
/**
84+
* @member {MediaStream | SendStream | BidirectionalStream | undefined} stream
85+
* @instance
86+
* @memberof Owt.Base.Stream
87+
* @see {@link https://www.w3.org/TR/mediacapture-streams/#mediastream|MediaStream API of Media Capture and Streams}
88+
* @see {@link https://wicg.github.io/web-transport/ WebTransport}.
89+
*/
90+
Object.defineProperty(this, 'stream', {
7391
configurable: false,
7492
writable: true,
7593
value: stream,
@@ -112,8 +130,8 @@ export class Stream extends EventDispatcher {
112130
export class LocalStream extends Stream {
113131
// eslint-disable-next-line require-jsdoc
114132
constructor(stream, sourceInfo, attributes) {
115-
if (!(stream instanceof MediaStream)) {
116-
throw new TypeError('Invalid stream.');
133+
if (!stream) {
134+
throw new TypeError('Stream cannot be null.');
117135
}
118136
super(stream, sourceInfo, attributes);
119137
/**

src/sdk/conference/client.js

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ export const ConferenceClient = function(config, signalingImpl) {
112112
const participants = new Map(); // Key is participant ID, value is a Participant object.
113113
const publishChannels = new Map(); // Key is MediaStream's ID, value is pc channel.
114114
const channels = new Map(); // Key is channel's internal ID, value is channel.
115-
let quicTransportChannel = null;
115+
let quicTransportChannel;
116116

117117
/**
118118
* @function onSignalingMessage
@@ -349,6 +349,12 @@ export const ConferenceClient = function(config, signalingImpl) {
349349
* @param {string} tokenString Token is issued by conference server(nuve).
350350
*/
351351
this.join = function(tokenString) {
352+
if (QuicConnection) {
353+
// TODO: Get URL from token.
354+
quicTransportChannel = new QuicConnection(
355+
'quic-transport://jianjunz-nuc-ubuntu.sh.intel.com:7700/echo',
356+
createSignalingForChannel());
357+
}
352358
return new Promise((resolve, reject) => {
353359
const token = JSON.parse(Base64.decodeBase64(tokenString));
354360
const isSecured = (token.secure === true);
@@ -414,6 +420,9 @@ export const ConferenceClient = function(config, signalingImpl) {
414420
if (!(stream instanceof StreamModule.LocalStream)) {
415421
return Promise.reject(new ConferenceError('Invalid stream.'));
416422
}
423+
if (stream.source.data) {
424+
return quicTransportChannel.publish(stream);
425+
}
417426
if (publishChannels.has(stream.mediaStream.id)) {
418427
return Promise.reject(new ConferenceError(
419428
'Cannot publish a published stream.'));
@@ -478,18 +487,20 @@ export const ConferenceClient = function(config, signalingImpl) {
478487
});
479488
};
480489

481-
/**
482-
* @function createDataStream
490+
/**
491+
* @function createSendStream
483492
* @memberOf Owt.Conference.ConferenceClient
484493
* @instance
485-
* @desc Create a bidirectional stream.
486-
* @return {Promise<void, Error>} Returned promise will be resolved with a bidirectional stream once stream is created.
494+
* @desc Create a outgoing stream. Only available when WebTransport is supported by user's browser.
495+
* @return {Promise<SendStream, Error>} Returned promise will be resolved with a SendStream once stream is created.
487496
*/
488-
this.createQuicConnection = function() {
489-
const quicConnection = new QuicConnection(
490-
'quic-transport://jianjunz-nuc-ubuntu.sh.intel.com:7700/echo',
491-
createSignalingForChannel());
492-
quicTransportChannel = quicConnection;
493-
return quicConnection;
494-
};
497+
if (QuicConnection) {
498+
this.createSendStream = async function() {
499+
if (!quicTransportChannel) {
500+
// Try to create a new one or consider it as closed?
501+
throw new ConferenceError('No QUIC connection available.');
502+
}
503+
return quicTransportChannel.createSendStream();
504+
};
505+
}
495506
};

src/sdk/conference/quicconnection.js

Lines changed: 34 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
EventDispatcher,
1313
MessageEvent,
1414
} from '../base/event.js';
15+
import {Publication} from '../base/publication.js';
1516
import {Subscription} from './subscription.js';
1617

1718
/**
@@ -112,9 +113,16 @@ export class QuicConnection extends EventDispatcher {
112113
writer.write(new Uint8Array(16));
113114
const encoder = new TextEncoder();
114115
writer.write(encoder.encode(token));
116+
Logger.info('End of auth.');
115117
}
116118

117-
async createSendStream(sessionId) {
119+
async createSendStream() {
120+
await this._quicTransport.ready;
121+
const quicStream = await this._quicTransport.createSendStream();
122+
return quicStream;
123+
}
124+
125+
async createSendStream1(sessionId) {
118126
Logger.info('Create stream.');
119127
await this._quicTransport.ready;
120128
// TODO: Potential failure because of publication stream is created faster
@@ -129,6 +137,28 @@ export class QuicConnection extends EventDispatcher {
129137
return quicStream;
130138
}
131139

140+
async publish(stream) {
141+
// TODO: Avoid a stream to be published twice. The first 16 bit data send to
142+
// server must be it's publication ID.
143+
// TODO: Potential failure because of publication stream is created faster
144+
// than signaling stream(created by the 1st call to initiatePublication).
145+
const publicationId = await this._initiatePublication();
146+
const quicStream = stream.stream;
147+
const writer = quicStream.writable.getWriter();
148+
await writer.ready;
149+
writer.write(this._uuidToUint8Array(publicationId));
150+
writer.releaseLock();
151+
Logger.info('publish id');
152+
this._quicStreams.set(publicationId, quicStream);
153+
const publication = new Publication(publicationId, () => {
154+
this._signaling.sendSignalingMessage('unpublish', {id: publication})
155+
.catch((e) => {
156+
Logger.warning('MCU returns negative ack for unpublishing, ' + e);
157+
});
158+
} /* TODO: getStats, mute, unmute is not implemented */);
159+
return publication;
160+
}
161+
132162
hasContentSessionId(id) {
133163
return this._quicStreams.has(id);
134164
}
@@ -154,29 +184,6 @@ export class QuicConnection extends EventDispatcher {
154184
return s;
155185
}
156186

157-
/**
158-
* @function createStream
159-
* @desc Create a bidirectional stream.
160-
* @param {string} sessionId Publication or subscription ID.
161-
* @private
162-
*/
163-
createStream(sessionId) {
164-
Logger.info('Create stream.');
165-
if (this._quicTransport && this._quicTransport.state == 'connected') {
166-
this._quicStreams.push(stream);
167-
return Promise.resolve(stream);
168-
}
169-
if (!this._quicTransport) {
170-
this._initialize();
171-
}
172-
return new Promise((resolve, reject) => {
173-
this._createStreamPromise = {
174-
resolve: resolve,
175-
reject: reject
176-
};
177-
});
178-
}
179-
180187
subscribe(stream) {
181188
const p = new Promise((resolve, reject) => {
182189
this._signaling
@@ -212,13 +219,13 @@ export class QuicConnection extends EventDispatcher {
212219
});
213220
}
214221

215-
_updateTransportId(id) {
222+
async _updateTransportId(id) {
216223
if (this._transportId) {
217224
Logger.error('Update transport ID is not supported.');
218225
return;
219226
}
220227
this._transportId = id;
221-
this._authenticate(id);
228+
await this._authenticate(id);
222229
}
223230

224231
async _initiatePublication() {
@@ -228,7 +235,7 @@ export class QuicConnection extends EventDispatcher {
228235
transport: {type: 'quic', id: this._transportId},
229236
});
230237
if (data.transportId) {
231-
this._updateTransportId(data.transportId);
238+
await this._updateTransportId(data.transportId);
232239
} else {
233240
if (this._transportId !== data.transportId) {
234241
throw new Error('Transport ID not match.');

0 commit comments

Comments
 (0)