Skip to content

Commit 7d1d0af

Browse files
authored
Separate RTP capabilities for sending and receiving (#360)
- Fixes #141 - This PR replaces PR #359 but it's basically a copy&paste of it with some minimal cosmetic changes. So absolutely all credits to @6uliver. - Now we generate different RTP capabilities for sending and receiving and the only change in the public API is that `device.rtpCapabilities` getter is now deprecated and instead the app should use `device.recvRtpCapabilities` and `device.sendRtpCapabilities`.
1 parent 34aaaee commit 7d1d0af

10 files changed

Lines changed: 228 additions & 106 deletions

File tree

src/Device.ts

Lines changed: 70 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -130,10 +130,12 @@ export class Device {
130130
// Callback for sending Transports to request sending extended RTP capabilities
131131
// on demand.
132132
private _getSendExtendedRtpCapabilities?: (
133-
nativeRtpCapabilities: RtpCapabilities
133+
nativeSendRtpCapabilities: RtpCapabilities
134134
) => ExtendedRtpCapabilities;
135135
// Local RTP capabilities for receiving media.
136136
private _recvRtpCapabilities?: RtpCapabilities;
137+
// Local RTP capabilities for sending media.
138+
private _sendRtpCapabilities?: RtpCapabilities;
137139
// Whether we can produce audio/video based on remote RTP capabilities.
138140
private readonly _canProduceByKind: CanProduceByKind = {
139141
audio: false,
@@ -260,16 +262,40 @@ export class Device {
260262
/**
261263
* RTP capabilities of the Device for receiving media.
262264
*
265+
* @deprecated Use {@link recvRtpCapabilities} instead.
266+
*
263267
* @throws {InvalidStateError} if not loaded.
264268
*/
265269
get rtpCapabilities(): RtpCapabilities {
270+
return this.recvRtpCapabilities;
271+
}
272+
273+
/**
274+
* RTP capabilities of the Device for receiving media.
275+
*
276+
* @throws {InvalidStateError} if not loaded.
277+
*/
278+
get recvRtpCapabilities(): RtpCapabilities {
266279
if (!this._loaded) {
267280
throw new InvalidStateError('not loaded');
268281
}
269282

270283
return this._recvRtpCapabilities!;
271284
}
272285

286+
/**
287+
* RTP capabilities of the Device for sending media.
288+
*
289+
* @throws {InvalidStateError} if not loaded.
290+
*/
291+
get sendRtpCapabilities(): RtpCapabilities {
292+
if (!this._loaded) {
293+
throw new InvalidStateError('not loaded');
294+
}
295+
296+
return this._sendRtpCapabilities!;
297+
}
298+
273299
/**
274300
* SCTP capabilities of the Device.
275301
*
@@ -314,32 +340,44 @@ export class Device {
314340
const { getNativeRtpCapabilities, getNativeSctpCapabilities } =
315341
this._handlerFactory;
316342

317-
const clonedNativeRtpCapabilities = utils.clone<RtpCapabilities>(
318-
await getNativeRtpCapabilities()
343+
const clonedNativeRecvRtpCapabilities = utils.clone<RtpCapabilities>(
344+
await getNativeRtpCapabilities({ direction: 'recvonly' })
345+
);
346+
347+
logger.debug(
348+
'load() | got native receiving RTP capabilities:%o',
349+
clonedNativeRecvRtpCapabilities
319350
);
320351

321352
// This may throw.
322-
ortc.validateAndNormalizeRtpCapabilities(clonedNativeRtpCapabilities);
353+
ortc.validateAndNormalizeRtpCapabilities(clonedNativeRecvRtpCapabilities);
354+
355+
const clonedNativeSendRtpCapabilities = utils.clone<RtpCapabilities>(
356+
await getNativeRtpCapabilities({ direction: 'sendonly' })
357+
);
323358

324359
logger.debug(
325-
'load() | got native RTP capabilities:%o',
326-
clonedNativeRtpCapabilities
360+
'load() | got native sending RTP capabilities:%o',
361+
clonedNativeSendRtpCapabilities
327362
);
328363

364+
// This may throw.
365+
ortc.validateAndNormalizeRtpCapabilities(clonedNativeSendRtpCapabilities);
366+
329367
this._getSendExtendedRtpCapabilities = (
330-
nativeRtpCapabilities: RtpCapabilities
368+
nativeSendRtpCapabilities: RtpCapabilities
331369
) => {
332370
return utils.clone<ExtendedRtpCapabilities>(
333371
ortc.getExtendedRtpCapabilities(
334-
nativeRtpCapabilities,
372+
nativeSendRtpCapabilities,
335373
clonedRouterRtpCapabilities,
336374
preferLocalCodecsOrder
337375
)
338376
);
339377
};
340378

341379
const recvExtendedRtpCapabilities = ortc.getExtendedRtpCapabilities(
342-
clonedNativeRtpCapabilities,
380+
clonedNativeRecvRtpCapabilities,
343381
clonedRouterRtpCapabilities,
344382
/* preferLocalCodecsOrder */ false
345383
);
@@ -349,22 +387,41 @@ export class Device {
349387
recvExtendedRtpCapabilities
350388
);
351389

390+
logger.debug(
391+
'load() | got receiving RTP capabilities:%o',
392+
this._recvRtpCapabilities
393+
);
394+
352395
// This may throw.
353396
ortc.validateAndNormalizeRtpCapabilities(this._recvRtpCapabilities);
354397

398+
const sendExtendedRtpCapabilities = ortc.getExtendedRtpCapabilities(
399+
clonedNativeSendRtpCapabilities,
400+
clonedRouterRtpCapabilities,
401+
preferLocalCodecsOrder
402+
);
403+
404+
// Generate our sending RTP capabilities for sending media.
405+
this._sendRtpCapabilities = ortc.getSendRtpCapabilities(
406+
sendExtendedRtpCapabilities
407+
);
408+
355409
logger.debug(
356-
'load() | got receiving RTP capabilities:%o',
357-
this._recvRtpCapabilities
410+
'load() | got sending RTP capabilities:%o',
411+
this._sendRtpCapabilities
358412
);
359413

414+
// This may throw.
415+
ortc.validateAndNormalizeRtpCapabilities(this._sendRtpCapabilities);
416+
360417
// Check whether we can produce audio/video.
361418
this._canProduceByKind.audio = ortc.canSend(
362419
'audio',
363-
this._recvRtpCapabilities
420+
this._sendRtpCapabilities
364421
);
365422
this._canProduceByKind.video = ortc.canSend(
366423
'video',
367-
this._recvRtpCapabilities
424+
this._sendRtpCapabilities
368425
);
369426

370427
// Generate our SCTP capabilities.

src/handlers/Chrome111.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import type {
2323
HandlerInterface,
2424
HandlerEvents,
2525
HandlerOptions,
26+
HandlerGetNativeRtpCapabilitiesOptions,
2627
HandlerSendOptions,
2728
HandlerSendResult,
2829
HandlerReceiveOptions,
@@ -50,7 +51,7 @@ export class Chrome111
5051
private _remoteSdp: RemoteSdp;
5152
// Callback to request sending extended RTP capabilities on demand.
5253
private _getSendExtendedRtpCapabilities: (
53-
nativeRtpCapabilities: RtpCapabilities
54+
nativeSendRtpCapabilities: RtpCapabilities
5455
) => ExtendedRtpCapabilities;
5556
// Initial server side DTLS role. If not 'auto', it will force the opposite
5657
// value in client side.
@@ -76,8 +77,10 @@ export class Chrome111
7677
return {
7778
name: NAME,
7879
factory: (options: HandlerOptions): Chrome111 => new Chrome111(options),
79-
getNativeRtpCapabilities: async (): Promise<RtpCapabilities> => {
80-
logger.debug('getNativeRtpCapabilities()');
80+
getNativeRtpCapabilities: async ({
81+
direction,
82+
}: HandlerGetNativeRtpCapabilitiesOptions): Promise<RtpCapabilities> => {
83+
logger.debug('getNativeRtpCapabilities() [direction:%o]', direction);
8184

8285
let pc: RTCPeerConnection | undefined = new RTCPeerConnection({
8386
iceServers: [],
@@ -87,10 +90,11 @@ export class Chrome111
8790
});
8891

8992
try {
90-
pc.addTransceiver('audio');
93+
pc.addTransceiver('audio', { direction });
9194
// Create video transceiver with scalability mode in order to retrieve
9295
// Dependency Descriptor header extension.
9396
pc.addTransceiver('video', {
97+
direction,
9498
sendEncodings: [{ scalabilityMode: 'L3T3' }],
9599
});
96100

src/handlers/Chrome74.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import type {
2424
HandlerEvents,
2525
HandlerInterface,
2626
HandlerOptions,
27+
HandlerGetNativeRtpCapabilitiesOptions,
2728
HandlerSendOptions,
2829
HandlerSendResult,
2930
HandlerReceiveOptions,
@@ -51,7 +52,7 @@ export class Chrome74
5152
private _remoteSdp: RemoteSdp;
5253
// Callback to request sending extended RTP capabilities on demand.
5354
private _getSendExtendedRtpCapabilities: (
54-
nativeRtpCapabilities: RtpCapabilities
55+
nativeSendRtpCapabilities: RtpCapabilities
5556
) => ExtendedRtpCapabilities;
5657
// Initial server side DTLS role. If not 'auto', it will force the opposite
5758
// value in client side.
@@ -77,8 +78,10 @@ export class Chrome74
7778
return {
7879
name: NAME,
7980
factory: (options: HandlerOptions): Chrome74 => new Chrome74(options),
80-
getNativeRtpCapabilities: async (): Promise<RtpCapabilities> => {
81-
logger.debug('getNativeRtpCapabilities()');
81+
getNativeRtpCapabilities: async ({
82+
direction,
83+
}: HandlerGetNativeRtpCapabilitiesOptions): Promise<RtpCapabilities> => {
84+
logger.debug('getNativeRtpCapabilities() [direction:%o]', direction);
8285

8386
let pc: RTCPeerConnection | undefined = new RTCPeerConnection({
8487
iceServers: [],
@@ -88,8 +91,8 @@ export class Chrome74
8891
});
8992

9093
try {
91-
pc.addTransceiver('audio');
92-
pc.addTransceiver('video');
94+
pc.addTransceiver('audio', { direction });
95+
pc.addTransceiver('video', { direction });
9396

9497
const offer = await pc.createOffer();
9598

src/handlers/FakeHandler.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import type {
3131
HandlerInterface,
3232
HandlerEvents,
3333
HandlerOptions,
34+
HandlerGetNativeRtpCapabilitiesOptions,
3435
HandlerSendOptions,
3536
HandlerSendResult,
3637
HandlerReceiveOptions,
@@ -84,8 +85,10 @@ export class FakeHandler
8485
name: NAME,
8586
factory: (options: HandlerOptions): FakeHandler =>
8687
new FakeHandler(options, fakeParameters),
87-
getNativeRtpCapabilities: async (): Promise<RtpCapabilities> => {
88-
logger.debug('getNativeRtpCapabilities()');
88+
getNativeRtpCapabilities: async ({
89+
direction,
90+
}: HandlerGetNativeRtpCapabilitiesOptions): Promise<RtpCapabilities> => {
91+
logger.debug('getNativeRtpCapabilities() [direction:%o]', direction);
8992

9093
return FakeHandler.getLocalRtpCapabilities(fakeParameters);
9194
},

src/handlers/Firefox120.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import type {
2222
HandlerInterface,
2323
HandlerEvents,
2424
HandlerOptions,
25+
HandlerGetNativeRtpCapabilitiesOptions,
2526
HandlerSendOptions,
2627
HandlerSendResult,
2728
HandlerReceiveOptions,
@@ -49,7 +50,7 @@ export class Firefox120
4950
private _remoteSdp: RemoteSdp;
5051
// Callback to request sending extended RTP capabilities on demand.
5152
private _getSendExtendedRtpCapabilities: (
52-
nativeRtpCapabilities: RtpCapabilities
53+
nativeSendRtpCapabilities: RtpCapabilities
5354
) => ExtendedRtpCapabilities;
5455
// RTCPeerConnection instance.
5556
private _pc: RTCPeerConnection;
@@ -72,8 +73,10 @@ export class Firefox120
7273
return {
7374
name: NAME,
7475
factory: (options: HandlerOptions): Firefox120 => new Firefox120(options),
75-
getNativeRtpCapabilities: async (): Promise<RtpCapabilities> => {
76-
logger.debug('getNativeRtpCapabilities()');
76+
getNativeRtpCapabilities: async ({
77+
direction,
78+
}: HandlerGetNativeRtpCapabilitiesOptions): Promise<RtpCapabilities> => {
79+
logger.debug('getNativeRtpCapabilities() [direction:%o]', direction);
7780

7881
let pc: RTCPeerConnection | undefined = new RTCPeerConnection({
7982
iceServers: [],
@@ -93,10 +96,10 @@ export class Firefox120
9396
const fakeVideoTrack = fakeStream.getVideoTracks()[0]!;
9497

9598
try {
96-
pc.addTransceiver('audio', { direction: 'sendrecv' });
99+
pc.addTransceiver('audio', { direction });
97100

98101
pc.addTransceiver(fakeVideoTrack, {
99-
direction: 'sendrecv',
102+
direction,
100103
sendEncodings: [
101104
{ rid: 'r0', maxBitrate: 100000 },
102105
{ rid: 'r1', maxBitrate: 500000 },

src/handlers/HandlerInterface.ts

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,15 @@ import type {
2525
SctpStreamParameters,
2626
} from '../SctpParameters';
2727

28+
export type HandlerFactory = {
29+
name: string;
30+
factory: (options: HandlerOptions) => HandlerInterface;
31+
getNativeRtpCapabilities(
32+
options: HandlerGetNativeRtpCapabilitiesOptions
33+
): Promise<RtpCapabilities>;
34+
getNativeSctpCapabilities(): Promise<SctpCapabilities>;
35+
};
36+
2837
export type HandlerOptions = {
2938
direction: 'send' | 'recv';
3039
iceParameters: IceParameters;
@@ -35,15 +44,12 @@ export type HandlerOptions = {
3544
iceTransportPolicy?: RTCIceTransportPolicy;
3645
additionalSettings?: Partial<RTCConfiguration>;
3746
getSendExtendedRtpCapabilities: (
38-
nativeRtpCapabilities: RtpCapabilities
47+
nativeSendRtpCapabilities: RtpCapabilities
3948
) => ExtendedRtpCapabilities;
4049
};
4150

42-
export type HandlerFactory = {
43-
name: string;
44-
factory: (options: HandlerOptions) => HandlerInterface;
45-
getNativeRtpCapabilities(): Promise<RtpCapabilities>;
46-
getNativeSctpCapabilities(): Promise<SctpCapabilities>;
51+
export type HandlerGetNativeRtpCapabilitiesOptions = {
52+
direction: Extract<RTCRtpTransceiverDirection, 'sendonly' | 'recvonly'>;
4753
};
4854

4955
export type HandlerSendOptions = {

src/handlers/ReactNative106.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import type {
2424
HandlerInterface,
2525
HandlerEvents,
2626
HandlerOptions,
27+
HandlerGetNativeRtpCapabilitiesOptions,
2728
HandlerSendOptions,
2829
HandlerSendResult,
2930
HandlerReceiveOptions,
@@ -51,7 +52,7 @@ export class ReactNative106
5152
private _remoteSdp: RemoteSdp;
5253
// Callback to request sending extended RTP capabilities on demand.
5354
private _getSendExtendedRtpCapabilities: (
54-
nativeRtpCapabilities: RtpCapabilities
55+
nativeSendRtpCapabilities: RtpCapabilities
5556
) => ExtendedRtpCapabilities;
5657
// Initial server side DTLS role. If not 'auto', it will force the opposite
5758
// value in client side.
@@ -78,8 +79,10 @@ export class ReactNative106
7879
name: NAME,
7980
factory: (options: HandlerOptions): ReactNative106 =>
8081
new ReactNative106(options),
81-
getNativeRtpCapabilities: async (): Promise<RtpCapabilities> => {
82-
logger.debug('getNativeRtpCapabilities()');
82+
getNativeRtpCapabilities: async ({
83+
direction,
84+
}: HandlerGetNativeRtpCapabilitiesOptions): Promise<RtpCapabilities> => {
85+
logger.debug('getNativeRtpCapabilities() [direction:%o]', direction);
8386

8487
let pc: RTCPeerConnection | undefined = new RTCPeerConnection({
8588
iceServers: [],
@@ -89,8 +92,8 @@ export class ReactNative106
8992
});
9093

9194
try {
92-
pc.addTransceiver('audio');
93-
pc.addTransceiver('video');
95+
pc.addTransceiver('audio', { direction });
96+
pc.addTransceiver('video', { direction });
9497

9598
const offer = await pc.createOffer();
9699

0 commit comments

Comments
 (0)