@vkontakte/calls-sdk 2.8.13-dev.58787f8a.0 → 2.8.13-dev.5a31cf44.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.
@@ -1,5 +1,6 @@
1
1
  import type { IEffect } from '@vkontakte/calls-video-effects';
2
2
  import EventEmitter from '../classes/EventEmitter';
3
+ import ActiveFeature from '../enums/ActiveFeature';
3
4
  import MediaOption from '../enums/MediaOption';
4
5
  import { type DebugLogger } from '../static/Debug';
5
6
  import MediaSettings, { IVideoDimentions } from '../types/MediaSettings';
@@ -77,6 +78,8 @@ export declare class MediaSource extends EventEmitter {
77
78
  */
78
79
  getMediaSettings(): MediaSettings;
79
80
  get mediaSettings(): MediaSettings;
81
+ /** Что сейчас включено у пользователя — для метрики active_features */
82
+ get activeFeatures(): ActiveFeature[];
80
83
  changeDevice(kind: MediaDeviceKind): Promise<void>;
81
84
  /**
82
85
  * Установка кастомного стрима для видео, например внешний шаринг экрана
@@ -2,7 +2,7 @@ import BaseApi from '../abstract/BaseApi';
2
2
  import BaseLogger from '../abstract/BaseLogger';
3
3
  import StatLog from '../enums/StatLog';
4
4
  import TransportTopology from '../enums/TransportTopology';
5
- type ClientStatsPayload = Record<string, string | number | boolean | undefined | null>;
5
+ type ClientStatsPayload = Record<string, string | string[] | number | boolean | undefined | null>;
6
6
  export type LogClientStatsOptions = {
7
7
  immediately?: boolean;
8
8
  occurredAt?: number;
@@ -66,6 +66,7 @@ export default class Conversation extends EventEmitter {
66
66
  private _reservedId;
67
67
  private readonly _onUnload;
68
68
  private readonly _onRestore;
69
+ private readonly _onVisibilityChange;
69
70
  private readonly _audioOutput;
70
71
  private readonly _stats;
71
72
  private _lastStalled;
@@ -452,6 +453,11 @@ export default class Conversation extends EventEmitter {
452
453
  private _onVideoSuspendSuggest;
453
454
  private _onParticipantHold;
454
455
  private _isMe;
456
+ /**
457
+ * Сколько человек сейчас в звонке. Считаем только принявших: приглашенные,
458
+ * у которых еще идет вызов, ресурсы не потребляют.
459
+ */
460
+ private _getParticipantsCount;
455
461
  private _getMuteStatesForRoomId;
456
462
  private _getMuteStatesForCurrentRoom;
457
463
  private _setMuteStatesForRoomId;
@@ -0,0 +1,41 @@
1
+ import ActiveFeature from '../../enums/ActiveFeature';
2
+ import { type DebugLogger } from '../../static/Debug';
3
+ /** Метрики ресурсов клиента за интервал между отправками callStat */
4
+ export type ClientResourceReport = {
5
+ /** Максимум участников за интервал */
6
+ participants_max?: number;
7
+ /** Фичи, включенные в любой момент интервала */
8
+ active_features?: string[];
9
+ /** Максимальная площадь окна за интервал, в мегапикселях */
10
+ app_total_area_mpx_max?: number;
11
+ };
12
+ export type ClientResourceSources = {
13
+ getParticipantsCount: () => number;
14
+ getActiveFeatures: () => ActiveFeature[];
15
+ };
16
+ /**
17
+ * Копит ресурсные метрики между отправками callStat: репортер забирает накопленное
18
+ * через takeReport() и начинает копить заново.
19
+ *
20
+ * Замеряем чаще, чем отправляем, потому что нас интересует не состояние в момент отправки,
21
+ * а что происходило за интервал: пик участников и все фичи, которые успели поработать.
22
+ */
23
+ export declare class ClientResourceStats {
24
+ private readonly _sources;
25
+ private readonly _debug;
26
+ private _timer;
27
+ private _participantsMax;
28
+ private _areaMpxMax;
29
+ private _features;
30
+ constructor(sources: ClientResourceSources, debug?: DebugLogger);
31
+ /** Забрать накопленное за интервал и начать копить заново */
32
+ takeReport(): ClientResourceReport;
33
+ destroy(): void;
34
+ private _sample;
35
+ /**
36
+ * Площадь окна в физических пикселях: CSS-пиксели умножаем на devicePixelRatio,
37
+ * иначе одно и то же окно на экране с ретиной и без давало бы одинаковую цифру.
38
+ * Приложение в вебе — это одна вкладка, суммировать нечего.
39
+ */
40
+ private _measureAreaMpx;
41
+ }
@@ -5,6 +5,7 @@ import HangupReason from '../HangupReason';
5
5
  import StatEventCollector from './StatEventCollector';
6
6
  import { ApiCallStats } from './ApiCallStats';
7
7
  import { CallLifecycleStats } from './CallLifecycleStats';
8
+ import { ClientResourceSources, ClientResourceStats } from './ClientResourceStats';
8
9
  import { CodecStatsAggregator } from './CodecStatsAggregator';
9
10
  import { StatAggregator } from './StatAggregator';
10
11
  import { StatPings } from './StatPings';
@@ -17,9 +18,10 @@ export declare class ConversationStats {
17
18
  readonly pings: StatPings;
18
19
  readonly signalingCommands: StatSignalingCommands;
19
20
  readonly apiCalls: ApiCallStats;
21
+ readonly resources: ClientResourceStats;
20
22
  private readonly _api;
21
23
  private _unloading;
22
- constructor(api: BaseApi, externalLogger: BaseLogger | null, getConversationId: () => string | null, getTopology: () => TransportTopology | undefined);
24
+ constructor(api: BaseApi, externalLogger: BaseLogger | null, getConversationId: () => string | null, getTopology: () => TransportTopology | undefined, resourceSources: ClientResourceSources);
23
25
  /**
24
26
  * Вызывается из pagehide-обработчика: события финиша должны пережить смерть
25
27
  * вкладки. Сводки пингов и команд сбрасываем здесь же — destroy() их только
@@ -28,6 +30,7 @@ export declare class ConversationStats {
28
30
  prepareForUnload(): void;
29
31
  /** Вкладка пережила pagehide: возвращаем запись в очередь. */
30
32
  restoreAfterUnload(): void;
33
+ resetPingBaseline(): void;
31
34
  logHangup(reason: HangupReason): void;
32
35
  flushCallMetrics(): void;
33
36
  destroy(): void;
@@ -0,0 +1,35 @@
1
+ import { StatAggregator } from './StatAggregator';
2
+ /** Причина события client_requested_server_topology */
3
+ export declare const enum ServerTopologyReason {
4
+ NO_CONNECTION_TIMEOUT = "no_connection_timeout",
5
+ CONNECTION_FAILED = "connection_failed",
6
+ SUCCESS_CONNECTION = "success_connection",
7
+ /** Возможна на бэке, в вебе пока не поддержана */
8
+ NO_DATA_TIMEOUT = "no_data_timeout",
9
+ /** Возможна на бэке, в вебе пока не поддержана */
10
+ SUCCESS_AUDIO = "success_audio",
11
+ /** Возможна на бэке, в вебе пока не поддержана */
12
+ CONNECTION_ACCEPTED_FAILED = "connection_accepted_failed"
13
+ }
14
+ export declare const enum NetworkQuality {
15
+ GOOD = "good",
16
+ BAD_1 = "bad_1",
17
+ BAD_2 = "bad_2"
18
+ }
19
+ export type VideoEncoderChange = {
20
+ /** Круговая задержка, мс */
21
+ rtt: number;
22
+ /** Потери, проценты */
23
+ loss: number;
24
+ networkQuality: NetworkQuality;
25
+ /** mimeType исходящего видео, например video/VP8 */
26
+ mimeType: string | undefined;
27
+ source: 'camera' | 'screencast' | 'all';
28
+ };
29
+ /** Отправляет в стату решения клиента по смене топологии и настроек видеоэнкодера */
30
+ export declare class NetworkAdaptationStats {
31
+ private readonly _statAggregator;
32
+ constructor(statAggregator: StatAggregator | null);
33
+ logServerTopologyRequested(reason: ServerTopologyReason, elapsed: number): void;
34
+ logVideoEncoderChanged(change: VideoEncoderChange): void;
35
+ }
@@ -32,6 +32,7 @@ export declare class SdpStats {
32
32
  /** Не смогли применить SDP собеседника */
33
33
  logSetRemoteFailed(sdp: SdpDescription, error: unknown): void;
34
34
  destroy(): void;
35
+ private _intervalSince;
35
36
  private _logFailure;
36
37
  private _log;
37
38
  }
@@ -1,11 +1,13 @@
1
1
  import { ICallStatLog } from '../../types/PerfStatReporter';
2
2
  import { IEventualStatLog } from '../../types/IEventualStatLog';
3
3
  import StatEventCollector from './StatEventCollector';
4
+ import { ClientResourceStats } from './ClientResourceStats';
4
5
  export declare class StatAggregator {
5
6
  private readonly _logger;
7
+ private readonly _resources;
6
8
  private readonly _eventualLogs;
7
9
  private _lastCallStatContext;
8
- constructor(logger: StatEventCollector);
10
+ constructor(logger: StatEventCollector, resources?: ClientResourceStats | null);
9
11
  logCallStat(params: ICallStatLog): void;
10
12
  /**
11
13
  * Событие уходит с теми полями, что переданы. Без value — уходит без value.
@@ -2,7 +2,7 @@ import BaseApi from '../../abstract/BaseApi';
2
2
  import BaseLogger from '../../abstract/BaseLogger';
3
3
  import StatLog from '../../enums/StatLog';
4
4
  import TransportTopology from '../../enums/TransportTopology';
5
- type ClientStatsPayload = Record<string, string | number | boolean | undefined | null>;
5
+ type ClientStatsPayload = Record<string, string | string[] | number | boolean | undefined | null>;
6
6
  export type LogClientStatsOptions = {
7
7
  /** Время наступления события. По умолчанию — момент записи. */
8
8
  occurredAt?: number;
@@ -12,5 +12,7 @@ export declare class StatPings {
12
12
  mark(transport: SignalingTransportType): void;
13
13
  /** Отправляем данные в стату */
14
14
  logMetrics(): void;
15
+ /** Сбрасываем baseline после скрытия страницы, чтобы фоновой простой не стал интервалом ping. */
16
+ resetBaseline(): void;
15
17
  destroy(): void;
16
18
  }
@@ -2,8 +2,8 @@
2
2
  export declare const RECORD_LIMIT = 5000;
3
3
  /** Срок жизни события в очереди. */
4
4
  export declare const MAX_AGE_MS: number;
5
- /** Произвольный набор скалярных полей события. */
6
- export type StatPayload = Record<string, string | number | boolean | null>;
5
+ /** Произвольный набор полей события: скаляры и списки строк. */
6
+ export type StatPayload = Record<string, string | string[] | number | boolean | null>;
7
7
  /** Запись очереди без сгенерированного ключа. */
8
8
  export type StatQueueEntry = {
9
9
  /** userId владельца события. Не может быть неизвестным. */
@@ -31,6 +31,10 @@ export default class DirectTransport extends BaseTransport {
31
31
  private _lastStat;
32
32
  private _fingerprint;
33
33
  private _neverConnected;
34
+ private _connectionStartedAt;
35
+ private _connectionLostAt;
36
+ /** Запросили переход на серверную топологию, не дождавшись первого подключения p2p */
37
+ private _serverRequestedOnNoConnection;
34
38
  private _serverSettings;
35
39
  private _prevConsumerSettings;
36
40
  private _networkLimitsForVideo;
@@ -41,6 +45,7 @@ export default class DirectTransport extends BaseTransport {
41
45
  private _directStatReporter;
42
46
  private readonly _sdpStats;
43
47
  private readonly _peerConnectionStats;
48
+ private readonly _networkAdaptationStats;
44
49
  private readonly _debug;
45
50
  private readonly _logger;
46
51
  private readonly _statAggregator;
@@ -8,10 +8,8 @@ export default class PerfStatReporter extends EventEmitter {
8
8
  private _previousPerfStatReportTimestamp;
9
9
  private _previousNetworkStatReportTimestamp;
10
10
  private _previousCallStatReportTimestamp;
11
- private _previousCounters;
11
+ private _previousCallStatReport;
12
12
  private _previousRemoteInboundRtps;
13
- private _previousInboundRtps;
14
- private _previousOutboundRtps;
15
13
  private _previousCandidatePair;
16
14
  private _screenShareStats;
17
15
  private _signaling;
@@ -27,7 +25,6 @@ export default class PerfStatReporter extends EventEmitter {
27
25
  private _reportCallStats;
28
26
  private _reportCandidatePair;
29
27
  private _calculatePacketLoss;
30
- private _calculateOutboundDeltas;
31
28
  private _handleScreenSharingStat;
32
29
  private _handleTransportStateChanged;
33
30
  }
@@ -83,8 +83,6 @@ export default class ServerTransport extends BaseTransport {
83
83
  private _startSettingsInterval;
84
84
  private _stopSettingsInterval;
85
85
  private _collectStat;
86
- /** mid потока быстрой шары, чтобы отделить его от камеры в статистике */
87
- private _getScreenShareMid;
88
86
  private _reportStats;
89
87
  private _detectStaleTracks;
90
88
  private _allocateConsumer;
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Фичи, активные во время звонка. Уходят в метрику active_features,
3
+ * чтобы по ним разрезать остальную статистику: сколько фризов при включённой камере,
4
+ * какой битрейт при шаре и так далее.
5
+ *
6
+ * Здесь только то, что реально включено прямо сейчас, а не то, что разрешено настройками:
7
+ * иначе фича попадала бы в метрику у всех, кому ее просто не запретили.
8
+ *
9
+ * Сервер принимает только имена из своего списка, незнакомые отбрасывает с ошибкой.
10
+ * Новое имя добавляем сюда после того, как его добавят на сервере.
11
+ */
12
+ declare enum ActiveFeature {
13
+ MICROPHONE = "MICROPHONE",
14
+ CAMERA = "CAMERA",
15
+ /** Любая шара экрана, в том числе быстрая */
16
+ SCREEN = "SCREEN",
17
+ ANIMOJI = "ANIMOJI"
18
+ }
19
+ export default ActiveFeature;
package/enums/Stat.d.ts CHANGED
@@ -37,6 +37,8 @@ declare enum Stat {
37
37
  SDP_SET_REMOTE_ROLLBACK = "sdp_set_remote_rollback",
38
38
  SDP_GENERATED = "sdp_generated",
39
39
  SDP_RECEIVED = "sdp_received",
40
+ CLIENT_REQUESTED_SERVER_TOPOLOGY = "client_requested_server_topology",
41
+ VIDEO_ENCODER_CHANGED_BY_NETWORK_ADAPTER = "video_encoder_changed_by_network_adapter",
40
42
  WEBSOCKET_CONNECTED = "websocket_connected",
41
43
  WEBSOCKET_RECONNECTED = "websocket_reconnected",
42
44
  WEBSOCKET_FAILED_PINGS = "websocket_failed_pings",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vkontakte/calls-sdk",
3
- "version": "2.8.13-dev.58787f8a.0",
3
+ "version": "2.8.13-dev.5a31cf44.0",
4
4
  "author": "vk.com",
5
5
  "description": "Library for video calls based on the vk.com platform",
6
6
  "homepage": "https://vk.com",
@@ -42,22 +42,12 @@ export interface ICallStatLog extends Pick<CallStatReport, 'call_topology' | 'na
42
42
  concealment_audio_avg_size?: number;
43
43
  video_loss?: number;
44
44
  audio_loss?: number;
45
- /** Потери входящего видео за период, в процентах */
46
- in_video_loss?: number;
47
- /** Потери входящего аудио за период, в процентах */
48
- in_audio_loss?: number;
49
- /** Байты, отправленные по исходящим аудио потокам за период, включая шару звука */
50
- audio_bytes_sent?: number;
51
- /** Уровень исходящего звука в шкале 16-битного PCM, от 0 до 32767 */
52
- audio_level?: number;
53
- /** Битрейт исходящего видео без ретрансмитов, кибибит/с */
54
- br_encode?: number;
55
- /** Битрейт отправки видео камеры, кибибит/с */
56
- br_transmit?: number;
57
- /** Битрейт ретрансмитов видео камеры, кибибит/с */
58
- br_retransmit?: number;
59
- /** Кадры камеры, закодированные энкодером за период */
60
- frames_encoded?: number;
61
45
  cpu_hardware_concurrency?: number;
62
- [k: string]: string | number | boolean | undefined;
46
+ /** Максимум участников за интервал между отправками */
47
+ participants_max?: number;
48
+ /** Фичи, включенные в любой момент интервала */
49
+ active_features?: string[];
50
+ /** Максимальная площадь окна приложения за интервал, в мегапикселях */
51
+ app_total_area_mpx_max?: number;
52
+ [k: string]: string | string[] | number | boolean | undefined;
63
53
  }
@@ -36,10 +36,6 @@ interface StatRtpOutboundVideo {
36
36
  framesSent?: number;
37
37
  framesPerSecond?: number;
38
38
  targetBitrate?: number;
39
- /**
40
- * Общее количество кадров, закодированных энкодером
41
- */
42
- framesEncoded?: number;
43
39
  }
44
40
  export interface StatRtp extends StatRtpOutboundVideo {
45
41
  /**
@@ -69,10 +65,6 @@ export interface StatRtp extends StatRtpOutboundVideo {
69
65
  * Общее количество байтов, отправленных по этому потоку
70
66
  */
71
67
  bytesSent: number;
72
- /**
73
- * Общее количество байтов, отправленных повторно (ретрансмиты) по этому потоку
74
- */
75
- retransmittedBytesSent?: number;
76
68
  /**
77
69
  * Общее количество байтов заголовков, полученных по этому потоку
78
70
  */
@@ -81,11 +73,6 @@ export interface StatRtp extends StatRtpOutboundVideo {
81
73
  * Общее количество байтов заголовков, отправленных по этому потоку
82
74
  */
83
75
  headerBytesSent: number;
84
- /**
85
- * Уровень звука исходящего аудио потока в момент снятия статистики, от 0 до 1.
86
- * Берется из media-source, у входящих потоков его нет.
87
- */
88
- audioLevel?: number;
89
76
  /**
90
77
  * Среднее значение джиттера в секундах
91
78
  * Джиттер — это вариация задержки в получении пакетов данных.
@@ -126,10 +113,6 @@ export interface StatRtp extends StatRtpOutboundVideo {
126
113
  * Идентификатор пользователя, связанный с этим потоком
127
114
  */
128
115
  userId?: string;
129
- /**
130
- * Поток демонстрации экрана (быстрая шара), а не камеры
131
- */
132
- isScreenShare?: boolean;
133
116
  /**
134
117
  * Пропускная способность в битах в секунду
135
118
  */