Проблема

Sony постепенно ограничивает возможности PS5: кнопка «Broadcast» есть, но она работает только с парой поддерживаемых сервисов. Стоит захотеть сделать что-то своё — начинаются проблемы.

Регулярно возникает необходимость стримить игры друзьям в Discord, но консоль не поддерживает трансляцию туда. Очевидное решение — capture card: подключить HDMI в карту захвата, затем в OBS на Mac и стримить оттуда. Но приличные карты стоят от $100, а такие расходы казались избыточными.

Remote Play

Remote Play частично помог. Можно подключить PS5 к MacBook, расшарить экран Mac в Discord и играть оттуда.

Но для этого нужно перепроключить контроллер, наушники и прочее на Mac. Плюс иногда появляется input lag, а качество трансляции полностью контролирует PS5 — настроить ничего нельзя.

Переключать физическое подключение каждый раз для стрима — не лучший вариант.

Как работает стриминг PS5

PS5 поддерживает трансляцию на YouTube и Twitch по умолчанию, если вы авторизованы. Протокол — RTMP (Real-Time Messaging Protocol), стандартный для live audio/video.

Когда начинается трансляция, PS5 примерно делает так:

А что если заставить собственное устройство подделаться под Twitch и получить тот RTMP-поток?

PS5 не хардкодит IP Twitch — каждый раз ищет через DNS. Если контролировать ответы DNS, получится контролировать, куда попадёт поток.

Поиск правильного хоста

Первый шаг — подделать ingest.twitch.tv напрямую. Это же имя PS5 разрешает при запуске трансляции, должно сработать?

Не совсем. ingest.twitch.tv:443 — это не сам RTMP-сервер, а эндпоинт обнаружения. PS5 делает HTTPS-запрос: «какой региональный ingest-сервер мне использовать?» Twitch отвечает что-то вроде ap-southeast-1.prod.fi.contribute.live-video.net. Уже туда идёт реальный поток.

Попытка подделать этот хост столкнулась с другой проблемой: Twitch использует RTMPS (RTMP over TLS на порту 443), и PS5 проверяет сертификат по trusted CA. Самоподписный сертификат не проходит, а установить кастомные CA на PS5 нельзя.

Попробовали YouTube — его RTMP ingest использует plain RTMP на порту 1935, без TLS. PS5 счастливо отправил поток на Mac, базовый подход работал.

Но YouTube периодически проверяет API, транслируется ли стрим на самом деле. Раз YouTube не получил поток, проверка не прошла, и через 60 секунд трансляция остановилась.

Нужен был Twitch-эндпоинт с plain RTMP. Ответ нашёлся в логах DNS при трансляции:

sudo tail -f /tmp/dnsmasq.log
# Sep 22 23:20:28 dnsmasq: query[A] ingest.global-contribute.live-video.net from 192.168.8.171
# Sep 22 23:20:28 dnsmasq: reply aps30.contribute.live-video.net is 35.55.13.0

PS5 разрешал ingest.global-contribute.live-video.net, который ведёт к aps30.contribute.live-video.net. Это настоящий RTMP-сервер. Подделав contribute.live-video.net, можно перехватить поток на Mac без сертификатов.

DNS-трюк

Решение состоит из двух частей: dnsmasq и nginx-rtmp. На Mac запущена небольшая app в меню, которая управляет обоими.

На Mac работает dnsmasq, настроенный разрешать домены Twitch ingest на локальный IP:

server=1.1.1.1
server=8.8.8.8

# Redirect Twitch ingest traffic to the Mac
address=/contribute.live-video.net/192.168.8.175
address=/ingest.global-contribute.live-video.net/192.168.8.175
address=/live.twitch.tv/192.168.8.175
address=/live-sin.twitch.tv/192.168.8.175
address=/live-nrt.twitch.tv/192.168.8.175
address=/live-syd.twitch.tv/192.168.8.175
address=/live-fra.twitch.tv/192.168.8.175
address=/live-ams.twitch.tv/192.168.8.175
address=/live-lhr.twitch.tv/192.168.8.175
address=/live-jfk.twitch.tv/192.168.8.175
address=/live-lax.twitch.tv/192.168.8.175
address=/live-sea.twitch.tv/192.168.8.175

log-queries
log-facility=/tmp/dnsmasq.log

no-hosts
listen-address=0.0.0.0

192.168.8.175 — IP Mac. Когда PS5 спрашивает DNS один из этих эндпоинтов, dnsmasq возвращает IP Mac. PS5 подключается, думая, что это Twitch.

Последний шаг — указать PS5 на этот DNS-сервер. На GL.iNet роутере с OpenWRT настроил выдачу IP Mac как DNS-сервера именно для PS5:

# SSH into the router and run:
uci add_list dhcp.lan.dhcp_option="tag:PS5,6,192.168.8.175"
uci commit dhcp
/etc/init.d/dnsmasq restart

tag:PS5 работает, потому что у PS5 уже есть тег в /etc/config/dhcp. Опция 6 — это DHCP-опция для DNS-сервера. PS5 подхватит это при следующем обновлении DHCP, на консоли ничего настраивать не нужно!

Получение потока

Для этого используется nginx-rtmp:

worker_processes 1;

error_log /tmp/nginx-error.log warn;
pid /tmp/nginx.pid;

events {
    worker_connections 512;
}

rtmp {
    server {
        listen 1935;
        chunk_size 4096;
        application ps5 {
            live on;
            record off;
            sync 10ms;
            # Notify our app when a stream starts
            on_publish http://127.0.0.1:9988/on_publish;
        }
    }
}

http {
    server {
        listen 8080;
        location /stat {
            rtmp_stat all;
        }
    }
}

Колбэк on_publish — это то, как app узнаёт о начале трансляции с PS5. Nginx отправляет POST на localhost:9988 с именем потока, и app выводит готовый RTMP URL.

На этом этапе PS5 отправляет свой поток (1080p60, H.264, AAC stereo) напрямую на Mac вместо Twitch.

Дальше поток можно использовать где угодно: натянуть в OBS для перетрансляции, записать локально или просто смотреть.

Просмотр

Вместо OBS использован mpv — он вытягивает поток и расшаривает окно в Discord. Профиль low-latency держит задержку менее секунды:

mpv --profile=low-latency --audio-buffer=0.3 rtmp://127.0.0.1/ps5/stream-key

Оказалось достаточно надёжно. Несколько недель использования — никаких проблем. Весь исходный код на GitHub.