Сбой соединения Kurento WebRTC в ~30% случаев

Я провел дни, выискивая проблему с подключением без какой-либо удачи. Я пытаюсь реализовать относительно простой one2one Call с Kurento.

Ниже вы найдете журнал отладки Kurento для случая, когда соединение могло быть установлено, и случая, когда соединение не удалось.

Если вам нужно больше журналов (например, клиентов, сигнального сервера, tcpdumps или журналов трассировки Kurento, просто дайте мне знать, и я предоставлю!)

Любая помощь или новый вклад с благодарностью!

Описание проблемы:

Примерно в 30% случаев соединение WebRTC не может быть установлено. К сожалению, мне не хватает какого-либо паттерна, когда Соединение может быть установлено, а когда нет, оно кажется совершенно случайным. Я нахожусь в той же сети, использую те же устройства, использую тот же сервер TURN, использую тот же протокол сигнализации, но в 30% случаев соединение не может быть установлено.

Когда я запускаю приложение локально, кажется, что оно работает намного надежнее, соединение может быть установлено почти в 100% случаев (или, может быть, даже в 100% случаев, я столько раз тестировал, что терял трек). Я настроил инфраструктуру локально с помощью Docker и запускаю различные контейнеры (TURN, Kurento, Signaling) в отдельных сетях, чтобы имитировать производственное развертывание.

Такое же поведение мы наблюдаем в нашей среде разработки и производства. В нашей среде разработки у нас абсолютно нет брандмауэров, так что, похоже, это не проблема.

Что я пытался найти причину проблемы:

В основном я сравнивал журналы дел, которые работали, и дел, которые не работали, но я не смог найти какой-либо существенной разницы между ними, которая могла бы указать мне на проблему.

Я проверил соединение WebRTC через сервер TURN (с Firefox и флагом force_relay) и напрямую через Kurento, но в обоих случаях соединение обрывается в ~30% случаев.

Я попытался отфильтровать всех кандидатов ICE, которые не являются кандидатами на ретрансляцию.

Я прослушал трафик между нашим сервером сигнализации (который также контролирует Kurento) и Kurento, чтобы увидеть какие-либо различия в обмене сообщениями JSON RPS, но они, по сути, одинаковы.

Я проверил наш сервер STUN и TURN с помощью этого инструмента: https://webrtc.github.io/samples/src/content/peerconnection/trickle-ice/ и я получил как серверные рефлексы, так и ретрансляторы, которые выглядят правильно

Я обнаружил трафик от клиентов успешного и неудачного соединения, но смог заметить существенную разницу

Я упростил медиа-конвейер Kurento (без записи, без хабов), но поведение такое же

Я использовал разные браузеры (Chrome, Firefox и нативная реализация iOS), но поведение такое же

Куренто отлаживает логи случая, когда соединение может быть установлено:

https://gist.github.com/omnibrain/2bc7ad54f626d278d3c8bac29767ac4c

Kurento отладки журналов случая, когда соединение не может быть установлено:

https://gist.github.com/omnibrain/f7caee04a5c6d77ea22a9ccfa95dd825

2 ответа

После нескольких дней отладки и почти безумия мы наконец нашли причину нашей проблемы:

Мы использовали Swift-клиент Socket.IO и серверную реализацию Java Netty Socket.IO Socket.IO. Клиент (iOS) использует длинный опрос для связи с сервером (Java). Оказывается, что сервер Netty Socket.IO выполняет URL-декодирование полезной нагрузки длинного опроса клиента Swift Socket.IO, но клиент Swift Socket.IO фактически не кодирует его URL-адресом. Это означало, что каждое "+", которое было отправлено с клиента Swift Socket.IO, было заменено на " " (пробел) на сервере. Почему это проблема? Потому что предложение SDP клиента содержит ufrag, который может содержать знак плюс! Таким образом, если SDP содержал "+", он был заменен на сервере пробелом, что приводило к сбою эхо-запросов STUN из-за невозможности проверки целостности сообщения.

Глядя на ваши следы, ваш рабочий случай выбирает кандидата 10, затем выбирает кандидата 7, нерабочий выбирает только кандидата 10.

kurento_logs_webrtc_working.txt

New candidate pair selected, local: 'candidate:10 1 UDP 335544831 10.10.36.134 50589 typ relay raddr 172.19.0.2 rport 9', remote: 'candidate:3993072200 1 UDP 41885695 10.10.36.134 53894 typ relay', stream_id: '1', component_id: 1
...
New candidate pair selected, local: 'candidate:7 1 UDP 1677722111 10.10.36.131 46842 typ srflx raddr 172.19.0.2 rport 46842', remote: 'candidate:266015763 1 UDP 2122260223 10.10.1.57 55125 typ host', stream_id: '1', component_id: 1

kurento_logs_webrtc_NOT_working.txt

new candidate pair selected, local: 'candidate:10 1 UDP 335544831 10.10.36.134 51280 typ relay raddr 172.19.0.2 rport 9', remote: 'candidate:3993072200 1 UDP 41885695 10.10.36.134 51287 typ relay', stream_id: '1', component_id: 1

Сначала я подумал, что вы повторно используете старых кандидатов, но порты изменились. Смена браузеров может изменить число кандидатов, я не ожидал, что они будут детерминированными между прогонами, поэтому мне пришлось посмотреть дважды.

Есть одно небольшое отличие от журнала - это нерабочий IceComponentStateChanged изменения в connecting после candidate:266015763 появляется скорее, чем раньше. Я не знаю, если это важно.

Главные примечания:

В прошлом, когда у нас было несколько категорий проблем:

  • на стороне клиента мы теряли кандидатов ICE - некоторые из кандидатов были отправлены до того, как мы были готовы, поэтому нам нужно было поставить их в очередь. IIRC, возможно, есть некоторые кандидаты в предложении SDP (или ответ, извините, это было давно), поэтому ваши слушатели должны быть готовы, прежде чем начать.
  • мы отправляли старых кандидатов - на сервере сигнализации использовался неправильный элемент воспроизведения, чтобы предложить кандидатов клиентам, и они больше не действительны.

Я бы порекомендовал вам использовать Chrome с http://chrome//webrtc-internals, чтобы помочь. Проблемы кандидатов в ICE видны в webrtc-internals, поскольку вы можете видеть конечный автомат, проходящий через его состояние. В нашем рабочем случае гораздо больше переходов, чем в сломанных.

Добавление слушателей на стороне клиента для трех ледовых событий также полезно:

this.peer.peerConnection.oniceconnectionstatechange = this.logloglog.bind(this, this.peer.peerConnection);
this.peer.peerConnection.onicegatheringstatechange = this.logloglog.bind(this, this.peer.peerConnection);
this.peer.peerConnection.onsignalingstatechange = this.logloglog.bind(this, this.peer.peerConnection);

Это позволяет увидеть, как идут переговоры, но в основном это то, что находится в http://chrome//webrtc-internals.

последнее замечание, это то, что я использовал в разделе журнала /etc/default/kurento-media-server:


# ICE debug logging: uncomment to enable in KMS and in the 3rd-party library 'libnice'
# - Note: This can get very verbose, log size will explode in the long term
#export GST_DEBUG="$GST_DEBUG,kmsiceniceagent:5,kmswebrtcsession:5,webrtcendpoint:4"
export G_MESSAGES_DEBUG="libnice,libnice-stun"
export NICE_DEBUG="$G_MESSAGES_DEBUG"

Я не помню, были ли они лучше, чем вы использовали, но я добавлю это там.

Другие вопросы по тегам