Skip to content
This repository was archived by the owner on Oct 25, 2024. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/design/owt_with_webrtc_apis.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ OWT(Open WebRTC Toolkit) Client SDKs provide convenient APIs to create, publish,
- Set preferred codecs.
- Disable or enable RTX / RED / FEC.
#### API Changes
- A new method `getSender` will be added to `Publication`. It returns an `RTCRtpSender` for certain `Publication`.
- A new method `getReceiver` will be added to `Subscription`. It returns an `RTCRtpReceiver` for certain `Subscription`.
- A new member `rtpTransceivers` will be added to `TransportSettings`. It returns an array `RTCRtpReceiver`s for RTP transport.
- A new member `transport` will be added to `Publication` and `Subscription`. Developers could get `RTPTransceiver`s from its `rtpTransceivers` property.
- A new method `addTransceiver(DOMString trackKind, sequence<RTCRtpEncodingParameters> sendEncodings)` will be added to `ConferenceClient`. It invokes `RTCPeerConnection.addTransceiver(trackKind, {direction:inactive, sendEncodings:sendEncodings})`, returns an `RTCRtpTransceiver`. Please note that direction is `inactive` until a `publish` with return transceiver is called.
- The second parameter of `ConferenceClient.publish` accepts an `RTCRtpTransceiver` created by `RTCPeerConnection.addTransceiver`. When this method is called, certain `RTCRtpTransceiver`'s direction is changed to `sendonly`, and its sender's `setStreams` is called with the first parameter's `mediaStream`.
#### Server Requirements
Expand Down
2 changes: 2 additions & 0 deletions docs/mdfiles/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ Change Log
==========
# 5.1
* When subscribe a stream in conference mode, the subscribed MediaStream or BidirectionalStream is associated with a `Owt.Conference.Subscription` instead of a `Owt.Base.RemoteStream`. The `stream` property of a RemoteStream in conference mode is always undefined, while a new property `stream` is added to `Subscription`. It allows a RemoteStream to be subscribed multiple times, as well as subscribing audio and video tracks from different streams.
* Add a new property `transport` to `Publication` for getting `TransportSettings`.
* Add a new property `rtpTransceivers` to `TransportSettings` and `TransportConstraints`.
# 5.0
* Add WebTransport support for conference mode, see [this design doc](../../design/webtransport.md) for detailed information.
* All publications and subscriptions for the same conference use the same `PeerConnection`.
Expand Down
14 changes: 13 additions & 1 deletion src/sdk/base/publication.js
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ export class PublicationSettings {
*/
export class Publication extends EventDispatcher {
// eslint-disable-next-line require-jsdoc
constructor(id, stop, getStats, mute, unmute) {
constructor(id, transport, stop, getStats, mute, unmute) {
super();
/**
* @member {string} id
Expand All @@ -135,6 +135,18 @@ export class Publication extends EventDispatcher {
writable: false,
value: id ? id : Utils.createUuid(),
});
/**
* @member {Owt.Base.TransportSettings} transport
* @instance
* @readonly
* @desc Transport settings for the publication.
* @memberof Owt.Base.Publication
*/
Object.defineProperty(this, 'transport', {
configurable: false,
writable: false,
value: transport,
});
/**
* @function stop
* @instance
Expand Down
17 changes: 14 additions & 3 deletions src/sdk/base/transport.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,18 +56,29 @@ export class TransportSettings {
// eslint-disable-next-line require-jsdoc
constructor(type, id) {
/**
* @member {Array.<Owt.Base.TransportType>} type
* @member {Owt.Base.TransportType} type
* @instance
* @memberof Owt.Base.TransportConstraints
* @memberof Owt.Base.TransportSettings
* @desc Transport type for publication and subscription.
*/
this.type = type;
/**
* @member {string} id
* @instance
* @memberof Owt.Base.TransportConstraints
* @memberof Owt.Base.TransportSettings
* @desc Transport ID.
*/
this.id = id;

/**
* @member {?Array.<RTCRtpTransceiver>} rtpTransceivers
* @instance
* @memberof Owt.Base.TransportSettings
* @desc A list of RTCRtpTransceiver associated with the publication or
* subscription. It's only available in conference mode when TransportType
* is webrtc.
* @see {@link https://w3c.github.io/webrtc-pc/#rtcrtptransceiver-interface|RTCRtpTransceiver Interface of WebRTC 1.0}.
*/
this.rtpTransceivers = undefined;
}
}
40 changes: 28 additions & 12 deletions src/sdk/conference/channel.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {Subscription} from './subscription.js';
import {ConferenceError} from './error.js';
import * as Utils from '../base/utils.js';
import * as SdpUtils from '../base/sdputils.js';
import {TransportSettings, TransportType} from '../base/transport.js';

/**
* @class ConferencePeerConnectionChannel
Expand Down Expand Up @@ -876,25 +877,40 @@ export class ConferencePeerConnectionChannel extends EventDispatcher {
const internalId = this._reverseIdMap.get(sessionId);
if (this._subscribePromises.has(internalId)) {
const mediaStream = this._remoteMediaStreams.get(sessionId);
const subscription = new Subscription(sessionId, mediaStream, () => {
this._unsubscribe(internalId);
}, () => this._getStats(),
(trackKind) => this._muteOrUnmute(sessionId, true, false, trackKind),
(trackKind) => this._muteOrUnmute(sessionId, false, false, trackKind),
(options) => this._applyOptions(sessionId, options));
const transportSettings =
new TransportSettings(TransportType.WEBRTC, this._id);
transportSettings.rtpTransceivers =
this._subscribeTransceivers.get(internalId).transceivers;
const subscription = new Subscription(
sessionId, mediaStream, transportSettings,
() => {
this._unsubscribe(internalId);
},
() => this._getStats(),
(trackKind) => this._muteOrUnmute(sessionId, true, false, trackKind),
(trackKind) => this._muteOrUnmute(sessionId, false, false, trackKind),
(options) => this._applyOptions(sessionId, options));
this._subscriptions.set(sessionId, subscription);
// Resolve subscription if mediaStream is ready.
if (this._subscriptions.get(sessionId).stream) {
this._subscribePromises.get(internalId).resolve(subscription);
this._subscribePromises.delete(internalId);
}
} else if (this._publishPromises.has(internalId)) {
const publication = new Publication(sessionId, () => {
this._unpublish(internalId);
return Promise.resolve();
}, () => this._getStats(),
(trackKind) => this._muteOrUnmute(sessionId, true, true, trackKind),
(trackKind) => this._muteOrUnmute(sessionId, false, true, trackKind));
const transportSettings =
new TransportSettings(TransportType.WEBRTC, this._id);
transportSettings.transceivers =
this._publishTransceivers.get(internalId).transceivers;
const publication = new Publication(
sessionId,
transportSettings,
() => {
this._unpublish(internalId);
return Promise.resolve();
},
() => this._getStats(),
(trackKind) => this._muteOrUnmute(sessionId, true, true, trackKind),
(trackKind) => this._muteOrUnmute(sessionId, false, true, trackKind));
this._publications.set(sessionId, publication);
this._publishPromises.get(internalId).resolve(publication);
// Do not fire publication's ended event when associated stream is ended.
Expand Down
15 changes: 14 additions & 1 deletion src/sdk/conference/subscription.js
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,8 @@ export class SubscriptionUpdateOptions {
*/
export class Subscription extends EventDispatcher {
// eslint-disable-next-line require-jsdoc
constructor(id, stream, stop, getStats, mute, unmute, applyOptions) {
constructor(
id, stream, transport, stop, getStats, mute, unmute, applyOptions) {
super();
if (!id) {
throw new TypeError('ID cannot be null or undefined.');
Expand Down Expand Up @@ -298,6 +299,18 @@ export class Subscription extends EventDispatcher {
writable: true,
value: stream,
});
/**
* @member {Owt.Base.TransportSettings} transport
* @instance
* @readonly
* @desc Transport settings for the subscription.
* @memberof Owt.Base.Subscription
*/
Object.defineProperty(this, 'transport', {
configurable: false,
writable: false,
value: transport,
});
/**
* @function stop
* @instance
Expand Down
3 changes: 2 additions & 1 deletion src/sdk/p2p/peerconnection-channel.js
Original file line number Diff line number Diff line change
Expand Up @@ -305,8 +305,9 @@ class P2PPeerConnectionChannel extends EventDispatcher {
(element) => element.mediaStream.id == mediaStreamId);
const targetStream = this._publishingStreams[targetStreamIndex];
this._publishingStreams.splice(targetStreamIndex, 1);
// TODO: Set transceivers for Publication.
const publication = new Publication(
id, () => {
id, undefined, () => {
this._unpublish(targetStream).then(() => {
publication.dispatchEvent(new OwtEvent('ended'));
}, (err) => {
Expand Down
14 changes: 13 additions & 1 deletion test/unit/resources/scripts/base.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ import * as MediaStreamFactoryModule from '../../../../src/sdk/base/mediastream-
import * as StreamModule from '../../../../src/sdk/base/stream.js';
import * as MediaFormatModule from '../../../../src/sdk/base/mediaformat.js'
import * as SdpUtils from '../../../../src/sdk/base/sdputils.js'
import * as PublicationModule from '../../../../src/sdk/base/publication.js'

const expect = chai.expect;
const screenSharingExtensionId = 'jniliohjdiikfjjdlpapmngebedgigjn';
chai.use(chaiAsPromised);
describe('Unit tests for MediaStreamFactory', function() {
function createMediaStream(constraints, audioTracksExpected,
Expand Down Expand Up @@ -181,3 +181,15 @@ describe('Unit tests for SDP utils.', function() {
done();
});
});

describe('Unit tests for Publication.', () => {
it('Get senders returns all transceivers\' sender.', () => {
it('Get transport returns correct TransportSettings.', () => {
const transportSettings =
new TransportSettings(TransportType.WEBRTC, 'randomId');
const publication =
new PublicationModule.Publication('sessionId', transportSettings);
expect(publication.transport).to.equal(transportSettings);
});
});
});
13 changes: 12 additions & 1 deletion test/unit/resources/scripts/conference.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@ import {ConferenceClient} from '../../../../src/sdk/conference/client.js';
import {ConferencePeerConnectionChannel} from '../../../../src/sdk/conference/channel.js';
import * as StreamModule from '../../../../src/sdk/base/stream.js';
import * as EventModule from '../../../../src/sdk/base/event.js'
import * as SubscriptionModule from '../../../../src/sdk/conference/subscription.js'
import { TransportSettings, TransportType } from '../../../../src/sdk/base/transport.js';

const expect = chai.expect;
const screenSharingExtensionId = 'jniliohjdiikfjjdlpapmngebedgigjn';
chai.use(chaiAsPromised);

describe('Unit tests for ConferenceClient', function() {
Expand Down Expand Up @@ -98,4 +99,14 @@ describe('Unit tests for ConferencePeerConnectionChannel.', () => {
}
});
});
});

describe('Unit tests for Subscription.', () => {
it('Get transport returns correct TransportSettings.', () => {
const transportSettings =
new TransportSettings(TransportType.WEBRTC, 'randomId');
const subscription = new SubscriptionModule.Subscription(
'sessionId', undefined, transportSettings);
expect(subscription.transport).to.equal(transportSettings);
});
});