Как Peering передаёт экран Mac на iPhone
Удалённый рабочий стол это видеопоток с одним необычным требованием: тот, кто смотрит, ещё и управляет. Все решения ниже вытекают из желания держать эту петлю короткой.
Захват: просим у системы картинку
Приложение на Mac получает кадры через ScreenCaptureKit от Apple. Источником может быть весь дисплей, все окна одного приложения или одно окно, и между ними можно переключаться, не разрывая соединение. Поэтому macOS при первом запуске и спрашивает разрешение «Запись экрана»: без него Mac может отдать только чёрную картинку.
Кодирование: малая задержка, без перестановки кадров
Кадры попадают в кодировщик VideoToolbox от Apple на Mac, как H.264 или HEVC, в зависимости от того, что iPhone умеет декодировать. Настройки противоположны тем, что у стриминговых сервисов:
- Без B-кадров. B-кадру нужен кадр из будущего, поэтому их использование означает, что картинки приходится придерживать. Без них порядок декодирования совпадает с порядком показа, и никто никого не ждёт.
- Управление битрейтом с малой задержкой. Кодировщик тратит биты по ходу дела, а не заглядывает вперёд.
- Ключевой кадр не реже чем раз в две секунды и сразу же, когда подключается новый зритель, возобновляется показ или меняется источник, так что потерянная картинка быстро восстанавливается.
- Битрейт, который растёт вместе с экраном. По умолчанию это число пикселей, умноженное на частоту кадров и на 0,12, в пределах от 4 до 30 Мбит/с, при 60 кадрах в секунду по умолчанию.
Служебная информация для декодера (наборы параметров) отправляется один раз отдельным сообщением и не повторяется в каждом кадре. iPhone, который подключился посреди потока, получает это сообщение, а затем ключевой кадр.
Отправка: кадры можно отбрасывать, ключевые кадры нельзя
Каждый кадр идёт с небольшим 25-байтным заголовком: ключевой ли он, его размер в пикселях и время показа. В релейном или прямом соединении он нарезается на датаграммы примерно по 1080 байт, и каждая запечатывается ChaCha20-Poly1305 ключом, который знают только два устройства. Счётчик в каждой датаграмме питает окно защиты от повторов на 64 записи, так что перехваченный пакет нельзя воспроизвести позже.
Правило при перегрузке прямолинейно: видео можно отбрасывать, ключевые кадры нельзя. Если новый кадр готов, пока старый ещё ждёт отправки, старый заменяется, кроме одного случая: недоставленный ключевой кадр никогда не заменяется обычным. Показать экран таким, какой он сейчас, важнее, чем показать каждый кадр, который когда-либо существовал.
В домашней сети картинка идёт по собственному TCP-соединению, где сеть достаточно надёжна, и это
правило срабатывает редко. На каждом сокете включён TCP_NODELAY. Поведение по
умолчанию, когда мелкие записи склеиваются в пакет, добавляет десятки миллисекунд на каждом
отрезке пути. При скачивании файла это незаметно, а когда вы двигаете курсор, очень заметно.
Восстановление: за потери платим картинкой, а не задержкой
UDP не пересылает потерянное, поэтому потерянная датаграмма означает повреждённый кадр. iPhone её не ждёт. Он продолжает декодировать, и искажение пропадает на следующем ключевом кадре, не позже чем через две секунды. Если после неудачного участка Wi-Fi вы заметили смазанность, это она и есть. Пауза и возобновление картинки немедленно вызывают ключевой кадр.
Если быстрый путь перестаёт доставлять вообще, поток переходит на управляющее соединение с меньшим битрейтом, как описано в статье о соединении, и возвращается, когда быстрый путь оживает.
Показ: под iPhone, а не под Mac
iPhone выбирает уровень качества и может запросить меньше кадров в секунду, а Mac приведёт это к разумному диапазону. Приложение может уместить весь рабочий стол на экране или заполнить им экран, а ещё попросить у Mac виртуальный дисплей по форме iPhone, чтобы широкий монитор не сжимался в вертикальный экран. Касания картинки идут в обратную сторону, об этом рассказывает статья как касание становится кликом.
Вопросы
Какой видеокодек использует Peering?
H.264 или HEVC, кодирование на Mac через VideoToolbox, без B-кадров и с настройками малой задержки. iPhone сообщает Mac, что он умеет декодировать.
Почему картинка иногда на миг смазывается?
Потерянный сетевой пакет повреждает кадр, и картинка восстанавливается на следующем ключевом кадре, который приходит не реже чем раз в две секунды. Peering предпочитает короткую смазанность ожиданию повторной отправки.