@webex/plugin-meetings 3.0.0-beta.404 → 3.0.0-beta.406
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/dist/breakouts/breakout.js +1 -1
- package/dist/breakouts/index.js +1 -1
- package/dist/interpretation/index.js +1 -1
- package/dist/interpretation/siLanguage.js +1 -1
- package/dist/meeting/index.js +4 -2
- package/dist/meeting/index.js.map +1 -1
- package/dist/statsAnalyzer/index.js +53 -30
- package/dist/statsAnalyzer/index.js.map +1 -1
- package/dist/webinar/index.js +1 -1
- package/package.json +19 -19
- package/src/meeting/index.ts +4 -2
- package/src/statsAnalyzer/index.ts +63 -27
- package/test/unit/spec/meeting/index.js +28 -0
- package/test/unit/spec/stats-analyzer/index.js +179 -0
|
@@ -264,7 +264,7 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
264
264
|
|
|
265
265
|
// Add stats for individual streams
|
|
266
266
|
Object.keys(this.statsResults).forEach((mediaType) => {
|
|
267
|
-
if (mediaType.
|
|
267
|
+
if (mediaType.startsWith('audio-send')) {
|
|
268
268
|
const audioSenderStream = cloneDeep(emptyAudioTransmitStream);
|
|
269
269
|
|
|
270
270
|
getAudioSenderStreamMqa({
|
|
@@ -276,7 +276,7 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
276
276
|
newMqa.audioTransmit[0].streams.push(audioSenderStream);
|
|
277
277
|
|
|
278
278
|
this.lastMqaDataSent[mediaType].send = cloneDeep(this.statsResults[mediaType].send);
|
|
279
|
-
} else if (mediaType.
|
|
279
|
+
} else if (mediaType.startsWith('audio-share-send')) {
|
|
280
280
|
const audioSenderStream = cloneDeep(emptyAudioTransmitStream);
|
|
281
281
|
|
|
282
282
|
getAudioSenderStreamMqa({
|
|
@@ -288,7 +288,7 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
288
288
|
newMqa.audioTransmit[1].streams.push(audioSenderStream);
|
|
289
289
|
|
|
290
290
|
this.lastMqaDataSent[mediaType].send = cloneDeep(this.statsResults[mediaType].send);
|
|
291
|
-
} else if (mediaType.
|
|
291
|
+
} else if (mediaType.startsWith('audio-recv')) {
|
|
292
292
|
const audioReceiverStream = cloneDeep(emptyAudioReceiveStream);
|
|
293
293
|
|
|
294
294
|
getAudioReceiverStreamMqa({
|
|
@@ -300,7 +300,7 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
300
300
|
newMqa.audioReceive[0].streams.push(audioReceiverStream);
|
|
301
301
|
|
|
302
302
|
this.lastMqaDataSent[mediaType].recv = cloneDeep(this.statsResults[mediaType].recv);
|
|
303
|
-
} else if (mediaType.
|
|
303
|
+
} else if (mediaType.startsWith('audio-share-recv')) {
|
|
304
304
|
const audioReceiverStream = cloneDeep(emptyAudioReceiveStream);
|
|
305
305
|
|
|
306
306
|
getAudioReceiverStreamMqa({
|
|
@@ -312,7 +312,8 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
312
312
|
newMqa.audioReceive[1].streams.push(audioReceiverStream);
|
|
313
313
|
|
|
314
314
|
this.lastMqaDataSent[mediaType].recv = cloneDeep(this.statsResults[mediaType].recv);
|
|
315
|
-
} else if (mediaType.
|
|
315
|
+
} else if (mediaType.startsWith('video-send-layer')) {
|
|
316
|
+
// We only want the stream-specific stats we get with video-send-layer-0, video-send-layer-1, etc.
|
|
316
317
|
const videoSenderStream = cloneDeep(emptyVideoTransmitStream);
|
|
317
318
|
|
|
318
319
|
getVideoSenderStreamMqa({
|
|
@@ -324,7 +325,7 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
324
325
|
newMqa.videoTransmit[0].streams.push(videoSenderStream);
|
|
325
326
|
|
|
326
327
|
this.lastMqaDataSent[mediaType].send = cloneDeep(this.statsResults[mediaType].send);
|
|
327
|
-
} else if (mediaType.
|
|
328
|
+
} else if (mediaType.startsWith('video-share-send')) {
|
|
328
329
|
const videoSenderStream = cloneDeep(emptyVideoTransmitStream);
|
|
329
330
|
|
|
330
331
|
getVideoSenderStreamMqa({
|
|
@@ -336,7 +337,7 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
336
337
|
newMqa.videoTransmit[1].streams.push(videoSenderStream);
|
|
337
338
|
|
|
338
339
|
this.lastMqaDataSent[mediaType].send = cloneDeep(this.statsResults[mediaType].send);
|
|
339
|
-
} else if (mediaType.
|
|
340
|
+
} else if (mediaType.startsWith('video-recv')) {
|
|
340
341
|
const videoReceiverStream = cloneDeep(emptyVideoReceiveStream);
|
|
341
342
|
|
|
342
343
|
getVideoReceiverStreamMqa({
|
|
@@ -348,7 +349,7 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
348
349
|
newMqa.videoReceive[0].streams.push(videoReceiverStream);
|
|
349
350
|
|
|
350
351
|
this.lastMqaDataSent[mediaType].recv = cloneDeep(this.statsResults[mediaType].recv);
|
|
351
|
-
} else if (mediaType.
|
|
352
|
+
} else if (mediaType.startsWith('video-share-recv')) {
|
|
352
353
|
const videoReceiverStream = cloneDeep(emptyVideoReceiveStream);
|
|
353
354
|
|
|
354
355
|
getVideoReceiverStreamMqa({
|
|
@@ -373,9 +374,14 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
373
374
|
name: MEDIA_DEVICES.MICROPHONE,
|
|
374
375
|
});
|
|
375
376
|
}
|
|
376
|
-
|
|
377
|
+
|
|
378
|
+
const existingVideoSender = Object.keys(this.statsResults).find((item) =>
|
|
379
|
+
item.includes('video-send')
|
|
380
|
+
);
|
|
381
|
+
|
|
382
|
+
if (existingVideoSender) {
|
|
377
383
|
newMqa.intervalMetadata.peripherals.push({
|
|
378
|
-
information: this.statsResults[
|
|
384
|
+
information: this.statsResults[existingVideoSender].trackLabel || _UNKNOWN_,
|
|
379
385
|
name: MEDIA_DEVICES.CAMERA,
|
|
380
386
|
});
|
|
381
387
|
}
|
|
@@ -552,9 +558,21 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
552
558
|
}
|
|
553
559
|
});
|
|
554
560
|
|
|
561
|
+
let videoSenderIndex = 0;
|
|
555
562
|
statsItem.report.forEach((result) => {
|
|
556
563
|
if (types.includes(result.type)) {
|
|
557
|
-
|
|
564
|
+
// if the video sender has multiple streams in the report, it is a new stream object.
|
|
565
|
+
if (type === 'video-send' && result.type === 'outbound-rtp') {
|
|
566
|
+
const newType = `video-send-layer-${videoSenderIndex}`;
|
|
567
|
+
this.parseGetStatsResult(result, newType, isSender);
|
|
568
|
+
videoSenderIndex += 1;
|
|
569
|
+
|
|
570
|
+
this.statsResults[newType].direction = statsItem.currentDirection;
|
|
571
|
+
this.statsResults[newType].trackLabel = statsItem.localTrackLabel;
|
|
572
|
+
this.statsResults[newType].csi = statsItem.csi;
|
|
573
|
+
} else {
|
|
574
|
+
this.parseGetStatsResult(result, type, isSender);
|
|
575
|
+
}
|
|
558
576
|
}
|
|
559
577
|
});
|
|
560
578
|
|
|
@@ -664,12 +682,23 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
664
682
|
const getCurrentStatsTotals = (keyPrefix: string, value: string): number =>
|
|
665
683
|
Object.keys(this.statsResults)
|
|
666
684
|
.filter((key) => key.startsWith(keyPrefix))
|
|
667
|
-
.reduce(
|
|
685
|
+
.reduce(
|
|
686
|
+
(prev, cur) =>
|
|
687
|
+
prev +
|
|
688
|
+
(this.statsResults[cur]?.[keyPrefix.includes('send') ? 'send' : 'recv'][value] || 0),
|
|
689
|
+
0
|
|
690
|
+
);
|
|
668
691
|
|
|
669
692
|
const getPreviousStatsTotals = (keyPrefix: string, value: string): number =>
|
|
670
693
|
Object.keys(this.statsResults)
|
|
671
694
|
.filter((key) => key.startsWith(keyPrefix))
|
|
672
|
-
.reduce(
|
|
695
|
+
.reduce(
|
|
696
|
+
(prev, cur) =>
|
|
697
|
+
prev +
|
|
698
|
+
(this.lastStatsResults[cur]?.[keyPrefix.includes('send') ? 'send' : 'recv'][value] ||
|
|
699
|
+
0),
|
|
700
|
+
0
|
|
701
|
+
);
|
|
673
702
|
|
|
674
703
|
// Audio Transmit
|
|
675
704
|
if (this.lastStatsResults['audio-send']) {
|
|
@@ -731,47 +760,54 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
731
760
|
false
|
|
732
761
|
);
|
|
733
762
|
|
|
763
|
+
const currentTotalPacketsSent = getCurrentStatsTotals('video-send', 'totalPacketsSent');
|
|
764
|
+
const previousTotalPacketsSent = getPreviousStatsTotals('video-send', 'totalPacketsSent');
|
|
765
|
+
|
|
766
|
+
const currentFramesEncoded = getCurrentStatsTotals('video-send', 'framesEncoded');
|
|
767
|
+
const previousFramesEncoded = getPreviousStatsTotals('video-send', 'framesEncoded');
|
|
768
|
+
|
|
769
|
+
const currentFramesSent = getCurrentStatsTotals('video-send', 'framesSent');
|
|
770
|
+
const previousFramesSent = getPreviousStatsTotals('video-send', 'framesSent');
|
|
771
|
+
|
|
772
|
+
const doesVideoSendExist = Object.keys(this.lastStatsResults).some((item) =>
|
|
773
|
+
item.includes('video-send')
|
|
774
|
+
);
|
|
775
|
+
|
|
734
776
|
// Video Transmit
|
|
735
|
-
if (
|
|
777
|
+
if (doesVideoSendExist) {
|
|
736
778
|
// compare video stats sent
|
|
737
|
-
const currentStats = this.statsResults['video-send'].send;
|
|
738
|
-
const previousStats = this.lastStatsResults['video-send'].send;
|
|
739
779
|
|
|
740
780
|
if (
|
|
741
781
|
this.meetingMediaStatus.expected.sendVideo &&
|
|
742
|
-
(
|
|
743
|
-
currentStats.totalPacketsSent === 0)
|
|
782
|
+
(currentTotalPacketsSent === previousTotalPacketsSent || currentTotalPacketsSent === 0)
|
|
744
783
|
) {
|
|
745
784
|
LoggerProxy.logger.info(
|
|
746
785
|
`StatsAnalyzer:index#compareLastStatsResult --> No video RTP packets sent`,
|
|
747
|
-
|
|
786
|
+
currentTotalPacketsSent
|
|
748
787
|
);
|
|
749
788
|
} else {
|
|
750
789
|
if (
|
|
751
790
|
this.meetingMediaStatus.expected.sendVideo &&
|
|
752
|
-
(
|
|
753
|
-
currentStats.framesEncoded === 0)
|
|
791
|
+
(currentFramesEncoded === previousFramesEncoded || currentFramesEncoded === 0)
|
|
754
792
|
) {
|
|
755
793
|
LoggerProxy.logger.info(
|
|
756
794
|
`StatsAnalyzer:index#compareLastStatsResult --> No video Frames Encoded`,
|
|
757
|
-
|
|
795
|
+
currentFramesEncoded
|
|
758
796
|
);
|
|
759
797
|
}
|
|
760
798
|
|
|
761
799
|
if (
|
|
762
800
|
this.meetingMediaStatus.expected.sendVideo &&
|
|
763
|
-
(
|
|
764
|
-
this.lastStatsResults['video-send'].send.framesSent ||
|
|
765
|
-
this.statsResults['video-send'].send.framesSent === 0)
|
|
801
|
+
(currentFramesSent === previousFramesSent || currentFramesSent === 0)
|
|
766
802
|
) {
|
|
767
803
|
LoggerProxy.logger.info(
|
|
768
804
|
`StatsAnalyzer:index#compareLastStatsResult --> No video Frames sent`,
|
|
769
|
-
|
|
805
|
+
currentFramesSent
|
|
770
806
|
);
|
|
771
807
|
}
|
|
772
808
|
}
|
|
773
809
|
|
|
774
|
-
this.emitStartStopEvents('video',
|
|
810
|
+
this.emitStartStopEvents('video', previousFramesSent, currentFramesSent, true);
|
|
775
811
|
}
|
|
776
812
|
|
|
777
813
|
// Video Receive
|
|
@@ -8630,6 +8630,34 @@ describe('plugin-meetings', () => {
|
|
|
8630
8630
|
|
|
8631
8631
|
checkParseMeetingInfo(expectedInfoToParse);
|
|
8632
8632
|
});
|
|
8633
|
+
|
|
8634
|
+
it('should parse meeting info, set values, and return null when permissionToken is not present', () => {
|
|
8635
|
+
meeting.config.experimental = {enableMediaNegotiatedEvent: true};
|
|
8636
|
+
meeting.config.experimental.enableUnifiedMeetings = true;
|
|
8637
|
+
const FAKE_STRING_DESTINATION = 'sipUrl';
|
|
8638
|
+
const FAKE_MEETING_INFO = {
|
|
8639
|
+
conversationUrl: uuid1,
|
|
8640
|
+
locusUrl: url1,
|
|
8641
|
+
meetingJoinUrl: url2,
|
|
8642
|
+
meetingNumber: '12345',
|
|
8643
|
+
sipMeetingUri: test1,
|
|
8644
|
+
sipUrl: test1,
|
|
8645
|
+
owner: test2,
|
|
8646
|
+
};
|
|
8647
|
+
|
|
8648
|
+
meeting.parseMeetingInfo(FAKE_MEETING_INFO, FAKE_STRING_DESTINATION);
|
|
8649
|
+
const expectedInfoToParse = {
|
|
8650
|
+
conversationUrl: uuid1,
|
|
8651
|
+
locusUrl: url1,
|
|
8652
|
+
sipUri: test1,
|
|
8653
|
+
meetingNumber: '12345',
|
|
8654
|
+
meetingJoinUrl: url2,
|
|
8655
|
+
owner: test2,
|
|
8656
|
+
};
|
|
8657
|
+
|
|
8658
|
+
checkParseMeetingInfo(expectedInfoToParse);
|
|
8659
|
+
});
|
|
8660
|
+
|
|
8633
8661
|
it('should parse interpretation info correctly', () => {
|
|
8634
8662
|
const parseInterpretationInfo = sinon.spy(MeetingUtil, 'parseInterpretationInfo');
|
|
8635
8663
|
const mockToggleOnData = {
|
|
@@ -1543,6 +1543,185 @@ describe('plugin-meetings', () => {
|
|
|
1543
1543
|
},
|
|
1544
1544
|
]);
|
|
1545
1545
|
});
|
|
1546
|
+
|
|
1547
|
+
it('has three streams for video senders for simulcast', async () => {
|
|
1548
|
+
pc.getTransceiverStats = sinon.stub().resolves({
|
|
1549
|
+
audio: {
|
|
1550
|
+
senders: [fakeStats.audio.senders[0]],
|
|
1551
|
+
receivers: [fakeStats.audio.receivers[0]],
|
|
1552
|
+
},
|
|
1553
|
+
video: {
|
|
1554
|
+
senders: [
|
|
1555
|
+
{
|
|
1556
|
+
localTrackLabel: 'fake-camera',
|
|
1557
|
+
report: [
|
|
1558
|
+
{
|
|
1559
|
+
type: 'outbound-rtp',
|
|
1560
|
+
bytesSent: 1,
|
|
1561
|
+
framesSent: 0,
|
|
1562
|
+
packetsSent: 0,
|
|
1563
|
+
},
|
|
1564
|
+
{
|
|
1565
|
+
type: 'outbound-rtp',
|
|
1566
|
+
bytesSent: 0,
|
|
1567
|
+
framesSent: 0,
|
|
1568
|
+
packetsSent: 0,
|
|
1569
|
+
},
|
|
1570
|
+
{
|
|
1571
|
+
type: 'outbound-rtp',
|
|
1572
|
+
bytesSent: 1000,
|
|
1573
|
+
framesSent: 1,
|
|
1574
|
+
packetsSent: 1,
|
|
1575
|
+
},
|
|
1576
|
+
{
|
|
1577
|
+
type: 'remote-inbound-rtp',
|
|
1578
|
+
packetsLost: 0,
|
|
1579
|
+
},
|
|
1580
|
+
{
|
|
1581
|
+
type: 'candidate-pair',
|
|
1582
|
+
state: 'succeeded',
|
|
1583
|
+
localCandidateId: 'fake-candidate-id',
|
|
1584
|
+
},
|
|
1585
|
+
{
|
|
1586
|
+
type: 'candidate-pair',
|
|
1587
|
+
state: 'failed',
|
|
1588
|
+
localCandidateId: 'bad-candidate-id',
|
|
1589
|
+
},
|
|
1590
|
+
{
|
|
1591
|
+
type: 'local-candidate',
|
|
1592
|
+
id: 'fake-candidate-id',
|
|
1593
|
+
protocol: 'tcp',
|
|
1594
|
+
},
|
|
1595
|
+
],
|
|
1596
|
+
},
|
|
1597
|
+
],
|
|
1598
|
+
receivers: [fakeStats.video.receivers[0]],
|
|
1599
|
+
},
|
|
1600
|
+
screenShareAudio: {
|
|
1601
|
+
senders: [fakeStats.audio.senders[0]],
|
|
1602
|
+
receivers: [fakeStats.audio.receivers[0]],
|
|
1603
|
+
},
|
|
1604
|
+
screenShareVideo: {
|
|
1605
|
+
senders: [fakeStats.video.senders[0]],
|
|
1606
|
+
receivers: [fakeStats.video.receivers[0]],
|
|
1607
|
+
},
|
|
1608
|
+
});
|
|
1609
|
+
|
|
1610
|
+
await startStatsAnalyzer({expected: {receiveVideo: true}});
|
|
1611
|
+
|
|
1612
|
+
await progressTime();
|
|
1613
|
+
|
|
1614
|
+
assert.deepEqual(mqeData.videoTransmit[0].streams, [
|
|
1615
|
+
{
|
|
1616
|
+
common: {
|
|
1617
|
+
codec: 'H264',
|
|
1618
|
+
csi: [],
|
|
1619
|
+
duplicateSsci: 0,
|
|
1620
|
+
requestedBitrate: 0,
|
|
1621
|
+
requestedFrames: 0,
|
|
1622
|
+
rtpPackets: 0,
|
|
1623
|
+
ssci: 0,
|
|
1624
|
+
transmittedBitrate: 0.13333333333333333,
|
|
1625
|
+
transmittedFrameRate: 0
|
|
1626
|
+
},
|
|
1627
|
+
h264CodecProfile: 'BP',
|
|
1628
|
+
isAvatar: false,
|
|
1629
|
+
isHardwareEncoded: false,
|
|
1630
|
+
localConfigurationChanges: 2,
|
|
1631
|
+
maxFrameQp: 0,
|
|
1632
|
+
maxNoiseLevel: 0,
|
|
1633
|
+
minRegionQp: 0,
|
|
1634
|
+
remoteConfigurationChanges: 0,
|
|
1635
|
+
requestedFrameSize: 0,
|
|
1636
|
+
requestedKeyFrames: 0,
|
|
1637
|
+
transmittedFrameSize: 0,
|
|
1638
|
+
transmittedHeight: 0,
|
|
1639
|
+
transmittedKeyFrames: 0,
|
|
1640
|
+
transmittedKeyFramesClient: 0,
|
|
1641
|
+
transmittedKeyFramesConfigurationChange: 0,
|
|
1642
|
+
transmittedKeyFramesFeedback: 0,
|
|
1643
|
+
transmittedKeyFramesLocalDrop: 0,
|
|
1644
|
+
transmittedKeyFramesOtherLayer: 0,
|
|
1645
|
+
transmittedKeyFramesPeriodic: 0,
|
|
1646
|
+
transmittedKeyFramesSceneChange: 0,
|
|
1647
|
+
transmittedKeyFramesStartup: 0,
|
|
1648
|
+
transmittedKeyFramesUnknown: 0,
|
|
1649
|
+
transmittedWidth: 0,
|
|
1650
|
+
},
|
|
1651
|
+
{
|
|
1652
|
+
common: {
|
|
1653
|
+
codec: 'H264',
|
|
1654
|
+
csi: [],
|
|
1655
|
+
duplicateSsci: 0,
|
|
1656
|
+
requestedBitrate: 0,
|
|
1657
|
+
requestedFrames: 0,
|
|
1658
|
+
rtpPackets: 0,
|
|
1659
|
+
ssci: 0,
|
|
1660
|
+
transmittedBitrate: 0,
|
|
1661
|
+
transmittedFrameRate: 0,
|
|
1662
|
+
},
|
|
1663
|
+
h264CodecProfile: 'BP',
|
|
1664
|
+
isAvatar: false,
|
|
1665
|
+
isHardwareEncoded: false,
|
|
1666
|
+
localConfigurationChanges: 2,
|
|
1667
|
+
maxFrameQp: 0,
|
|
1668
|
+
maxNoiseLevel: 0,
|
|
1669
|
+
minRegionQp: 0,
|
|
1670
|
+
remoteConfigurationChanges: 0,
|
|
1671
|
+
requestedFrameSize: 0,
|
|
1672
|
+
requestedKeyFrames: 0,
|
|
1673
|
+
transmittedFrameSize: 0,
|
|
1674
|
+
transmittedHeight: 0,
|
|
1675
|
+
transmittedKeyFrames: 0,
|
|
1676
|
+
transmittedKeyFramesClient: 0,
|
|
1677
|
+
transmittedKeyFramesConfigurationChange: 0,
|
|
1678
|
+
transmittedKeyFramesFeedback: 0,
|
|
1679
|
+
transmittedKeyFramesLocalDrop: 0,
|
|
1680
|
+
transmittedKeyFramesOtherLayer: 0,
|
|
1681
|
+
transmittedKeyFramesPeriodic: 0,
|
|
1682
|
+
transmittedKeyFramesSceneChange: 0,
|
|
1683
|
+
transmittedKeyFramesStartup: 0,
|
|
1684
|
+
transmittedKeyFramesUnknown: 0,
|
|
1685
|
+
transmittedWidth: 0,
|
|
1686
|
+
},
|
|
1687
|
+
{
|
|
1688
|
+
common: {
|
|
1689
|
+
codec: 'H264',
|
|
1690
|
+
csi: [],
|
|
1691
|
+
duplicateSsci: 0,
|
|
1692
|
+
requestedBitrate: 0,
|
|
1693
|
+
requestedFrames: 0,
|
|
1694
|
+
rtpPackets: 1,
|
|
1695
|
+
ssci: 0,
|
|
1696
|
+
transmittedBitrate: 133.33333333333334,
|
|
1697
|
+
transmittedFrameRate: 0,
|
|
1698
|
+
},
|
|
1699
|
+
h264CodecProfile: 'BP',
|
|
1700
|
+
isAvatar: false,
|
|
1701
|
+
isHardwareEncoded: false,
|
|
1702
|
+
localConfigurationChanges: 2,
|
|
1703
|
+
maxFrameQp: 0,
|
|
1704
|
+
maxNoiseLevel: 0,
|
|
1705
|
+
minRegionQp: 0,
|
|
1706
|
+
remoteConfigurationChanges: 0,
|
|
1707
|
+
requestedFrameSize: 0,
|
|
1708
|
+
requestedKeyFrames: 0,
|
|
1709
|
+
transmittedFrameSize: 0,
|
|
1710
|
+
transmittedHeight: 0,
|
|
1711
|
+
transmittedKeyFrames: 0,
|
|
1712
|
+
transmittedKeyFramesClient: 0,
|
|
1713
|
+
transmittedKeyFramesConfigurationChange: 0,
|
|
1714
|
+
transmittedKeyFramesFeedback: 0,
|
|
1715
|
+
transmittedKeyFramesLocalDrop: 0,
|
|
1716
|
+
transmittedKeyFramesOtherLayer: 0,
|
|
1717
|
+
transmittedKeyFramesPeriodic: 0,
|
|
1718
|
+
transmittedKeyFramesSceneChange: 0,
|
|
1719
|
+
transmittedKeyFramesStartup: 0,
|
|
1720
|
+
transmittedKeyFramesUnknown: 0,
|
|
1721
|
+
transmittedWidth: 0,
|
|
1722
|
+
}
|
|
1723
|
+
]);
|
|
1724
|
+
});
|
|
1546
1725
|
});
|
|
1547
1726
|
});
|
|
1548
1727
|
});
|