@stream-io/video-client 1.8.3 → 1.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/dist/index.browser.es.js +434 -449
- package/dist/index.browser.es.js.map +1 -1
- package/dist/index.cjs.js +434 -449
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.es.js +434 -449
- package/dist/index.es.js.map +1 -1
- package/dist/src/Call.d.ts +10 -12
- package/dist/src/compatibility.d.ts +7 -0
- package/dist/src/devices/CameraManager.d.ts +2 -22
- package/dist/src/events/internal.d.ts +0 -4
- package/dist/src/gen/video/sfu/event/events.d.ts +2 -71
- package/dist/src/helpers/sdp-munging.d.ts +8 -0
- package/dist/src/rtc/Publisher.d.ts +18 -23
- package/dist/src/rtc/bitrateLookup.d.ts +2 -0
- package/dist/src/rtc/codecs.d.ts +9 -2
- package/dist/src/rtc/videoLayers.d.ts +31 -4
- package/dist/src/types.d.ts +30 -2
- package/package.json +1 -1
- package/src/Call.ts +21 -38
- package/src/compatibility.ts +7 -0
- package/src/devices/CameraManager.ts +18 -47
- package/src/devices/ScreenShareManager.ts +1 -3
- package/src/devices/__tests__/CameraManager.test.ts +7 -15
- package/src/devices/__tests__/ScreenShareManager.test.ts +0 -14
- package/src/events/callEventHandlers.ts +0 -2
- package/src/events/internal.ts +0 -16
- package/src/gen/video/sfu/event/events.ts +8 -120
- package/src/helpers/sdp-munging.ts +38 -15
- package/src/rtc/Publisher.ts +211 -317
- package/src/rtc/__tests__/Publisher.test.ts +196 -7
- package/src/rtc/__tests__/bitrateLookup.test.ts +12 -0
- package/src/rtc/__tests__/mocks/webrtc.mocks.ts +2 -0
- package/src/rtc/__tests__/videoLayers.test.ts +51 -36
- package/src/rtc/bitrateLookup.ts +61 -0
- package/src/rtc/codecs.ts +56 -9
- package/src/rtc/videoLayers.ts +74 -23
- package/src/types.ts +30 -2
|
@@ -4,7 +4,8 @@ import { CameraDirection, CameraManagerState } from './CameraManagerState';
|
|
|
4
4
|
import { InputMediaDeviceManager } from './InputMediaDeviceManager';
|
|
5
5
|
import { getVideoDevices, getVideoStream } from './devices';
|
|
6
6
|
import { TrackType } from '../gen/video/sfu/models/models';
|
|
7
|
-
import { PreferredCodec
|
|
7
|
+
import { PreferredCodec } from '../types';
|
|
8
|
+
import { isMobile } from '../compatibility';
|
|
8
9
|
|
|
9
10
|
export class CameraManager extends InputMediaDeviceManager<CameraManagerState> {
|
|
10
11
|
private targetResolution = {
|
|
@@ -12,13 +13,6 @@ export class CameraManager extends InputMediaDeviceManager<CameraManagerState> {
|
|
|
12
13
|
height: 720,
|
|
13
14
|
};
|
|
14
15
|
|
|
15
|
-
/**
|
|
16
|
-
* The options to use when publishing the video stream.
|
|
17
|
-
*
|
|
18
|
-
* @internal
|
|
19
|
-
*/
|
|
20
|
-
publishOptions: PublishOptions | undefined;
|
|
21
|
-
|
|
22
16
|
/**
|
|
23
17
|
* Constructs a new CameraManager.
|
|
24
18
|
*
|
|
@@ -34,10 +28,14 @@ export class CameraManager extends InputMediaDeviceManager<CameraManagerState> {
|
|
|
34
28
|
* @param direction the direction of the camera to select.
|
|
35
29
|
*/
|
|
36
30
|
async selectDirection(direction: Exclude<CameraDirection, undefined>) {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
31
|
+
if (isMobile()) {
|
|
32
|
+
this.state.setDirection(direction);
|
|
33
|
+
// Providing both device id and direction doesn't work, so we deselect the device
|
|
34
|
+
this.state.setDevice(undefined);
|
|
35
|
+
await this.applySettingsToStream();
|
|
36
|
+
} else {
|
|
37
|
+
this.logger('warn', 'Camera direction ignored for desktop devices');
|
|
38
|
+
}
|
|
41
39
|
}
|
|
42
40
|
|
|
43
41
|
/**
|
|
@@ -65,10 +63,10 @@ export class CameraManager extends InputMediaDeviceManager<CameraManagerState> {
|
|
|
65
63
|
this.logger('warn', 'could not apply target resolution', error);
|
|
66
64
|
}
|
|
67
65
|
}
|
|
68
|
-
if (this.enabled) {
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
|
|
66
|
+
if (this.enabled && this.state.mediaStream) {
|
|
67
|
+
const [videoTrack] = this.state.mediaStream.getVideoTracks();
|
|
68
|
+
if (!videoTrack) return;
|
|
69
|
+
const { width, height } = videoTrack.getSettings();
|
|
72
70
|
if (
|
|
73
71
|
width !== this.targetResolution.width ||
|
|
74
72
|
height !== this.targetResolution.height
|
|
@@ -86,38 +84,11 @@ export class CameraManager extends InputMediaDeviceManager<CameraManagerState> {
|
|
|
86
84
|
* Sets the preferred codec for encoding the video.
|
|
87
85
|
*
|
|
88
86
|
* @internal internal use only, not part of the public API.
|
|
87
|
+
* @deprecated use {@link call.updatePublishOptions} instead.
|
|
89
88
|
* @param codec the codec to use for encoding the video.
|
|
90
89
|
*/
|
|
91
90
|
setPreferredCodec(codec: PreferredCodec | undefined) {
|
|
92
|
-
this.updatePublishOptions({ preferredCodec: codec });
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Updates the preferred publish options for the video stream.
|
|
97
|
-
*
|
|
98
|
-
* @internal
|
|
99
|
-
* @param options the options to use.
|
|
100
|
-
*/
|
|
101
|
-
updatePublishOptions(options: PublishOptions) {
|
|
102
|
-
this.publishOptions = { ...this.publishOptions, ...options };
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* Returns the capture resolution of the camera.
|
|
107
|
-
*/
|
|
108
|
-
getCaptureResolution() {
|
|
109
|
-
const { mediaStream } = this.state;
|
|
110
|
-
if (!mediaStream) return;
|
|
111
|
-
|
|
112
|
-
const [videoTrack] = mediaStream.getVideoTracks();
|
|
113
|
-
if (!videoTrack) return;
|
|
114
|
-
|
|
115
|
-
const settings = videoTrack.getSettings();
|
|
116
|
-
return {
|
|
117
|
-
width: settings.width,
|
|
118
|
-
height: settings.height,
|
|
119
|
-
frameRate: settings.frameRate,
|
|
120
|
-
};
|
|
91
|
+
this.call.updatePublishOptions({ preferredCodec: codec });
|
|
121
92
|
}
|
|
122
93
|
|
|
123
94
|
protected getDevices(): Observable<MediaDeviceInfo[]> {
|
|
@@ -131,7 +102,7 @@ export class CameraManager extends InputMediaDeviceManager<CameraManagerState> {
|
|
|
131
102
|
constraints.height = this.targetResolution.height;
|
|
132
103
|
// We can't set both device id and facing mode
|
|
133
104
|
// Device id has higher priority
|
|
134
|
-
if (!constraints.deviceId && this.state.direction) {
|
|
105
|
+
if (!constraints.deviceId && this.state.direction && isMobile()) {
|
|
135
106
|
constraints.facingMode =
|
|
136
107
|
this.state.direction === 'front' ? 'user' : 'environment';
|
|
137
108
|
}
|
|
@@ -139,7 +110,7 @@ export class CameraManager extends InputMediaDeviceManager<CameraManagerState> {
|
|
|
139
110
|
}
|
|
140
111
|
|
|
141
112
|
protected publishStream(stream: MediaStream): Promise<void> {
|
|
142
|
-
return this.call.publishVideoStream(stream
|
|
113
|
+
return this.call.publishVideoStream(stream);
|
|
143
114
|
}
|
|
144
115
|
|
|
145
116
|
protected stopPublishStream(stopTracks: boolean): Promise<void> {
|
|
@@ -80,9 +80,7 @@ export class ScreenShareManager extends InputMediaDeviceManager<
|
|
|
80
80
|
}
|
|
81
81
|
|
|
82
82
|
protected publishStream(stream: MediaStream): Promise<void> {
|
|
83
|
-
return this.call.publishScreenShareStream(stream
|
|
84
|
-
screenShareSettings: this.state.settings,
|
|
85
|
-
});
|
|
83
|
+
return this.call.publishScreenShareStream(stream);
|
|
86
84
|
}
|
|
87
85
|
|
|
88
86
|
protected async stopPublishStream(stopTracks: boolean): Promise<void> {
|
|
@@ -36,6 +36,13 @@ vi.mock('../../Call.ts', () => {
|
|
|
36
36
|
};
|
|
37
37
|
});
|
|
38
38
|
|
|
39
|
+
vi.mock('../../compatibility.ts', () => {
|
|
40
|
+
console.log('MOCKING mobile device');
|
|
41
|
+
return {
|
|
42
|
+
isMobile: () => true,
|
|
43
|
+
};
|
|
44
|
+
});
|
|
45
|
+
|
|
39
46
|
describe('CameraManager', () => {
|
|
40
47
|
let manager: CameraManager;
|
|
41
48
|
|
|
@@ -82,21 +89,6 @@ describe('CameraManager', () => {
|
|
|
82
89
|
|
|
83
90
|
expect(manager['call'].publishVideoStream).toHaveBeenCalledWith(
|
|
84
91
|
manager.state.mediaStream,
|
|
85
|
-
undefined,
|
|
86
|
-
);
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
it('publish stream with preferred codec', async () => {
|
|
90
|
-
manager['call'].state.setCallingState(CallingState.JOINED);
|
|
91
|
-
manager.setPreferredCodec('h264');
|
|
92
|
-
|
|
93
|
-
await manager.enable();
|
|
94
|
-
|
|
95
|
-
expect(manager['call'].publishVideoStream).toHaveBeenCalledWith(
|
|
96
|
-
manager.state.mediaStream,
|
|
97
|
-
{
|
|
98
|
-
preferredCodec: 'h264',
|
|
99
|
-
},
|
|
100
92
|
);
|
|
101
93
|
});
|
|
102
94
|
|
|
@@ -115,20 +115,6 @@ describe('ScreenShareManager', () => {
|
|
|
115
115
|
await manager.enable();
|
|
116
116
|
expect(call.publishScreenShareStream).toHaveBeenCalledWith(
|
|
117
117
|
manager.state.mediaStream,
|
|
118
|
-
{ screenShareSettings: undefined },
|
|
119
|
-
);
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
it('publishes screen share stream with settings', async () => {
|
|
123
|
-
const call = manager['call'];
|
|
124
|
-
call.state.setCallingState(CallingState.JOINED);
|
|
125
|
-
|
|
126
|
-
manager.setSettings({ maxFramerate: 15, maxBitrate: 1000 });
|
|
127
|
-
|
|
128
|
-
await manager.enable();
|
|
129
|
-
expect(call.publishScreenShareStream).toHaveBeenCalledWith(
|
|
130
|
-
manager.state.mediaStream,
|
|
131
|
-
{ screenShareSettings: { maxFramerate: 15, maxBitrate: 1000 } },
|
|
132
118
|
);
|
|
133
119
|
});
|
|
134
120
|
|
|
@@ -7,7 +7,6 @@ import {
|
|
|
7
7
|
watchCallEnded,
|
|
8
8
|
watchCallGrantsUpdated,
|
|
9
9
|
watchCallRejected,
|
|
10
|
-
watchChangePublishQuality,
|
|
11
10
|
watchConnectionQualityChanged,
|
|
12
11
|
watchDominantSpeakerChanged,
|
|
13
12
|
watchLiveEnded,
|
|
@@ -46,7 +45,6 @@ export const registerEventHandlers = (call: Call, dispatcher: Dispatcher) => {
|
|
|
46
45
|
|
|
47
46
|
watchLiveEnded(dispatcher, call),
|
|
48
47
|
watchSfuErrorReports(dispatcher),
|
|
49
|
-
watchChangePublishQuality(dispatcher, call),
|
|
50
48
|
watchConnectionQualityChanged(dispatcher, state),
|
|
51
49
|
watchParticipantCountChanged(dispatcher, state),
|
|
52
50
|
|
package/src/events/internal.ts
CHANGED
|
@@ -10,22 +10,6 @@ import {
|
|
|
10
10
|
} from '../gen/video/sfu/models/models';
|
|
11
11
|
import { OwnCapability } from '../gen/coordinator';
|
|
12
12
|
|
|
13
|
-
/**
|
|
14
|
-
* An event responder which handles the `changePublishQuality` event.
|
|
15
|
-
*/
|
|
16
|
-
export const watchChangePublishQuality = (
|
|
17
|
-
dispatcher: Dispatcher,
|
|
18
|
-
call: Call,
|
|
19
|
-
) => {
|
|
20
|
-
return dispatcher.on('changePublishQuality', (e) => {
|
|
21
|
-
const { videoSenders } = e;
|
|
22
|
-
videoSenders.forEach((videoSender) => {
|
|
23
|
-
const { layers } = videoSender;
|
|
24
|
-
call.updatePublishQuality(layers.filter((l) => l.active));
|
|
25
|
-
});
|
|
26
|
-
});
|
|
27
|
-
};
|
|
28
|
-
|
|
29
13
|
export const watchConnectionQualityChanged = (
|
|
30
14
|
dispatcher: Dispatcher,
|
|
31
15
|
state: CallState,
|
|
@@ -682,45 +682,15 @@ export interface AudioLevelChanged {
|
|
|
682
682
|
*/
|
|
683
683
|
audioLevels: AudioLevel[];
|
|
684
684
|
}
|
|
685
|
-
/**
|
|
686
|
-
* @generated from protobuf message stream.video.sfu.event.AudioMediaRequest
|
|
687
|
-
*/
|
|
688
|
-
export interface AudioMediaRequest {
|
|
689
|
-
/**
|
|
690
|
-
* @generated from protobuf field: int32 channel_count = 1;
|
|
691
|
-
*/
|
|
692
|
-
channelCount: number;
|
|
693
|
-
}
|
|
694
685
|
/**
|
|
695
686
|
* @generated from protobuf message stream.video.sfu.event.AudioSender
|
|
696
687
|
*/
|
|
697
688
|
export interface AudioSender {
|
|
698
|
-
/**
|
|
699
|
-
* @generated from protobuf field: stream.video.sfu.event.AudioMediaRequest media_request = 1;
|
|
700
|
-
*/
|
|
701
|
-
mediaRequest?: AudioMediaRequest;
|
|
702
689
|
/**
|
|
703
690
|
* @generated from protobuf field: stream.video.sfu.models.Codec codec = 2;
|
|
704
691
|
*/
|
|
705
692
|
codec?: Codec;
|
|
706
693
|
}
|
|
707
|
-
/**
|
|
708
|
-
* @generated from protobuf message stream.video.sfu.event.VideoMediaRequest
|
|
709
|
-
*/
|
|
710
|
-
export interface VideoMediaRequest {
|
|
711
|
-
/**
|
|
712
|
-
* @generated from protobuf field: int32 ideal_height = 1;
|
|
713
|
-
*/
|
|
714
|
-
idealHeight: number;
|
|
715
|
-
/**
|
|
716
|
-
* @generated from protobuf field: int32 ideal_width = 2;
|
|
717
|
-
*/
|
|
718
|
-
idealWidth: number;
|
|
719
|
-
/**
|
|
720
|
-
* @generated from protobuf field: int32 ideal_frame_rate = 3;
|
|
721
|
-
*/
|
|
722
|
-
idealFrameRate: number;
|
|
723
|
-
}
|
|
724
694
|
/**
|
|
725
695
|
* VideoLayerSetting is used to specify various parameters of a particular encoding in simulcast.
|
|
726
696
|
* The parameters are specified here - https://developer.mozilla.org/en-US/docs/Web/API/RTCRtpEncodingParameters
|
|
@@ -745,10 +715,6 @@ export interface VideoLayerSetting {
|
|
|
745
715
|
* @generated from protobuf field: float scale_resolution_down_by = 4;
|
|
746
716
|
*/
|
|
747
717
|
scaleResolutionDownBy: number;
|
|
748
|
-
/**
|
|
749
|
-
* @generated from protobuf field: stream.video.sfu.event.VideoLayerSetting.Priority priority = 5;
|
|
750
|
-
*/
|
|
751
|
-
priority: VideoLayerSetting_Priority;
|
|
752
718
|
/**
|
|
753
719
|
* @generated from protobuf field: stream.video.sfu.models.Codec codec = 6;
|
|
754
720
|
*/
|
|
@@ -757,36 +723,15 @@ export interface VideoLayerSetting {
|
|
|
757
723
|
* @generated from protobuf field: uint32 max_framerate = 7;
|
|
758
724
|
*/
|
|
759
725
|
maxFramerate: number;
|
|
760
|
-
}
|
|
761
|
-
/**
|
|
762
|
-
* @generated from protobuf enum stream.video.sfu.event.VideoLayerSetting.Priority
|
|
763
|
-
*/
|
|
764
|
-
export enum VideoLayerSetting_Priority {
|
|
765
|
-
/**
|
|
766
|
-
* @generated from protobuf enum value: PRIORITY_HIGH_UNSPECIFIED = 0;
|
|
767
|
-
*/
|
|
768
|
-
HIGH_UNSPECIFIED = 0,
|
|
769
|
-
/**
|
|
770
|
-
* @generated from protobuf enum value: PRIORITY_LOW = 1;
|
|
771
|
-
*/
|
|
772
|
-
LOW = 1,
|
|
773
|
-
/**
|
|
774
|
-
* @generated from protobuf enum value: PRIORITY_MEDIUM = 2;
|
|
775
|
-
*/
|
|
776
|
-
MEDIUM = 2,
|
|
777
726
|
/**
|
|
778
|
-
* @generated from protobuf
|
|
727
|
+
* @generated from protobuf field: string scalability_mode = 8;
|
|
779
728
|
*/
|
|
780
|
-
|
|
729
|
+
scalabilityMode: string;
|
|
781
730
|
}
|
|
782
731
|
/**
|
|
783
732
|
* @generated from protobuf message stream.video.sfu.event.VideoSender
|
|
784
733
|
*/
|
|
785
734
|
export interface VideoSender {
|
|
786
|
-
/**
|
|
787
|
-
* @generated from protobuf field: stream.video.sfu.event.VideoMediaRequest media_request = 1;
|
|
788
|
-
*/
|
|
789
|
-
mediaRequest?: VideoMediaRequest;
|
|
790
735
|
/**
|
|
791
736
|
* @generated from protobuf field: stream.video.sfu.models.Codec codec = 2;
|
|
792
737
|
*/
|
|
@@ -1537,32 +1482,9 @@ class AudioLevelChanged$Type extends MessageType<AudioLevelChanged> {
|
|
|
1537
1482
|
*/
|
|
1538
1483
|
export const AudioLevelChanged = new AudioLevelChanged$Type();
|
|
1539
1484
|
// @generated message type with reflection information, may provide speed optimized methods
|
|
1540
|
-
class AudioMediaRequest$Type extends MessageType<AudioMediaRequest> {
|
|
1541
|
-
constructor() {
|
|
1542
|
-
super('stream.video.sfu.event.AudioMediaRequest', [
|
|
1543
|
-
{
|
|
1544
|
-
no: 1,
|
|
1545
|
-
name: 'channel_count',
|
|
1546
|
-
kind: 'scalar',
|
|
1547
|
-
T: 5 /*ScalarType.INT32*/,
|
|
1548
|
-
},
|
|
1549
|
-
]);
|
|
1550
|
-
}
|
|
1551
|
-
}
|
|
1552
|
-
/**
|
|
1553
|
-
* @generated MessageType for protobuf message stream.video.sfu.event.AudioMediaRequest
|
|
1554
|
-
*/
|
|
1555
|
-
export const AudioMediaRequest = new AudioMediaRequest$Type();
|
|
1556
|
-
// @generated message type with reflection information, may provide speed optimized methods
|
|
1557
1485
|
class AudioSender$Type extends MessageType<AudioSender> {
|
|
1558
1486
|
constructor() {
|
|
1559
1487
|
super('stream.video.sfu.event.AudioSender', [
|
|
1560
|
-
{
|
|
1561
|
-
no: 1,
|
|
1562
|
-
name: 'media_request',
|
|
1563
|
-
kind: 'message',
|
|
1564
|
-
T: () => AudioMediaRequest,
|
|
1565
|
-
},
|
|
1566
1488
|
{ no: 2, name: 'codec', kind: 'message', T: () => Codec },
|
|
1567
1489
|
]);
|
|
1568
1490
|
}
|
|
@@ -1572,30 +1494,6 @@ class AudioSender$Type extends MessageType<AudioSender> {
|
|
|
1572
1494
|
*/
|
|
1573
1495
|
export const AudioSender = new AudioSender$Type();
|
|
1574
1496
|
// @generated message type with reflection information, may provide speed optimized methods
|
|
1575
|
-
class VideoMediaRequest$Type extends MessageType<VideoMediaRequest> {
|
|
1576
|
-
constructor() {
|
|
1577
|
-
super('stream.video.sfu.event.VideoMediaRequest', [
|
|
1578
|
-
{
|
|
1579
|
-
no: 1,
|
|
1580
|
-
name: 'ideal_height',
|
|
1581
|
-
kind: 'scalar',
|
|
1582
|
-
T: 5 /*ScalarType.INT32*/,
|
|
1583
|
-
},
|
|
1584
|
-
{ no: 2, name: 'ideal_width', kind: 'scalar', T: 5 /*ScalarType.INT32*/ },
|
|
1585
|
-
{
|
|
1586
|
-
no: 3,
|
|
1587
|
-
name: 'ideal_frame_rate',
|
|
1588
|
-
kind: 'scalar',
|
|
1589
|
-
T: 5 /*ScalarType.INT32*/,
|
|
1590
|
-
},
|
|
1591
|
-
]);
|
|
1592
|
-
}
|
|
1593
|
-
}
|
|
1594
|
-
/**
|
|
1595
|
-
* @generated MessageType for protobuf message stream.video.sfu.event.VideoMediaRequest
|
|
1596
|
-
*/
|
|
1597
|
-
export const VideoMediaRequest = new VideoMediaRequest$Type();
|
|
1598
|
-
// @generated message type with reflection information, may provide speed optimized methods
|
|
1599
1497
|
class VideoLayerSetting$Type extends MessageType<VideoLayerSetting> {
|
|
1600
1498
|
constructor() {
|
|
1601
1499
|
super('stream.video.sfu.event.VideoLayerSetting', [
|
|
@@ -1608,16 +1506,6 @@ class VideoLayerSetting$Type extends MessageType<VideoLayerSetting> {
|
|
|
1608
1506
|
kind: 'scalar',
|
|
1609
1507
|
T: 2 /*ScalarType.FLOAT*/,
|
|
1610
1508
|
},
|
|
1611
|
-
{
|
|
1612
|
-
no: 5,
|
|
1613
|
-
name: 'priority',
|
|
1614
|
-
kind: 'enum',
|
|
1615
|
-
T: () => [
|
|
1616
|
-
'stream.video.sfu.event.VideoLayerSetting.Priority',
|
|
1617
|
-
VideoLayerSetting_Priority,
|
|
1618
|
-
'PRIORITY_',
|
|
1619
|
-
],
|
|
1620
|
-
},
|
|
1621
1509
|
{ no: 6, name: 'codec', kind: 'message', T: () => Codec },
|
|
1622
1510
|
{
|
|
1623
1511
|
no: 7,
|
|
@@ -1625,6 +1513,12 @@ class VideoLayerSetting$Type extends MessageType<VideoLayerSetting> {
|
|
|
1625
1513
|
kind: 'scalar',
|
|
1626
1514
|
T: 13 /*ScalarType.UINT32*/,
|
|
1627
1515
|
},
|
|
1516
|
+
{
|
|
1517
|
+
no: 8,
|
|
1518
|
+
name: 'scalability_mode',
|
|
1519
|
+
kind: 'scalar',
|
|
1520
|
+
T: 9 /*ScalarType.STRING*/,
|
|
1521
|
+
},
|
|
1628
1522
|
]);
|
|
1629
1523
|
}
|
|
1630
1524
|
}
|
|
@@ -1636,12 +1530,6 @@ export const VideoLayerSetting = new VideoLayerSetting$Type();
|
|
|
1636
1530
|
class VideoSender$Type extends MessageType<VideoSender> {
|
|
1637
1531
|
constructor() {
|
|
1638
1532
|
super('stream.video.sfu.event.VideoSender', [
|
|
1639
|
-
{
|
|
1640
|
-
no: 1,
|
|
1641
|
-
name: 'media_request',
|
|
1642
|
-
kind: 'message',
|
|
1643
|
-
T: () => VideoMediaRequest,
|
|
1644
|
-
},
|
|
1645
1533
|
{ no: 2, name: 'codec', kind: 'message', T: () => Codec },
|
|
1646
1534
|
{
|
|
1647
1535
|
no: 3,
|
|
@@ -118,21 +118,15 @@ const getOpusFmtp = (sdp: string): Fmtp | undefined => {
|
|
|
118
118
|
*/
|
|
119
119
|
export const toggleDtx = (sdp: string, enable: boolean): string => {
|
|
120
120
|
const opusFmtp = getOpusFmtp(sdp);
|
|
121
|
-
if (opusFmtp)
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
} else {
|
|
131
|
-
const newFmtp = `${opusFmtp.original};${requiredDtxConfig}`;
|
|
132
|
-
return sdp.replace(opusFmtp.original, newFmtp);
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
return sdp;
|
|
121
|
+
if (!opusFmtp) return sdp;
|
|
122
|
+
|
|
123
|
+
const matchDtx = /usedtx=(\d)/.exec(opusFmtp.config);
|
|
124
|
+
const requiredDtxConfig = `usedtx=${enable ? '1' : '0'}`;
|
|
125
|
+
const newFmtp = matchDtx
|
|
126
|
+
? opusFmtp.original.replace(/usedtx=(\d)/, requiredDtxConfig)
|
|
127
|
+
: `${opusFmtp.original};${requiredDtxConfig}`;
|
|
128
|
+
|
|
129
|
+
return sdp.replace(opusFmtp.original, newFmtp);
|
|
136
130
|
};
|
|
137
131
|
|
|
138
132
|
/**
|
|
@@ -181,3 +175,32 @@ export const enableHighQualityAudio = (
|
|
|
181
175
|
|
|
182
176
|
return SDP.write(parsedSdp);
|
|
183
177
|
};
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Extracts the mid from the transceiver or the SDP.
|
|
181
|
+
*
|
|
182
|
+
* @param transceiver the transceiver.
|
|
183
|
+
* @param transceiverInitIndex the index of the transceiver in the transceiver's init array.
|
|
184
|
+
* @param sdp the SDP.
|
|
185
|
+
*/
|
|
186
|
+
export const extractMid = (
|
|
187
|
+
transceiver: RTCRtpTransceiver,
|
|
188
|
+
transceiverInitIndex: number,
|
|
189
|
+
sdp: string | undefined,
|
|
190
|
+
): string => {
|
|
191
|
+
if (transceiver.mid) return transceiver.mid;
|
|
192
|
+
if (!sdp) return '';
|
|
193
|
+
|
|
194
|
+
const track = transceiver.sender.track!;
|
|
195
|
+
const parsedSdp = SDP.parse(sdp);
|
|
196
|
+
const media = parsedSdp.media.find((m) => {
|
|
197
|
+
return (
|
|
198
|
+
m.type === track.kind &&
|
|
199
|
+
// if `msid` is not present, we assume that the track is the first one
|
|
200
|
+
(m.msid?.includes(track.id) ?? true)
|
|
201
|
+
);
|
|
202
|
+
});
|
|
203
|
+
if (typeof media?.mid !== 'undefined') return String(media.mid);
|
|
204
|
+
if (transceiverInitIndex === -1) return '';
|
|
205
|
+
return String(transceiverInitIndex);
|
|
206
|
+
};
|