/
SimulcastTransceiverController.ts
137 lines (121 loc) · 4.92 KB
/
SimulcastTransceiverController.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import AudioVideoControllerState from '../audiovideocontroller/AudioVideoControllerState';
import BrowserBehavior from '../browserbehavior/BrowserBehavior';
import Logger from '../logger/Logger';
import DefaultTransceiverController from './DefaultTransceiverController';
export default class SimulcastTransceiverController extends DefaultTransceiverController {
static readonly LOW_LEVEL_NAME: string = 'low';
static readonly MID_LEVEL_NAME: string = 'mid';
static readonly HIGH_LEVEL_NAME: string = 'hi';
static readonly NAME_ARR_ASCENDING = ['low', 'mid', 'hi'];
static readonly BITRATE_ARR_ASCENDING = [200, 400, 1100];
protected videoQualityControlParameterMap: Map<string, RTCRtpEncodingParameters> = new Map<
string,
RTCRtpEncodingParameters
>();
constructor(
logger: Logger,
browserBehavior: BrowserBehavior,
meetingSessionContext?: AudioVideoControllerState
) {
super(logger, browserBehavior, meetingSessionContext);
let scale = 4;
for (let i = 0; i < SimulcastTransceiverController.NAME_ARR_ASCENDING.length; i++) {
const ridName = SimulcastTransceiverController.NAME_ARR_ASCENDING[i];
this.videoQualityControlParameterMap.set(ridName, {
rid: ridName,
scaleResolutionDownBy: scale,
maxBitrate: SimulcastTransceiverController.BITRATE_ARR_ASCENDING[i] * 1000,
});
scale = scale / 2;
}
}
// Note: `scaleResolutionDownBy` has only been tested with values 1, 2, and 4.
async setEncodingParameters(
encodingParamMap: Map<string, RTCRtpEncodingParameters>
): Promise<void> {
if (!this._localCameraTransceiver || this._localCameraTransceiver.direction !== 'sendrecv') {
return;
}
const sender = this._localCameraTransceiver.sender;
const newEncodingParams = Array.from(encodingParamMap.values());
if (newEncodingParams.length <= 0) {
return;
}
const oldParam: RTCRtpSendParameters = sender.getParameters();
if (!oldParam.encodings) {
oldParam.encodings = newEncodingParams;
} else {
for (const encoding of oldParam.encodings) {
if (encoding.rid === SimulcastTransceiverController.LOW_LEVEL_NAME) {
this.copyEncodingParams(
encodingParamMap.get(SimulcastTransceiverController.LOW_LEVEL_NAME),
encoding
);
}
if (encoding.rid === SimulcastTransceiverController.MID_LEVEL_NAME) {
this.copyEncodingParams(
encodingParamMap.get(SimulcastTransceiverController.MID_LEVEL_NAME),
encoding
);
}
if (encoding.rid === SimulcastTransceiverController.HIGH_LEVEL_NAME) {
this.copyEncodingParams(
encodingParamMap.get(SimulcastTransceiverController.HIGH_LEVEL_NAME),
encoding
);
}
}
}
await sender.setParameters(oldParam);
this.logVideoTransceiverParameters();
}
async setVideoSendingBitrateKbps(_bitrateKbps: number): Promise<void> {
return;
}
setupLocalTransceivers(): void {
if (!this.useTransceivers()) {
return;
}
if (!this.defaultMediaStream && typeof MediaStream !== 'undefined') {
this.defaultMediaStream = new MediaStream();
}
if (!this._localAudioTransceiver) {
this._localAudioTransceiver = this.peer.addTransceiver('audio', {
direction: 'inactive',
streams: [this.defaultMediaStream],
});
if (this.meetingSessionContext?.audioProfile?.hasRedundancyEnabled()) {
// This will perform additional necessary setup for the audio transceiver.
this.setupAudioRedWorker();
}
}
if (!this._localCameraTransceiver) {
const encodingParams = Array.from(this.videoQualityControlParameterMap.values());
this._localCameraTransceiver = this.addTransceiver('video', {
direction: 'inactive',
streams: [this.defaultMediaStream],
sendEncodings: encodingParams,
});
}
}
protected logVideoTransceiverParameters(): void {
const params = this._localCameraTransceiver.sender.getParameters();
const encodings = params.encodings;
let msg = 'simulcast: current encoding parameters \n';
for (const encodingParam of encodings) {
msg += `rid=${encodingParam.rid} maxBitrate=${encodingParam.maxBitrate} active=${encodingParam.active} scaleDownBy=${encodingParam.scaleResolutionDownBy} maxFrameRate = ${encodingParam.maxFramerate} \n`;
}
this.logger.info(msg);
}
protected copyEncodingParams(
fromEncodingParams: RTCRtpEncodingParameters,
toEncodingParams: RTCRtpEncodingParameters
): void {
toEncodingParams.active = fromEncodingParams.active;
toEncodingParams.maxBitrate = fromEncodingParams.maxBitrate;
toEncodingParams.scaleResolutionDownBy = fromEncodingParams.scaleResolutionDownBy;
toEncodingParams.maxFramerate = fromEncodingParams.maxFramerate;
}
}