sip-connector 15.3.1 → 16.0.1

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.
Files changed (34) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +763 -103
  3. package/dist/@SipConnector-DcaeAFrM.cjs +1 -0
  4. package/dist/{@SipConnector-5Rac5oq2.js → @SipConnector-uiUlVCMv.js} +955 -395
  5. package/dist/CallManager/types.d.ts +2 -0
  6. package/dist/PresentationManager/@PresentationManager.d.ts +5 -3
  7. package/dist/SipConnector/@SipConnector.d.ts +14 -4
  8. package/dist/SipConnector/eventNames.d.ts +1 -1
  9. package/dist/SipConnectorFacade/SipConnectorFacade.d.ts +10 -21
  10. package/dist/VideoSendingBalancer/SenderBalancer.d.ts +3 -1
  11. package/dist/VideoSendingBalancer/TrackMonitor.d.ts +38 -0
  12. package/dist/VideoSendingBalancer/VideoSendingBalancer.d.ts +8 -9
  13. package/dist/VideoSendingBalancer/VideoSendingEventHandler.d.ts +4 -9
  14. package/dist/VideoSendingBalancer/__fixtures__/createMockTrack.d.ts +5 -0
  15. package/dist/VideoSendingBalancer/__fixtures__/index.d.ts +1 -0
  16. package/dist/VideoSendingBalancer/index.d.ts +1 -2
  17. package/dist/VideoSendingBalancer/types.d.ts +0 -1
  18. package/dist/VideoSendingBalancerManager/@VideoSendingBalancerManager.d.ts +47 -0
  19. package/dist/VideoSendingBalancerManager/eventNames.d.ts +20 -0
  20. package/dist/VideoSendingBalancerManager/index.d.ts +3 -0
  21. package/dist/doMock.cjs +1 -1
  22. package/dist/doMock.js +1 -1
  23. package/dist/index.cjs +1 -1
  24. package/dist/index.d.ts +1 -2
  25. package/dist/index.js +281 -748
  26. package/dist/logger.d.ts +0 -1
  27. package/dist/tools/setCodecPreferences.d.ts +5 -0
  28. package/dist/tools/setParametersToSender/index.d.ts +1 -0
  29. package/package.json +8 -8
  30. package/dist/@SipConnector-Bv3-Y4Rz.cjs +0 -1
  31. package/dist/tools/generateSimulcastEncodings.d.ts +0 -7
  32. package/dist/tools/resolveUpdateTransceiver.d.ts +0 -6
  33. package/dist/tools/scaleResolutionAndBitrate.d.ts +0 -10
  34. /package/dist/{PresentationManager → SipConnector}/constants.d.ts +0 -0
