Загрузка данных
# Master cabinet and streaming
## User
1. Создай у модели Master поле "пароль". И его редактирование в админке. По умолчанию, оно генерируется автоматически.
2. Создай отдельную страницу на фронте (master/cabinet). Вход на нее, по паролю из п.1. Там мастер будет видеть все свои трансляции (модели Shedule, где поле master соответствует залогинившемуся мастеру и тип занятия - онлайн) в виде таблицы с названием и указанием дня недели и времени вещания. Если день и время соответствует текущему, то есть кнопка "начать трансляцию"
3. Попадая на нее, начинается прямо в браузере видео трансляция через наш сервер.
4. Также создай отдельную временную страницу (нигде в меню не появляющуюся) со списком всех онлайн занятий Shedule И кнопкой "присоединиться к трансляции". При клике на нее любой человек попадает на страницу, где видит идущую трансляцию из п.3
## Assistant
Разберу структуру моделей Master/Schedule и админки, затем добавлю пароль, кабинет мастера и страницы трансляции.
### Tool Todo Write
### Tool New agent
### Tool Get Mcp Tools
```
{"server":"user-context7","toolCallId":"call-2c1137fa-fbe8-449a-9505-5c20129e01be-2\nfc_c088a317-495c-9bc6-9fa9-408c183f8fb2_2"}
```
## Assistant
Проверяю модели, админку и наличие медиа-сервера для стриминга.
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\app\\Models\\Master.php"}
```
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\app\\Http\\Controllers\\Admin\\MasterAdminController.php"}
```
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\resources\\views\\admin\\masters\\form.php"}
```
### Tool Ripgrep Raw Search
```
{"pattern":"mediamtx|webrtc|rtmp|livekit|janus|mediasoup|hls|streaming|whip|whep","path":"c:\\OSPanel\\home\\inbi.loc","caseInsensitive":true,"multiline":false,"toolCallId":"call-9552df08-6cee-4dab-a55e-847a573ca651-6\nfc_0696738f-b2c7-97a1-9ee6-a9500b612f1b_3","offset":0}
```
### Tool Ripgrep Raw Search
```
{"pattern":"Master|Schedule|cabinet|master","path":"c:\\OSPanel\\home\\inbi.loc\\routes\\web.php","caseInsensitive":false,"multiline":false,"toolCallId":"call-9552df08-6cee-4dab-a55e-847a573ca651-7\nfc_0696738f-b2c7-97a1-9ee6-a9500b612f1b_4","offset":0}
```
### Tool Glob File Search
```
{"targetDirectory":"c:\\OSPanel\\home\\inbi.loc","globPattern":"**/docker*"}
```
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\app\\Models\\Schedule.php","limit":200}
```
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\routes\\web.php","offset":1,"limit":100}
```
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\composer.json","limit":80}
```
### Tool Glob File Search
```
{"targetDirectory":"c:\\OSPanel\\home\\inbi.loc","globPattern":"**/.env*"}
```
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\resources\\views\\layouts\\header.php","limit":80}
```
### Tool Ripgrep Raw Search
```
{"pattern":"getDay|day_of_week|start_time","path":"c:\\OSPanel\\home\\inbi.loc\\app\\Models\\Schedule.php","caseInsensitive":false,"multiline":false,"toolCallId":"call-91c1e96b-436c-4e7c-8546-f080f4b45a40-14\nfc_b9dff7bc-0e73-9202-b215-1fa82e1f1670_5","offset":0}
```
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\bootstrap\\app.php"}
```
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\resources\\views\\auth\\login.php","limit":80}
```
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\routes\\web.php","offset":280,"limit":50}
```
### Tool Glob File Search
```
{"targetDirectory":"c:\\OSPanel\\home\\inbi.loc","globPattern":"**/Middleware/*.php"}
```
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\.env.example","limit":80}
```
### Tool Mcp
```
{"name":"user-context7-resolve-library-id","args":{"libraryName":"Laravel","query":"Laravel 12 migration model middleware session authentication"},"toolCallId":"call-dbf82417-b015-45b9-96d4-4e820f547e4a-20\nfc_caa68e10-e000-9a4d-bdb2-f7aeb88fc39e_5","providerIdentifier":"context7","toolName":"resolve-library-id","smartModeApprovalOnly":false,"skipApproval":false}
```
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\app\\Http\\Middleware\\UserAuth.php"}
```
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\config\\app.php","limit":100}
```
### Tool Ripgrep Raw Search
```
{"pattern":"timezone|Europe/Moscow","path":"c:\\OSPanel\\home\\inbi.loc\\config","caseInsensitive":false,"multiline":false,"toolCallId":"call-eb062170-903b-4106-ab84-2a7cfbe14222-23\nfc_4b31275a-ffe5-901f-aae1-527c15ef4360_2","offset":0}
```
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\resources\\views\\cabinet\\index.php","limit":60}
```
### Tool Glob File Search
```
{"targetDirectory":"c:\\OSPanel\\home\\inbi.loc","globPattern":"**/migrations/*masters*"}
```
### Tool Mcp
```
{"name":"user-context7-query-docs","args":{"libraryId":"/websites/laravel_12_x","query":"How to create a migration to add a column, hash passwords with Hash facade, and register custom middleware alias"},"toolCallId":"call-eb062170-903b-4106-ab84-2a7cfbe14222-26\nfc_4b31275a-ffe5-901f-aae1-527c15ef4360_5","providerIdentifier":"context7","toolName":"query-docs","smartModeApprovalOnly":false,"skipApproval":false}
```
## Assistant
Реализую пароль мастера, кабинет и WebRTC-трансляцию с сигналингом через Laravel.
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\database\\migrations\\2026_01_29_120000_add_notes_to_masters_table.php"}
```
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\app\\Models\\Schedule.php","offset":200}
```
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\resources\\views\\layouts\\footer.php","limit":40}
```
### Tool Ripgrep Raw Search
```
{"pattern":"btn more|section_standart|\\.table","path":"c:\\OSPanel\\home\\inbi.loc\\public\\src\\styles","glob":"*.css","caseInsensitive":false,"headLimit":30,"multiline":false,"toolCallId":"call-c111085b-8b07-4dae-b7fd-38c897948a4b-30\nfc_1d867c24-b1a6-999e-9951-112d4b7acdb8_3","offset":0}
```
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
## Assistant
Исправляю роут логина и создаю представления со стримингом.
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Ripgrep Raw Search
```
{"pattern":"view\\.|ViewService|Blade::|php.*engine","path":"c:\\OSPanel\\home\\inbi.loc\\app","caseInsensitive":false,"multiline":false,"toolCallId":"call-42d263c3-33d6-4c5a-9966-4b83dbcddae0-58\nfc_8947bc98-4f7f-9842-a860-006af133fd7c_0","offset":0}
```
### Tool Glob File Search
```
{"targetDirectory":"c:\\OSPanel\\home\\inbi.loc","globPattern":"**/AppServiceProvider.php"}
```
### Tool Ripgrep Raw Search
```
{"pattern":"\\.php|addExtension|view","path":"c:\\OSPanel\\home\\inbi.loc\\config","caseInsensitive":false,"multiline":false,"toolCallId":"call-42d263c3-33d6-4c5a-9966-4b83dbcddae0-60\nfc_8947bc98-4f7f-9842-a860-006af133fd7c_2","offset":0}
```
### Tool Edit File V2
### Tool Run Terminal Command V2
### Tool Todo Write
## Assistant
БД сейчас недоступна — попробую применить миграции через MySQL MCP и проверю код на ошибки.
### Tool Get Mcp Tools
```
{"server":"user-MySQL","toolCallId":"call-7539f1ce-2a92-4a7a-a5b7-9776c0ac4126-64\nfc_e0cced8e-68ce-9f42-a3ae-19b6735b2e70_0"}
```
### Tool Run Terminal Command V2
### Tool Edit File V2
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\routes\\web.php","offset":300,"limit":90}
```
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
## Assistant
Готово. Кратко по пунктам:
### 1. Пароль мастера
- Поле `cabinet_password` в модели `Master` (уникальное)
- При создании генерируется автоматически; в админке можно изменить или нажать «Сгенерировать»
- Миграция: `2026_07_22_000001_add_cabinet_password_to_masters_table.php` (для существующих мастеров пароли тоже проставятся)
### 2. Кабинет мастера
- `/master/cabinet/login` — вход по паролю
- `/master/cabinet` — таблица онлайн-занятий (`hall = Online`) с днём и временем
- Кнопка «Начать трансляцию» — в день занятия, с −15 мин до старта и до конца слота (часовой пояс `Europe/Moscow`)
### 3. Трансляция
- `/master/cabinet/broadcast/{id}` — камера/микрофон в браузере
- Сигналинг WebRTC через Laravel (cache); медиа — напрямую браузер↔браузер (STUN Google)
- За зрителями NAT может понадобиться свой TURN-сервер
### 4. Временная страница зрителей (без меню)
- `/online-streams` — все онлайн-занятия + «Присоединиться к трансляции»
- `/online-streams/{id}` — просмотр эфира (ждёт старта, если ещё не в эфире)
**Важно:** MySQL сейчас недоступен, миграции не применились. Когда БД будет запущена:
```bash
php artisan migrate
```
## User
При старте трансляции мастером, вроде как, появляется окно видео и камера активна, но в консоли браузера ошибки:
2
33:187 poll error OperationError: Failed to execute 'setRemoteDescription' on 'RTCPeerConnection': Failed to parse SessionDescription. a=rtpmap:126 telephone-event/8000 Invalid SDP line.
at handleOffer (33:134:18)
at poll (33:172:27)
6
33:150 ICE add failed InvalidStateError: Failed to execute 'addIceCandidate' on 'RTCPeerConnection': The remote description was null
33:187 poll error OperationError: Failed to execute 'setRemoteDescription' on 'RTCPeerConnection': Failed to parse SessionDescription. a=rtpmap:126 telephone-event/8000 Invalid SDP line.
at handleOffer (33:134:18)
at poll (33:172:27)
6
33:150 ICE add failed InvalidStateError: Failed to execute 'addIceCandidate' on 'RTCPeerConnection': The remote description was null
А у клиента, который смотрит трансляцию, все застревает на "Подключение к трансляции…". Дальше трансляция не начинается, никаких ошибок в браузере нет
## Assistant
Ошибка парсинга SDP обычно из‑за порчи описания при передаче через JSON/cache. Исправлю сериализацию SDP и буферизацию ICE-кандидатов.
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\resources\\views\\master\\cabinet\\broadcast.php"}
```
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\resources\\views\\online_streams\\watch.php"}
```
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\app\\Services\\WebRtcSignalingService.php"}
```
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\app\\Http\\Controllers\\MasterCabinetController.php","offset":130,"limit":80}
```
## Assistant
SDP ломается при сериализации через cache. Переведу сигналинг на явный JSON и нормализую SDP/ICE.
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
## Assistant
Для надёжности закодирую SDP в base64 — так переносы строк не смогут повредиться в cache/MySQL.
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
## Assistant
Причина была в повреждении SDP при проходе через PHP/cache: переносы строк ломались, Chrome не мог разобрать строку `a=rtpmap:126 telephone-event/8000`, handshake не завершался, зритель зависал на «Подключение…». Ошибки ICE шли уже как следствие.
Что изменено:
- SDP передаётся в **base64** (`sdp_b64`)
- сигналинг в cache хранится как **JSON**, а не PHP-serialize
- ICE-кандидаты **буферизуются**, пока не установлен remote description
Обновите обе страницы (hard refresh) и попробуйте снова: мастер начинает эфир → зритель заходит на `/online-streams/{id}`. У мастера в счётчике зрителей должно появиться `1`, у зрителя — «Вы в эфире».
## User
Теперь опиши, как реализована эта трансляция, с помощью каких технологий? Ее слабые стороны.
## Assistant
Сверю реализацию по коду и опишу архитектуру, технологии и ограничения.
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\app\\Services\\WebRtcSignalingService.php","limit":40}
```
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\app\\Models\\LiveBroadcast.php"}
```
### Tool Ripgrep Raw Search
```
{"pattern":"RTCPeerConnection|WebRtc|live_broadcast","path":"c:\\OSPanel\\home\\inbi.loc","glob":"*.{php,js}","caseInsensitive":false,"headLimit":30,"multiline":false,"toolCallId":"tool_1736a574-dff2-4a63-83d6-bac48c903d0","offset":0}
```
## Assistant
## Как устроена трансляция
Это **не классический стриминг через медиасервер** (не RTMP, не HLS, не YouTube-подобный эфир). Реализован **WebRTC в браузере** с **P2P-моделью**: видео и аудио идут напрямую между браузером мастера и браузером зрителя. Laravel выступает только как **сигнальный сервер** и хранит состояние эфира.
```mermaid
sequenceDiagram
participant M as Браузер мастера
participant L as Laravel (HTTP + Cache)
participant V as Браузер зрителя
M->>L: POST /master/cabinet/broadcast/{id}/stop (старт эфира)
L->>L: live_broadcasts (status=live)
V->>L: GET /online-streams/{id}/status
V->>L: POST signal (offer SDP)
L->>L: Cache queue
M->>L: GET signal/poll (каждые ~800ms)
L-->>M: offer от зрителя
M->>L: POST signal (answer + ICE)
L-->>V: GET signal/poll → answer
M<<->>V: WebRTC P2P (видео/аудио напрямую)
```
---
## Технологии
| Слой | Что используется |
|------|------------------|
| Фронт | Обычные PHP-views + vanilla JavaScript |
| Видео в браузере | **WebRTC API**: `getUserMedia`, `RTCPeerConnection` |
| Сигналинг | HTTP **long polling** (`/signal/poll` раз в ~800–1000 мс) |
| Обмен SDP/ICE | JSON через Laravel, SDP в **base64** (`sdp_b64`) |
| Очередь сигналов | **Laravel Cache** (`WebRtcSignalingService`) |
| Состояние эфира | MySQL, таблица `live_broadcasts` |
| NAT traversal | Только **STUN** (`stun:stun.l.google.com:19302`) |
| Авторизация мастера | Сессия `master_cabinet_id` по паролю `cabinet_password` |
| Зритель | Без авторизации, `viewer_id` = session id |
### Поток мастера
1. Вход в `/master/cabinet` по паролю.
2. «Начать трансляцию» → запись в `live_broadcasts`, страница `/master/cabinet/broadcast/{scheduleId}`.
3. Браузер запрашивает камеру/микрофон (`getUserMedia`).
4. На каждого зрителя — отдельный `RTCPeerConnection`, мастер отвечает на offer зрителя answer’ом.
### Поток зрителя
1. `/online-streams` → «Присоединиться» → `/online-streams/{scheduleId}`.
2. Ожидание `status: live`.
3. Создаётся `RTCPeerConnection` (только приём: `recvonly`).
4. Отправляется **offer**, по polling приходит **answer** и ICE-кандидаты.
5. После handshake видео идёт **напрямую с браузера мастера**.
---
## Что важно понимать
**Видео через Laravel не проходит.** Сервер не кодирует, не транскодирует и не раздаёт поток — только помогает браузерам договориться (SDP/ICE).
Это **mesh-топология**: один мастер → N отдельных P2P-соединений. Не SFU (Selective Forwarding Unit) и не MCU.
---
## Слабые стороны
### 1. Масштабируемость
- Каждый зритель = отдельное соединение у мастера.
- Камера/микрофон кодируются и отправляются N раз с одного ПК.
- На практике обычно **2–5 зрителей**, дальше нагрузка на CPU и сеть мастера растёт быстро.
### 2. NAT и сети без TURN
- Есть только STUN, **TURN-сервера нет**.
- За строгим NAT, корпоративным файрволом или мобильным CGNAT соединение часто **не устанавливается** — зритель зависает на «Подключение…» без явной ошибки.
### 3. Polling вместо WebSocket
- Сигналинг через HTTP polling каждые ~800 мс.
- Медленнее установка связи, лишняя нагрузка на сервер, хуже при многих зрителях.
### 4. Cache как шина сообщений
- Очереди в Laravel Cache (часто database/redis) — не для realtime.
- При нескольких PHP-воркерах возможны гонки и потеря сообщений.
- TTL 4 часа, нет гарантий доставки.
### 5. Нет записи и пересмотра
- Нет DVR, архива, HLS для iOS/Safari в фоне.
- Эфир только live, пока мастер в браузере.
### 6. Зависимость от браузера мастера
- Закрыл вкладку — эфир обрывается (если не нажал «Завершить»).
- Нет отдельного стримингового ПО (OBS и т.п.).
### 7. Безопасность и доступ
- Зритель без авторизации: любой со ссылкой может смотреть.
- Пароль мастера в БД в открытом виде (не хэш).
- Нет rate limiting на сигналинг.
### 8. Качество и адаптация
- Нет адаптивного битрейта (как у HLS).
- Качество зависит от uplink мастера и числа зрителей.
- Нет модерации, чата, синхронизации.
### 9. Ограничения WebRTC в браузере
- Нужен **HTTPS** (кроме localhost).
- На iOS/Safari возможны особенности с autoplay и фоном.
- Разные браузеры — разное поведение ICE.
---
## Когда этого достаточно
Подходит для **внутреннего пилота**: 1 мастер, 1–3 зрителя, оба в нормальной сети, короткие занятия.
## Когда нужно менять архитектуру
Для продакшена с десятками зрителей обычно ставят **медиасервер**:
- **LiveKit**, **Janus**, **mediasoup** — WebRTC SFU
- **MediaMTX** — WHIP/WHEP или RTMP → HLS
- **Cloudflare Stream**, **Mux**, **Agora** — managed-решения
Тогда видео идёт: **мастер → сервер → зрители**, а не P2P с ноутбука мастера.
---
**Итог:** сейчас это лёгкий WebRTC P2P-прототип на Laravel для сигналинга. Для регулярных онлайн-занятий с надёжностью и масштабом понадобится медиасервер и, как минимум, TURN + WebSocket для сигналинга.
## User
Давай переделаем, чтобы видео шло через сервер и HLS, чтобы была возможность, во-первых, регулировать доступ, во-вторых, записывать записи, и в-третьих, оно нормально работало при 50 зрителях.
## Assistant
Переведём трансляцию на серверный HLS (MediaMTX): изучу текущую реализацию и спроектирую архитектуру с контролем доступа и записью.
### Tool New agent
### Tool Get Mcp Tools
```
{"server":"user-context7","toolName":"resolve-library-id","toolCallId":"tool_4ab702c7-fa98-47a2-aeee-4d0e647f98d"}
```
### Tool Mcp
```
{"name":"user-context7-resolve-library-id","args":{"libraryName":"MediaMTX","query":"MediaMTX WHIP ingest HLS output recording configuration paths"},"toolCallId":"tool_d757b1e2-4d9a-4450-a32b-4f0b3879796","providerIdentifier":"context7","toolName":"resolve-library-id","smartModeApprovalOnly":false,"skipApproval":false}
```
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\app\\Http\\Controllers\\MasterCabinetController.php"}
```
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\app\\Http\\Controllers\\OnlineStreamController.php"}
```
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\app\\Models\\UserAbonement.php","limit":80}
```
### Tool Mcp
```
{"name":"user-context7-query-docs","args":{"libraryId":"/bluenviron/mediamtx","query":"WHIP publish browser HLS playback recording configuration yaml paths recordPath"},"toolCallId":"tool_0f0ade97-7c2e-4b98-9fbc-3e4a147f05f","providerIdentifier":"context7","toolName":"query-docs","smartModeApprovalOnly":false,"skipApproval":false}
```
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\app\\Models\\LiveBroadcast.php"}
```
### Tool Ripgrep Raw Search
```
{}
```
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\app\\Http\\Controllers\\Admin\\ScheduleAdminController.php","limit":120}
```
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\config\\filesystems.php"}
```
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\.env.example","limit":50}
```
### Tool Ripgrep Raw Search
```
{"pattern":"hall|Online","path":"c:\\OSPanel\\home\\inbi.loc\\resources\\views\\admin\\schedules","caseInsensitive":false,"multiline":false,"toolCallId":"tool_a51d5063-1e14-43ec-9f3e-fa04fe50a36","offset":0}
```
### Tool Todo Write
## Assistant
Создаю серверную HLS-архитектуру на MediaMTX с контролем доступа и записью.
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Delete File
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\app\\Services\\WebRtcSignalingService.php","toolCallId":"tool_f9eda6a4-6bd2-4d77-a33f-30986112359"}
```
### Tool Edit File V2
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\resources\\views\\admin\\schedules\\index.php","offset":60,"limit":40}
```
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\resources\\views\\admin\\schedules\\index.php","offset":560,"limit":40}
```
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\resources\\views\\admin\\schedules\\index.php","offset":285,"limit":30}
```
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\resources\\views\\admin\\schedules\\index.php","offset":475,"limit":30}
```
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\resources\\views\\admin\\schedules\\index.php","offset":735,"limit":30}
```
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\resources\\views\\admin\\schedules\\index.php","offset":375,"limit":40}
```
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\resources\\views\\admin\\schedules\\index.php","offset":500,"limit":30}
```
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\app\\Http\\Controllers\\Admin\\ScheduleAdminController.php","offset":120,"limit":80}
```
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\app\\Http\\Controllers\\Admin\\ScheduleAdminController.php","offset":198,"limit":60}
```
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Ripgrep Raw Search
```
{"pattern":"stream_access","path":"c:\\OSPanel\\home\\inbi.loc\\resources\\views\\admin\\schedules\\index.php","caseInsensitive":false,"multiline":false,"toolCallId":"tool_fde9f911-6740-41d4-93bc-85a1031e613","offset":0}
```
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\resources\\views\\admin\\schedules\\index.php","offset":74,"limit":25}
```
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\resources\\views\\admin\\schedules\\index.php","offset":76,"limit":15}
```
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\resources\\views\\master\\cabinet\\broadcast.php","limit":35}
```
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Ripgrep Raw Search
```
{"pattern":"motion","path":"c:\\OSPanel\\home\\inbi.loc\\resources\\views\\master\\cabinet\\broadcast.php","caseInsensitive":false,"multiline":false,"toolCallId":"tool_8c52f8ae-6a76-41e7-b74e-ee3597ecbbb","offset":0}
```
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Ripgrep Raw Search
```
{"pattern":"motion","path":"c:\\OSPanel\\home\\inbi.loc\\resources\\views","caseInsensitive":false,"multiline":false,"toolCallId":"tool_3724c97a-0477-4f2c-a90e-c6bedbb4a3d","offset":0}
```
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Run Terminal Command V2
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\resources\\views\\online_streams\\watch.php","limit":35}
```
### Tool Todo Write
## Assistant
Трансляция переведена с P2P WebRTC на **серверный HLS через MediaMTX**.
## Новая архитектура
```mermaid
flowchart LR
M[Браузер мастера] -->|WHIP WebRTC| MTX[MediaMTX]
MTX -->|HLS сегменты| L[Laravel proxy]
L -->|подписанный URL| V[Зрители hls.js]
MTX -->|fMP4 запись| DISK[storage/stream-recordings]
```
| Компонент | Роль |
|-----------|------|
| **MediaMTX** | Принимает поток от мастера (WHIP), отдаёт HLS, пишет запись на диск |
| **Laravel** | Контроль доступа, подписанные HLS-URL, прокси плейлиста/сегментов |
| **hls.js** | Воспроизведение у зрителей (50+ без нагрузки на ПК мастера) |
## Что сделано
1. **MediaMTX** — `docker-compose.yml`, `docker/mediamtx/mediamtx.yml`
2. **Миграция** — `stream_key`, `recording_*` в `live_broadcasts`; `stream_access` в `schedules`; таблица `stream_recordings`
3. **Доступ к просмотру** (`schedules.stream_access`):
- `public` — всем
- `authenticated` — только вошедшим (по умолчанию)
- `abonement` — только с активным абонементом
4. **HLS-прокси** — `/stream/hls/{scheduleId}/{file}` с подписью и проверкой доступа
5. **Записи** — MediaMTX пишет fMP4; после остановки эфира `FinalizeStreamRecordingJob` сохраняет метаданные; просмотр через `/stream/recordings/{id}`
6. **Админка расписания** — поле «Доступ к трансляции» для онлайн-занятий
7. **Удалён** старый P2P-сигналинг (`WebRtcSignalingService`)
## Запуск
**1. Миграции:**
```bash
php artisan migrate
```
**2. MediaMTX:**
```bash
docker compose up -d
```
**3. `.env`:**
```env
STREAMING_WHIP_PUBLIC_URL=https://stream.inbi.ru # HTTPS для камеры в браузере
STREAMING_HLS_INTERNAL_URL=http://127.0.0.1:8888 # только для Laravel
STREAMING_API_URL=http://127.0.0.1:9997
```
**4. Nginx** — проксировать `stream.inbi.ru` на порт `8889` (WHIP). Порт `8888` (HLS) **не открывать** наружу — только Laravel.
**5. Очередь** (для обработки записей):
```bash
php artisan queue:work
```
## Как это работает
- **Мастер:** `/master/cabinet/broadcast/{id}` → камера → WHIP → MediaMTX
- **Зритель:** `/online-streams/{id}` → проверка доступа → hls.js → Laravel-прокси → MediaMTX
- **Запись:** после «Завершить трансляцию» файл появляется в `storage/app/stream-recordings/`, доступен на странице занятия
## Важно
- WHIP **обязательно по HTTPS** (кроме localhost) — иначе браузер не даст камеру
- Для 50 зрителей HLS достаточно; при росте нагрузки можно поставить nginx-кэш перед HLS или CDN
- Записи сейчас автоматически `published=true`; при необходимости можно добавить модерацию в админке
Если нужно — могу подготовить пример конфига nginx для `stream.inbi.ru` под ваш OSPanel.
## User
Что там в докере? Не будет ли оно конфликтовать с текущим nginx на сервере?
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\docker-compose.yml"}
```
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\docker\\mediamtx\\mediamtx.yml"}
```
## Assistant
В Docker сейчас **только MediaMTX** — один контейнер, без nginx и без Laravel.
## Что поднимается
| Порт | Назначение |
|------|------------|
| **8888** | HLS (внутренний, Laravel ходит сюда за плейлистом/сегментами) |
| **8889** | WHIP — приём потока от браузера мастера |
| **9997** | API MediaMTX (healthcheck/управление) |
Сайт по-прежнему обслуживает ваш текущий nginx (80/443) → PHP/Laravel.
## Конфликт с nginx?
**Нет**, если nginx слушает только 80 и 443. MediaMTX занимает другие порты.
Конфликт возможен только если на сервере уже что-то слушает **8888 / 8889 / 9997**.
## Как они должны жить рядом
```
Интернет
│
├─ :443 nginx → Laravel (test.inbi.ru, админка…)
│ │
│ └── HTTP → 127.0.0.1:8888 (HLS, только с сервера)
│
└─ :443 nginx → proxy_pass http://127.0.0.1:8889 (WHIP для мастера)
│
Docker MediaMTX
```
- Laravel **сам** проксирует HLS зрителям — порт 8888 наружу открывать не нужно.
- Порт 8889 лучше **не светить в интернет напрямую**, а проксировать через nginx по HTTPS (иначе камера в браузере не заработает на проде).
## Если порты заняты
В `docker-compose.yml` можно сменить маппинг, например:
```yaml
ports:
- "127.0.0.1:18888:8888"
- "127.0.0.1:18889:8889"
- "127.0.0.1:19997:9997"
```
и поправить `.env`:
```env
STREAMING_HLS_INTERNAL_URL=http://127.0.0.1:18888
STREAMING_WHIP_PUBLIC_URL=https://stream.inbi.ru # через nginx
STREAMING_API_URL=http://127.0.0.1:19997
```
Привязка к `127.0.0.1` ещё и безопаснее: порты видны только с самой машины, не снаружи.
**Итог:** Docker не заменяет nginx и не конфликтует с ним по 80/443. Это отдельный медиасервер на других портах; nginx остаётся фронтом и при необходимости только проксирует WHIP.
## User
Ок. Скажи, что сейчас надо прописать в nginx, чтобы это заработало
## Assistant
Сверю, какие URL сейчас ожидает приложение, и дам готовый фрагмент для nginx.
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\config\\streaming.php"}
```
### Tool Ripgrep Raw Search
```
{"pattern":"STREAMING_|whip|8889|8888","path":"c:\\OSPanel\\home\\inbi.loc","glob":"*.{php,yml,env.example,md}","caseInsensitive":false,"multiline":false,"toolCallId":"call-a06a94f1-3e46-468e-b639-d7d31f461416-172\nfc_0cb4e356-885d-9b23-93c9-f10f8047979e_1","offset":0}
```
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\resources\\views\\master\\cabinet\\broadcast.php","offset":40,"limit":50}
```
## Assistant
Нужно проксировать **только WHIP** (порт 8889). HLS (8888) и API (9997) в nginx **не открывать** — Laravel ходит к ним сам по `127.0.0.1`.
## 1. `.env`
```env
STREAMING_WHIP_PUBLIC_URL=https://stream.inbi.ru
STREAMING_HLS_INTERNAL_URL=http://127.0.0.1:8888
STREAMING_API_URL=http://127.0.0.1:9997
```
Сайт мастера (`test.inbi.ru`) и WHIP (`stream.inbi.ru`) — разные домены, поэтому в nginx нужны CORS.
## 2. DNS
`stream.inbi.ru` → IP сервера (A-запись).
## 3. Nginx — отдельный vhost
```nginx
# /etc/nginx/sites-available/stream.inbi.ru
map $http_origin $stream_cors_origin {
default "";
"https://test.inbi.ru" $http_origin;
"https://inbi.ru" $http_origin;
"https://www.inbi.ru" $http_origin;
}
server {
listen 80;
server_name stream.inbi.ru;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name stream.inbi.ru;
# свои пути к сертификатам
ssl_certificate /etc/letsencrypt/live/stream.inbi.ru/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/stream.inbi.ru/privkey.pem;
# WHIP / WebRTC signaling → MediaMTX :8889
location / {
if ($request_method = OPTIONS) {
add_header Access-Control-Allow-Origin $stream_cors_origin always;
add_header Access-Control-Allow-Methods "GET, POST, OPTIONS, DELETE, PATCH" always;
add_header Access-Control-Allow-Headers "Content-Type, Authorization" always;
add_header Access-Control-Expose-Headers "Location, Link" always;
add_header Access-Control-Max-Age 86400 always;
add_header Content-Length 0;
add_header Content-Type text/plain;
return 204;
}
proxy_pass http://127.0.0.1:8889;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# WHIP отдаёт Location сессии — переписываем на публичный HTTPS
proxy_redirect http://127.0.0.1:8889/ https://stream.inbi.ru/;
proxy_redirect http://localhost:8889/ https://stream.inbi.ru/;
proxy_pass_header Location;
proxy_hide_header Access-Control-Allow-Origin;
add_header Access-Control-Allow-Origin $stream_cors_origin always;
add_header Access-Control-Allow-Methods "GET, POST, OPTIONS, DELETE, PATCH" always;
add_header Access-Control-Allow-Headers "Content-Type, Authorization" always;
add_header Access-Control-Expose-Headers "Location, Link" always;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
client_max_body_size 0;
}
}
```
Включить и проверить:
```bash
sudo ln -s /etc/nginx/sites-available/stream.inbi.ru /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
```
Сертификат, если через certbot:
```bash
sudo certbot --nginx -d stream.inbi.ru
```
## 4. UDP для медиа (иначе WHIP подключится, а картинки не будет)
Сигналинг идёт по HTTPS через nginx, а **видео/аудио WebRTC — по UDP**. MediaMTX по умолчанию слушает UDP `:8189`.
В `docker-compose.yml` добавьте порт:
```yaml
ports:
- "8888:8888"
- "8889:8889"
- "8189:8189/udp"
- "9997:9997"
```
В `docker/mediamtx/mediamtx.yml` укажите публичный адрес сервера:
```yaml
webrtcAddress: :8889
webrtcLocalUDPAddress: :8189
webrtcAdditionalHosts: [stream.inbi.ru]
# или публичный IP:
# webrtcAdditionalHosts: [1.2.3.4]
```
В файрволе откройте **UDP 8189**.
## 5. Что не трогать
| Порт | В nginx |
|------|---------|
| 80/443 текущего сайта | без изменений |
| 8888 HLS | не публиковать |
| 9997 API | не публиковать |
Зрители смотрят через Laravel: `/stream/hls/...` на `test.inbi.ru` — отдельный stream-vhost им не нужен.
## 6. Проверка
```bash
docker compose up -d
curl -I https://stream.inbi.ru/
```
Потом: мастер на `https://test.inbi.ru/master/cabinet` → «Начать трансляцию». Если в консоли CORS/WHIP 502 — смотрите, что MediaMTX слушает `127.0.0.1:8889` и origin сайта есть в `map`.
## User
root@vm736755:~# sudo certbot --nginx -d stream.inbi.ru
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Error while running nginx -c /etc/nginx/nginx.conf -t.
2026/07/22 18:25:00 [emerg] 2894280#2894280: cannot load certificate "/etc/letsencrypt/live/stream.inbi.ru/fullchain.pem": BIO_new_file() failed (SSL: error:80000002:system library::No such file or directory:calling fopen(/etc/letsencrypt/live/stream.inbi.ru/fullchain.pem, r) error:10000080:BIO routines::no such file)
nginx: configuration file /etc/nginx/nginx.conf test failed
The nginx plugin is not working; there may be problems with your existing configuration.
The error was: MisconfigurationError('Error while running nginx -c /etc/nginx/nginx.conf -t.\n\n2026/07/22 18:25:00 [emerg] 2894280#2894280: cannot load certificate "/etc/letsencrypt/live/stream.inbi.ru/fullchain.pem": BIO_new_file() failed (SSL: error:80000002:system library::No such file or directory:calling fopen(/etc/letsencrypt/live/stream.inbi.ru/fullchain.pem, r) error:10000080:BIO routines::no such file)\nnginx: configuration file /etc/nginx/nginx.conf test failed\n')
## Assistant
Это классическая «курица и яйцо»: в nginx уже прописаны пути к сертификату, которого ещё нет, поэтому `nginx -t` падает и certbot не может продолжить.
## Что сделать
### 1. Временно убрать HTTPS-блок для `stream.inbi.ru`
Оставьте **только HTTP** (порт 80):
```nginx
server {
listen 80;
server_name stream.inbi.ru;
location / {
proxy_pass http://127.0.0.1:8889;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
client_max_body_size 0;
}
}
```
Блок `listen 443 ssl` с `ssl_certificate ... stream.inbi.ru` **закомментируйте или удалите**.
### 2. Проверить и перезагрузить nginx
```bash
sudo nginx -t
sudo systemctl reload nginx
```
### 3. Выпустить сертификат
```bash
sudo certbot --nginx -d stream.inbi.ru
```
Certbot сам добавит HTTPS и редирект с 80 на 443.
### 4. После certbot — вернуть CORS и WHIP-настройки
В HTTPS-блок (который certbot создаст или обновит) добавьте `map` и заголовки из прошлой инструкции:
```nginx
map $http_origin $stream_cors_origin {
default "";
"https://test.inbi.ru" $http_origin;
"https://inbi.ru" $http_origin;
}
# внутри server { listen 443 ssl; ... location / { ... } }
```
И снова:
```bash
sudo nginx -t && sudo systemctl reload nginx
```
---
## Если certbot снова ругается
Выпустите сертификат отдельно, без правки nginx:
```bash
sudo certbot certonly --nginx -d stream.inbi.ru
```
или через webroot, если сайт уже отдаётся:
```bash
sudo certbot certonly --webroot -w /var/www/html -d stream.inbi.ru
```
Потом вручную пропишите в HTTPS-блоке:
```nginx
ssl_certificate /etc/letsencrypt/live/stream.inbi.ru/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/stream.inbi.ru/privkey.pem;
```
---
## Перед certbot проверьте
```bash
dig +short stream.inbi.ru
curl -I http://stream.inbi.ru/
```
DNS должен указывать на этот сервер, а с 80-го порта nginx должен отвечать (не 502).
**Итог:** сначала nginx только на HTTP без ссылок на несуществующий `.pem`, потом certbot, потом полный HTTPS-конфиг с CORS.
## User
root@vm736755:/var/www/inbi# sudo certbot --nginx -d stream.inbi.ru
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Requesting a certificate for stream.inbi.ru
Encountered exception during recovery: certbot.errors.MisconfigurationError: nginx restart failed:
nginx: [emerg] bind() to 0.0.0.0:443 failed (98: Address already in use)
nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
nginx: [emerg] bind() to [::]:80 failed (98: Address already in use)
nginx: [emerg] bind() to 0.0.0.0:443 failed (98: Address already in use)
nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
nginx: [emerg] bind() to [::]:80 failed (98: Address already in use)
nginx: [emerg] bind() to 0.0.0.0:443 failed (98: Address already in use)
nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
nginx: [emerg] bind() to [::]:80 failed (98: Address already in use)
nginx: [emerg] bind() to 0.0.0.0:443 failed (98: Address already in use)
nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
nginx: [emerg] bind() to [::]:80 failed (98: Address already in use)
nginx: [emerg] bind() to 0.0.0.0:443 failed (98: Address already in use)
nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
nginx: [emerg] bind() to [::]:80 failed (98: Address already in use)
nginx: [emerg] still could not bind()
nginx restart failed:
nginx: [emerg] bind() to 0.0.0.0:443 failed (98: Address already in use)
nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
nginx: [emerg] bind() to [::]:80 failed (98: Address already in use)
nginx: [emerg] bind() to 0.0.0.0:443 failed (98: Address already in use)
nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
nginx: [emerg] bind() to [::]:80 failed (98: Address already in use)
nginx: [emerg] bind() to 0.0.0.0:443 failed (98: Address already in use)
nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
nginx: [emerg] bind() to [::]:80 failed (98: Address already in use)
nginx: [emerg] bind() to 0.0.0.0:443 failed (98: Address already in use)
nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
nginx: [emerg] bind() to [::]:80 failed (98: Address already in use)
nginx: [emerg] bind() to 0.0.0.0:443 failed (98: Address already in use)
nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
nginx: [emerg] bind() to [::]:80 failed (98: Address already in use)
nginx: [emerg] still could not bind()
Ask for help or search for solutions at https://community.letsencrypt.org. See the logfile /var/log/letsencrypt/letsencrypt.log or re-run Certbot with -v for more details.
root@vm736755:/var/www/inbi#
## Assistant
Сертификат, скорее всего, уже почти выпущен, а упал именно **рестарт nginx**: certbot пытается поднять второй nginx, пока старый всё ещё держит 80/443.
Обойдите плагин `--nginx` и выпустите сертификат отдельно.
## Вариант A (предпочтительный): webroot
Пока nginx уже слушает 80 для `stream.inbi.ru`:
```bash
# 1. Убедитесь, что HTTP-блок stream.inbi.ru отдаёт ACME-челлендж
# В location / или отдельным location:
# location ^~ /.well-known/acme-challenge/ {
# root /var/www/certbot;
# default_type text/plain;
# }
sudo mkdir -p /var/www/certbot
sudo nginx -t && sudo systemctl reload nginx
# 2. Только сертификат, без рестарта nginx
sudo certbot certonly --webroot -w /var/www/certbot -d stream.inbi.ru
```
В HTTP-конфиге `stream.inbi.ru` добавьте **выше** `location /`:
```nginx
location ^~ /.well-known/acme-challenge/ {
root /var/www/certbot;
default_type text/plain;
}
location / {
proxy_pass http://127.0.0.1:8889;
# ...
}
```
## Вариант B: остановить nginx на время
```bash
sudo systemctl stop nginx
sudo certbot certonly --standalone -d stream.inbi.ru
sudo systemctl start nginx
```
---
## После успешного выпуска
Проверьте, что файлы есть:
```bash
sudo ls -la /etc/letsencrypt/live/stream.inbi.ru/
```
Добавьте HTTPS-блок (или верните тот, что был) с этими путями:
```nginx
ssl_certificate /etc/letsencrypt/live/stream.inbi.ru/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/stream.inbi.ru/privkey.pem;
```
И:
```bash
sudo nginx -t
sudo systemctl reload nginx
```
Не `restart`, а именно `reload` — так не будет конфликта bind.
---
## Если после неудачного certbot nginx «битый»
```bash
sudo ss -tlnp | grep -E ':80|:443'
sudo systemctl status nginx
sudo nginx -t
```
Если висит несколько nginx или порт занят «зомби»:
```bash
sudo systemctl stop nginx
# при необходимости: sudo pkill nginx
sudo systemctl start nginx
```
---
## Почему так
`certbot --nginx` сам правит конфиг и делает restart. У вас порт уже занят рабочим nginx → второй процесс не биндится → ошибка 98.
`certbot certonly` только кладёт сертификат в `/etc/letsencrypt/live/...`, а конфиг nginx вы правите сами и делаете `reload`.
После `certonly` пришлите вывод `ls /etc/letsencrypt/live/stream.inbi.ru/` — подскажу точный HTTPS-блок под ваш текущий HTTP-конфиг.
## User
root@vm736755:/etc/nginx/sites-available# sudo systemctl stop nginx
root@vm736755:/etc/nginx/sites-available# service nginx stop
root@vm736755:/etc/nginx/sites-available# sudo certbot certonly --standalone -d stream.inbi.ru
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Requesting a certificate for stream.inbi.ru
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Could not bind TCP port 80 because it is already in use by another process on
this system (such as a web server). Please stop the program in question and then
try again.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(R)etry/(C)ancel: c
Could not bind TCP port 80 because it is already in use by another process on this system (such as a web server). Please stop the program in question and then try again.
Ask for help or search for solutions at https://community.letsencrypt.org. See the logfile /var/log/letsencrypt/letsencrypt.log or re-run Certbot with -v for more details.
## Assistant
Порт 80 всё ещё занят — это не обязательно nginx. Найдите процесс и либо остановите его, либо возьмите сертификат через webroot.
## 1. Кто держит 80/443
```bash
sudo ss -tlnp | grep -E ':80|:443'
# или
sudo lsof -i :80 -i :443
```
Часто это бывает:
- ещё один nginx (`nginx: master`)
- Apache (`apache2` / `httpd`)
- Caddy, Traefik, Docker-прокси
- другой экземпляр nginx не через systemd
## 2. Если это nginx / apache
```bash
# nginx
ps aux | grep nginx
sudo pkill -9 nginx
# apache
sudo systemctl stop apache2
# или
sudo systemctl stop httpd
```
Потом снова:
```bash
sudo ss -tlnp | grep ':80'
sudo certbot certonly --standalone -d stream.inbi.ru
sudo systemctl start nginx
```
## 3. Надёжнее: не трогать порт 80 — webroot
Если 80 должен оставаться у nginx (сайт живой), **не используйте standalone**.
Сначала поднимите nginx обратно:
```bash
sudo systemctl start nginx
```
Добавьте в HTTP-блок `stream.inbi.ru`:
```nginx
server {
listen 80;
server_name stream.inbi.ru;
location ^~ /.well-known/acme-challenge/ {
root /var/www/certbot;
default_type text/plain;
}
location / {
proxy_pass http://127.0.0.1:8889;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
```
```bash
sudo mkdir -p /var/www/certbot
sudo nginx -t && sudo systemctl reload nginx
# проверка снаружи
curl -I http://stream.inbi.ru/.well-known/acme-challenge/test
sudo certbot certonly --webroot -w /var/www/certbot -d stream.inbi.ru
```
После успеха:
```bash
sudo ls /etc/letsencrypt/live/stream.inbi.ru/
```
И уже тогда добавляйте `listen 443 ssl` с этими сертификатами + `reload`.
---
Пришлите вывод:
```bash
sudo ss -tlnp | grep -E ':80|:443'
```
по нему сразу скажу, что именно останавливать.
## User
root@vm736755:/var/www/inbi# docker compose up -d
unknown shorthand flag: 'd' in -d
Usage: docker [OPTIONS] COMMAND [ARG...]
Run 'docker --help' for more information
## Assistant
На сервере, скорее всего, **нет Docker Compose v2** (плагин `docker compose`), поэтому флаг `-d` «ломается» на уровне CLI.
## Проверьте, что есть
```bash
docker --version
docker compose version # v2-плагин
docker-compose --version # старый отдельный бинарь
```
## Если есть старый `docker-compose` (с дефисом)
```bash
cd /var/www/inbi
sudo docker-compose up -d
```
## Если нет ни того, ни другого — поставьте Compose v2
Ubuntu/Debian:
```bash
sudo apt-get update
sudo apt-get install -y docker-compose-plugin
docker compose version
cd /var/www/inbi
sudo docker compose up -d
```
Или пакет со старым именем:
```bash
sudo apt-get install -y docker-compose
cd /var/www/inbi
sudo docker-compose up -d
```
## Проверка, что MediaMTX поднялся
```bash
sudo docker ps
curl -I http://127.0.0.1:8888/
curl -I http://127.0.0.1:8889/
```
---
**Важно:** `docker compose` (пробел) и `docker-compose` (дефис) — разные команды. У вас сработала первая без плагина — используйте вторую или поставьте `docker-compose-plugin`.
## User
Теперь трансляция включается, пишет "Эфир идёт — зрители смотрят через HLS".
Но зрители видят "Подключение к трансляции…" и больше ничего не показывает
## Assistant
Проверю цепочку HLS: от подписанного URL зрителя до проксирования плейлиста из MediaMTX.
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\app\\Services\\Streaming\\HlsProxyService.php"}
```
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\app\\Http\\Controllers\\StreamHlsController.php"}
```
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\app\\Services\\Streaming\\MediaMtxService.php"}
```
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\resources\\views\\online_streams\\watch.php"}
```
### Tool Mcp
```
{"name":"user-context7-query-docs","args":{"libraryId":"/bluenviron/mediamtx","query":"HLS playlist URL path format index.m3u8 segment names after WHIP publish"},"toolCallId":"call-ebdeef46-be53-4653-8a22-6faf0d658abf-178\nfc_922f4d2e-d2a9-94cc-b35a-1fa3f63271be_4","providerIdentifier":"context7","toolName":"query-docs","smartModeApprovalOnly":false,"skipApproval":false}
```
## Assistant
Нашёл несколько вероятных причин: не переписываются URI в `EXT-X-MAP` (fMP4 у MediaMTX), всегда тянется только `index.m3u8`, и подписанные URL могут строиться с неверным `APP_URL`. Исправляю.
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\routes\\web.php","offset":348,"limit":30}
```
### Tool Ripgrep Raw Search
```
{"pattern":"APP_URL|forceRootUrl|URL::","path":"c:\\OSPanel\\home\\inbi.loc\\config\\app.php","caseInsensitive":false,"multiline":false,"toolCallId":"call-1950057e-d7c3-4621-972a-6f9a6ed9442f-180\nfc_5dd73608-06ba-9511-8178-cbd71b2f8726_1","offset":0}
```
### Tool Mcp
```
{"name":"user-context7-query-docs","args":{"libraryId":"/bluenviron/mediamtx","query":"hlsVariant fMP4 EXT-X-MAP default HLS segment format"},"toolCallId":"call-1950057e-d7c3-4621-972a-6f9a6ed9442f-181\nfc_5dd73608-06ba-9511-8178-cbd71b2f8726_2","providerIdentifier":"context7","toolName":"query-docs","smartModeApprovalOnly":false,"skipApproval":false}
```
## Assistant
Перевожу HLS на query-параметр `file` (надёжнее для подписи) и корректно переписываю URI в плейлисте MediaMTX.
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Run Terminal Command V2
## Assistant
Исправил типичные причины зависания на «Подключение…».
## Что было не так
1. MediaMTX отдаёт **fMP4 HLS** с `EXT-X-MAP:URI="init.mp4"` — эти URI **не переписывались** в подписанные ссылки → сегменты шли без signature → 403.
2. Подписанный URL зависел от `APP_URL` (часто `localhost`) — плейлист мог открываться на неверный хост.
3. HLS у MediaMTX по умолчанию стартует **только при первом зрителе** → первые запросы давали 503.
## Что сделано
- Переписываются и обычные строки плейлиста, и `URI="..."` в тегах
- Подписанные URL **относительные** (`/stream/hls/...?file=...&signature=...`)
- `file` в query, а не в path
- В MediaMTX: `hlsAlwaysRemux: yes`, `hlsVariant: fmp4`
- На странице зрителя — диагностика HTTP-статуса плейлиста и ретраи
## Что сделать на сервере
```bash
cd /var/www/inbi
# обновить код, затем:
sudo docker-compose restart
# или: sudo docker compose restart
# очистить кэш конфига Laravel
php artisan config:clear
php artisan route:clear
```
Потом:
1. Мастер заново запускает эфир
2. Зритель обновляет страницу (hard refresh)
Если снова «Подключение…» — на странице зрителя теперь должен появиться конкретный текст вроде `Плейлист: HTTP 503` или `403`. Пришлите его.
Быстрая проверка с сервера, пока мастер в эфире (подставьте `stream_key` из БД):
```bash
curl -sI "http://127.0.0.1:8888/live/STREAM_KEY/index.m3u8"
```
Должен быть `200`. Если `404` — поток до MediaMTX не доходит / неверный key.
## User
Теперь ошибка у зрителя 33:131 GET https://test.inbi.ru/stream/hls/33?expires=1784762693&file=index.m3u8&signature=f301a9ecf19ed5f6c70bf3ca5a733ffb8c7c4a73c9f66464238ffba62456575d 403 (Forbidden)
## Assistant
Похоже, подпись генерируется как относительный URL, а проверяется как абсолютный — из‑за этого Laravel отдаёт 403. Исправляю.
### Tool Edit File V2
### Tool Edit File V2
## Assistant
Для записей URL абсолютный — верну проверку подписи; для HLS оставлю relative.
### Tool Edit File V2
## Assistant
Причина: плейлист подписывался как **относительный** URL (`/stream/hls/...?signature=...`), а проверка шла как для **абсолютного** (`https://test.inbi.ru/...`) — подписи не совпадали → 403.
Исправление: `hasValidSignature(false)`.
Залейте правку на сервер, обновите страницу зрителя (лучше hard refresh) и попробуйте снова. Если снова 403 — в ответе будет текст; пришлите его (там уже будет понятно: подпись или доступ).
## User
Теперь у зрителя показывается "вы в эфире", но у видео черный экран, и в браузере:
33:96 HLS error {type: 'mediaError', details: 'fragGap', fatal: false, frag: e, error: Error: GAP tag found
at si (https://cdn.jsdelivr.net/npm/hls.js@1.5.7/dist/hls.min.js:1:115860)…, …}
(anonymous) @ 33:96
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ base-stream-controller.ts:843
(anonymous) @ base-stream-controller.ts:789
Promise.catch
(anonymous) @ base-stream-controller.ts:789
(anonymous) @ base-stream-controller.ts:370
(anonymous) @ base-stream-controller.ts:346
(anonymous) @ stream-controller.ts:380
(anonymous) @ stream-controller.ts:356
(anonymous) @ stream-controller.ts:211
(anonymous) @ task-loop.ts:106
(anonymous) @ base-stream-controller.ts:545
(anonymous) @ base-stream-controller.ts:524
Promise.then
(anonymous) @ base-stream-controller.ts:478
(anonymous) @ stream-controller.ts:372
(anonymous) @ stream-controller.ts:356
(anonymous) @ stream-controller.ts:211
(anonymous) @ task-loop.ts:106
(anonymous) @ stream-controller.ts:696
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:683
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
set @ level-controller.ts:477
set @ level-controller.ts:629
set @ hls.ts:574
(anonymous) @ stream-controller.ts:143
(anonymous) @ hls.ts:434
(anonymous) @ hls.ts:433
(anonymous) @ level-controller.ts:376
(anonymous) @ level-controller.ts:200
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:429
onSuccess @ playlist-loader.ts:327
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:154
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ hls.ts:420
startHls @ 33:92
(anonymous) @ 33:142
Promise.then
(anonymous) @ 33:132
(anonymous) @ 33:145
33:96 HLS error {type: 'mediaError', details: 'fragGap', fatal: false, frag: e, error: Error: GAP tag found
at si (https://cdn.jsdelivr.net/npm/hls.js@1.5.7/dist/hls.min.js:1:115860)…, …}
(anonymous) @ 33:96
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ base-stream-controller.ts:843
(anonymous) @ base-stream-controller.ts:789
Promise.catch
(anonymous) @ base-stream-controller.ts:789
(anonymous) @ base-stream-controller.ts:370
(anonymous) @ base-stream-controller.ts:346
(anonymous) @ stream-controller.ts:380
(anonymous) @ stream-controller.ts:356
(anonymous) @ stream-controller.ts:211
(anonymous) @ task-loop.ts:106
setTimeout
(anonymous) @ task-loop.ts:119
(anonymous) @ base-stream-controller.ts:1566
(anonymous) @ stream-controller.ts:900
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ base-stream-controller.ts:843
(anonymous) @ base-stream-controller.ts:789
Promise.catch
(anonymous) @ base-stream-controller.ts:789
(anonymous) @ base-stream-controller.ts:370
(anonymous) @ base-stream-controller.ts:346
(anonymous) @ stream-controller.ts:380
(anonymous) @ stream-controller.ts:356
(anonymous) @ stream-controller.ts:211
(anonymous) @ task-loop.ts:106
(anonymous) @ base-stream-controller.ts:545
(anonymous) @ base-stream-controller.ts:524
Promise.then
(anonymous) @ base-stream-controller.ts:478
(anonymous) @ stream-controller.ts:372
(anonymous) @ stream-controller.ts:356
(anonymous) @ stream-controller.ts:211
(anonymous) @ task-loop.ts:106
(anonymous) @ stream-controller.ts:696
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:683
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
set @ level-controller.ts:477
set @ level-controller.ts:629
set @ hls.ts:574
(anonymous) @ stream-controller.ts:143
(anonymous) @ hls.ts:434
(anonymous) @ hls.ts:433
(anonymous) @ level-controller.ts:376
(anonymous) @ level-controller.ts:200
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:429
onSuccess @ playlist-loader.ts:327
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:154
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ hls.ts:420
startHls @ 33:92
(anonymous) @ 33:142
Promise.then
(anonymous) @ 33:132
(anonymous) @ 33:145
33:96 HLS error {type: 'mediaError', details: 'fragGap', fatal: false, frag: e, error: Error: GAP tag found
at si (https://cdn.jsdelivr.net/npm/hls.js@1.5.7/dist/hls.min.js:1:115860)…, …}
(anonymous) @ 33:96
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ base-stream-controller.ts:843
(anonymous) @ base-stream-controller.ts:789
Promise.catch
(anonymous) @ base-stream-controller.ts:789
(anonymous) @ base-stream-controller.ts:370
(anonymous) @ base-stream-controller.ts:346
(anonymous) @ stream-controller.ts:380
(anonymous) @ stream-controller.ts:356
(anonymous) @ stream-controller.ts:211
(anonymous) @ task-loop.ts:106
setTimeout
(anonymous) @ task-loop.ts:119
(anonymous) @ base-stream-controller.ts:294
seeking
(anonymous) @ stream-controller.ts:1028
(anonymous) @ base-stream-controller.ts:601
(anonymous) @ stream-controller.ts:884
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ buffer-controller.ts:605
(anonymous) @ buffer-controller.ts:1137
Promise.then
(anonymous) @ buffer-controller.ts:1135
(anonymous) @ buffer-controller.ts:619
(anonymous) @ index.js:182
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ base-stream-controller.ts:1758
(anonymous) @ base-stream-controller.ts:875
(anonymous) @ transmuxer-interface.ts:376
(anonymous) @ transmuxer-interface.ts:92
postMessage
Bn @ 5bc75f4f-adc9-4843-b9c8-053afbcfea23:1
(anonymous) @ 5bc75f4f-adc9-4843-b9c8-053afbcfea23:1
Worker.postMessage
(anonymous) @ transmuxer-interface.ts:296
(anonymous) @ base-stream-controller.ts:627
(anonymous) @ base-stream-controller.ts:394
Promise.then
(anonymous) @ base-stream-controller.ts:371
(anonymous) @ base-stream-controller.ts:346
(anonymous) @ stream-controller.ts:380
(anonymous) @ stream-controller.ts:356
(anonymous) @ stream-controller.ts:211
(anonymous) @ task-loop.ts:106
setTimeout
(anonymous) @ task-loop.ts:119
(anonymous) @ base-stream-controller.ts:1566
(anonymous) @ stream-controller.ts:900
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ base-stream-controller.ts:843
(anonymous) @ base-stream-controller.ts:789
Promise.catch
(anonymous) @ base-stream-controller.ts:789
(anonymous) @ base-stream-controller.ts:370
(anonymous) @ base-stream-controller.ts:346
(anonymous) @ stream-controller.ts:380
(anonymous) @ stream-controller.ts:356
(anonymous) @ stream-controller.ts:211
(anonymous) @ task-loop.ts:106
setTimeout
(anonymous) @ task-loop.ts:119
(anonymous) @ base-stream-controller.ts:1566
(anonymous) @ stream-controller.ts:900
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ base-stream-controller.ts:843
(anonymous) @ base-stream-controller.ts:789
Promise.catch
(anonymous) @ base-stream-controller.ts:789
(anonymous) @ base-stream-controller.ts:370
(anonymous) @ base-stream-controller.ts:346
(anonymous) @ stream-controller.ts:380
(anonymous) @ stream-controller.ts:356
(anonymous) @ stream-controller.ts:211
(anonymous) @ task-loop.ts:106
(anonymous) @ base-stream-controller.ts:545
(anonymous) @ base-stream-controller.ts:524
Promise.then
(anonymous) @ base-stream-controller.ts:478
(anonymous) @ stream-controller.ts:372
(anonymous) @ stream-controller.ts:356
(anonymous) @ stream-controller.ts:211
(anonymous) @ task-loop.ts:106
(anonymous) @ stream-controller.ts:696
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:683
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
set @ level-controller.ts:477
set @ level-controller.ts:629
set @ hls.ts:574
(anonymous) @ stream-controller.ts:143
(anonymous) @ hls.ts:434
(anonymous) @ hls.ts:433
(anonymous) @ level-controller.ts:376
(anonymous) @ level-controller.ts:200
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:429
onSuccess @ playlist-loader.ts:327
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:154
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ hls.ts:420
startHls @ 33:92
(anonymous) @ 33:142
Promise.then
(anonymous) @ 33:132
(anonymous) @ 33:145
33:96 HLS error {type: 'mediaError', details: 'fragGap', fatal: false, frag: e, error: Error: GAP tag found
at si (https://cdn.jsdelivr.net/npm/hls.js@1.5.7/dist/hls.min.js:1:115860)…, …}
(anonymous) @ 33:96
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ base-stream-controller.ts:843
(anonymous) @ base-stream-controller.ts:789
Promise.catch
(anonymous) @ base-stream-controller.ts:789
(anonymous) @ base-stream-controller.ts:370
(anonymous) @ base-stream-controller.ts:346
(anonymous) @ stream-controller.ts:380
(anonymous) @ stream-controller.ts:356
(anonymous) @ stream-controller.ts:211
(anonymous) @ task-loop.ts:106
setTimeout
(anonymous) @ task-loop.ts:119
(anonymous) @ base-stream-controller.ts:1566
(anonymous) @ stream-controller.ts:900
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ base-stream-controller.ts:843
(anonymous) @ base-stream-controller.ts:789
Promise.catch
(anonymous) @ base-stream-controller.ts:789
(anonymous) @ base-stream-controller.ts:370
(anonymous) @ base-stream-controller.ts:346
(anonymous) @ stream-controller.ts:380
(anonymous) @ stream-controller.ts:356
(anonymous) @ stream-controller.ts:211
(anonymous) @ task-loop.ts:106
setTimeout
(anonymous) @ task-loop.ts:119
(anonymous) @ base-stream-controller.ts:294
seeking
(anonymous) @ stream-controller.ts:1028
(anonymous) @ base-stream-controller.ts:601
(anonymous) @ stream-controller.ts:884
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ buffer-controller.ts:605
(anonymous) @ buffer-controller.ts:1137
Promise.then
(anonymous) @ buffer-controller.ts:1135
(anonymous) @ buffer-controller.ts:619
(anonymous) @ index.js:182
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ base-stream-controller.ts:1758
(anonymous) @ base-stream-controller.ts:875
(anonymous) @ transmuxer-interface.ts:376
(anonymous) @ transmuxer-interface.ts:92
postMessage
Bn @ 5bc75f4f-adc9-4843-b9c8-053afbcfea23:1
(anonymous) @ 5bc75f4f-adc9-4843-b9c8-053afbcfea23:1
Worker.postMessage
(anonymous) @ transmuxer-interface.ts:296
(anonymous) @ base-stream-controller.ts:627
(anonymous) @ base-stream-controller.ts:394
Promise.then
(anonymous) @ base-stream-controller.ts:371
(anonymous) @ base-stream-controller.ts:346
(anonymous) @ stream-controller.ts:380
(anonymous) @ stream-controller.ts:356
(anonymous) @ stream-controller.ts:211
(anonymous) @ task-loop.ts:106
setTimeout
(anonymous) @ task-loop.ts:119
(anonymous) @ base-stream-controller.ts:1566
(anonymous) @ stream-controller.ts:900
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ base-stream-controller.ts:843
(anonymous) @ base-stream-controller.ts:789
Promise.catch
(anonymous) @ base-stream-controller.ts:789
(anonymous) @ base-stream-controller.ts:370
(anonymous) @ base-stream-controller.ts:346
(anonymous) @ stream-controller.ts:380
(anonymous) @ stream-controller.ts:356
(anonymous) @ stream-controller.ts:211
(anonymous) @ task-loop.ts:106
setTimeout
(anonymous) @ task-loop.ts:119
(anonymous) @ base-stream-controller.ts:1566
(anonymous) @ stream-controller.ts:900
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ base-stream-controller.ts:843
(anonymous) @ base-stream-controller.ts:789
Promise.catch
(anonymous) @ base-stream-controller.ts:789
(anonymous) @ base-stream-controller.ts:370
(anonymous) @ base-stream-controller.ts:346
(anonymous) @ stream-controller.ts:380
(anonymous) @ stream-controller.ts:356
(anonymous) @ stream-controller.ts:211
(anonymous) @ task-loop.ts:106
(anonymous) @ base-stream-controller.ts:545
(anonymous) @ base-stream-controller.ts:524
Promise.then
(anonymous) @ base-stream-controller.ts:478
(anonymous) @ stream-controller.ts:372
(anonymous) @ stream-controller.ts:356
(anonymous) @ stream-controller.ts:211
(anonymous) @ task-loop.ts:106
(anonymous) @ stream-controller.ts:696
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:683
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
set @ level-controller.ts:477
set @ level-controller.ts:629
set @ hls.ts:574
(anonymous) @ stream-controller.ts:143
(anonymous) @ hls.ts:434
(anonymous) @ hls.ts:433
(anonymous) @ level-controller.ts:376
(anonymous) @ level-controller.ts:200
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:429
onSuccess @ playlist-loader.ts:327
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:154
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ hls.ts:420
startHls @ 33:92
(anonymous) @ 33:142
Promise.then
(anonymous) @ 33:132
(anonymous) @ 33:145
xhr-loader.ts:166 GET https://test.inbi.ru/stream/hls/33?expires=1784762851&file=audio1_stream.m3u8&signature=b039966d9f35c6ddc100ea808238529a39e4f99c86b1979722cd8d6553d6be11&_HLS_msn=8&_HLS_part=4&_HLS_skip=YES 403 (Forbidden)
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:287
setTimeout
(anonymous) @ base-playlist-controller.ts:286
(anonymous) @ level-controller.ts:571
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:683
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
set @ level-controller.ts:477
set @ level-controller.ts:629
set @ hls.ts:574
(anonymous) @ stream-controller.ts:143
(anonymous) @ hls.ts:434
(anonymous) @ hls.ts:433
(anonymous) @ level-controller.ts:376
(anonymous) @ level-controller.ts:200
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:429
onSuccess @ playlist-loader.ts:327
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:154
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ hls.ts:420
startHls @ 33:92
(anonymous) @ 33:142
Promise.then
(anonymous) @ 33:132
(anonymous) @ 33:145
33:96 HLS error {type: 'networkError', details: 'levelLoadError', fatal: false, url: 'https://test.inbi.ru/stream/hls/33?expires=1784762…8d6553d6be11&_HLS_msn=8&_HLS_part=4&_HLS_skip=YES', loader: t, …}
(anonymous) @ 33:96
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:612
onError @ playlist-loader.ts:331
(anonymous) @ xhr-loader.ts:253
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:287
setTimeout
(anonymous) @ base-playlist-controller.ts:286
(anonymous) @ level-controller.ts:571
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:683
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
set @ level-controller.ts:477
set @ level-controller.ts:629
set @ hls.ts:574
(anonymous) @ stream-controller.ts:143
(anonymous) @ hls.ts:434
(anonymous) @ hls.ts:433
(anonymous) @ level-controller.ts:376
(anonymous) @ level-controller.ts:200
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:429
onSuccess @ playlist-loader.ts:327
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:154
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ hls.ts:420
startHls @ 33:92
(anonymous) @ 33:142
Promise.then
(anonymous) @ 33:132
(anonymous) @ 33:145
33:96 HLS error {type: 'mediaError', details: 'bufferStalledError', fatal: false, error: Error: Playback stalling at @6.942816 due to low buffer ({"len":0.057184000000000346,"start":6,"end…, buffer: 0.057184000000000346, …}
(anonymous) @ 33:96
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ gap-controller.ts:234
(anonymous) @ gap-controller.ts:157
(anonymous) @ stream-controller.ts:946
(anonymous) @ stream-controller.ts:218
(anonymous) @ stream-controller.ts:213
(anonymous) @ task-loop.ts:106
setInterval
(anonymous) @ task-loop.ts:68
(anonymous) @ stream-controller.ts:127
(anonymous) @ hls.ts:434
(anonymous) @ hls.ts:433
(anonymous) @ level-controller.ts:376
(anonymous) @ level-controller.ts:200
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:429
onSuccess @ playlist-loader.ts:327
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:154
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ hls.ts:420
startHls @ 33:92
(anonymous) @ 33:142
Promise.then
(anonymous) @ 33:132
(anonymous) @ 33:145
xhr-loader.ts:166 GET https://test.inbi.ru/stream/hls/33?expires=1784762851&file=audio1_stream.m3u8&signature=b039966d9f35c6ddc100ea808238529a39e4f99c86b1979722cd8d6553d6be11&_HLS_msn=10&_HLS_part=4&_HLS_skip=YES 403 (Forbidden)
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:287
setTimeout
(anonymous) @ base-playlist-controller.ts:286
(anonymous) @ level-controller.ts:571
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:683
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:337
setTimeout
(anonymous) @ base-playlist-controller.ts:337
(anonymous) @ level-controller.ts:529
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:612
onError @ playlist-loader.ts:331
(anonymous) @ xhr-loader.ts:253
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:287
setTimeout
(anonymous) @ base-playlist-controller.ts:286
(anonymous) @ level-controller.ts:571
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:683
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
set @ level-controller.ts:477
set @ level-controller.ts:629
set @ hls.ts:574
(anonymous) @ stream-controller.ts:143
(anonymous) @ hls.ts:434
(anonymous) @ hls.ts:433
(anonymous) @ level-controller.ts:376
(anonymous) @ level-controller.ts:200
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:429
onSuccess @ playlist-loader.ts:327
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:154
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ hls.ts:420
startHls @ 33:92
(anonymous) @ 33:142
Promise.then
(anonymous) @ 33:132
(anonymous) @ 33:145
33:96 HLS error {type: 'networkError', details: 'levelLoadError', fatal: false, url: 'https://test.inbi.ru/stream/hls/33?expires=1784762…d6553d6be11&_HLS_msn=10&_HLS_part=4&_HLS_skip=YES', loader: t, …}
(anonymous) @ 33:96
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:612
onError @ playlist-loader.ts:331
(anonymous) @ xhr-loader.ts:253
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:287
setTimeout
(anonymous) @ base-playlist-controller.ts:286
(anonymous) @ level-controller.ts:571
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:683
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:337
setTimeout
(anonymous) @ base-playlist-controller.ts:337
(anonymous) @ level-controller.ts:529
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:612
onError @ playlist-loader.ts:331
(anonymous) @ xhr-loader.ts:253
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:287
setTimeout
(anonymous) @ base-playlist-controller.ts:286
(anonymous) @ level-controller.ts:571
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:683
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
set @ level-controller.ts:477
set @ level-controller.ts:629
set @ hls.ts:574
(anonymous) @ stream-controller.ts:143
(anonymous) @ hls.ts:434
(anonymous) @ hls.ts:433
(anonymous) @ level-controller.ts:376
(anonymous) @ level-controller.ts:200
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:429
onSuccess @ playlist-loader.ts:327
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:154
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ hls.ts:420
startHls @ 33:92
(anonymous) @ 33:142
Promise.then
(anonymous) @ 33:132
(anonymous) @ 33:145
xhr-loader.ts:166 GET https://test.inbi.ru/stream/hls/33?expires=1784762851&file=audio1_stream.m3u8&signature=b039966d9f35c6ddc100ea808238529a39e4f99c86b1979722cd8d6553d6be11&_HLS_msn=12&_HLS_part=4&_HLS_skip=YES 403 (Forbidden)
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:287
setTimeout
(anonymous) @ base-playlist-controller.ts:286
(anonymous) @ level-controller.ts:571
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:683
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:337
setTimeout
(anonymous) @ base-playlist-controller.ts:337
(anonymous) @ level-controller.ts:529
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:612
onError @ playlist-loader.ts:331
(anonymous) @ xhr-loader.ts:253
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:287
setTimeout
(anonymous) @ base-playlist-controller.ts:286
(anonymous) @ level-controller.ts:571
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:683
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:337
setTimeout
(anonymous) @ base-playlist-controller.ts:337
(anonymous) @ level-controller.ts:529
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:612
onError @ playlist-loader.ts:331
(anonymous) @ xhr-loader.ts:253
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:287
setTimeout
(anonymous) @ base-playlist-controller.ts:286
(anonymous) @ level-controller.ts:571
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:683
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
set @ level-controller.ts:477
set @ level-controller.ts:629
set @ hls.ts:574
(anonymous) @ stream-controller.ts:143
(anonymous) @ hls.ts:434
(anonymous) @ hls.ts:433
(anonymous) @ level-controller.ts:376
(anonymous) @ level-controller.ts:200
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:429
onSuccess @ playlist-loader.ts:327
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:154
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ hls.ts:420
startHls @ 33:92
(anonymous) @ 33:142
Promise.then
(anonymous) @ 33:132
(anonymous) @ 33:145
33:96 HLS error {type: 'networkError', details: 'levelLoadError', fatal: false, url: 'https://test.inbi.ru/stream/hls/33?expires=1784762…d6553d6be11&_HLS_msn=12&_HLS_part=4&_HLS_skip=YES', loader: t, …}
(anonymous) @ 33:96
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:612
onError @ playlist-loader.ts:331
(anonymous) @ xhr-loader.ts:253
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:287
setTimeout
(anonymous) @ base-playlist-controller.ts:286
(anonymous) @ level-controller.ts:571
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:683
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:337
setTimeout
(anonymous) @ base-playlist-controller.ts:337
(anonymous) @ level-controller.ts:529
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:612
onError @ playlist-loader.ts:331
(anonymous) @ xhr-loader.ts:253
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:287
setTimeout
(anonymous) @ base-playlist-controller.ts:286
(anonymous) @ level-controller.ts:571
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:683
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:337
setTimeout
(anonymous) @ base-playlist-controller.ts:337
(anonymous) @ level-controller.ts:529
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:612
onError @ playlist-loader.ts:331
(anonymous) @ xhr-loader.ts:253
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:287
setTimeout
(anonymous) @ base-playlist-controller.ts:286
(anonymous) @ level-controller.ts:571
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:683
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
set @ level-controller.ts:477
set @ level-controller.ts:629
set @ hls.ts:574
(anonymous) @ stream-controller.ts:143
(anonymous) @ hls.ts:434
(anonymous) @ hls.ts:433
(anonymous) @ level-controller.ts:376
(anonymous) @ level-controller.ts:200
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:429
onSuccess @ playlist-loader.ts:327
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:154
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ hls.ts:420
startHls @ 33:92
(anonymous) @ 33:142
Promise.then
(anonymous) @ 33:132
(anonymous) @ 33:145
xhr-loader.ts:166 GET https://test.inbi.ru/stream/hls/33?expires=1784762851&file=audio1_stream.m3u8&signature=b039966d9f35c6ddc100ea808238529a39e4f99c86b1979722cd8d6553d6be11&_HLS_msn=14&_HLS_part=1&_HLS_skip=YES 403 (Forbidden)
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:228
(anonymous) @ level-controller.ts:571
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:683
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:337
setTimeout
(anonymous) @ base-playlist-controller.ts:337
(anonymous) @ level-controller.ts:529
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:612
onError @ playlist-loader.ts:331
(anonymous) @ xhr-loader.ts:253
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:287
setTimeout
(anonymous) @ base-playlist-controller.ts:286
(anonymous) @ level-controller.ts:571
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:683
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:337
setTimeout
(anonymous) @ base-playlist-controller.ts:337
(anonymous) @ level-controller.ts:529
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:612
onError @ playlist-loader.ts:331
(anonymous) @ xhr-loader.ts:253
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:287
setTimeout
(anonymous) @ base-playlist-controller.ts:286
(anonymous) @ level-controller.ts:571
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:683
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:337
setTimeout
(anonymous) @ base-playlist-controller.ts:337
(anonymous) @ level-controller.ts:529
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:612
onError @ playlist-loader.ts:331
(anonymous) @ xhr-loader.ts:253
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:287
setTimeout
(anonymous) @ base-playlist-controller.ts:286
(anonymous) @ level-controller.ts:571
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:683
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
set @ level-controller.ts:477
set @ level-controller.ts:629
set @ hls.ts:574
(anonymous) @ stream-controller.ts:143
(anonymous) @ hls.ts:434
(anonymous) @ hls.ts:433
(anonymous) @ level-controller.ts:376
(anonymous) @ level-controller.ts:200
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:429
onSuccess @ playlist-loader.ts:327
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:154
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ hls.ts:420
startHls @ 33:92
(anonymous) @ 33:142
Promise.then
(anonymous) @ 33:132
(anonymous) @ 33:145
33:96 HLS error {type: 'networkError', details: 'levelLoadError', fatal: false, url: 'https://test.inbi.ru/stream/hls/33?expires=1784762…d6553d6be11&_HLS_msn=14&_HLS_part=1&_HLS_skip=YES', loader: t, …}
(anonymous) @ 33:96
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:612
onError @ playlist-loader.ts:331
(anonymous) @ xhr-loader.ts:253
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:228
(anonymous) @ level-controller.ts:571
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:683
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:337
setTimeout
(anonymous) @ base-playlist-controller.ts:337
(anonymous) @ level-controller.ts:529
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:612
onError @ playlist-loader.ts:331
(anonymous) @ xhr-loader.ts:253
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:287
setTimeout
(anonymous) @ base-playlist-controller.ts:286
(anonymous) @ level-controller.ts:571
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:683
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:337
setTimeout
(anonymous) @ base-playlist-controller.ts:337
(anonymous) @ level-controller.ts:529
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:612
onError @ playlist-loader.ts:331
(anonymous) @ xhr-loader.ts:253
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:287
setTimeout
(anonymous) @ base-playlist-controller.ts:286
(anonymous) @ level-controller.ts:571
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:683
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:337
setTimeout
(anonymous) @ base-playlist-controller.ts:337
(anonymous) @ level-controller.ts:529
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:612
onError @ playlist-loader.ts:331
(anonymous) @ xhr-loader.ts:253
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:287
setTimeout
(anonymous) @ base-playlist-controller.ts:286
(anonymous) @ level-controller.ts:571
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:683
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
set @ level-controller.ts:477
set @ level-controller.ts:629
set @ hls.ts:574
(anonymous) @ stream-controller.ts:143
(anonymous) @ hls.ts:434
(anonymous) @ hls.ts:433
(anonymous) @ level-controller.ts:376
(anonymous) @ level-controller.ts:200
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:429
onSuccess @ playlist-loader.ts:327
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:154
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ hls.ts:420
startHls @ 33:92
(anonymous) @ 33:142
Promise.then
(anonymous) @ 33:132
(anonymous) @ 33:145
xhr-loader.ts:166 GET https://test.inbi.ru/stream/hls/33?expires=1784762851&file=audio1_stream.m3u8&signature=b039966d9f35c6ddc100ea808238529a39e4f99c86b1979722cd8d6553d6be11&_HLS_msn=15&_HLS_part=2&_HLS_skip=YES 403 (Forbidden)
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:228
(anonymous) @ level-controller.ts:571
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:683
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:337
setTimeout
(anonymous) @ base-playlist-controller.ts:337
(anonymous) @ level-controller.ts:529
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:612
onError @ playlist-loader.ts:331
(anonymous) @ xhr-loader.ts:253
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:228
(anonymous) @ level-controller.ts:571
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:683
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:337
setTimeout
(anonymous) @ base-playlist-controller.ts:337
(anonymous) @ level-controller.ts:529
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:612
onError @ playlist-loader.ts:331
(anonymous) @ xhr-loader.ts:253
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:287
setTimeout
(anonymous) @ base-playlist-controller.ts:286
(anonymous) @ level-controller.ts:571
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:683
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:337
setTimeout
(anonymous) @ base-playlist-controller.ts:337
(anonymous) @ level-controller.ts:529
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:612
onError @ playlist-loader.ts:331
(anonymous) @ xhr-loader.ts:253
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:287
setTimeout
(anonymous) @ base-playlist-controller.ts:286
(anonymous) @ level-controller.ts:571
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:683
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:337
setTimeout
(anonymous) @ base-playlist-controller.ts:337
(anonymous) @ level-controller.ts:529
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:612
onError @ playlist-loader.ts:331
(anonymous) @ xhr-loader.ts:253
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:287
setTimeout
(anonymous) @ base-playlist-controller.ts:286
(anonymous) @ level-controller.ts:571
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:683
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
set @ level-controller.ts:477
set @ level-controller.ts:629
set @ hls.ts:574
(anonymous) @ stream-controller.ts:143
(anonymous) @ hls.ts:434
(anonymous) @ hls.ts:433
(anonymous) @ level-controller.ts:376
(anonymous) @ level-controller.ts:200
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:429
onSuccess @ playlist-loader.ts:327
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:154
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ hls.ts:420
startHls @ 33:92
(anonymous) @ 33:142
Promise.then
(anonymous) @ 33:132
(anonymous) @ 33:145
33:96 HLS error {type: 'networkError', details: 'levelLoadError', fatal: false, url: 'https://test.inbi.ru/stream/hls/33?expires=1784762…d6553d6be11&_HLS_msn=15&_HLS_part=2&_HLS_skip=YES', loader: t, …}
(anonymous) @ 33:96
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:612
onError @ playlist-loader.ts:331
(anonymous) @ xhr-loader.ts:253
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:228
(anonymous) @ level-controller.ts:571
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:683
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:337
setTimeout
(anonymous) @ base-playlist-controller.ts:337
(anonymous) @ level-controller.ts:529
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:612
onError @ playlist-loader.ts:331
(anonymous) @ xhr-loader.ts:253
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:228
(anonymous) @ level-controller.ts:571
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:683
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:337
setTimeout
(anonymous) @ base-playlist-controller.ts:337
(anonymous) @ level-controller.ts:529
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:612
onError @ playlist-loader.ts:331
(anonymous) @ xhr-loader.ts:253
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:287
setTimeout
(anonymous) @ base-playlist-controller.ts:286
(anonymous) @ level-controller.ts:571
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:683
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:337
setTimeout
(anonymous) @ base-playlist-controller.ts:337
(anonymous) @ level-controller.ts:529
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:612
onError @ playlist-loader.ts:331
(anonymous) @ xhr-loader.ts:253
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:287
setTimeout
(anonymous) @ base-playlist-controller.ts:286
(anonymous) @ level-controller.ts:571
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:683
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:337
setTimeout
(anonymous) @ base-playlist-controller.ts:337
(anonymous) @ level-controller.ts:529
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:612
onError @ playlist-loader.ts:331
(anonymous) @ xhr-loader.ts:253
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:287
setTimeout
(anonymous) @ base-playlist-controller.ts:286
(anonymous) @ level-controller.ts:571
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:683
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
set @ level-controller.ts:477
set @ level-controller.ts:629
set @ hls.ts:574
(anonymous) @ stream-controller.ts:143
(anonymous) @ hls.ts:434
(anonymous) @ hls.ts:433
(anonymous) @ level-controller.ts:376
(anonymous) @ level-controller.ts:200
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:429
onSuccess @ playlist-loader.ts:327
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:154
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ hls.ts:420
startHls @ 33:92
(anonymous) @ 33:142
Promise.then
(anonymous) @ 33:132
(anonymous) @ 33:145
xhr-loader.ts:166 GET https://test.inbi.ru/stream/hls/33?expires=1784762851&file=audio1_stream.m3u8&signature=b039966d9f35c6ddc100ea808238529a39e4f99c86b1979722cd8d6553d6be11&_HLS_msn=16&_HLS_part=4&_HLS_skip=YES 403 (Forbidden)
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:228
(anonymous) @ level-controller.ts:571
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:683
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:337
setTimeout
(anonymous) @ base-playlist-controller.ts:337
(anonymous) @ level-controller.ts:529
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:612
onError @ playlist-loader.ts:331
(anonymous) @ xhr-loader.ts:253
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:228
(anonymous) @ level-controller.ts:571
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:683
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:337
setTimeout
(anonymous) @ base-playlist-controller.ts:337
(anonymous) @ level-controller.ts:529
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:612
onError @ playlist-loader.ts:331
(anonymous) @ xhr-loader.ts:253
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:228
(anonymous) @ level-controller.ts:571
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:683
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:337
setTimeout
(anonymous) @ base-playlist-controller.ts:337
(anonymous) @ level-controller.ts:529
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:612
onError @ playlist-loader.ts:331
(anonymous) @ xhr-loader.ts:253
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:287
setTimeout
(anonymous) @ base-playlist-controller.ts:286
(anonymous) @ level-controller.ts:571
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:683
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:337
setTimeout
(anonymous) @ base-playlist-controller.ts:337
(anonymous) @ level-controller.ts:529
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:612
onError @ playlist-loader.ts:331
(anonymous) @ xhr-loader.ts:253
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:287
setTimeout
(anonymous) @ base-playlist-controller.ts:286
(anonymous) @ level-controller.ts:571
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:683
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:337
setTimeout
(anonymous) @ base-playlist-controller.ts:337
(anonymous) @ level-controller.ts:529
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:612
onError @ playlist-loader.ts:331
(anonymous) @ xhr-loader.ts:253
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:287
setTimeout
(anonymous) @ base-playlist-controller.ts:286
(anonymous) @ level-controller.ts:571
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:683
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
set @ level-controller.ts:477
set @ level-controller.ts:629
set @ hls.ts:574
(anonymous) @ stream-controller.ts:143
(anonymous) @ hls.ts:434
(anonymous) @ hls.ts:433
(anonymous) @ level-controller.ts:376
(anonymous) @ level-controller.ts:200
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:429
onSuccess @ playlist-loader.ts:327
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:154
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ hls.ts:420
startHls @ 33:92
(anonymous) @ 33:142
Promise.then
(anonymous) @ 33:132
(anonymous) @ 33:145
33:96 HLS error {type: 'networkError', details: 'levelLoadError', fatal: false, url: 'https://test.inbi.ru/stream/hls/33?expires=1784762…d6553d6be11&_HLS_msn=16&_HLS_part=4&_HLS_skip=YES', loader: t, …}
(anonymous) @ 33:96
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:612
onError @ playlist-loader.ts:331
(anonymous) @ xhr-loader.ts:253
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:228
(anonymous) @ level-controller.ts:571
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:683
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:337
setTimeout
(anonymous) @ base-playlist-controller.ts:337
(anonymous) @ level-controller.ts:529
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:612
onError @ playlist-loader.ts:331
(anonymous) @ xhr-loader.ts:253
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:228
(anonymous) @ level-controller.ts:571
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:683
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:337
setTimeout
(anonymous) @ base-playlist-controller.ts:337
(anonymous) @ level-controller.ts:529
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:612
onError @ playlist-loader.ts:331
(anonymous) @ xhr-loader.ts:253
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:228
(anonymous) @ level-controller.ts:571
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:683
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:337
setTimeout
(anonymous) @ base-playlist-controller.ts:337
(anonymous) @ level-controller.ts:529
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:612
onError @ playlist-loader.ts:331
(anonymous) @ xhr-loader.ts:253
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:287
setTimeout
(anonymous) @ base-playlist-controller.ts:286
(anonymous) @ level-controller.ts:571
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:683
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:337
setTimeout
(anonymous) @ base-playlist-controller.ts:337
(anonymous) @ level-controller.ts:529
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:612
onError @ playlist-loader.ts:331
(anonymous) @ xhr-loader.ts:253
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:287
setTimeout
(anonymous) @ base-playlist-controller.ts:286
(anonymous) @ level-controller.ts:571
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:683
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:337
setTimeout
(anonymous) @ base-playlist-controller.ts:337
(anonymous) @ level-controller.ts:529
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:612
onError @ playlist-loader.ts:331
(anonymous) @ xhr-loader.ts:253
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:287
setTimeout
(anonymous) @ base-playlist-controller.ts:286
(anonymous) @ level-controller.ts:571
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:683
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
set @ level-controller.ts:477
set @ level-controller.ts:629
set @ hls.ts:574
(anonymous) @ stream-controller.ts:143
(anonymous) @ hls.ts:434
(anonymous) @ hls.ts:433
(anonymous) @ level-controller.ts:376
(anonymous) @ level-controller.ts:200
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:429
onSuccess @ playlist-loader.ts:327
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:154
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ hls.ts:420
startHls @ 33:92
(anonymous) @ 33:142
Promise.then
(anonymous) @ 33:132
(anonymous) @ 33:145
xhr-loader.ts:166 GET https://test.inbi.ru/stream/hls/33?expires=1784762851&file=audio1_stream.m3u8&signature=b039966d9f35c6ddc100ea808238529a39e4f99c86b1979722cd8d6553d6be11&_HLS_msn=18&_HLS_part=1&_HLS_skip=YES 403 (Forbidden)
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:228
(anonymous) @ level-controller.ts:571
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:683
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:337
setTimeout
(anonymous) @ base-playlist-controller.ts:337
(anonymous) @ level-controller.ts:529
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:612
onError @ playlist-loader.ts:331
(anonymous) @ xhr-loader.ts:253
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:228
(anonymous) @ level-controller.ts:571
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:683
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:337
setTimeout
(anonymous) @ base-playlist-controller.ts:337
(anonymous) @ level-controller.ts:529
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:612
onError @ playlist-loader.ts:331
(anonymous) @ xhr-loader.ts:253
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:228
(anonymous) @ level-controller.ts:571
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:683
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:337
setTimeout
(anonymous) @ base-playlist-controller.ts:337
(anonymous) @ level-controller.ts:529
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:612
onError @ playlist-loader.ts:331
(anonymous) @ xhr-loader.ts:253
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:228
(anonymous) @ level-controller.ts:571
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:683
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:337
setTimeout
(anonymous) @ base-playlist-controller.ts:337
(anonymous) @ level-controller.ts:529
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:612
onError @ playlist-loader.ts:331
(anonymous) @ xhr-loader.ts:253
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:287
setTimeout
(anonymous) @ base-playlist-controller.ts:286
(anonymous) @ level-controller.ts:571
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:683
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:337
setTimeout
(anonymous) @ base-playlist-controller.ts:337
(anonymous) @ level-controller.ts:529
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:612
onError @ playlist-loader.ts:331
(anonymous) @ xhr-loader.ts:253
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:287
setTimeout
(anonymous) @ base-playlist-controller.ts:286
(anonymous) @ level-controller.ts:571
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:683
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:337
setTimeout
(anonymous) @ base-playlist-controller.ts:337
(anonymous) @ level-controller.ts:529
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:612
onError @ playlist-loader.ts:331
(anonymous) @ xhr-loader.ts:253
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:287
setTimeout
(anonymous) @ base-playlist-controller.ts:286
(anonymous) @ level-controller.ts:571
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:683
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
set @ level-controller.ts:477
set @ level-controller.ts:629
set @ hls.ts:574
(anonymous) @ stream-controller.ts:143
(anonymous) @ hls.ts:434
(anonymous) @ hls.ts:433
(anonymous) @ level-controller.ts:376
(anonymous) @ level-controller.ts:200
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:429
onSuccess @ playlist-loader.ts:327
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:154
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ hls.ts:420
startHls @ 33:92
(anonymous) @ 33:142
Promise.then
(anonymous) @ 33:132
(anonymous) @ 33:145
33:96 HLS error {type: 'networkError', details: 'levelLoadError', fatal: false, url: 'https://test.inbi.ru/stream/hls/33?expires=1784762…d6553d6be11&_HLS_msn=18&_HLS_part=1&_HLS_skip=YES', loader: t, …}
## Assistant
Hls.js при обновлении плейлиста добавляет `_HLS_msn` / `_HLS_part` / `_HLS_skip` — из‑за них ломается подпись Laravel (403). Плюс в потоке ещё LL-HLS (`fragGap`). Исправляю оба момента.
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\app\\Http\\Controllers\\StreamHlsController.php"}
```
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\docker\\mediamtx\\mediamtx.yml"}
```
### Tool Get Mcp Tools
```
{"server":"user-context7","toolName":"query-docs","toolCallId":"call-567fc535-fb8d-4dba-87f5-e059ed215914-194\nfc_6d00e56c-d86c-9995-8971-df27373af69e_2"}
```
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Mcp
```
{"name":"user-context7-query-docs","args":{"libraryId":"/websites/laravel_12_x","query":"hasValidSignatureWhileIgnoring relative absolute signed URL"},"toolCallId":"call-533b1dde-0204-4ab0-966c-4fbb9437f89c-199\nfc_c7c183a8-c30d-95c0-ab20-12ffb813e108_0","providerIdentifier":"context7","toolName":"query-docs","smartModeApprovalOnly":false,"skipApproval":false}
```
### Tool Ripgrep Raw Search
```
{}
```
## Assistant
Две причины чёрного экрана:
1. **hls.js** при обновлении плейлиста дописывает `_HLS_msn`, `_HLS_part`, `_HLS_skip` → подпись Laravel ломается → **403** на `audio1_stream.m3u8`
2. MediaMTX отдавал **LL-HLS** (`fragGap`, отдельные audio/video playlist)
## Что исправлено
- Подпись игнорирует `_HLS_*` параметры
- Эти параметры пробрасываются в MediaMTX при запросе плейлиста
- В MediaMTX включён **`hlsVariant: mpegts`** (совместимее с hls.js, без LL-HLS)
## На сервере
```bash
cd /var/www/inbi
# обновить код + конфиг mediamtx.yml
sudo docker-compose down
sudo docker-compose up -d
# или: sudo docker compose down && sudo docker compose up -d
php artisan config:clear
```
Затем:
1. Мастер **полностью останавливает** эфир и запускает заново
2. Зритель делает hard refresh
В Network у зрителя сегменты должны быть вида `*.ts` (не `audio1_stream.m3u8` с `_HLS_*`). Если `audio1_*` всё ещё есть — MediaMTX не подхватил новый `mediamtx.yml` (проверьте volume и restart).
## User
Теперь ошибка
33:136
GET https://test.inbi.ru/stream/hls/33?expires=1784763193&file=index.m3u8&signature=e839995… 503 (Service Unavailable)
## Assistant
Скорее всего `mpegts` не стыкуется с WebRTC (Opus/VP8) — плейлист с MediaMTX не отдаётся. Вернём `fmp4` и усилим диагностику 503.
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
## Assistant
**503** значит: Laravel не смог получить плейлист у MediaMTX. После смены на `mpegts` это ожидаемо — WebRTC (Opus) часто **не собирается** в MPEG-TS без перекодирования, MediaMTX отдаёт 404, Laravel → 503.
Вернул **`hlsVariant: fmp4`** (без LL-HLS). Игнор `_HLS_*` в подписи оставил.
## На сервере
```bash
cd /var/www/inbi
# залить обновлённый mediamtx.yml и код
sudo docker-compose down
sudo docker-compose up -d
php artisan config:clear
```
Затем **обязательно**:
1. Мастер нажимает «Завершить трансляцию»
2. Снова «Начать трансляцию» (после рестарта Docker старый WHIP-сеанс мёртв)
3. Зритель обновляет страницу
## Проверка
Пока мастер в эфире:
```bash
# stream_key из БД:
# SELECT id, stream_key, status FROM live_broadcasts ORDER BY id DESC LIMIT 1;
curl -sI "http://127.0.0.1:8888/live/STREAM_KEY/index.m3u8"
sudo docker ps
sudo docker logs inbi-mediamtx --tail 50
```
Нужен **HTTP 200**. Если 404 — поток не опубликован в MediaMTX. Если `Connection refused` — контейнер не слушает 8888.
В ответе 503 теперь будет текст с причиной — пришлите его, если снова не заработает.
## User
все еще не отдает. Вот ответ:
root@vm736755:/var/www/inbicurl -sI "http://127.0.0.1:8888/live/STREAM_KEY/index.m3u8"8"
sudo docker ps
sudo docker logs inbi-mediamtx --tail 50
HTTP/1.1 404 Not Found
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: *
Content-Type: text/plain
Server: mediamtx
Date: Wed, 22 Jul 2026 19:44:02 GMT
Content-Length: 18
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
53d530c6f878 bluenviron/mediamtx:1.11.3 "/mediamtx" 5 minutes ago Up 5 minutes 0.0.0.0:8888-8889->8888-8889/tcp, [::]:8888-8889->8888-8889/tcp, 0.0.0.0:9997->9997/tcp, [::]:9997->9997/tcp inbi-mediamtx
2026/07/22 19:38:59 INF MediaMTX v1.11.3
2026/07/22 19:38:59 INF configuration loaded from /mediamtx.yml
2026/07/22 19:38:59 INF [RTSP] listener opened on :8554 (TCP), :8000 (UDP/RTP), :8001 (UDP/RTCP)
2026/07/22 19:38:59 INF [RTMP] listener opened on :1935
2026/07/22 19:38:59 INF [HLS] listener opened on :8888
2026/07/22 19:38:59 INF [WebRTC] listener opened on :8889 (HTTP), :8189 (ICE/UDP)
2026/07/22 19:38:59 INF [SRT] listener opened on :8890 (UDP)
2026/07/22 19:38:59 INF [API] listener opened on :9997
2026/07/22 19:41:42 INF [WebRTC] [session 41bb87f6] created by 172.18.0.1:47472
2026/07/22 19:41:52 INF [WebRTC] [session 41bb87f6] closed: deadline exceeded while waiting connection
## Assistant
В логах видно главное: WHIP-сессия создаётся, но обрывается — `deadline exceeded while waiting connection`. Медиа по UDP не устанавливается. В `docker ps` нет порта `8189/udp`.
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\docker-compose.yml"}
```
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\docker\\mediamtx\\mediamtx.yml"}
```
### Tool Mcp
```
{"name":"user-context7-query-docs","args":{"libraryId":"/bluenviron/mediamtx","query":"WebRTC ICE UDP mux webrtcAdditionalHosts NAT docker deadline exceeded while waiting connection"},"toolCallId":"call-632b8781-ea65-4928-ade9-86a52e79f6f1-206\nfc_8e9c5a54-e9cb-92d6-8ff2-cdd884c3cf09_2","providerIdentifier":"context7","toolName":"query-docs","smartModeApprovalOnly":false,"skipApproval":false}
```
## Assistant
WHIP-сигналинг проходит, но ICE/UDP не устанавливается — в Docker не проброшен порт `8189`. Исправляю.
### Tool Edit File V2
### Tool Edit File V2
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\resources\\views\\master\\cabinet\\broadcast.php"}
```
### Tool Edit File V2
## Assistant
Проблема не в HLS-прокси. В логах MediaMTX:
```text
closed: deadline exceeded while waiting connection
```
WHIP (сигналинг по HTTPS) проходит, а **медиапоток по WebRTC/ICE не устанавливается**. В `docker ps` был только TCP `8888-8889`, **без UDP 8189** — браузер не может отдать видео на сервер, путь в MediaMTX не появляется → HLS `404` → у зрителя `503`.
`curl .../live/STREAM_KEY/...` тоже был с плейсхолдером, не с реальным ключом — но это вторично.
## Что изменено
1. Docker → **`network_mode: host`** (без Docker NAT для ICE)
2. ICE: UDP + TCP **8189**, STUN, `webrtcAdditionalHosts`
3. У мастера статус «Эфир идёт» только после **реального ICE connected**
## На сервере
```bash
cd /var/www/inbi
# залить docker-compose.yml и mediamtx.yml
# если в mediamtx.yml только домен — лучше добавить ПУБЛИЧНЫЙ IP:
# webrtcAdditionalHosts: [stream.inbi.ru, 1.2.3.4]
sudo docker-compose down
sudo docker-compose up -d
# файрвол — обязательно
sudo ufw allow 8189/udp
sudo ufw allow 8189/tcp
# 8889 уже должен быть доступен через nginx; 8888 наружу не нужен
```
Проверка:
```bash
sudo ss -ulnp | grep 8189
sudo ss -tlnp | grep -E '8888|8889|8189'
sudo docker logs inbi-mediamtx --tail 20
```
## Тест эфира
1. Мастер заново начинает трансляцию
2. В статусе должно быть «Ожидание ICE…», затем «Эфир идёт»
3. В логах MediaMTX должно появиться что-то вроде `peer connection established` / `path created`, **не** `deadline exceeded`
4. Затем:
```bash
# реальный ключ:
mysql ... -e "SELECT id, stream_key, status FROM live_broadcasts ORDER BY id DESC LIMIT 1;"
curl -sI "http://127.0.0.1:8888/live/РЕАЛЬНЫЙ_КЛЮЧ/index.m3u8"
```
Ожидается **200**.
Если ICE снова timeout — пришлите публичный IP сервера и кусок SDP answer (или лог MediaMTX после новой попытки). Тогда пропишем IP явно в `webrtcAdditionalHosts` или добавим TURN.
## User
Теперь никаких ошибок нет, пишет "вы в эфире". Но экран видео черный.
root@vm736755:/var/www/inbi# sudo docker logs inbi-mediamtx --tail 20
2026/07/22 19:46:13 INF MediaMTX v1.11.3
2026/07/22 19:46:13 INF configuration loaded from /mediamtx.yml
2026/07/22 19:46:13 INF [RTSP] listener opened on :8554 (TCP), :8000 (UDP/RTP), :8001 (UDP/RTCP)
2026/07/22 19:46:13 INF [RTMP] listener opened on :1935
2026/07/22 19:46:13 INF [HLS] listener opened on :8888
2026/07/22 19:46:13 INF [WebRTC] listener opened on :8889 (HTTP), :8189 (ICE/UDP), :8189 (ICE/TCP)
2026/07/22 19:46:13 INF [SRT] listener opened on :8890 (UDP)
2026/07/22 19:46:13 INF [API] listener opened on :9997
2026/07/22 19:47:40 INF [WebRTC] [session bc09935c] created by 127.0.0.1:46456
2026/07/22 19:47:47 INF [WebRTC] [session bc09935c] peer connection established, local candidate: host/udp/127.0.0.1/8189, remote candidate: prflx/udp/178.157.135.193/18222
2026/07/22 19:47:47 WAR [path live/dq8q90n6o031vcsua0jk4k2kpna66u0t] [recorder] skipping track 2 (VP8)
2026/07/22 19:47:47 INF [path live/dq8q90n6o031vcsua0jk4k2kpna66u0t] [recorder] recording 1 track (Opus)
2026/07/22 19:47:47 INF [WebRTC] [session bc09935c] is publishing to path 'live/dq8q90n6o031vcsua0jk4k2kpna66u0t', 2 tracks (Opus, VP8)
2026/07/22 19:47:47 INF [HLS] [muxer live/dq8q90n6o031vcsua0jk4k2kpna66u0t] created automatically
2026/07/22 19:47:47 WAR [HLS] [muxer live/dq8q90n6o031vcsua0jk4k2kpna66u0t] skipping track 2 (VP8)
2026/07/22 19:47:47 INF [HLS] [muxer live/dq8q90n6o031vcsua0jk4k2kpna66u0t] is converting into HLS, 1 track (Opus)
## Assistant
В логах ясно: MediaMTX пропускает VP8 и в HLS попадает только Opus (звук без картинки). Браузер мастера шлёт VP8 — для HLS нужен H.264. Принудительно выставлю H.264 на стороне мастера.
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\resources\\views\\master\\cabinet\\broadcast.php"}
```
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
## Assistant
Причина чёрного экрана в логах:
```text
skipping track 2 (VP8)
is converting into HLS, 1 track (Opus)
```
Браузер мастера слал **VP8**. MediaMTX в HLS **не кладёт VP8** — только Opus. Зритель получает поток без видео.
## Что сделано
На стороне мастера принудительно:
- предпочтение **H.264** через `setCodecPreferences`
- вырезание VP8/VP9 из SDP
- проверка исходящего кодека после ICE
## Что сделать
1. Залить обновлённый `broadcast.php`
2. Мастер: **завершить** эфир и начать заново (лучше в **Chrome/Edge**)
3. В логах должно быть:
```bash
sudo docker logs inbi-mediamtx --tail 30
```
Ожидается примерно:
```text
is publishing ... (H264, Opus)
is converting into HLS, 2 tracks (H264, Opus)
```
Не `VP8` и не `1 track (Opus)`.
4. Зритель — hard refresh
Если снова будет `VP8` — напишите, какой браузер у мастера (Firefox часто без нормального H.264).
## User
Теперь все работает, но задержка почти 30 секунд. И в консоли браузера зрителя:
33:101 HLS error {type: 'mediaError', details: 'bufferStalledError', fatal: false, error: Error: Playback stalling at @19.297073 due to low buffer ({"len":0,"start":19.297073,"end":19.29707…, buffer: 0, …}
(anonymous) @ 33:101
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ gap-controller.ts:234
(anonymous) @ gap-controller.ts:157
(anonymous) @ stream-controller.ts:946
(anonymous) @ stream-controller.ts:218
(anonymous) @ stream-controller.ts:213
(anonymous) @ task-loop.ts:106
setInterval
(anonymous) @ task-loop.ts:68
(anonymous) @ stream-controller.ts:127
(anonymous) @ hls.ts:434
(anonymous) @ hls.ts:433
(anonymous) @ level-controller.ts:376
(anonymous) @ level-controller.ts:200
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:429
onSuccess @ playlist-loader.ts:327
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:154
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ hls.ts:420
startHls @ 33:97
(anonymous) @ 33:147
Promise.then
(anonymous) @ 33:137
(anonymous) @ 33:150
33:101 HLS error {type: 'mediaError', details: 'bufferStalledError', fatal: false, error: Error: Playback stalling at @23.191927 due to low buffer ({"len":0,"start":23.191927,"end":23.19192…, buffer: 0, …}
(anonymous) @ 33:101
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ gap-controller.ts:234
(anonymous) @ gap-controller.ts:157
(anonymous) @ stream-controller.ts:946
(anonymous) @ stream-controller.ts:218
(anonymous) @ stream-controller.ts:213
(anonymous) @ task-loop.ts:106
setInterval
(anonymous) @ task-loop.ts:68
(anonymous) @ stream-controller.ts:127
(anonymous) @ hls.ts:434
(anonymous) @ hls.ts:433
(anonymous) @ level-controller.ts:376
(anonymous) @ level-controller.ts:200
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:429
onSuccess @ playlist-loader.ts:327
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:154
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ hls.ts:420
startHls @ 33:97
(anonymous) @ 33:147
Promise.then
(anonymous) @ 33:137
(anonymous) @ 33:150
33:101 HLS error {type: 'mediaError', details: 'bufferNudgeOnStall', error: Error: Nudging 'currentTime' from 23.191927 to 23.291927
at e._tryNudgeBuffer (https://cdn.jsde…, fatal: false, errorAction: {…}}
(anonymous) @ 33:101
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ gap-controller.ts:353
(anonymous) @ gap-controller.ts:214
(anonymous) @ gap-controller.ts:168
(anonymous) @ stream-controller.ts:946
(anonymous) @ stream-controller.ts:218
(anonymous) @ stream-controller.ts:213
(anonymous) @ task-loop.ts:106
(anonymous) @ stream-controller.ts:696
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:683
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:287
setTimeout
(anonymous) @ base-playlist-controller.ts:286
(anonymous) @ level-controller.ts:571
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:683
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:287
setTimeout
(anonymous) @ base-playlist-controller.ts:286
(anonymous) @ level-controller.ts:571
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:683
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:287
setTimeout
(anonymous) @ base-playlist-controller.ts:286
(anonymous) @ level-controller.ts:571
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:683
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:287
setTimeout
(anonymous) @ base-playlist-controller.ts:286
(anonymous) @ level-controller.ts:571
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:683
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:287
setTimeout
(anonymous) @ base-playlist-controller.ts:286
(anonymous) @ level-controller.ts:571
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:683
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:287
setTimeout
(anonymous) @ base-playlist-controller.ts:286
(anonymous) @ level-controller.ts:571
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:683
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:287
setTimeout
(anonymous) @ base-playlist-controller.ts:286
(anonymous) @ level-controller.ts:571
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:683
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:287
setTimeout
(anonymous) @ base-playlist-controller.ts:286
(anonymous) @ level-controller.ts:571
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:683
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:287
setTimeout
(anonymous) @ base-playlist-controller.ts:286
(anonymous) @ level-controller.ts:571
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:683
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:287
setTimeout
(anonymous) @ base-playlist-controller.ts:286
(anonymous) @ level-controller.ts:571
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:683
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:287
setTimeout
(anonymous) @ base-playlist-controller.ts:286
(anonymous) @ level-controller.ts:571
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:683
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
(anonymous) @ base-playlist-controller.ts:287
setTimeout
(anonymous) @ base-playlist-controller.ts:286
(anonymous) @ level-controller.ts:571
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:683
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:166
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ level-controller.ts:610
set @ level-controller.ts:477
set @ level-controller.ts:629
set @ hls.ts:574
(anonymous) @ stream-controller.ts:143
(anonymous) @ hls.ts:434
(anonymous) @ hls.ts:433
(anonymous) @ level-controller.ts:376
(anonymous) @ level-controller.ts:200
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:429
onSuccess @ playlist-loader.ts:327
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:154
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ hls.ts:420
startHls @ 33:97
(anonymous) @ 33:147
Promise.then
(anonymous) @ 33:137
(anonymous) @ 33:150
33:101 HLS error {type: 'networkError', details: 'audioTrackLoadTimeOut', fatal: false, url: 'https://test.inbi.ru/stream/hls/33?expires=1784764…d1b7b9b148a40cf4bb0395488dfd8afd2c4d2465e7e7e6aee', loader: t, …}
(anonymous) @ 33:101
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:612
onTimeout @ playlist-loader.ts:340
(anonymous) @ xhr-loader.ts:275
setTimeout
(anonymous) @ xhr-loader.ts:162
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:182
(anonymous) @ index.js:182
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ audio-track-controller.ts:422
(anonymous) @ base-playlist-controller.ts:287
setTimeout
(anonymous) @ base-playlist-controller.ts:286
(anonymous) @ audio-track-controller.ts:105
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:693
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:182
(anonymous) @ index.js:182
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ audio-track-controller.ts:422
(anonymous) @ base-playlist-controller.ts:287
setTimeout
(anonymous) @ base-playlist-controller.ts:286
(anonymous) @ audio-track-controller.ts:105
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:693
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:182
(anonymous) @ index.js:182
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ audio-track-controller.ts:422
(anonymous) @ base-playlist-controller.ts:287
setTimeout
(anonymous) @ base-playlist-controller.ts:286
(anonymous) @ audio-track-controller.ts:105
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:693
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:182
(anonymous) @ index.js:182
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ audio-track-controller.ts:422
(anonymous) @ base-playlist-controller.ts:287
setTimeout
(anonymous) @ base-playlist-controller.ts:286
(anonymous) @ audio-track-controller.ts:105
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:693
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:182
(anonymous) @ index.js:182
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ audio-track-controller.ts:422
(anonymous) @ base-playlist-controller.ts:287
setTimeout
(anonymous) @ base-playlist-controller.ts:286
(anonymous) @ audio-track-controller.ts:105
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:693
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:182
(anonymous) @ index.js:182
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ audio-track-controller.ts:422
(anonymous) @ base-playlist-controller.ts:287
setTimeout
(anonymous) @ base-playlist-controller.ts:286
(anonymous) @ audio-track-controller.ts:105
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:693
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:182
(anonymous) @ index.js:182
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ audio-track-controller.ts:422
(anonymous) @ base-playlist-controller.ts:287
setTimeout
(anonymous) @ base-playlist-controller.ts:286
(anonymous) @ audio-track-controller.ts:105
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:693
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:182
(anonymous) @ index.js:182
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ audio-track-controller.ts:422
(anonymous) @ base-playlist-controller.ts:287
setTimeout
(anonymous) @ base-playlist-controller.ts:286
(anonymous) @ audio-track-controller.ts:105
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:693
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:182
(anonymous) @ index.js:182
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ audio-track-controller.ts:422
(anonymous) @ base-playlist-controller.ts:287
setTimeout
(anonymous) @ base-playlist-controller.ts:286
(anonymous) @ audio-track-controller.ts:105
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:693
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:182
(anonymous) @ index.js:182
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ audio-track-controller.ts:422
(anonymous) @ base-playlist-controller.ts:287
setTimeout
(anonymous) @ base-playlist-controller.ts:286
(anonymous) @ audio-track-controller.ts:105
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:693
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:182
(anonymous) @ index.js:182
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ audio-track-controller.ts:422
(anonymous) @ base-playlist-controller.ts:287
setTimeout
(anonymous) @ base-playlist-controller.ts:286
(anonymous) @ audio-track-controller.ts:105
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:693
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:182
(anonymous) @ index.js:182
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ audio-track-controller.ts:422
(anonymous) @ base-playlist-controller.ts:287
setTimeout
(anonymous) @ base-playlist-controller.ts:286
(anonymous) @ audio-track-controller.ts:105
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:693
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:182
(anonymous) @ index.js:182
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ audio-track-controller.ts:422
(anonymous) @ base-playlist-controller.ts:287
setTimeout
(anonymous) @ base-playlist-controller.ts:286
(anonymous) @ audio-track-controller.ts:105
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:693
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:182
(anonymous) @ index.js:182
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ audio-track-controller.ts:422
(anonymous) @ base-playlist-controller.ts:287
setTimeout
(anonymous) @ base-playlist-controller.ts:286
(anonymous) @ audio-track-controller.ts:105
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:693
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:182
(anonymous) @ index.js:182
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ audio-track-controller.ts:422
(anonymous) @ base-playlist-controller.ts:287
setTimeout
(anonymous) @ base-playlist-controller.ts:286
(anonymous) @ audio-track-controller.ts:105
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:693
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:182
(anonymous) @ index.js:182
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ audio-track-controller.ts:422
(anonymous) @ base-playlist-controller.ts:287
setTimeout
(anonymous) @ base-playlist-controller.ts:286
(anonymous) @ audio-track-controller.ts:105
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:693
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:182
(anonymous) @ index.js:182
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ audio-track-controller.ts:422
(anonymous) @ base-playlist-controller.ts:287
setTimeout
(anonymous) @ base-playlist-controller.ts:286
(anonymous) @ audio-track-controller.ts:105
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:693
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:182
(anonymous) @ index.js:182
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ audio-track-controller.ts:422
(anonymous) @ base-playlist-controller.ts:287
setTimeout
(anonymous) @ base-playlist-controller.ts:286
(anonymous) @ audio-track-controller.ts:105
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:693
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:182
(anonymous) @ index.js:182
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ audio-track-controller.ts:422
(anonymous) @ base-playlist-controller.ts:287
setTimeout
(anonymous) @ base-playlist-controller.ts:286
(anonymous) @ audio-track-controller.ts:105
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:693
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:182
(anonymous) @ index.js:182
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ audio-track-controller.ts:422
(anonymous) @ base-playlist-controller.ts:287
setTimeout
(anonymous) @ base-playlist-controller.ts:286
(anonymous) @ audio-track-controller.ts:105
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:693
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:182
(anonymous) @ index.js:182
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ audio-track-controller.ts:422
(anonymous) @ base-playlist-controller.ts:287
setTimeout
(anonymous) @ base-playlist-controller.ts:286
(anonymous) @ audio-track-controller.ts:105
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:693
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:182
(anonymous) @ index.js:182
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ audio-track-controller.ts:422
(anonymous) @ base-playlist-controller.ts:287
setTimeout
(anonymous) @ base-playlist-controller.ts:286
(anonymous) @ audio-track-controller.ts:105
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:693
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:182
(anonymous) @ index.js:182
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ audio-track-controller.ts:422
(anonymous) @ base-playlist-controller.ts:287
setTimeout
(anonymous) @ base-playlist-controller.ts:286
(anonymous) @ audio-track-controller.ts:105
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:693
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:182
(anonymous) @ index.js:182
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ audio-track-controller.ts:422
(anonymous) @ base-playlist-controller.ts:287
setTimeout
(anonymous) @ base-playlist-controller.ts:286
(anonymous) @ audio-track-controller.ts:105
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:693
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:182
(anonymous) @ index.js:182
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ audio-track-controller.ts:422
(anonymous) @ base-playlist-controller.ts:287
setTimeout
(anonymous) @ base-playlist-controller.ts:286
(anonymous) @ audio-track-controller.ts:105
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:693
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:182
(anonymous) @ index.js:182
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ audio-track-controller.ts:422
(anonymous) @ base-playlist-controller.ts:287
setTimeout
(anonymous) @ base-playlist-controller.ts:286
(anonymous) @ audio-track-controller.ts:105
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:693
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:182
(anonymous) @ index.js:182
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ audio-track-controller.ts:422
(anonymous) @ base-playlist-controller.ts:287
setTimeout
(anonymous) @ base-playlist-controller.ts:286
(anonymous) @ audio-track-controller.ts:105
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:693
(anonymous) @ playlist-loader.ts:505
onSuccess @ playlist-loader.ts:319
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:182
(anonymous) @ index.js:182
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ audio-track-controller.ts:422
(anonymous) @ base-playlist-controller.ts:47
(anonymous) @ hls.ts:434
(anonymous) @ hls.ts:433
(anonymous) @ level-controller.ts:376
(anonymous) @ level-controller.ts:200
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:429
onSuccess @ playlist-loader.ts:327
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:154
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ hls.ts:420
startHls @ 33:97
(anonymous) @ 33:147
Promise.then
(anonymous) @ 33:137
(anonymous) @ 33:150
33:101 HLS error {type: 'mediaError', details: 'bufferStalledError', fatal: false, error: Error: Playback stalling at @77.581342 due to low buffer ({"len":0,"start":77.581342,"end":77.58134…, buffer: 0, …}
(anonymous) @ 33:101
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ gap-controller.ts:234
(anonymous) @ gap-controller.ts:157
(anonymous) @ stream-controller.ts:946
(anonymous) @ stream-controller.ts:218
(anonymous) @ stream-controller.ts:213
(anonymous) @ task-loop.ts:106
setInterval
(anonymous) @ task-loop.ts:68
(anonymous) @ stream-controller.ts:127
(anonymous) @ hls.ts:434
(anonymous) @ hls.ts:433
(anonymous) @ level-controller.ts:376
(anonymous) @ level-controller.ts:200
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ playlist-loader.ts:429
onSuccess @ playlist-loader.ts:327
(anonymous) @ xhr-loader.ts:239
XMLHttpRequest.send
(anonymous) @ xhr-loader.ts:166
(anonymous) @ xhr-loader.ts:125
(anonymous) @ xhr-loader.ts:84
(anonymous) @ playlist-loader.ts:352
(anonymous) @ playlist-loader.ts:154
(anonymous) @ index.js:203
(anonymous) @ hls.ts:310
(anonymous) @ hls.ts:321
(anonymous) @ hls.ts:420
startHls @ 33:97
(anonymous) @ 33:147
Promise.then
(anonymous) @ 33:137
(anonymous) @ 33:150
33:101 HLS error {type: 'networkError', details: 'levelLoadTimeOut', fatal: false, url: 'https://test.inbi.ru/stream/hls/33?expires=1784764…26e1c6bf160df72c3c96b0e01ad11652b2f6f4c43c2dc9712', loader: t, …}
С этим можно что-то сделать?
## Assistant
~30 с — типично для HLS: длинный GOP у H.264 из браузера + буфер сегментов + медленный PHP-прокси на каждый запрос (особенно отдельный audio track). Сокращаю сегменты, форсирую keyframe и ускоряю прокси.
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\resources\\views\\online_streams\\watch.php"}
```
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\app\\Http\\Controllers\\StreamHlsController.php"}
```
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\docker\\mediamtx\\mediamtx.yml"}
```
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
## Assistant
Да, можно. ~30 с и `bufferStalled` / `audioTrackLoadTimeOut` шли из трёх вещей:
1. **Редкие keyframe** у H.264 из браузера → сегменты HLS получались длинными
2. **Обычный fMP4 HLS** + буфер 3+ сегмента
3. **Медленный PHP-прокси** (на каждый кусок снова доступ + БД) → таймауты audio playlist
## Что изменено
| Место | Изменение |
|--------|-----------|
| MediaMTX | `hlsVariant: lowLatency`, сегменты 1 с, parts 300 мс |
| Мастер | `generateKeyFrame()` каждую 1 с (Chrome/Edge) |
| HLS-прокси | без повторного `canWatch`, кэш broadcast 3 с |
| Зритель | hls.js LL-режим, короче live buffer, не падать на stall |
Ожидаемая задержка после правок: **примерно 3–8 с** (для HLS это нормально). Субсекундной задержки у HLS не будет — для неё нужен WHEP/WebRTC у зрителя.
## На сервере
```bash
cd /var/www/inbi
sudo docker-compose down && sudo docker-compose up -d
php artisan config:clear
```
Мастер **перезапускает** эфир (лучше Chrome), зритель — hard refresh.
`bufferStalledError` / `bufferNudgeOnStall` с `fatal: false` можно не считать поломкой — плеер сам подтягивается. Если снова будут `*LoadTimeOut` — пришлите; следующий шаг — отдавать сегменты напрямую через nginx, минуя PHP.
## User
А расскажи, когда включается запись, а когда - онлайн трансляция? Может ли мастер заранее записать видео, чтобы его потом смотрели?
## Assistant
Сейчас у вас это **одна кнопка / один процесс**, а не два разных режима.
## Как работает сейчас
| Что | Когда включается |
|-----|------------------|
| **Онлайн-трансляция** | Мастер в кабинете нажимает «Начать трансляцию» → камера идёт в MediaMTX → зрители смотрят HLS |
| **Запись** | **Автоматически вместе с эфиром** — MediaMTX пишет на диск, пока идёт публикация |
| **Конец записи** | Мастер жмёт «Завершить» → сессия WHIP закрывается → через несколько секунд `FinalizeStreamRecordingJob` ищет файл и сохраняет в `stream_recordings` |
То есть запись — это не отдельная кнопка, а **побочный продукт live-эфира**: нет эфира → нет этой серверной записи.
Кнопка «Начать» доступна только в окне занятия (день недели + время ±15 мин до старта и до конца).
## Может ли мастер заранее записать видео «на потом»?
**В текущей реализации — нет.**
Нет сценария: «записать сейчас без зрителей / вне слота → опубликовать как VOD».
Что есть по факту:
- запись появляется только если был live;
- после эфира файл может открываться на странице занятия (если запись нашлась и `published`);
- заранее залить готовое видео как «эфир на потом» — не сделано.
## Как это обычно делают, если нужно
1. **Предзапись (VOD)** — мастер загружает MP4 в админке/кабинете, зрители смотрят файл (без MediaMTX live).
2. **«Репетиция»** — мастер запускает тот же live вне расписания (нужно ослабить окно времени), запись сохранится, потом её показывают как запись.
3. **Гибрид** — live как сейчас + отдельно библиотека загруженных уроков.
Если нужно именно «записать заранее и раздать позже» — это отдельная фича (загрузка видео + привязка к `Schedule` + страница просмотра без WHIP). Могу набросать, как встроить в текущую схему.
## User
Теперь у ведущего пишет ошибку: Ошибка: WHIP: сервер вернул 502
## Assistant
502 на WHIP почти всегда значит: nginx не достучался до MediaMTX на `:8889`. Проверяю конфиг и типичные причины после перехода на `network_mode: host`.
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\docker-compose.yml"}
```
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\docker\\mediamtx\\mediamtx.yml"}
```
### Tool Mcp
```
{"name":"user-context7-query-docs","args":{"libraryId":"/bluenviron/mediamtx","query":"hlsPartHoldBack hlsVariant lowLatency configuration parameters valid yaml"},"toolCallId":"call-f905b0b6-117f-45a5-b775-543dc5d6d709-226\nfc_81a8dfc8-58a0-9366-b7c1-0cb4a96d985e_2","providerIdentifier":"context7","toolName":"query-docs","smartModeApprovalOnly":false,"skipApproval":false}
```
## Assistant
Убираю из конфига параметры, из‑за которых MediaMTX 1.11 может не стартовать — тогда nginx и отдаёт 502.
### Tool Edit File V2
## Assistant
**502** = nginx проксирует на `127.0.0.1:8889`, а MediaMTX там не отвечает (упал / не запустился / порт занят).
Частая причина после прошлого обновления — в `mediamtx.yml` были поля вроде `hlsPartHoldBack` / `hlsSegmentMaxSize`, из‑за которых MediaMTX 1.11 может **не стартовать**. Конфиг упрощён.
## На сервере выполните
```bash
cd /var/www/inbi
# 1. Обновить mediamtx.yml, затем:
sudo docker-compose down
sudo docker-compose up -d
# 2. Жив ли контейнер?
sudo docker ps -a | grep mediamtx
sudo docker logs inbi-mediamtx --tail 40
# 3. Слушает ли 8889?
sudo ss -tlnp | grep -E '8888|8889|8189'
# 4. Отвечает ли WHIP напрямую (минуя nginx)?
curl -sI http://127.0.0.1:8889/
curl -sI https://stream.inbi.ru/
```
В логах должно быть:
```text
INF configuration loaded from /mediamtx.yml
INF [WebRTC] listener opened on :8889
```
Если вместо этого `ERR` / `unsupported parameter` — пришлите вывод `docker logs`.
## Если контейнер Restarting / Exited
```bash
sudo docker-compose logs --tail 80
```
Часто после `network_mode: host` порт уже занят старым процессом:
```bash
sudo ss -tlnp | grep 8889
# если висит старый mediamtx / другой процесс — убить и снова up
```
## Если `curl http://127.0.0.1:8889/` ок, а WHIP с сайта 502
Смотрите nginx:
```bash
sudo tail -30 /var/log/nginx/error.log
```
Там будет `connect() failed` к upstream — значит proxy_pass смотрит не туда (нужен `http://127.0.0.1:8889`).
---
После того как `curl -sI http://127.0.0.1:8889/` отвечает не 502/connection refused — мастер снова «Начать трансляцию». Пришлите вывод пунктов 2–4, если не оживёт.
## User
Теперь мастер видит: Эфир идёт — зрители смотрят через HLS
А зритель: Плейлист: HTTP 503 — MediaMTX ещё не отдаёт плейлист. [http_404]
root@vm736755:/var/www/inbisudo docker-compose logs --tail 8080
Attaching to inbi-mediamtx
inbi-mediamtx | 2026/07/22 20:04:28 INF MediaMTX v1.11.3
inbi-mediamtx | 2026/07/22 20:04:28 INF configuration loaded from /mediamtx.yml
inbi-mediamtx | 2026/07/22 20:04:28 INF [RTSP] listener opened on :8554 (TCP), :8000 (UDP/RTP), :8001 (UDP/RTCP)
inbi-mediamtx | 2026/07/22 20:04:28 INF [RTMP] listener opened on :1935
inbi-mediamtx | 2026/07/22 20:04:28 INF [HLS] listener opened on :8888
inbi-mediamtx | 2026/07/22 20:04:28 INF [WebRTC] listener opened on :8889 (HTTP), :8189 (ICE/UDP), :8189 (ICE/TCP)
inbi-mediamtx | 2026/07/22 20:04:28 INF [SRT] listener opened on :8890 (UDP)
inbi-mediamtx | 2026/07/22 20:04:28 INF [API] listener opened on :9997
inbi-mediamtx | 2026/07/22 20:05:03 INF [WebRTC] [session 5aa62d74] created by 127.0.0.1:53114
inbi-mediamtx | 2026/07/22 20:05:14 INF [WebRTC] [session 5aa62d74] peer connection established, local candidate: host/udp/172.18.0.1/8189, remote candidate: prflx/udp/178.157.135.193/17994
inbi-mediamtx | 2026/07/22 20:05:14 INF [path live/i3zt6yzj0akkatsid8pzez6i6uhnqagq] [recorder] recording 2 tracks (Opus, H264)
inbi-mediamtx | 2026/07/22 20:05:14 INF [WebRTC] [session 5aa62d74] is publishing to path 'live/i3zt6yzj0akkatsid8pzez6i6uhnqagq', 2 tracks (Opus, H264)
inbi-mediamtx | 2026/07/22 20:05:14 INF [HLS] [muxer live/i3zt6yzj0akkatsid8pzez6i6uhnqagq] created automatically
inbi-mediamtx | 2026/07/22 20:05:14 ERR [HLS] [muxer live/i3zt6yzj0akkatsid8pzez6i6uhnqagq] Low-Latency HLS requires at least 7 segments
inbi-mediamtx | 2026/07/22 20:05:24 ERR [HLS] [muxer live/i3zt6yzj0akkatsid8pzez6i6uhnqagq] Low-Latency HLS requires at least 7 segments
inbi-mediamtx | 2026/07/22 20:05:34 ERR [HLS] [muxer live/i3zt6yzj0akkatsid8pzez6i6uhnqagq] Low-Latency HLS requires at least 7 segments
inbi-mediamtx | 2026/07/22 20:05:44 ERR [HLS] [muxer live/i3zt6yzj0akkatsid8pzez6i6uhnqagq] Low-Latency HLS requires at least 7 segments
inbi-mediamtx | 2026/07/22 20:05:54 ERR [HLS] [muxer live/i3zt6yzj0akkatsid8pzez6i6uhnqagq] Low-Latency HLS requires at least 7 segments
inbi-mediamtx | 2026/07/22 20:06:04 ERR [HLS] [muxer live/i3zt6yzj0akkatsid8pzez6i6uhnqagq] Low-Latency HLS requires at least 7 segments
inbi-mediamtx | 2026/07/22 20:06:14 ERR [HLS] [muxer live/i3zt6yzj0akkatsid8pzez6i6uhnqagq] Low-Latency HLS requires at least 7 segments
root@vm736755:/var/www/inbi#
## Assistant
В логах прямо указано: Low-Latency HLS требует минимум 7 сегментов — у нас было 4. Исправляю.
### Tool Edit File V2
## Assistant
Причина в логе:
```text
Low-Latency HLS requires at least 7 segments
```
В конфиге было `hlsSegmentCount: 4` — muxer падал, плейлист не отдавался → 404/503.
Исправлено на **`hlsSegmentCount: 7`**.
```bash
cd /var/www/inbi
# обновить mediamtx.yml
sudo docker-compose down && sudo docker-compose up -d
```
Мастер: завершить эфир → начать снова. Зритель: обновить страницу.
В логах должно появиться `is converting into HLS`, без этой ERR.
## User
Убери текст "Поток уходит на медиасервер в H.264 (нужно для HLS). Рекомендуется Chrome или Edge. В логах MediaMTX должно быть: converting into HLS, 2 tracks (H264, Opus) — не VP8."
### Tool Edit File V2
## Assistant
Готово — этот текст убран со страницы трансляции мастера.
## User
1. Можно ли как-то качество выбирать? Или это дополнительная нагрузка на сервер?
2. Блок прогресса видео выглядит очень криво при трансляции - то прыгает, то рандомно меняет цифры и т.п. Можно его вообще убрать?
## Assistant
По качеству кратко отвечу в конце; прогресс-бар у live уберу — для HLS он и ведёт себя так.
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\resources\\views\\online_streams\\watch.php","limit":50}
```
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
## Assistant
### 1. Выбор качества
**Сейчас — нет.** Идёт один поток: то, что кодирует браузер мастера (H.264), MediaMTX его только перекладывает в HLS, **без перекодирования**.
Несколько качеств (360p / 720p / 1080p) = **доп. нагрузка на сервер**:
- ffmpeg/транскодинг нескольких битрейтов (CPU/GPU заметно);
- или несколько потоков от мастера (на практике почти не делают).
Без транскодинга можно лишь косвенно влиять: разрешение/битрейт камеры у мастера. Отдельный селектор качества — отдельная фича с медиасервером/транскодером.
### 2. Полоса прогресса
У live HLS время «плывёт», поэтому нативный scrubber прыгает — это нормально для эфира, не баг плеера.
Убрал стандартные `controls`. Для live остались только:
- Пауза / Смотреть
- Звук
- На весь экран
- бейдж LIVE
У **записей** (не live) обычные controls с прогрессом по-прежнему есть.
## User
Скажи примерно, какие системные требования нужны, чтобы хотя бы для 10-20 зрителей это работало?
И могут ли 2 мастера одновременно проводить трансляции разных мероприятий?
## Assistant
## Системные требования (10–20 зрителей)
У вас схема: **1 мастер → MediaMTX (remux, без транскодинга) → HLS через Laravel-прокси**. Нагрузка на CPU небольшая; упираетесь в **сеть** и в то, что сегменты сейчас идут через PHP.
### Минимум (нормально для 10–20)
| Ресурс | Ориентир |
|--------|----------|
| **CPU** | 2 vCPU (лучше 4) |
| **RAM** | 4 GB (спокойно 8 GB, если рядом сайт + MySQL + nginx) |
| **Диск** | SSD, + место под записи (~1–2 GB/час на эфир) |
| **Канал исходящий** | **50–100 Мбит/с** запас |
Примерная исходящая полоса на зрителя при ~1.5–2.5 Мбит/с видео:
- 10 зрителей ≈ **15–25 Мбит/с**
- 20 зрителей ≈ **30–50 Мбит/с**
Плюс WHIP от мастера (~2–4 Мбит/с входящих) и запись на диск.
Ваш текущий VPS, на котором уже крутятся сайт + nginx + MySQL + MediaMTX, для **10–20** обычно хватает, если канал не урезан.
### Узкие места именно вашей сборки
1. **Laravel-прокси HLS** — каждый сегмент/плейлист через PHP. На 10–20 ещё терпимо; на 50+ лучше отдавать HLS напрямую nginx’ом (с проверкой доступа).
2. **Канал сервера** — чаще упираются сюда, а не в CPU.
3. **Запись** — почти не грузит CPU (remux), только диск.
Транскодинг нескольких качеств **не включён** — это сильно снижает требования к CPU.
---
## Два мастера одновременно?
**Да.** У каждого эфира свой `stream_key` и путь `live/{key}` в MediaMTX. Два мастера = два независимых publisher’а.
Учтите запас:
| | 1 эфир | 2 эфира сразу |
|--|--------|----------------|
| Входящий WHIP | ~2–4 Мбит/с | ~4–8 Мбит/с |
| Исходящий HLS | зрители × битрейт | сумма по обоим |
| CPU MediaMTX | низкий | всё ещё низкий без транскода |
| Диск (запись) | 1 поток | 2 потока |
Если у каждого по 10 зрителей (итого 20) — те же ориентиры, что выше. Если у каждого по 20 (итого 40) — целитесь в **~80–100 Мбит/с** исходящих и лучше 4 vCPU / 8 GB.
В коде нет блокировки «только один эфир на весь сайт». Ограничение только у мастера: свои онлайн-занятия в своём кабинете; два разных мастера могут вещать параллельно без конфликта путей.
---
**Кратко:** для 10–20 зрителей достаточно скромного VPS (2–4 CPU, 4–8 GB, SSD) и стабильных **~50+ Мбит/с** наружу. Два мастера одновременно — да, это штатный режим MediaMTX.
## User
А почему у нас сейчас идет проксирование через laravel, а не напрямую nginx? Ради авторизации?
## Assistant
Да. Прокси через Laravel сделан **ради контроля доступа и подписи ссылок**, а не потому что MediaMTX так требует.
## Зачем Laravel в цепочке
1. **Проверка права смотреть** — `public` / `authenticated` / `abonement` (логин, абонемент).
2. **Подписанный URL** — `/stream/hls/...?file=...&signature=...`, чтобы нельзя было просто угадать путь `http://server:8888/live/{key}/index.m3u8`.
3. **Порт 8888 не торчит наружу** — зритель ходит только на `test.inbi.ru`, MediaMTX HLS остаётся на localhost.
4. **Переписывание плейлиста** — сегменты и `audio*.m3u8` тоже через те же подписанные ссылки (иначе hls.js полез бы на открытый MediaMTX).
То есть да: **авторизация + секретность stream_key**, одним местом в PHP.
## Минусы
Каждый `.m3u8` / сегмент → PHP → HTTP к MediaMTX. На 10–20 зрителях ок, на десятках+ — лишняя задержка, CPU и те самые timeout’ы.
## Как делают «правильно» на проде
Nginx отдаёт HLS **напрямую**, а Laravel только выдаёт доступ:
```text
Зритель → nginx (/hls/...) → MediaMTX :8888
↑
auth_request / secure_link
(Laravel отвечает 200/403)
```
Или: одноразовый JWT/cookie после `/online-streams/{id}`, дальше nginx пускает по нему без прогона каждого байта через PHP.
**Итог:** сейчас Laravel-прокси — осознанный упрощённый вариант «доступ + закрытый MediaMTX». Для масштаба и меньшей задержки имеет смысл вынести отдачу сегментов на nginx, оставив Laravel только на проверку права.
## User
Сейчас зритель видит намного менее плавно (меньше кадров в секунду), чем я вижу в окне мастера. С чем это связано?
## Assistant
Это ожидаемо при вашей схеме, а не баг «сломался плеер».
## Почему у мастера плавно, у зрителя — нет
**У мастера** в окне — локальный preview с камеры (`getUserMedia`). Кадры идут сразу с камеры в `<video>`, без сети и без HLS. Обычно 24–30 fps.
**У зрителя** путь другой:
```text
камера → H.264 в браузере → WebRTC → MediaMTX → нарезка HLS → Laravel → hls.js → экран
```
По дороге теряется плавность из‑за:
1. **Кодирование H.264 в браузере** — битрейт и FPS ограничены (часто 15–24 fps, особенно по CPU/вебкам).
2. **HLS + LL-HLS** — поток режется на сегменты/parts; плеер буферизует и иногда «подтягивает» время → ощущение рывков.
3. **Редкие keyframe** — между ключевыми кадрами HLS/декодер хуже переживает потери; мы шлём keyframe раз в секунду, но это не полноценные 30 fps «как локально».
4. **Задержка и буфер** — при нехватке буфера hls.js делает stall/nudge → краткие подвисания.
5. **PHP-прокси** — лишняя задержка на сегментах может усугублять рывки (не главная причина FPS, но влияет на «плавность»).
Локальное окно мастера **не показывает**, что реально уходит в эфир. Для сравнения смотрите глазами зрителя или второй вкладкой как зритель.
## Что можно улучшить (по эффекту)
| Мера | Эффект |
|------|--------|
| Мастер: Chrome/Edge, поменьше вкладок, лучше свет/вебка | Стабильнее FPS кодирования |
| Короткий GOP / частые keyframe (уже частично есть) | Меньше «квадратов» и рывков |
| Отдача HLS через nginx, не через Laravel | Ровнее доставка сегментов |
| WHEP/WebRTC у зрителя вместо HLS | Ближе к «живому» FPS, задержка 1–2 с |
| Транскод на сервере (ffmpeg) | Контроль fps/битрейта, но нагрузка на CPU |
**Кратко:** мастер смотрит сырую камеру; зритель — сжатый HLS с задержкой и буфером. Меньше fps и «неровность» — свойство текущего пайплайна, не того, что камера у мастера «рисует» 30 fps на экране.
## User
Почему сейчас не сделано WHEP/WebRTC у зрителя вместо HLS? Какие у текущей реализации преимущества и недостатки?
## Assistant
WHEP не сделали не потому что «нельзя», а потому что вы просили другое: **сервер + HLS + доступ + запись + много зрителей**. Под это HLS подходит лучше, чем WebRTC на каждого зрителя.
## Почему сейчас HLS, а не WHEP
| Ваш запрос | HLS | WHEP (WebRTC зрителю) |
|------------|-----|------------------------|
| Через сервер | да | да (SFU/ретрансляция) |
| Контроль доступа | удобно (подписанный `.m3u8` / nginx) | сложнее (токен на каждый peer/сессию) |
| Запись | MediaMTX пишет с publisher «из коробки» | запись тоже возможна, но зрительский протокол на неё не влияет |
| ~50 зрителей | один исходящий HLS, масштабируется проще | на каждого — отдельное WebRTC; нагрузка растёт быстрее |
| Простая выдача | hls.js / Safari native | свой JS + ICE/TURN снова |
Итог: HLS закрыл ваши три цели одним пайплайном. WHEP дал бы **плавность и задержку**, но усложнил бы доступ, NAT и нагрузку.
---
## Текущая реализация (мастер WHIP → MediaMTX → HLS зрителю)
### Плюсы
- **Масштаб 10–50+** без N исходящих WebRTC с сервера на каждого
- **Запись** рядом с тем же ingest
- **Доступ** через Laravel (подписи, абонемент) без открытия `:8888`
- **Один поток** от мастера, без транскода (CPU сервера низкий)
- **Знакомый стек** — браузер + hls.js, меньше возни с ICE у зрителей
### Минусы
- **Задержка** секунды (сейчас порядка нескольких–десятков)
- **Плавность/FPS** хуже, чем локальный preview мастера
- **Полоса прогресса** у live бессмысленна (уже убрали)
- **Прокси через PHP** — лишняя задержка/таймауты под нагрузкой
- **Один битрейт** — без выбора качества
- Зритель зависит от HLS-сегментов и буфера (stall/nudge)
---
## Если бы был WHEP у зрителя
### Плюсы
- Задержка **~0.5–2 с**
- Картинка ближе к «как у мастера»
- Меньше ощущения «телепередача с буфером»
### Минусы
- Снова **ICE/UDP/TURN** у каждого зрителя (у вас уже болело на WHIP)
- Нагрузка на MediaMTX **линейно по числу зрителей**
- Авторизация и «закрытый поток» сложнее, чем signed HLS
- Запись от этого не упрощается — она и так от publisher
---
## Практичный вывод
- **HLS** — «занятие на 10–50 человек, запись, доступ, терпимая задержка».
- **WHEP** — «почти как Zoom по задержке», но дороже в эксплуатации и хрупче по сети.
Гибрид на будущее: live смотреть по **WHEP**, запись/догоняющих/архив — по **HLS/VOD**. Сейчас сознательно выбран путь под ваше ТЗ про сервер, доступ, запись и число зрителей.
## User
Сделай окно чата справа у мастера и пользователей. С возможностью писать зрителям, а мастер бы это увидел. Сохранять его нигде не надо - достаточно, чтобы он был в моменте трансляции
## Assistant
Добавлю эфемерный чат через cache (без БД): сайдбар у мастера и зрителя, polling новых сообщений.
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\resources\\views\\master\\cabinet\\broadcast.php","limit":50}
```
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\resources\\views\\online_streams\\watch.php","limit":80}
```
### Tool Ripgrep Raw Search
```
{"pattern":"master\\.cabinet|online_streams|stream\\.","path":"c:\\OSPanel\\home\\inbi.loc\\routes\\web.php","caseInsensitive":false,"multiline":false,"toolCallId":"call-18dffc8b-05a3-4817-9cc8-be285bb9eb7e-236\nfc_27764bad-145d-91ac-b0ab-2265a2842a81_2","offset":0}
```
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\app\\Models\\User.php","limit":40}
```
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Ripgrep Raw Search
```
{"pattern":"online-streams|master/cabinet|StreamHls","path":"c:\\OSPanel\\home\\inbi.loc\\routes","caseInsensitive":false,"multiline":false,"toolCallId":"call-750a1a6b-1453-4306-b678-35c841da8b90-3\nfc_8e092b8b-4d45-9426-8346-b4c4098c19e7_0","offset":0}
```
### Tool Ripgrep Raw Search
```
{"pattern":"stopBroadcast|activeLiveBroadcast|function canWatch","path":"c:\\OSPanel\\home\\inbi.loc\\app","caseInsensitive":false,"multiline":false,"toolCallId":"call-750a1a6b-1453-4306-b678-35c841da8b90-4\nfc_8e092b8b-4d45-9426-8346-b4c4098c19e7_1","offset":0}
```
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\resources\\views\\master\\cabinet\\broadcast.php","limit":80}
```
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\resources\\views\\online_streams\\watch.php","limit":80}
```
### Tool Get Mcp Tools
```
{"server":"user-context7","toolName":"resolve-library-id","toolCallId":"call-750a1a6b-1453-4306-b678-35c841da8b90-7\nfc_8e092b8b-4d45-9426-8346-b4c4098c19e7_4"}
```
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\app\\Http\\Controllers\\MasterCabinetController.php","offset":100,"limit":80}
```
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\app\\Http\\Controllers\\OnlineStreamController.php"}
```
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\routes\\web.php","offset":325,"limit":50}
```
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\resources\\views\\online_streams\\watch.php","offset":80}
```
### Tool Ripgrep Raw Search
```
{"pattern":"full_name|first_name|fillable","path":"c:\\OSPanel\\home\\inbi.loc\\app\\Models\\User.php","caseInsensitive":false,"multiline":false,"toolCallId":"call-1144a86f-6259-4026-be4c-90467ceba0c9-12\nfc_7b6ccc09-995d-92e7-a35f-6c5e2e2c873c_4","offset":0}
```
### Tool Mcp
```
{"name":"user-context7-resolve-library-id","args":{"libraryName":"Laravel","query":"Cache put get array TTL Laravel 11"},"toolCallId":"call-1144a86f-6259-4026-be4c-90467ceba0c9-13\nfc_7b6ccc09-995d-92e7-a35f-6c5e2e2c873c_5","providerIdentifier":"context7","toolName":"resolve-library-id","smartModeApprovalOnly":false,"skipApproval":false}
```
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\app\\Models\\User.php","limit":80}
```
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\app\\Http\\Controllers\\MasterCabinetController.php","limit":50}
```
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Edit File V2
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\routes\\web.php","limit":30}
```
### Tool Ripgrep Raw Search
```
{"pattern":"csrf-token","path":"c:\\OSPanel\\home\\inbi.loc\\resources\\views\\layouts","caseInsensitive":false,"multiline":false,"toolCallId":"call-c4cd5931-d05c-4573-8b5c-a2fbc9960c39-28\nfc_5a84cb3d-5c68-9c96-9428-2148daa2e99c_1","offset":0}
```
### Tool Edit File V2
### Tool Run Terminal Command V2
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\app\\Services\\Streaming\\StreamChatService.php"}
```
### Tool Ripgrep Raw Search
```
{"pattern":"CACHE_","path":"c:\\OSPanel\\home\\inbi.loc\\.env","caseInsensitive":false,"multiline":false,"toolCallId":"call-b59abfc8-1bd6-4d4a-b10b-8eb0674798a4-32\nfc_73024080-e38d-9a3f-bdc1-ba358cdf2a8b_1","offset":0}
```
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\resources\\views\\online_streams\\watch.php","limit":60}
```
### Tool Read File V2
```
{"path":"c:\\OSPanel\\home\\inbi.loc\\resources\\views\\master\\cabinet\\broadcast.php","limit":55}
```
## Assistant
Готово: справа от видео у мастера и зрителей появился чат на время эфира.
**Как работает**
- Зрители пишут сообщения, мастер видит их (и может отвечать).
- Сообщения живут только в Cache, в БД не пишутся.
- После «Завершить трансляцию» чат очищается.
- Гостю без имени показывается поле «Ваше имя»; у авторизованных берётся имя из профиля.
Чат виден только пока трансляция live.