вступление
Недавно я только что закончил работать в компании, которая предоставила встраиваемую систему веб-чата с функцией голосового чата. Продукт не работал на iOS, когда я впервые присоединился к команде, из-за многочисленных проблем с iOS Safari, включая одну встроенную ошибку. Вот как я это исправил.
Как работало наше приложение
Наше приложение было спроектировано таким образом, чтобы создать новое окно (всплывающее окно) с помощью window.open(); и запустить базовый вызов WebRTC в дочернем окне. Это необходимо для настойчивости. Предоставление посетителю (Пользователю А) возможности продолжать просмотр веб-сайта без прерывания вызова. Это было одновременно улучшением пользовательского опыта и требованием нашего стороннего SIP-провайдера.
Первая проблема заключалась в том, что мы динамически создавали элемент видео/аудио с атрибутом autoplay, который не работает на iOS. Атрибут autoplay учитывается только при загрузке страницы. Достаточно простое решение — мы просто запускаем .play()и поток будет воспроизводиться. Милая, это было легко. Теперь все наше решение работает!… Подождите.
Проблема
Это по какой-то причине работает только для одного звонка. Любые последующие вызовы приведут к тому, что агент (пользователь B) не сможет услышать посетителя (пользователь A). Единственное решение - полностью сбросить настройки браузера.
Это очень странно, так как все выглядит нормально. При отладке ничего особо необычного не нашел.
Решение
После тестирования в нескольких разных средах я пришел к выводу, что проблема заключалась в закрытии всплывающего окна (содержащего вызов WebRTC). По какой-то причине кажется, что Safari не может правильно разорвать локальный поток MediaStream, что приводит к неработающему входному потоку. Единственное исправление - полная перезагрузка браузера.
К счастью, я нашел способ заставить браузер изящно закрыть всплывающее окно и не испортить дальнейшие вызовы.
Решение
В конце концов я наткнулся на исправление — если мы обновили или изменили расположение дочернего окна (которое завершает наш вызов, как упоминалось ранее), тогда MediaStream будет правильно разорван, и вы сможете закрыть окно.
Есть несколько способов сделать это, однако вот мой минимальный подход, который вы можете продемонстрировать на CodeSandbox.io.
Это приведет к полному разрыву соединения WebRTC, и агент (пользователь B) сможет слышать посетителя (пользователя A) при любых последующих вызовах. Предостережение заключается в том, что если посетитель (Пользователь А) вручную закроет всплывающее окно до того, как будет выполнен наш небольшой обходной путь, это приведет к той же ошибке, и ему потребуется перезапустить браузер.
Надеюсь, Apple исправит это в будущем обновлении. Это все еще проблема, начиная с iOS 12.