@webex/plugin-meetings 2.31.4 → 2.33.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.
@@ -671,7 +671,7 @@ describe('plugin-meetings', () => {
671
671
  const audioVideoSettings = {};
672
672
 
673
673
  sinon.stub(meeting.mediaProperties, 'videoDeviceId').value(videoDevice);
674
-
674
+ sinon.stub(meeting.mediaProperties, 'localQualityLevel').value('480p');
675
675
  await meeting.getMediaStreams(mediaDirection, audioVideoSettings);
676
676
 
677
677
  assert.calledWith(Media.getUserMedia, {
@@ -680,6 +680,8 @@ describe('plugin-meetings', () => {
680
680
  },
681
681
  {
682
682
  video: {
683
+ width: {max: 640, ideal: 640},
684
+ height: {max: 480, ideal: 480},
683
685
  deviceId: videoDevice
684
686
  }
685
687
  });
@@ -701,6 +703,30 @@ describe('plugin-meetings', () => {
701
703
  assert.calledWith(meeting.mediaProperties.setVideoDeviceId, newVideoDevice);
702
704
  });
703
705
 
706
+ it('uses the passed custom video resolution', async () => {
707
+ const mediaDirection = {sendAudio: true, sendVideo: true, sendShare: false};
708
+ const customAudioVideoSettings = {
709
+ video: {
710
+ width: {
711
+ max: 400,
712
+ ideal: 400
713
+ },
714
+ height: {
715
+ max: 200,
716
+ ideal: 200
717
+ }
718
+ }
719
+ };
720
+
721
+ sinon.stub(meeting.mediaProperties, 'localQualityLevel').value('200p');
722
+ await meeting.getMediaStreams(mediaDirection, customAudioVideoSettings);
723
+
724
+ assert.calledWith(Media.getUserMedia, {
725
+ ...mediaDirection,
726
+ isSharing: false
727
+ },
728
+ customAudioVideoSettings);
729
+ });
704
730
  it('should not access camera if sendVideo is false ', async () => {
705
731
  await meeting.getMediaStreams({sendAudio: true, sendVideo: false});
706
732
 
@@ -2155,11 +2181,19 @@ describe('plugin-meetings', () => {
2155
2181
  describe('#setLocalVideoQuality', () => {
2156
2182
  let mediaDirection;
2157
2183
 
2184
+ const fakeTrack = {getSettings: () => ({height: 720})};
2185
+ const USER_AGENT_CHROME_MAC =
2186
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) ' +
2187
+ 'AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.85 Safari/537.36';
2188
+
2158
2189
  beforeEach(() => {
2159
2190
  mediaDirection = {sendAudio: true, sendVideo: true, sendShare: false};
2160
2191
  meeting.getMediaStreams = sinon.stub().returns(Promise.resolve([]));
2161
- meeting.updateVideo = sinon.stub().returns(Promise.resolve());
2162
2192
  meeting.mediaProperties.mediaDirection = mediaDirection;
2193
+ meeting.canUpdateMedia = sinon.stub().returns(true);
2194
+ MeetingUtil.validateOptions = sinon.stub().returns(Promise.resolve());
2195
+ MeetingUtil.updateTransceiver = sinon.stub().returns(Promise.resolve());
2196
+ sinon.stub(MeetingUtil, 'getTrack').returns({videoTrack: fakeTrack});
2163
2197
  });
2164
2198
 
2165
2199
  it('should have #setLocalVideoQuality', () => {
@@ -2167,15 +2201,35 @@ describe('plugin-meetings', () => {
2167
2201
  });
2168
2202
 
2169
2203
  it('should call getMediaStreams with the proper level', () => meeting.setLocalVideoQuality(CONSTANTS.QUALITY_LEVELS.LOW).then(() => {
2204
+ delete mediaDirection.receiveVideo;
2170
2205
  assert.calledWith(meeting.getMediaStreams,
2171
2206
  mediaDirection,
2172
2207
  CONSTANTS.VIDEO_RESOLUTIONS[CONSTANTS.QUALITY_LEVELS.LOW]);
2173
2208
  }));
2174
2209
 
2210
+ it('when browser is chrome then it should stop previous video track', () => {
2211
+ meeting.mediaProperties.videoTrack = fakeTrack;
2212
+ assert.equal(
2213
+ BrowserDetection(USER_AGENT_CHROME_MAC).getBrowserName(),
2214
+ 'Chrome'
2215
+ );
2216
+ meeting.setLocalVideoQuality(CONSTANTS.QUALITY_LEVELS.LOW)
2217
+ .then(() => {
2218
+ assert.calledWith(Media.stopTracks, fakeTrack);
2219
+ });
2220
+ });
2221
+
2175
2222
  it('should set mediaProperty with the proper level', () => meeting.setLocalVideoQuality(CONSTANTS.QUALITY_LEVELS.LOW).then(() => {
2176
2223
  assert.equal(meeting.mediaProperties.localQualityLevel, CONSTANTS.QUALITY_LEVELS.LOW);
2177
2224
  }));
2178
2225
 
2226
+ it('when device does not support 1080p then it should set localQualityLevel with highest possible resolution', () => {
2227
+ meeting.setLocalVideoQuality(CONSTANTS.QUALITY_LEVELS['1080p'])
2228
+ .then(() => {
2229
+ assert.equal(meeting.mediaProperties.localQualityLevel, CONSTANTS.QUALITY_LEVELS['720p']);
2230
+ });
2231
+ });
2232
+
2179
2233
  it('should error if set to a invalid level', () => {
2180
2234
  assert.isRejected(meeting.setLocalVideoQuality('invalid'));
2181
2235
  });
@@ -2217,54 +2271,6 @@ describe('plugin-meetings', () => {
2217
2271
  });
2218
2272
  });
2219
2273
 
2220
- describe('#setMeetingQuality', () => {
2221
- let mediaDirection;
2222
-
2223
- beforeEach(() => {
2224
- mediaDirection = {
2225
- receiveAudio: true, receiveVideo: true, receiveShare: false, sendVideo: true
2226
- };
2227
- meeting.setRemoteQualityLevel = sinon.stub().returns(Promise.resolve());
2228
- meeting.setLocalVideoQuality = sinon.stub().returns(Promise.resolve());
2229
- meeting.mediaProperties.mediaDirection = mediaDirection;
2230
- });
2231
-
2232
- it('should have #setMeetingQuality', () => {
2233
- assert.exists(meeting.setMeetingQuality);
2234
- });
2235
-
2236
- it('should call setRemoteQualityLevel', () => meeting.setMeetingQuality(CONSTANTS.QUALITY_LEVELS.LOW).then(() => {
2237
- assert.calledOnce(meeting.setRemoteQualityLevel);
2238
- }));
2239
-
2240
- it('should not call setRemoteQualityLevel when receiveVideo and receiveAudio are false', () => {
2241
- mediaDirection.receiveAudio = false;
2242
- mediaDirection.receiveVideo = false;
2243
- meeting.mediaProperties.mediaDirection = mediaDirection;
2244
-
2245
- return meeting.setMeetingQuality(CONSTANTS.QUALITY_LEVELS.LOW).then(() => {
2246
- assert.notCalled(meeting.setRemoteQualityLevel);
2247
- });
2248
- });
2249
-
2250
- it('should call setLocalVideoQuality', () => meeting.setMeetingQuality(CONSTANTS.QUALITY_LEVELS.LOW).then(() => {
2251
- assert.calledOnce(meeting.setLocalVideoQuality);
2252
- }));
2253
-
2254
- it('should not call setLocalVideoQuality when sendVideo is false', () => {
2255
- mediaDirection.sendVideo = false;
2256
- meeting.mediaProperties.mediaDirection = mediaDirection;
2257
-
2258
- return meeting.setMeetingQuality(CONSTANTS.QUALITY_LEVELS.LOW).then(() => {
2259
- assert.notCalled(meeting.setLocalVideoQuality);
2260
- });
2261
- });
2262
-
2263
- it('should error if set to a invalid level', () => {
2264
- assert.isRejected(meeting.setMeetingQuality('invalid'));
2265
- });
2266
- });
2267
-
2268
2274
  describe('#usePhoneAudio', () => {
2269
2275
  beforeEach(() => {
2270
2276
  meeting.meetingRequest.dialIn = sinon.stub().returns(Promise.resolve({body: {locus: 'testData'}}));
@@ -1,19 +1,24 @@
1
-
2
1
  import {assert} from '@webex/test-helper-chai';
3
2
  import PeerConnectionUtils from '@webex/plugin-meetings/src/peer-connection-manager/util';
4
3
 
4
+ import {
5
+ SDP_MULTIPLE_VIDEO_CODECS,
6
+ SDP_MULTIPLE_VIDEO_CODECS_WITH_LOWERED_H264_PROFILE_LEVEL,
7
+ SDP_MULTIPLE_VIDEO_CODECS_WITH_MAX_FS
8
+ } from './utils.test-fixtures';
9
+
5
10
  describe('Peerconnection Manager', () => {
6
11
  describe('Utils', () => {
7
12
  describe('convertCLineToIpv4', () => {
8
13
  it('changes ipv6 to ipv4 default', () => {
9
14
  const localSdp = 'v=0\r\n' +
10
- 'm=video 5004 UDP/TLS/RTP/SAVPF 102 127 97 99\r\n' +
11
- 'c=IN IP6 2607:fb90:d27c:b314:211a:32dd:c47f:ffe\r\n' +
12
- 'a=rtpmap:127 H264/90000\r\n';
15
+ 'm=video 5004 UDP/TLS/RTP/SAVPF 102 127 97 99\r\n' +
16
+ 'c=IN IP6 2607:fb90:d27c:b314:211a:32dd:c47f:ffe\r\n' +
17
+ 'a=rtpmap:127 H264/90000\r\n';
13
18
  const resultSdp = 'v=0\r\n' +
14
- 'm=video 5004 UDP/TLS/RTP/SAVPF 102 127 97 99\r\n' +
15
- 'c=IN IP4 0.0.0.0\r\n' +
16
- 'a=rtpmap:127 H264/90000\r\n';
19
+ 'm=video 5004 UDP/TLS/RTP/SAVPF 102 127 97 99\r\n' +
20
+ 'c=IN IP4 0.0.0.0\r\n' +
21
+ 'a=rtpmap:127 H264/90000\r\n';
17
22
 
18
23
 
19
24
  const temp = PeerConnectionUtils.convertCLineToIpv4(localSdp);
@@ -21,5 +26,23 @@ describe('Peerconnection Manager', () => {
21
26
  assert.equal(temp, resultSdp);
22
27
  });
23
28
  });
29
+
30
+ describe('adjustH264Profile', () => {
31
+ it('appends max-fs and max-mbps to h264 fmtp lines when h264MaxFs value is higher than the value from the profile', () => {
32
+ const modifiedSdp = PeerConnectionUtils.adjustH264Profile(SDP_MULTIPLE_VIDEO_CODECS, 8192);
33
+
34
+ assert.equal(modifiedSdp, SDP_MULTIPLE_VIDEO_CODECS_WITH_MAX_FS);
35
+ });
36
+ it('keeps fmtp lines the same when h264MaxFs value matches the value from the profile', () => {
37
+ const modifiedSdp = PeerConnectionUtils.adjustH264Profile(SDP_MULTIPLE_VIDEO_CODECS, 3600);
38
+
39
+ assert.equal(modifiedSdp, SDP_MULTIPLE_VIDEO_CODECS);
40
+ });
41
+ it('changes the profile level in h264 fmtp lines when h264MaxFs value is lower than the value from the profile', () => {
42
+ const modifiedSdp = PeerConnectionUtils.adjustH264Profile(SDP_MULTIPLE_VIDEO_CODECS, 1620);
43
+
44
+ assert.equal(modifiedSdp, SDP_MULTIPLE_VIDEO_CODECS_WITH_LOWERED_H264_PROFILE_LEVEL);
45
+ });
46
+ });
24
47
  });
25
48
  });
@@ -0,0 +1,389 @@
1
+ // SDPs generated by browsers always have CRLF (\r\n) endings,
2
+ // here we're using tagged template literals to ensures that our SDP fixtures also have CRLF endings
3
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
4
+ const ensureCRLF = (strings: any, ...tags: string[]) => {
5
+ const stringsWithCRLF = strings.raw.map((str: string) => str.replace(/\n/g, '\r\n'));
6
+
7
+ // now construct the output the same way as it's done by default for template literals
8
+ let output = stringsWithCRLF[0];
9
+
10
+ tags.forEach((tag, index) => {
11
+ output += tag + stringsWithCRLF[index + 1];
12
+ });
13
+
14
+ return output;
15
+ };
16
+
17
+ // example SDP that has an audio and 2 video m-lines, video contains multiple codecs
18
+ // it's basically a trimmed down version of an SDP example from Chrome
19
+ export const SDP_MULTIPLE_VIDEO_CODECS = ensureCRLF`v=0
20
+ o=- 3328550572590672467 2 IN IP4 127.0.0.1
21
+ s=-
22
+ t=0 0
23
+ a=group:BUNDLE 0 1 2
24
+ a=extmap-allow-mixed
25
+ a=msid-semantic: WMS 38872d1a-f4c3-4234-b162-bb47bc55ec57
26
+ m=audio 9 UDP/TLS/RTP/SAVPF 111 63 9 0 8 106
27
+ c=IN IP4 0.0.0.0
28
+ a=ice-ufrag:vPie
29
+ a=ice-pwd:QWp1jfvbc4iUBXfLVSxhDFIN
30
+ a=ice-options:trickle
31
+ a=candidate:1 1 udp 2130706431 10.50.173.46 56821 typ host
32
+ a=fingerprint:sha-256 60:00:B9:57:5D:EC:CE:C7:7D:57:EA:EF:AF:37:23:64:63:39:F7:F3:D5:01:C7:18:C7:6E:B9:B4:46:19:40:06
33
+ a=setup:actpass
34
+ a=mid:0
35
+ a=rtcp-mux
36
+ a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
37
+ a=sendrecv
38
+ a=rtpmap:111 opus/48000/2
39
+ a=rtcp-fb:111 transport-cc
40
+ a=fmtp:111 minptime=10;useinbandfec=1
41
+ a=rtpmap:63 red/48000/2
42
+ a=fmtp:63 111/111
43
+ a=rtpmap:9 G722/8000
44
+ a=rtpmap:0 PCMU/8000
45
+ a=rtpmap:8 PCMA/8000
46
+ a=rtpmap:106 CN/32000
47
+ a=rtcp:9 IN IP4 0.0.0.0
48
+ a=msid:38872d1a-f4c3-4234-b162-bb47bc55ec57 0283c960-c78d-4164-a6f3-394342273ad4
49
+ a=ssrc:3693867886 cname:TGydLcYyPoQiRBlB
50
+ a=ssrc:3693867886 msid:38872d1a-f4c3-4234-b162-bb47bc55ec57 0283c960-c78d-4164-a6f3-394342273ad4
51
+ m=video 9 UDP/TLS/RTP/SAVPF 100 101 127 121 114 115 116 117 118
52
+ c=IN IP4 0.0.0.0
53
+ a=ice-ufrag:vPie
54
+ a=ice-pwd:QWp1jfvbc4iUBXfLVSxhDFIN
55
+ a=ice-options:trickle
56
+ a=candidate:1 1 udp 2130706431 10.50.173.46 56821 typ host
57
+ a=fingerprint:sha-256 60:00:B9:57:5D:EC:CE:C7:7D:57:EA:EF:AF:37:23:64:63:39:F7:F3:D5:01:C7:18:C7:6E:B9:B4:46:19:40:06
58
+ a=setup:actpass
59
+ a=mid:1
60
+ a=rtcp-mux
61
+ a=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
62
+ a=sendrecv
63
+ a=rtpmap:100 VP9/90000
64
+ a=rtcp-fb:100 goog-remb
65
+ a=rtcp-fb:100 transport-cc
66
+ a=rtcp-fb:100 ccm fir
67
+ a=rtcp-fb:100 nack
68
+ a=rtcp-fb:100 nack pli
69
+ a=fmtp:100 profile-id=2
70
+ a=rtpmap:101 rtx/90000
71
+ a=fmtp:101 apt=100
72
+ a=rtpmap:127 H264/90000
73
+ a=rtcp-fb:127 goog-remb
74
+ a=rtcp-fb:127 transport-cc
75
+ a=rtcp-fb:127 ccm fir
76
+ a=rtcp-fb:127 nack
77
+ a=rtcp-fb:127 nack pli
78
+ a=fmtp:127 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f
79
+ a=rtpmap:121 rtx/90000
80
+ a=fmtp:121 apt=127
81
+ a=rtpmap:114 H264/90000
82
+ a=rtcp-fb:114 goog-remb
83
+ a=rtcp-fb:114 transport-cc
84
+ a=rtcp-fb:114 ccm fir
85
+ a=rtcp-fb:114 nack
86
+ a=rtcp-fb:114 nack pli
87
+ a=fmtp:114 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=64001f
88
+ a=rtpmap:115 rtx/90000
89
+ a=fmtp:115 apt=114
90
+ a=rtpmap:116 red/90000
91
+ a=rtpmap:117 rtx/90000
92
+ a=fmtp:117 apt=116
93
+ a=rtpmap:118 ulpfec/90000
94
+ a=rtcp-rsize
95
+ a=rtcp:9 IN IP4 0.0.0.0
96
+ a=msid:38872d1a-f4c3-4234-b162-bb47bc55ec57 c0ea0a74-c991-4005-ab6a-3a29f23e67b7
97
+ a=ssrc:597013044 cname:TGydLcYyPoQiRBlB
98
+ a=ssrc:597013044 msid:38872d1a-f4c3-4234-b162-bb47bc55ec57 c0ea0a74-c991-4005-ab6a-3a29f23e67b7
99
+ m=video 9 UDP/TLS/RTP/SAVPF 102 122 127 121 108 109
100
+ c=IN IP4 0.0.0.0
101
+ a=ice-ufrag:vPie
102
+ a=ice-pwd:QWp1jfvbc4iUBXfLVSxhDFIN
103
+ a=ice-options:trickle
104
+ a=candidate:1 1 udp 2130706431 10.50.173.46 56821 typ host
105
+ a=fingerprint:sha-256 60:00:B9:57:5D:EC:CE:C7:7D:57:EA:EF:AF:37:23:64:63:39:F7:F3:D5:01:C7:18:C7:6E:B9:B4:46:19:40:06
106
+ a=setup:actpass
107
+ a=mid:2
108
+ a=rtcp-mux
109
+ a=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
110
+ a=recvonly
111
+ a=rtpmap:102 VP9/90000
112
+ a=rtcp-fb:102 goog-remb
113
+ a=rtcp-fb:102 transport-cc
114
+ a=rtcp-fb:102 ccm fir
115
+ a=rtcp-fb:102 nack
116
+ a=rtcp-fb:102 nack pli
117
+ a=fmtp:102 profile-id=1
118
+ a=rtpmap:122 rtx/90000
119
+ a=fmtp:122 apt=102
120
+ a=rtpmap:127 H264/90000
121
+ a=rtcp-fb:127 goog-remb
122
+ a=rtcp-fb:127 transport-cc
123
+ a=rtcp-fb:127 ccm fir
124
+ a=rtcp-fb:127 nack
125
+ a=rtcp-fb:127 nack pli
126
+ a=fmtp:127 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f
127
+ a=rtpmap:121 rtx/90000
128
+ a=fmtp:121 apt=127
129
+ a=rtpmap:108 H264/90000
130
+ a=rtcp-fb:108 goog-remb
131
+ a=rtcp-fb:108 transport-cc
132
+ a=rtcp-fb:108 ccm fir
133
+ a=rtcp-fb:108 nack
134
+ a=rtcp-fb:108 nack pli
135
+ a=fmtp:108 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f
136
+ a=rtpmap:109 rtx/90000
137
+ a=fmtp:109 apt=108
138
+ a=rtcp-rsize
139
+ a=rtcp:9 IN IP4 0.0.0.0
140
+ `;
141
+
142
+ // same as SDP_MULTIPLE_VIDEO_CODECS but with h264 profile level changed from 3.1 to 3.0
143
+ export const SDP_MULTIPLE_VIDEO_CODECS_WITH_LOWERED_H264_PROFILE_LEVEL = ensureCRLF`v=0
144
+ o=- 3328550572590672467 2 IN IP4 127.0.0.1
145
+ s=-
146
+ t=0 0
147
+ a=group:BUNDLE 0 1 2
148
+ a=extmap-allow-mixed
149
+ a=msid-semantic: WMS 38872d1a-f4c3-4234-b162-bb47bc55ec57
150
+ m=audio 9 UDP/TLS/RTP/SAVPF 111 63 9 0 8 106
151
+ c=IN IP4 0.0.0.0
152
+ a=ice-ufrag:vPie
153
+ a=ice-pwd:QWp1jfvbc4iUBXfLVSxhDFIN
154
+ a=ice-options:trickle
155
+ a=candidate:1 1 udp 2130706431 10.50.173.46 56821 typ host
156
+ a=fingerprint:sha-256 60:00:B9:57:5D:EC:CE:C7:7D:57:EA:EF:AF:37:23:64:63:39:F7:F3:D5:01:C7:18:C7:6E:B9:B4:46:19:40:06
157
+ a=setup:actpass
158
+ a=mid:0
159
+ a=rtcp-mux
160
+ a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
161
+ a=sendrecv
162
+ a=rtpmap:111 opus/48000/2
163
+ a=rtcp-fb:111 transport-cc
164
+ a=fmtp:111 minptime=10;useinbandfec=1
165
+ a=rtpmap:63 red/48000/2
166
+ a=fmtp:63 111/111
167
+ a=rtpmap:9 G722/8000
168
+ a=rtpmap:0 PCMU/8000
169
+ a=rtpmap:8 PCMA/8000
170
+ a=rtpmap:106 CN/32000
171
+ a=rtcp:9 IN IP4 0.0.0.0
172
+ a=msid:38872d1a-f4c3-4234-b162-bb47bc55ec57 0283c960-c78d-4164-a6f3-394342273ad4
173
+ a=ssrc:3693867886 cname:TGydLcYyPoQiRBlB
174
+ a=ssrc:3693867886 msid:38872d1a-f4c3-4234-b162-bb47bc55ec57 0283c960-c78d-4164-a6f3-394342273ad4
175
+ m=video 9 UDP/TLS/RTP/SAVPF 100 101 127 121 114 115 116 117 118
176
+ c=IN IP4 0.0.0.0
177
+ a=ice-ufrag:vPie
178
+ a=ice-pwd:QWp1jfvbc4iUBXfLVSxhDFIN
179
+ a=ice-options:trickle
180
+ a=candidate:1 1 udp 2130706431 10.50.173.46 56821 typ host
181
+ a=fingerprint:sha-256 60:00:B9:57:5D:EC:CE:C7:7D:57:EA:EF:AF:37:23:64:63:39:F7:F3:D5:01:C7:18:C7:6E:B9:B4:46:19:40:06
182
+ a=setup:actpass
183
+ a=mid:1
184
+ a=rtcp-mux
185
+ a=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
186
+ a=sendrecv
187
+ a=rtpmap:100 VP9/90000
188
+ a=rtcp-fb:100 goog-remb
189
+ a=rtcp-fb:100 transport-cc
190
+ a=rtcp-fb:100 ccm fir
191
+ a=rtcp-fb:100 nack
192
+ a=rtcp-fb:100 nack pli
193
+ a=fmtp:100 profile-id=2
194
+ a=rtpmap:101 rtx/90000
195
+ a=fmtp:101 apt=100
196
+ a=rtpmap:127 H264/90000
197
+ a=rtcp-fb:127 goog-remb
198
+ a=rtcp-fb:127 transport-cc
199
+ a=rtcp-fb:127 ccm fir
200
+ a=rtcp-fb:127 nack
201
+ a=rtcp-fb:127 nack pli
202
+ a=fmtp:127 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001e;max-mbps=48600
203
+ a=rtpmap:121 rtx/90000
204
+ a=fmtp:121 apt=127
205
+ a=rtpmap:114 H264/90000
206
+ a=rtcp-fb:114 goog-remb
207
+ a=rtcp-fb:114 transport-cc
208
+ a=rtcp-fb:114 ccm fir
209
+ a=rtcp-fb:114 nack
210
+ a=rtcp-fb:114 nack pli
211
+ a=fmtp:114 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=64001e;max-mbps=48600
212
+ a=rtpmap:115 rtx/90000
213
+ a=fmtp:115 apt=114
214
+ a=rtpmap:116 red/90000
215
+ a=rtpmap:117 rtx/90000
216
+ a=fmtp:117 apt=116
217
+ a=rtpmap:118 ulpfec/90000
218
+ a=rtcp-rsize
219
+ a=rtcp:9 IN IP4 0.0.0.0
220
+ a=msid:38872d1a-f4c3-4234-b162-bb47bc55ec57 c0ea0a74-c991-4005-ab6a-3a29f23e67b7
221
+ a=ssrc:597013044 cname:TGydLcYyPoQiRBlB
222
+ a=ssrc:597013044 msid:38872d1a-f4c3-4234-b162-bb47bc55ec57 c0ea0a74-c991-4005-ab6a-3a29f23e67b7
223
+ m=video 9 UDP/TLS/RTP/SAVPF 102 122 127 121 108 109
224
+ c=IN IP4 0.0.0.0
225
+ a=ice-ufrag:vPie
226
+ a=ice-pwd:QWp1jfvbc4iUBXfLVSxhDFIN
227
+ a=ice-options:trickle
228
+ a=candidate:1 1 udp 2130706431 10.50.173.46 56821 typ host
229
+ a=fingerprint:sha-256 60:00:B9:57:5D:EC:CE:C7:7D:57:EA:EF:AF:37:23:64:63:39:F7:F3:D5:01:C7:18:C7:6E:B9:B4:46:19:40:06
230
+ a=setup:actpass
231
+ a=mid:2
232
+ a=rtcp-mux
233
+ a=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
234
+ a=recvonly
235
+ a=rtpmap:102 VP9/90000
236
+ a=rtcp-fb:102 goog-remb
237
+ a=rtcp-fb:102 transport-cc
238
+ a=rtcp-fb:102 ccm fir
239
+ a=rtcp-fb:102 nack
240
+ a=rtcp-fb:102 nack pli
241
+ a=fmtp:102 profile-id=1
242
+ a=rtpmap:122 rtx/90000
243
+ a=fmtp:122 apt=102
244
+ a=rtpmap:127 H264/90000
245
+ a=rtcp-fb:127 goog-remb
246
+ a=rtcp-fb:127 transport-cc
247
+ a=rtcp-fb:127 ccm fir
248
+ a=rtcp-fb:127 nack
249
+ a=rtcp-fb:127 nack pli
250
+ a=fmtp:127 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001e;max-mbps=48600
251
+ a=rtpmap:121 rtx/90000
252
+ a=fmtp:121 apt=127
253
+ a=rtpmap:108 H264/90000
254
+ a=rtcp-fb:108 goog-remb
255
+ a=rtcp-fb:108 transport-cc
256
+ a=rtcp-fb:108 ccm fir
257
+ a=rtcp-fb:108 nack
258
+ a=rtcp-fb:108 nack pli
259
+ a=fmtp:108 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01e;max-mbps=48600
260
+ a=rtpmap:109 rtx/90000
261
+ a=fmtp:109 apt=108
262
+ a=rtcp-rsize
263
+ a=rtcp:9 IN IP4 0.0.0.0
264
+ `;
265
+
266
+
267
+ // same as SDP_MULTIPLE_VIDEO_CODECS, but has max-fs appended to all H264 fmtp lines
268
+ export const SDP_MULTIPLE_VIDEO_CODECS_WITH_MAX_FS = ensureCRLF`v=0
269
+ o=- 3328550572590672467 2 IN IP4 127.0.0.1
270
+ s=-
271
+ t=0 0
272
+ a=group:BUNDLE 0 1 2
273
+ a=extmap-allow-mixed
274
+ a=msid-semantic: WMS 38872d1a-f4c3-4234-b162-bb47bc55ec57
275
+ m=audio 9 UDP/TLS/RTP/SAVPF 111 63 9 0 8 106
276
+ c=IN IP4 0.0.0.0
277
+ a=ice-ufrag:vPie
278
+ a=ice-pwd:QWp1jfvbc4iUBXfLVSxhDFIN
279
+ a=ice-options:trickle
280
+ a=candidate:1 1 udp 2130706431 10.50.173.46 56821 typ host
281
+ a=fingerprint:sha-256 60:00:B9:57:5D:EC:CE:C7:7D:57:EA:EF:AF:37:23:64:63:39:F7:F3:D5:01:C7:18:C7:6E:B9:B4:46:19:40:06
282
+ a=setup:actpass
283
+ a=mid:0
284
+ a=rtcp-mux
285
+ a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
286
+ a=sendrecv
287
+ a=rtpmap:111 opus/48000/2
288
+ a=rtcp-fb:111 transport-cc
289
+ a=fmtp:111 minptime=10;useinbandfec=1
290
+ a=rtpmap:63 red/48000/2
291
+ a=fmtp:63 111/111
292
+ a=rtpmap:9 G722/8000
293
+ a=rtpmap:0 PCMU/8000
294
+ a=rtpmap:8 PCMA/8000
295
+ a=rtpmap:106 CN/32000
296
+ a=rtcp:9 IN IP4 0.0.0.0
297
+ a=msid:38872d1a-f4c3-4234-b162-bb47bc55ec57 0283c960-c78d-4164-a6f3-394342273ad4
298
+ a=ssrc:3693867886 cname:TGydLcYyPoQiRBlB
299
+ a=ssrc:3693867886 msid:38872d1a-f4c3-4234-b162-bb47bc55ec57 0283c960-c78d-4164-a6f3-394342273ad4
300
+ m=video 9 UDP/TLS/RTP/SAVPF 100 101 127 121 114 115 116 117 118
301
+ c=IN IP4 0.0.0.0
302
+ a=ice-ufrag:vPie
303
+ a=ice-pwd:QWp1jfvbc4iUBXfLVSxhDFIN
304
+ a=ice-options:trickle
305
+ a=candidate:1 1 udp 2130706431 10.50.173.46 56821 typ host
306
+ a=fingerprint:sha-256 60:00:B9:57:5D:EC:CE:C7:7D:57:EA:EF:AF:37:23:64:63:39:F7:F3:D5:01:C7:18:C7:6E:B9:B4:46:19:40:06
307
+ a=setup:actpass
308
+ a=mid:1
309
+ a=rtcp-mux
310
+ a=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
311
+ a=sendrecv
312
+ a=rtpmap:100 VP9/90000
313
+ a=rtcp-fb:100 goog-remb
314
+ a=rtcp-fb:100 transport-cc
315
+ a=rtcp-fb:100 ccm fir
316
+ a=rtcp-fb:100 nack
317
+ a=rtcp-fb:100 nack pli
318
+ a=fmtp:100 profile-id=2
319
+ a=rtpmap:101 rtx/90000
320
+ a=fmtp:101 apt=100
321
+ a=rtpmap:127 H264/90000
322
+ a=rtcp-fb:127 goog-remb
323
+ a=rtcp-fb:127 transport-cc
324
+ a=rtcp-fb:127 ccm fir
325
+ a=rtcp-fb:127 nack
326
+ a=rtcp-fb:127 nack pli
327
+ a=fmtp:127 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f;max-fs=8192;max-mbps=245760
328
+ a=rtpmap:121 rtx/90000
329
+ a=fmtp:121 apt=127
330
+ a=rtpmap:114 H264/90000
331
+ a=rtcp-fb:114 goog-remb
332
+ a=rtcp-fb:114 transport-cc
333
+ a=rtcp-fb:114 ccm fir
334
+ a=rtcp-fb:114 nack
335
+ a=rtcp-fb:114 nack pli
336
+ a=fmtp:114 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=64001f;max-fs=8192;max-mbps=245760
337
+ a=rtpmap:115 rtx/90000
338
+ a=fmtp:115 apt=114
339
+ a=rtpmap:116 red/90000
340
+ a=rtpmap:117 rtx/90000
341
+ a=fmtp:117 apt=116
342
+ a=rtpmap:118 ulpfec/90000
343
+ a=rtcp-rsize
344
+ a=rtcp:9 IN IP4 0.0.0.0
345
+ a=msid:38872d1a-f4c3-4234-b162-bb47bc55ec57 c0ea0a74-c991-4005-ab6a-3a29f23e67b7
346
+ a=ssrc:597013044 cname:TGydLcYyPoQiRBlB
347
+ a=ssrc:597013044 msid:38872d1a-f4c3-4234-b162-bb47bc55ec57 c0ea0a74-c991-4005-ab6a-3a29f23e67b7
348
+ m=video 9 UDP/TLS/RTP/SAVPF 102 122 127 121 108 109
349
+ c=IN IP4 0.0.0.0
350
+ a=ice-ufrag:vPie
351
+ a=ice-pwd:QWp1jfvbc4iUBXfLVSxhDFIN
352
+ a=ice-options:trickle
353
+ a=candidate:1 1 udp 2130706431 10.50.173.46 56821 typ host
354
+ a=fingerprint:sha-256 60:00:B9:57:5D:EC:CE:C7:7D:57:EA:EF:AF:37:23:64:63:39:F7:F3:D5:01:C7:18:C7:6E:B9:B4:46:19:40:06
355
+ a=setup:actpass
356
+ a=mid:2
357
+ a=rtcp-mux
358
+ a=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
359
+ a=recvonly
360
+ a=rtpmap:102 VP9/90000
361
+ a=rtcp-fb:102 goog-remb
362
+ a=rtcp-fb:102 transport-cc
363
+ a=rtcp-fb:102 ccm fir
364
+ a=rtcp-fb:102 nack
365
+ a=rtcp-fb:102 nack pli
366
+ a=fmtp:102 profile-id=1
367
+ a=rtpmap:122 rtx/90000
368
+ a=fmtp:122 apt=102
369
+ a=rtpmap:127 H264/90000
370
+ a=rtcp-fb:127 goog-remb
371
+ a=rtcp-fb:127 transport-cc
372
+ a=rtcp-fb:127 ccm fir
373
+ a=rtcp-fb:127 nack
374
+ a=rtcp-fb:127 nack pli
375
+ a=fmtp:127 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f;max-fs=8192;max-mbps=245760
376
+ a=rtpmap:121 rtx/90000
377
+ a=fmtp:121 apt=127
378
+ a=rtpmap:108 H264/90000
379
+ a=rtcp-fb:108 goog-remb
380
+ a=rtcp-fb:108 transport-cc
381
+ a=rtcp-fb:108 ccm fir
382
+ a=rtcp-fb:108 nack
383
+ a=rtcp-fb:108 nack pli
384
+ a=fmtp:108 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f;max-fs=8192;max-mbps=245760
385
+ a=rtpmap:109 rtx/90000
386
+ a=fmtp:109 apt=108
387
+ a=rtcp-rsize
388
+ a=rtcp:9 IN IP4 0.0.0.0
389
+ `;
@@ -0,0 +1,52 @@
1
+ import {assert} from '@webex/test-helper-chai';
2
+ import Reachability from '@webex/plugin-meetings/src/reachability/';
3
+
4
+ describe('isAnyClusterReachable', () => {
5
+ before(function () {
6
+ this.jsdom = require('jsdom-global')('', {url: 'http://localhost'});
7
+ });
8
+ after(function () {
9
+ this.jsdom();
10
+ });
11
+
12
+ afterEach(() => {
13
+ window.localStorage.clear()
14
+ });
15
+
16
+ const checkIsClusterReachable = (mockStorage: any, expectedValue: boolean) => {
17
+
18
+ if (mockStorage) {
19
+ window.localStorage.setItem('reachability.result', JSON.stringify(mockStorage))
20
+ }
21
+ const reachability = new Reachability({});
22
+
23
+ const result = reachability.isAnyClusterReachable();
24
+
25
+ assert.equal(result, expectedValue);
26
+
27
+ }
28
+
29
+ it('returns true when udp is reachable', () => {
30
+ checkIsClusterReachable({x: {udp: {reachable: 'true'}, tcp: {reachable: 'false'}}}, true)
31
+ });
32
+
33
+ it('returns true when tcp is reachable', () => {
34
+ checkIsClusterReachable({x: {udp: {reachable: 'false'}, tcp: {reachable: 'true'}}}, true)
35
+ });
36
+
37
+ it('returns true when both tcp and udp are reachable', () => {
38
+ checkIsClusterReachable({x: {udp: {reachable: 'true'}, tcp: {reachable: 'true'}}}, true)
39
+ });
40
+
41
+ it('returns false when both tcp and udp are unreachable', () => {
42
+ checkIsClusterReachable({x: {udp: {reachable: 'false'}, tcp: {reachable: 'false'}}}, false)
43
+ });
44
+
45
+ it('returns false when reachability result is empty', () => {
46
+ checkIsClusterReachable({x: {}}, false)
47
+ });
48
+
49
+ it('returns false when reachability.result item is not there', () => {
50
+ checkIsClusterReachable(undefined, false)
51
+ });
52
+ });
@@ -46,6 +46,7 @@ describe('TurnDiscovery', () => {
46
46
  testMeeting.roapSeq = newSeq;
47
47
  }),
48
48
  updateMediaConnections: sinon.stub(),
49
+ webex: {meetings: {reachability: {isAnyClusterReachable: () => false}}}
49
50
  };
50
51
  });
51
52
 
@@ -123,6 +124,7 @@ describe('TurnDiscovery', () => {
123
124
  username: FAKE_TURN_USERNAME,
124
125
  password: FAKE_TURN_PASSWORD
125
126
  });
127
+
126
128
  });
127
129
 
128
130
  it('sends TURN_DISCOVERY_REQUEST with empty mediaId when isReconnecting is true', async () => {
@@ -220,6 +222,18 @@ describe('TurnDiscovery', () => {
220
222
  checkFailureMetricsSent();
221
223
  });
222
224
 
225
+ it('resolves with undefined when cluster is reachable', async () => {
226
+ const prev = testMeeting.webex.meetings.reachability.isAnyClusterReachable;
227
+ testMeeting.webex.meetings.reachability.isAnyClusterReachable = () => true;
228
+ const result = await new TurnDiscovery(mockRoapRequest).doTurnDiscovery(testMeeting);
229
+
230
+ assert.isUndefined(result);
231
+ assert.notCalled(mockRoapRequest.sendRoap);
232
+ assert.notCalled(Metrics.sendBehavioralMetric);
233
+ testMeeting.webex.meetings.reachability.isAnyClusterReachable = prev;
234
+
235
+ });
236
+
223
237
  it('resolves with undefined if we don\'t get a response within 10s', async () => {
224
238
  const td = new TurnDiscovery(mockRoapRequest);
225
239