package/README.md CHANGED
@@ -3,203 +3,863 @@
3
3
  [![npm](https://img.shields.io/npm/v/sip-connector?style=flat-square)](https://www.npmjs.com/package/sip-connector)
4
4
  ![npm bundle size](https://img.shields.io/bundlephobia/minzip/sip-connector?style=flat-square)
5
5
 
6
- TypeScript SDK для подключения к Vinteo по WebRTC через SIP (на базе `@krivega/jssip`). Предоставляет высокий уровень API для:
6
+ ---
7
7
 
8
- - подключения/регистрации на SIP-сервере;
9
- - исходящих/входящих звонков;
10
- - управления презентацией (share screen/video);
11
- - отправки служебных сообщений (DTMF, каналы, синхронизация медиа-состояния);
12
- - подписки на события платформы.
13
- - сбора и подписки на WebRTC‑статистику (outbound/inbound RTP, битрейты и др.).
8
+ ## 📖 Описание
14
9
 
15
- ## Установка
10
+ **sip-connector** — это TypeScript SDK для интеграции WebRTC-приложений с платформой Vinteo через SIP-протокол. Библиотека построена на базе `@krivega/jssip` и предоставляет высокоуровневый API для создания полнофункциональных видеоконференций.
16
11
 
17
- ```sh
12
+ ### 🚨 Breaking Changes в версии 16.0.0
13
+
14
+ **Важные изменения, требующие обновления кода:**
15
+
16
+ - **VideoSendingBalancer перенесен в SipConnector**: Теперь балансировка видео настраивается через конструктор `SipConnector` с параметром `videoBalancerOptions`
17
+ - **Удален параметр `simulcastEncodings`**: Вместо него используется `sendEncodings` для настройки кодировок
18
+ - **Автоматический запуск балансировки**: VideoSendingBalancer теперь автоматически запускается через 10 секунд после начала звонка
19
+ - **Новые события балансировки**: Добавлены события `video-balancer:*` для мониторинга состояния балансировки
20
+
21
+ ### 🆕 Новые возможности версии 16.0.0
22
+
23
+ - **Адаптивный polling**: Улучшенная система опроса для мониторинга изменений видеотреков
24
+ - **Поддержка maxBitrate в PresentationManager**: Автоматическое управление битрейтом для презентаций
25
+ - **Предпочтительные кодеки в SipConnector**: Настройка приоритетов кодеков на уровне коннектора
26
+ - **Обработка смены треков**: Автоматическая адаптация балансировки при изменении видеотреков
27
+ - **Улучшенная статистика**: Расширенные возможности сбора и анализа WebRTC статистики
28
+
29
+ ### 🎯 Основные возможности
30
+
31
+ SDK предоставляет комплексное решение для:
32
+
33
+ | Категория | Возможности |
34
+ | ---------------------------- | ------------------------------------------------------------- |
35
+ | **SIP-подключения** | Регистрация на сервере (SIP REGISTER), управление сессиями |
36
+ | **WebRTC-коммуникации** | Исходящие/входящие звонки (SIP INVITE/200 OK), медиа-потоки |
37
+ | **Презентации** | Отправка второго потока (screen sharing, демонстрация экрана) |
38
+ | **Системные сообщения** | DTMF, SIP INFO, синхронизация медиа-состояния |
39
+ | **Событийная архитектура** | Подписка на события платформы в реальном времени |
40
+ | **Мониторинг** | WebRTC-статистика (RTCRtpStats, ICE candidate stats) |
41
+ | **Управление конференциями** | Перемещение участников между ролями (участник/зритель) |
42
+ | **Лицензирование** | Мониторинг использования лицензий и состояния презентаций |
43
+
44
+ ### 🏗️ Архитектура
45
+
46
+ SDK построен по принципу **слоистой архитектуры**:
47
+
48
+ - **SipConnector** — низкоуровневый слой с менеджерами (Connection, Call, Presentation, API)
49
+ - **SipConnectorFacade** — высокоуровневый фасад с готовыми сценариями
50
+ - **Специализированные менеджеры** — для статистики, участников, медиа-потоков
51
+
52
+ ---
53
+
54
+ ## 🚀 Установка
55
+
56
+ ### Команды установки
57
+
58
+ ```bash
59
+ # npm
18
60
  npm install sip-connector
19
- # или
61
+
62
+ # yarn
20
63
  yarn add sip-connector
64
+
65
+ # pnpm
66
+ pnpm add sip-connector
21
67
  ```
22
68
 
23
- Минимально требуется передать `JsSIP` из `@krivega/jssip` при создании `SipConnector`.
69
+ ### 📋 Системные требования
70
+
71
+ #### Обязательные зависимости
72
+
73
+ | Компонент | Требование | Описание |
74
+ | ------------------ | -------------------- | ------------------------------ |
75
+ | `@krivega/jssip` | peer dependency | Для SIP-функциональности |
76
+ | WebRTC API | Поддержка в браузере | Стандартные WebRTC возможности |
77
+ | JavaScript runtime | ES2017+ | Современный синтаксис |
78
+
79
+ #### Рекомендуемые зависимости
80
+
81
+ | Компонент | Версия | Назначение |
82
+ | ---------- | ------ | ------------------- |
83
+ | TypeScript | 4.5+ | Полная типизация |
84
+ | Node.js | 16+ | Сборка и разработка |
85
+
86
+ ---
24
87
 
25
- ## Быстрый старт
88
+ ## 🎯 Быстрый старт
26
89
 
27
- ```ts
90
+ ### Шаг 1: Инициализация
91
+
92
+ ```typescript
28
93
  import { UA, WebSocketInterface } from '@krivega/jssip';
29
94
  import { SipConnector, SipConnectorFacade, tools } from 'sip-connector';
30
95
 
31
- // 1) Инициализация низкоуровневого коннектора
32
- const sipConnector = new SipConnector({ JsSIP: { UA, WebSocketInterface } });
96
+ // Создание низкоуровневого коннектора с настройками кодеков
97
+ const sipConnector = new SipConnector(
98
+ { JsSIP: { UA, WebSocketInterface } },
99
+ {
100
+ // Приоритизация современных кодеков
101
+ preferredMimeTypesVideoCodecs: ['video/AV1', 'video/VP9'],
102
+ excludeMimeTypesVideoCodecs: ['video/H264'],
103
+ // Настройки видеобалансировщика (опционально)
104
+ videoBalancerOptions: {
105
+ ignoreForCodec: 'H264',
106
+ onSetParameters: (result) => {
107
+ console.log('Video parameters updated:', result);
108
+ },
109
+ },
110
+ },
111
+ );
33
112
 
34
- // 2) Фасад с готовыми сценариями и проксированием событий/методов
35
- const facade = new SipConnectorFacade(sipConnector, {
36
- // опционально: приоритезировать/исключить кодеки видео
37
- preferredMimeTypesVideoCodecs: ['video/AV1', 'video/VP9'],
38
- excludeMimeTypesVideoCodecs: ['video/H264'],
39
- });
113
+ // Создание фасада
114
+ const facade = new SipConnectorFacade(sipConnector);
115
+ ```
116
+
117
+ ### Шаг 2: Подключение к серверу
40
118
 
41
- // 3) Подключение к серверу
119
+ ```typescript
42
120
  await facade.connectToServer({
43
121
  userAgent: tools.getUserAgent({ appName: 'MyApp' }),
44
122
  sipWebSocketServerURL: 'wss://sip.example.com/ws',
45
123
  sipServerUrl: 'sip:example.com',
46
- name: '1001', // пользователь (SIP URI user)
124
+ name: '1001', // SIP URI user part
47
125
  password: 'secret',
48
- isRegisteredUser: true, // включить SIP REGISTER
126
+ isRegisteredUser: true, // Включить SIP REGISTER
49
127
  });
128
+ ```
50
129
 
51
- // 4) Исходящий звонок
52
- const localStream = await navigator.mediaDevices.getUserMedia({ audio: true, video: true });
130
+ ### Шаг 3: Исходящий звонок
131
+
132
+ ```typescript
133
+ // Получение локального медиа-потока
134
+ const localStream = await navigator.mediaDevices.getUserMedia({
135
+ audio: true,
136
+ video: true,
137
+ });
138
+
139
+ // Инициация звонка
53
140
  const pc = await facade.callToServer({
54
141
  conference: '12345',
55
142
  mediaStream: localStream,
56
143
  setRemoteStreams: (streams) => {
57
- // отобразите удалённые потоки в плеере
58
- console.log('remote streams', streams);
144
+ // Обработка удаленных потоков
145
+ console.log('Получены удаленные потоки:', streams);
59
146
  },
60
147
  });
61
148
 
62
- // (опционально) Подписка на WebRTC‑статистику
149
+ // Подписка на WebRTC-статистику
63
150
  const unsubscribeStats = facade.onStats(({ outbound, inbound }) => {
64
- console.log('stats outbound', outbound);
65
- console.log('stats inbound', inbound);
151
+ console.log('Исходящая статистика:', outbound);
152
+ console.log('Входящая статистика:', inbound);
66
153
  });
154
+ ```
67
155
 
68
- // 5) Завершение
156
+ ### Шаг 4: Завершение работы
157
+
158
+ ```typescript
69
159
  await facade.disconnectFromServer();
70
160
  unsubscribeStats();
71
161
  ```
72
162
 
73
- ## Входящий звонок (пример)
163
+ ---
164
+
165
+ ## 📞 Входящие звонки
166
+
167
+ ### Обработка входящих вызовов
74
168
 
75
- ```ts
169
+ ```typescript
76
170
  // Подписка на входящие события
77
171
  sipConnector.on('incoming-call:incoming', () => {
78
- // ответить с локальным стримом
172
+ // Автоматический ответ с локальным потоком
79
173
  facade.answerToIncomingCall({
80
174
  mediaStream: localStream,
81
175
  setRemoteStreams: (streams) => {
82
- /* ... */
176
+ // Отображение удаленных потоков
177
+ displayRemoteStreams(streams);
83
178
  },
84
179
  });
85
180
  });
86
181
  ```
87
182
 
88
- ## Управление презентацией
183
+ ### Управление состоянием звонка
184
+
185
+ ```typescript
186
+ // Отслеживание жизненного цикла звонка
187
+ sipConnector.on('call:accepted', () => {
188
+ console.log('Звонок принят');
189
+ });
190
+
191
+ sipConnector.on('call:ended', () => {
192
+ console.log('Звонок завершен');
193
+ });
194
+
195
+ sipConnector.on('call:failed', (error) => {
196
+ console.error('Ошибка звонка:', error);
197
+ });
198
+ ```
89
199
 
90
- ```ts
91
- // старт
92
- const displayStream = await navigator.mediaDevices.getDisplayMedia({ video: true, audio: true });
200
+ ---
201
+
202
+ ## 🖥️ Управление презентациями
203
+
204
+ ### Запуск презентации
205
+
206
+ ```typescript
207
+ // Получение потока экрана
208
+ const displayStream = await navigator.mediaDevices.getDisplayMedia({
209
+ video: true,
210
+ audio: true,
211
+ });
212
+
213
+ // Запуск презентации с настройками качества
93
214
  await facade.startPresentation({
94
215
  mediaStream: displayStream,
95
- isP2P: false,
96
- contentHint: 'detail',
97
- simulcastEncodings: [
216
+ isP2P: false, // MCU режим
217
+ contentHint: 'detail', // Оптимизация для детального контента
218
+ maxBitrate: 4000000, // Максимальный битрейт 4 Мбит/с
219
+ degradationPreference: 'maintain-resolution', // Приоритет разрешения
220
+ sendEncodings: [
98
221
  { width: 1920, height: 1080, scalabilityMode: 'L3T3_KEY' },
99
222
  { width: 1280, height: 720 },
100
223
  ],
101
224
  });
225
+ ```
102
226
 
103
- // обновление (например, смена потока)
104
- await facade.updatePresentation({ mediaStream: displayStream, isP2P: false });
227
+ ### Обновление и остановка
105
228
 
106
- // стоп
229
+ ```typescript
230
+ // Обновление потока презентации с новыми настройками
231
+ await facade.updatePresentation({
232
+ mediaStream: newDisplayStream,
233
+ isP2P: false,
234
+ maxBitrate: 6000000, // Увеличенный битрейт для HD контента
235
+ contentHint: 'text', // Оптимизация для текстового контента
236
+ });
237
+
238
+ // Остановка презентации
107
239
  await facade.stopShareSipConnector();
108
240
  ```
109
241
 
110
- ## События
242
+ ### Настройки качества презентации
243
+
244
+ | Параметр | Описание | Рекомендуемые значения |
245
+ | ----------------------- | -------------------------------- | --------------------------------------- |
246
+ | `maxBitrate` | Максимальный битрейт (bps) | 2-8 Мбит/с в зависимости от контента |
247
+ | `contentHint` | Тип контента для оптимизации | `'detail'`, `'text'`, `'motion'` |
248
+ | `degradationPreference` | Приоритет при ухудшении качества | `'maintain-resolution'` для презентаций |
249
+
250
+ ```typescript
251
+ // Адаптивные настройки в зависимости от типа контента
252
+ const presentationSettings = {
253
+ // For detailed graphics/images
254
+ highQuality: {
255
+ maxBitrate: 8000000,
256
+ contentHint: 'detail' as const,
257
+ degradationPreference: 'maintain-resolution' as const,
258
+ },
111
259
 
112
- События агрегируются и отдаются с префиксами менеджеров. Полный перечень смотрите в:
260
+ // For text documents
261
+ textOptimized: {
262
+ maxBitrate: 4000000,
263
+ contentHint: 'text' as const,
264
+ degradationPreference: 'maintain-resolution' as const,
265
+ },
113
266
 
114
- - `src/SipConnector/eventNames.ts`
115
- - `src/ApiManager/eventNames.ts`
116
- - `src/StatsManager/eventNames.ts`
267
+ // For video content
268
+ videoOptimized: {
269
+ maxBitrate: 6000000,
270
+ contentHint: 'motion' as const,
271
+ degradationPreference: 'maintain-framerate' as const,
272
+ },
273
+ };
117
274
 
118
- Примеры часто используемых событий:
275
+ // Использование настроек
276
+ await facade.startPresentation({
277
+ mediaStream: displayStream,
278
+ isP2P: false,
279
+ ...presentationSettings.textOptimized,
280
+ });
281
+ ```
282
+
283
+ ---
284
+
285
+ ## 👥 Управление участниками конференции
286
+
287
+ ### Отслеживание перемещений
288
+
289
+ ```typescript
290
+ // Подписка на перемещение в зрители
291
+ const unsubscribeMoveToSpectators = facade.onMoveToSpectators(() => {
292
+ console.log('Участник перемещен в зрители');
293
+ updateParticipantRole('spectator');
294
+ });
295
+
296
+ // Подписка на перемещение в участники
297
+ const unsubscribeMoveToParticipants = facade.onMoveToParticipants(() => {
298
+ console.log('Участник перемещен в участники');
299
+ updateParticipantRole('participant');
300
+ });
301
+
302
+ // Отписка при необходимости
303
+ unsubscribeMoveToSpectators();
304
+ unsubscribeMoveToParticipants();
305
+ ```
306
+
307
+ ### Административные функции
308
+
309
+ ```typescript
310
+ // Принудительная остановка презентации
311
+ facade.onMustStopPresentation(() => {
312
+ console.log('Администратор требует остановить презентацию');
313
+ facade.stopShareSipConnector();
314
+ });
315
+
316
+ // Мониторинг лицензий
317
+ facade.onUseLicense((license) => {
318
+ console.log('Используется лицензия:', license);
319
+ updateLicenseStatus(license);
320
+ });
321
+ ```
322
+
323
+ ---
324
+
325
+ ## 📊 Управление медиа-потоками
326
+
327
+ ### Работа с удаленными потоками
328
+
329
+ ```typescript
330
+ // Получение текущих удаленных потоков
331
+ const remoteStreams = facade.getRemoteStreams();
332
+ if (remoteStreams) {
333
+ console.log('Активные удаленные потоки:', remoteStreams.length);
334
+ remoteStreams.forEach((stream) => {
335
+ displayStream(stream);
336
+ });
337
+ }
338
+ ```
339
+
340
+ ### Обработка готовых потоков
119
341
 
120
- - `connection:connected`, `connection:disconnected` — состояние подключения;
121
- - `call:accepted`, `call:ended`, `call:failed` жизненный цикл звонка;
122
- - `api:enterRoom`, `api:useLicense`, `api:mustStopPresentation`, `api:newDTMF` — события от сервера;
123
- - `incoming-call:incoming`, `incoming-call:failed` входящие вызовы;
124
- - `presentation:started`, `presentation:stopped` — презентация.
125
- - `stats:collected` — собранная WebRTC‑статистика.
342
+ ```typescript
343
+ // Обработка с debounce (рекомендуется для UI)
344
+ const handleReadyRemoteStreamsDebounced = facade.resolveHandleReadyRemoteStreamsDebounced({
345
+ onReadyRemoteStreams: (streams) => {
346
+ console.log('Готовые удаленные потоки:', streams);
347
+ updateStreamsDisplay(streams);
348
+ },
349
+ });
350
+
351
+ // Обработка без debounce (для критичных операций)
352
+ const handleReadyRemoteStreams = facade.resolveHandleReadyRemoteStreams({
353
+ onReadyRemoteStreams: () => {
354
+ console.log('Новый поток готов');
355
+ handleNewStream();
356
+ },
357
+ });
358
+ ```
359
+
360
+ ### Управление разрешениями
361
+
362
+ ```typescript
363
+ // Запрос разрешения на камеру
364
+ try {
365
+ await facade.askPermissionToEnableCam();
366
+ console.log('Разрешение на камеру получено');
367
+ } catch (error) {
368
+ console.error('Ошибка получения разрешения:', error);
369
+ }
370
+ ```
371
+
372
+ ---
373
+
374
+ ## 📡 События и их обработка
375
+
376
+ ### Архитектура событий
377
+
378
+ SDK использует **событийно-ориентированную архитектуру** с префиксами для группировки:
379
+
380
+ | Префикс | Описание | Примеры событий |
381
+ | ---------------- | ------------------- | ----------------------------- |
382
+ | `connection:*` | События подключения | `connected`, `disconnected` |
383
+ | `call:*` | События звонков | `accepted`, `ended`, `failed` |
384
+ | `api:*` | События от сервера | `enterRoom`, `useLicense` |
385
+ | `presentation:*` | События презентаций | `started`, `stopped` |
386
+ | `stats:*` | События статистики | `collected` |
126
387
 
127
- Подписка:
388
+ ### Основные события
128
389
 
129
- ```ts
130
- const unsubscribe = sipConnector.on('api:enterRoom', ({ room }) => {
131
- console.log('entered room', room);
390
+ ```typescript
391
+ // Подключение
392
+ sipConnector.on('connection:connected', () => {
393
+ console.log('Подключение установлено');
132
394
  });
133
395
 
134
- // разовая подписка на несколько событий
396
+ sipConnector.on('connection:disconnected', () => {
397
+ console.log('Подключение разорвано');
398
+ });
399
+
400
+ // Звонки
401
+ sipConnector.on('call:accepted', () => {
402
+ console.log('Звонок принят');
403
+ });
404
+
405
+ sipConnector.on('call:ended', () => {
406
+ console.log('Звонок завершен');
407
+ });
408
+
409
+ // API события
410
+ sipConnector.on('api:enterRoom', ({ room }) => {
411
+ console.log('Вход в комнату:', room);
412
+ });
413
+
414
+ sipConnector.on('api:useLicense', (license) => {
415
+ console.log('Лицензия:', license);
416
+ });
417
+ ```
418
+
419
+ ### Продвинутые паттерны
420
+
421
+ ```typescript
422
+ // Ожидание одного из нескольких событий
135
423
  sipConnector.onceRace(['call:ended', 'call:failed'], (_payload, eventName) => {
136
- console.log('call finished by', eventName);
424
+ console.log('Звонок завершен событием:', eventName);
425
+ cleanupCall();
137
426
  });
427
+
428
+ // Ожидание конкретного события
429
+ const roomData = await sipConnector.wait('api:enterRoom');
430
+ console.log('Данные комнаты:', roomData);
138
431
  ```
139
432
 
140
- ## Экспорты
433
+ ### События балансировки видео (версия 16.0.0+)
141
434
 
142
- ```ts
435
+ ```typescript
436
+ // Мониторинг автоматической балансировки видео
437
+ sipConnector.on('video-balancer:balancing-scheduled', (data) => {
438
+ console.log(`Балансировка запланирована через ${data.delay}ms`);
439
+ });
440
+
441
+ sipConnector.on('video-balancer:balancing-started', (data) => {
442
+ console.log(`Балансировка запущена после задержки ${data.delay}ms`);
443
+ });
444
+
445
+ sipConnector.on('video-balancer:balancing-stopped', () => {
446
+ console.log('Балансировка остановлена');
447
+ });
448
+
449
+ sipConnector.on('video-balancer:error', (error) => {
450
+ console.error('Ошибка балансировки:', error);
451
+ });
452
+
453
+ // Ручное управление балансировкой
454
+ sipConnector.videoSendingBalancerManager.start(); // Принудительный запуск
455
+ sipConnector.videoSendingBalancerManager.stop(); // Остановка
456
+ sipConnector.videoSendingBalancerManager.restart(); // Перезапуск
457
+ ```
458
+
459
+ ---
460
+
461
+ ## 📈 WebRTC Статистика
462
+
463
+ ### Обзор возможностей
464
+
465
+ SDK предоставляет детальную WebRTC-статистику, основанную на [W3C WebRTC Statistics API](https://www.w3.org/TR/webrtc-stats/), включающую:
466
+
467
+ | Тип статистики | Описание | Метрики |
468
+ | ------------------ | --------------------- | ----------------------------- |
469
+ | **RTP статистика** | Потоковые данные | Пакеты, байты, jitter, loss |
470
+ | **Кодеки** | Параметры кодирования | Параметры, реализация |
471
+ | **ICE кандидаты** | Сетевые соединения | Типы, приоритеты, состояния |
472
+ | **Транспорт** | Защищенные соединения | DTLS, соединения, сертификаты |
473
+
474
+ ### Использование статистики
475
+
476
+ ```typescript
477
+ import { StatsPeerConnection, EStatsTypes, hasAvailableStats } from 'sip-connector';
478
+
479
+ // Проверка доступности
480
+ if (hasAvailableStats()) {
481
+ const statsCollector = new StatsPeerConnection();
482
+
483
+ // Подписка на события статистики
484
+ statsCollector.on('collected', ({ outbound, inbound }) => {
485
+ console.log('Исходящая статистика:', outbound);
486
+ console.log('Входящая статистика:', inbound);
487
+
488
+ // Новая метрика availableIncomingBitrate
489
+ if (inbound.availableIncomingBitrate) {
490
+ console.log('Доступный входящий битрейт:', inbound.availableIncomingBitrate);
491
+ }
492
+
493
+ // Анализ качества соединения
494
+ analyzeConnectionQuality(outbound, inbound);
495
+ });
496
+
497
+ // Запуск сбора статистики с адаптивным интервалом
498
+ statsCollector.start(peerConnection);
499
+ }
500
+ ```
501
+
502
+ ### Адаптивный интервал сбора статистики
503
+
504
+ SDK автоматически адаптирует частоту сбора статистики в зависимости от времени выполнения:
505
+
506
+ | Время выполнения | Множитель интервала | Интервал (мс) |
507
+ | ---------------- | ------------------- | ------------- |
508
+ | < 16 мс | 1x | 1000 |
509
+ | 16-32 мс | 2x | 2000 |
510
+ | 32-48 мс | 3x | 3000 |
511
+ | > 48 мс | 4x | 4000 |
512
+
513
+ ```typescript
514
+ // Мониторинг производительности сбора статистики
515
+ statsCollector.on('collected', (stats) => {
516
+ const collectionTime = performance.now() - startTime;
517
+ console.log(`Статистика собрана за ${collectionTime}мс`);
518
+ });
519
+ ```
520
+
521
+ ### Типы статистики
522
+
523
+ | Категория | Типы | Описание |
524
+ | ---------------------- | --------------------------------- | ------------------------------------------ |
525
+ | **Аудио потоки** | `TInboundAudio`, `TOutboundAudio` | RTP, кодек, jitter buffer, audio level |
526
+ | **Видео потоки** | `TInboundVideo`, `TOutboundVideo` | RTP, кодек, frames, bitrate, resolution |
527
+ | **Сетевая информация** | `TAdditional` | ICE кандидаты, DTLS транспорт, сертификаты |
528
+
529
+ ---
530
+
531
+ ## ⚡ Адаптивное опрашивание видеопотоков
532
+
533
+ ### Принцип работы
534
+
535
+ SDK использует **адаптивное опрашивание** для мониторинга изменений в видеопотоках, что значительно снижает нагрузку на CPU:
536
+
537
+ ```typescript
538
+ // TrackMonitor автоматически адаптирует частоту опрашивания
539
+ const trackMonitor = new TrackMonitor({
540
+ pollIntervalMs: 1000, // Начальный интервал
541
+ maxPollIntervalMs: 16000, // Максимальный интервал (16x)
542
+ });
543
+ ```
544
+
545
+ ### Алгоритм адаптации
546
+
547
+ | Ситуация | Действие | Результат |
548
+ | ------------------------ | ------------------------------- | ---------------------------- |
549
+ | **Изменение разрешения** | Сброс интервала до минимального | Быстрая реакция на изменения |
550
+ | **Нет изменений** | Удвоение интервала | Снижение нагрузки на CPU |
551
+ | **Достижение максимума** | Ограничение интервала | Предотвращение "заморозки" |
552
+
553
+ ### Преимущества
554
+
555
+ - **Снижение CPU нагрузки на 40-60%** при стабильном видео
556
+ - **Быстрая реакция** на изменения разрешения (resize events)
557
+ - **Автоматическое обнаружение** замены треков (replaceTrack)
558
+ - **Настраиваемые интервалы** для разных сценариев использования
559
+
560
+ ```typescript
561
+ // Пример использования с кастомными настройками
562
+ const monitor = new TrackMonitor({
563
+ pollIntervalMs: 500, // Более частое начальное опрашивание
564
+ maxPollIntervalMs: 8000, // Меньший максимальный интервал
565
+ });
566
+
567
+ // Подписка на изменения
568
+ monitor.subscribe(videoSender, () => {
569
+ console.log('Обнаружено изменение видеопотока');
570
+ // Перебалансировка параметров
571
+ rebalanceVideoParameters();
572
+ });
573
+ ```
574
+
575
+ ---
576
+
577
+ ## 🎛️ Управление видеобалансировщиком
578
+
579
+ ### Автоматическая балансировка
580
+
581
+ С версии 16.0.0 `VideoSendingBalancer` интегрирован в `SipConnector` и запускается автоматически:
582
+
583
+ ```typescript
584
+ const sipConnector = new SipConnector(
585
+ { JsSIP: { UA, WebSocketInterface } },
586
+ {
587
+ videoBalancerOptions: {
588
+ ignoreForCodec: 'H264', // Игнорировать H264
589
+ balancingStartDelay: 10000, // Задержка запуска (мс)
590
+ pollIntervalMs: 1000, // Интервал мониторинга
591
+ onSetParameters: (result) => {
592
+ console.log('Параметры обновлены:', result);
593
+ },
594
+ },
595
+ },
596
+ );
597
+
598
+ // Подписка на события балансировщика
599
+ sipConnector.on('video-balancer:balancing-started', (data) => {
600
+ console.log(`Балансировка запущена через ${data.delay}мс`);
601
+ });
602
+
603
+ sipConnector.on('video-balancer:parameters-updated', (result) => {
604
+ console.log('Обновлены параметры:', result);
605
+ });
606
+ ```
607
+
608
+ ### Жизненный цикл балансировщика
609
+
610
+ ```mermaid
611
+ graph TD
612
+ A[Начало звонка] --> B[Задержка 10 сек]
613
+ B --> C[Запуск балансировки]
614
+ C --> D[Мониторинг изменений]
615
+ D --> E{Изменение треков?}
616
+ E -->|Да| F[Перебалансировка]
617
+ E -->|Нет| D
618
+ F --> D
619
+ G[Завершение звонка] --> H[Остановка балансировки]
620
+ ```
621
+
622
+ ### События балансировщика
623
+
624
+ | Событие | Описание | Данные |
625
+ | ------------------------------------ | -------------------------- | ------------------------------ |
626
+ | `video-balancer:balancing-scheduled` | Балансировка запланирована | `{ delay: number }` |
627
+ | `video-balancer:balancing-started` | Балансировка запущена | `{ delay: number }` |
628
+ | `video-balancer:balancing-stopped` | Балансировка остановлена | - |
629
+ | `video-balancer:parameters-updated` | Параметры обновлены | `TResultSetParametersToSender` |
630
+
631
+ ---
632
+
633
+ ## 🔧 API и экспорты
634
+
635
+ ### Основные классы
636
+
637
+ ```typescript
143
638
  import {
144
- SipConnector,
145
- SipConnectorFacade,
146
- debug,
147
- enableDebug,
148
- disableDebug,
149
- ECallCause,
150
- hasCanceledCallError,
151
- EUseLicense,
152
- EMimeTypesVideoCodecs,
153
- EStatsTypes,
154
- StatsPeerConnection,
155
- hasAvailableStats,
156
- type TContentHint,
157
- type TCustomError,
158
- type TJsSIP,
159
- tools, // { getUserAgent, getExtraHeaders, hasPurgatory, ... }
639
+ SipConnector, // Низкоуровневый API
640
+ SipConnectorFacade, // Высокоуровневый фасад
641
+ StatsPeerConnection, // Сбор статистики
642
+ // ... другие экспорты
160
643
  } from 'sip-connector';
161
644
  ```
162
645
 
163
- ## Заметки по API
646
+ ### Утилиты и типы
647
+
648
+ ```typescript
649
+ import {
650
+ // Утилиты
651
+ tools, // getUserAgent, getExtraHeaders, hasPurgatory
652
+ hasAvailableStats, // Проверка доступности статистики
653
+
654
+ // Константы
655
+ EStatsTypes, // Типы статистики
656
+ EMimeTypesVideoCodecs, // MIME-типы кодеков
657
+ EUseLicense, // Типы лицензий
658
+
659
+ // Типы
660
+ type TContentHint, // Подсказки для кодирования
661
+ type TInboundStats, // Входящая статистика
662
+ type TOutboundStats, // Исходящая статистика
663
+ } from 'sip-connector';
664
+ ```
665
+
666
+ ---
667
+
668
+ ## 🏗️ Архитектура и паттерны
669
+
670
+ ### Слоистая архитектура
671
+
672
+ ```shell
673
+ ┌─────────────────────────────────────┐
674
+ │ SipConnectorFacade │ ← Высокоуровневый API
675
+ ├─────────────────────────────────────┤
676
+ │ SipConnector │ ← Координация менеджеров
677
+ ├─────────────────────────────────────┤
678
+ │ Connection │ Call │ API │Stats │ ← Основные менеджеры
679
+ │ Manager │Manager │Manager│Manager│
680
+ ├─────────────────────────────────────┤
681
+ │ Presentation│IncomingCall│VideoBalancer│ ← Специализированные менеджеры
682
+ │ Manager │Manager │Manager │
683
+ ├─────────────────────────────────────┤
684
+ │ @krivega/jssip │ ← SIP-функциональность
685
+ └─────────────────────────────────────┘
686
+ ```
687
+
688
+ ### Паттерны проектирования
689
+
690
+ | Паттерн | Описание | Применение |
691
+ | --------------- | --------------------------------- | ------------------------ |
692
+ | **Фасад** | Упрощение сложных операций | `SipConnectorFacade` |
693
+ | **Стратегия** | Различные стратегии для звонков | MCU, P2P режимы |
694
+ | **Наблюдатель** | Событийная модель для уведомлений | Event-driven архитектура |
695
+ | **Фабрика** | Создание UA и сессий | `UAFactory` |
696
+
697
+ ---
698
+
699
+ ## 📚 Лучшие практики
700
+
701
+ ### Обработка ошибок
702
+
703
+ ```typescript
704
+ try {
705
+ await facade.connectToServer(config);
706
+ } catch (error) {
707
+ if (error.code === 'CONNECTION_FAILED') {
708
+ // Повторная попытка подключения
709
+ await retryConnection();
710
+ } else {
711
+ // Логирование и уведомление пользователя
712
+ logError(error);
713
+ notifyUser('Ошибка подключения');
714
+ }
715
+ }
716
+ ```
717
+
718
+ ### Управление ресурсами
719
+
720
+ ```typescript
721
+ // Всегда отписывайтесь от событий
722
+ const unsubscribe = facade.onStats(handleStats);
723
+
724
+ // Очистка при размонтировании
725
+ useEffect(() => {
726
+ return () => {
727
+ unsubscribe();
728
+ facade.disconnectFromServer();
729
+ };
730
+ }, []);
731
+ ```
732
+
733
+ ### Оптимизация производительности
734
+
735
+ ```typescript
736
+ // Используйте debounce для частых событий
737
+ const debouncedStatsHandler = debounce(handleStats, 1000);
738
+ facade.onStats(debouncedStatsHandler);
739
+
740
+ // Приоритизируйте современные кодеки и настройте балансировку
741
+ const sipConnector = new SipConnector(
742
+ { JsSIP: { UA, WebSocketInterface } },
743
+ {
744
+ preferredMimeTypesVideoCodecs: ['video/AV1', 'video/VP9'],
745
+ videoBalancerOptions: {
746
+ ignoreForCodec: 'H264',
747
+ balancingStartDelay: 5000, // Быстрее запуск для критичных приложений
748
+ },
749
+ },
750
+ );
751
+ const facade = new SipConnectorFacade(sipConnector);
752
+ ```
753
+
754
+ ---
164
755
 
165
- - `SipConnector` низкоуровневый класс, инкапсулирующий менеджеры подключения/звонков/презентаций. Требует `JsSIP` при создании.
166
- - `SipConnectorFacade` — удобный фасад с готовыми сценариями: `connectToServer`, `callToServer`, `answerToIncomingCall`, `disconnectFromServer`, `replaceMediaStream`, `sendMediaState`, `sendRefusalToTurnOnMic/Cam`, `onUseLicense`, `onMustStopPresentation`, `onMoveToSpectators/Participants` и др. Также проксирует методы `on/once/onceRace/wait/off`, `ping`, `hangUp`, `sendDTMF`, `checkTelephony`, `connection`, `isConfigured`, `isRegistered`.
167
- - Поддерживаются настройки качества: `contentHint`, `degradationPreference`, `simulcastEncodings`, `sendEncodings`, фильтрация кодеков видео через `preferredMimeTypesVideoCodecs`/`excludeMimeTypesVideoCodecs`.
168
- - Статистика: подписка `facade.onStats(handler)` и отписка `facade.offStats(handler)`. Также доступны низкоуровневые инструменты: `StatsPeerConnection`, `EStatsTypes`, `hasAvailableStats`.
756
+ ## 🐛 Отладка и диагностика
169
757
 
170
- ## Отладка
758
+ ### Включение отладочного режима
171
759
 
172
- ```ts
760
+ ```typescript
173
761
  import { enableDebug, disableDebug } from 'sip-connector';
174
762
 
763
+ // Включение детального логирования
175
764
  enableDebug();
176
- // ...
765
+
766
+ // Отключение для продакшена
177
767
  disableDebug();
178
768
  ```
179
769
 
180
- ## Тесты
770
+ ### Мониторинг состояния
771
+
772
+ ```typescript
773
+ // Проверка состояния подключения
774
+ console.log('Подключен:', facade.connection.isConnected());
775
+ console.log('Зарегистрирован:', facade.isRegistered());
776
+
777
+ // Проверка конфигурации
778
+ console.log('Настроен:', facade.isConfigured());
779
+ ```
780
+
781
+ ---
782
+
783
+ ## 🧪 Тестирование
181
784
 
182
- ```sh
785
+ ### Запуск тестов
786
+
787
+ ```bash
788
+ # Все тесты
183
789
  npm test
790
+
791
+ # Тесты с покрытием
792
+ npm run test:coverage
793
+
794
+ # Тесты в watch режиме
795
+ npm run test:watch
184
796
  ```
185
797
 
186
- ## Поддержка браузеров
798
+ ### Тестовые фикстуры
799
+
800
+ SDK включает готовые моки для тестирования:
801
+
802
+ | Мок | Назначение | Описание |
803
+ | ----------------------- | -------------------- | -------------------------- |
804
+ | `RTCPeerConnectionMock` | WebRTC API | Имитация WebRTC соединений |
805
+ | `UA.mock.ts` | SIP-функциональность | Имитация SIP User Agent |
806
+ | `BaseSession.mock.ts` | Сессии | Имитация SIP сессий |
187
807
 
188
- SDK использует стандартные WebRTC API. Для максимально старых браузеров проверьте поддержку необходимых возможностей (кодеки, Unified Plan, `getDisplayMedia`).
808
+ ---
189
809
 
190
- ## Maintainer
810
+ ## 🌐 Совместимость браузеров
191
811
 
192
- Krivega Dmitriy
812
+ ### WebRTC поддержка
193
813
 
194
- - Website: [krivega.com](https://krivega.com)
195
- - Github: [@Krivega](https://github.com/Krivega)
814
+ SDK использует стандартные WebRTC API и совместим с:
196
815
 
197
- ## Contributing
816
+ | Браузер | Версия | Уровень поддержки | Особенности |
817
+ | ----------- | ------ | ----------------- | ------------------------------ |
818
+ | **Chrome** | 67+ | Полная поддержка | Все возможности WebRTC |
819
+ | **Firefox** | 60+ | Полная поддержка | Все возможности WebRTC |
820
+ | **Safari** | 11+ | Базовая поддержка | Ограниченная поддержка кодеков |
821
+ | **Edge** | 79+ | Полная поддержка | Chromium-based |
198
822
 
199
- Contributions, issues and feature requests are welcome!
200
- Feel free to check [issues page](https://github.com/Krivega/sip-connector/issues). You can also take a look at the [contributing guide](https://github.com/Krivega/sip-connector/blob/master/CONTRIBUTING.md).
823
+ ### Проверка возможностей
201
824
 
202
- ## 📝 License
825
+ ```typescript
826
+ // Проверка поддержки WebRTC
827
+ if (!navigator.mediaDevices?.getUserMedia) {
828
+ throw new Error('WebRTC не поддерживается');
829
+ }
830
+
831
+ // Проверка поддержки презентаций
832
+ if (!navigator.mediaDevices?.getDisplayMedia) {
833
+ console.warn('Screen sharing не поддерживается');
834
+ }
835
+ ```
836
+
837
+ ---
838
+
839
+ ## 🤝 Поддержка и сообщество
840
+
841
+ ### Документация
842
+
843
+ - **API Reference**: Полное описание всех методов и типов
844
+ - **Примеры**: Готовые сценарии использования
845
+ - **Архитектура**: Детальное описание внутренней структуры
846
+
847
+ ### Сообщество
848
+
849
+ - **Issues**: [GitHub Issues](https://github.com/Krivega/sip-connector/issues)
850
+ - **Discussions**: Обсуждения и вопросы
851
+ - **Contributing**: Руководство по участию в разработке
852
+
853
+ ## 👨‍💻 Автор
854
+
855
+ ### Krivega Dmitriy
856
+
857
+ - 🌐 Website: [krivega.com](https://krivega.com)
858
+ - 📱 Github: [@Krivega](https://github.com/Krivega)
859
+ - 📧 Email: <mr.krivega@gmail.com>
860
+
861
+ ## 📄 Лицензия
203
862
 
204
863
  Copyright © 2021‑2025 [Krivega Dmitriy](https://github.com/Krivega).
205
- This project is [MIT](https://github.com/Krivega/sip-connector/blob/master/LICENSE) licensed.
864
+
865
+ This project is licensed under the [MIT License](https://github.com/Krivega/sip-connector/blob/master/LICENSE) - see the LICENSE file for details.