Пользователь
0,1
рейтинг
26 декабря 2013 в 15:03

Администрирование → Стандарт Miracast — старые протоколы в новой обёртке из песочницы

Не так давно (начиная с JellyBean 4.2) Google добавила в Android поддержку технологии Miracast.
Практическому исследованию этой технологии методами reverse engineering и посвящена статья.

Что такое Miracast в двух словах? Это очередное детище Wi-Fi альянса — стандарт для передачи мультимедийного контента по сети Wi-Fi в peer-to-peer режиме. Для пользователя это означает прежде всего то, что для соединения с телевизором (к примеру) ему не понадобится Wi-Fi маршрутизатор. Два устройства по задумке альянса должны связываться друг с другом напрямую. Это обеспечивается использованием стандарта Wi-Fi Direct за авторством той же организации. Иными словами, новый стандарт решает задачи очень похожие на AirPlay от Apple, WiDi от Intel, или старое-доброе DLNA.

Зачем было городить огород — спросите вы. Почему было не воспользоваться уже существующим решением? Тут мне будет трудно ответить. Понятно, что лицензировать решения от прямых конкурентов или даже от Intel — не кошерный вариант имеющий к тому же фатальный недостаток, но почему не взять то же DLNA, возможно, чуть доработав рашпилем. Быть может, хотелось чего-то новенького, с модными нонче словами peer-to-peer? Не буду гадать. Так или иначе, технология была реализована в Android, и свежие телефоны типа Nexus 4 и Samsung Galaxy S3 имеют ее на борту.

Хуже обстоит дело с производителями телевизоров. Если поддержка DLNА уже есть практически в каждом современном телевизоре достаточно высокого уровня, то с Miracast дела обстоят хуже. Несмотря на существование чипов, модели телевизоров и проекторов умеющие принимать Miracast можно пересчитать по пальцам. Впрочем, ситуация наверняка изменится в 2014 году, а пока — пользователь может довольствоваться многочисленными гаджетами, принимающими сигнал по Wi-Fi и преобразующими его в HDMI. Такая штука втыкается в HDMI-разъем телевизора, и вот уже у вас есть Miracast-enabled устройство!

Один из инженерных образцов с чипом Broadcom попал в мои цепкие руки:

внешний вид

Убедившись, что с Android-смартфоном все работает на ура, я задумался над вопросом — нельзя ли наладить вещание через Miracast прямо из под Linux? Ведь что такое Android внутри? Тот же Linux…

Для начала, хотелось понять как вообще выглядит стек протоколов Miracast? Что стоит за красивым названием? Гонится ли видео-сигнал напрямую в Ethernet-фреймах или используется IP и еще более высокоуровневые протоколы. К сожалению, сам стандарт, хоть и открытый, но далеко не бесплатный, так что пришлось изыскивать иные, более традиционные пути исследования. В какой-то презентации я ухватил ключевые слова — MPEG-TS и RTSP, и это дало возможность раскрутить клубок дальше. Если я хоть что-то в чем-то смыслю, то RTSP — это TCP, а TCP — это IP. А IP — это подходящий протокол, который можно послушать tcpdump-ом! Сказано-сделано, запустив на Nexus-е tcpdump и включив Wireless display в настройках, через 5 минут я имел дамп пакетов, приемлемый для дальнейшего анализа.

Временно отложив трудности с соединением через Wi-Fi я взялся сразу за анализ TCP-потока. И вот что увидел:

OPTIONS * RTSP/1.0
Date: Fri, 08 Mar 2013 12:37:54 +0000
Server: Mine/1.0
CSeq: 1
Require: org.wfa.wfd1.0

RTSP/1.0 200 OK
CSeq: 1
Public: org.wfa.wfd1.0, GET_PARAMETER, SET_PARAMETER

OPTIONS * RTSP/1.0
CSeq: 1
Require: org.wfa.wfd1.0

RTSP/1.0 200 OK
Date: Fri, 08 Mar 2013 12:37:54 +0000
Server: Mine/1.0
CSeq: 1
Public: org.wfa.wfd1.0, SETUP, TEARDOWN, PLAY, PAUSE, GET_PARAMETER, SET_PARAMETER

GET_PARAMETER rtsp://localhost/wfd1.0 RTSP/1.0
Date: Fri, 08 Mar 2013 12:37:54 +0000
Server: Mine/1.0
CSeq: 2
Content-Type: text/parameters
Content-Length: 83

wfd_content_protection
wfd_video_formats
wfd_audio_codecs
wfd_client_rtp_ports

RTSP/1.0 200 OK
CSeq: 2
Content-Type: text/parameters
Content-Length: 751

wfd_content_protection: none
wfd_video_formats: 00 00 02 10 0001bdeb 3fffffff 00000fff 00 0000 0000 11 none none, 02 08 0001bdeb 3fffffff 00000fff 00 0000 0000 11 none none, 02 04 0001bdeb 3fffffff 00000fff 00 0000 0000 11 none none, 02 02 0001bdeb 3fffffff 00000fff 00 0000 0000 11 none none, 02 01 0001bdeb 3fffffff 00000fff 00 0000 0000 11 none none, 01 10 0001bdeb 3fffffff 00000fff 00 0000 0000 11 none none, 01 08 0001bdeb 3fffffff 00000fff 00 0000 0000 11 none none, 01 04 0001bdeb 3fffffff 00000fff 00 0000 0000 11 none none, 01 02 0001bdeb 3fffffff 00000fff 00 0000 0000 11 none none, 01 01 0001bdeb 3fffffff 00000fff 00 0000 0000 11 none none
wfd_audio_codecs: LPCM 00000003 00
wfd_client_rtp_ports: RTP/AVP/UDP;unicast 6500 0 mode=play
SET_PARAMETER rtsp://localhost/wfd1.0 RTSP/1.0
Date: Fri, 08 Mar 2013 12:37:54 +0000
Server: Mine/1.0
CSeq: 3
Content-Type: text/parameters
Content-Length: 248

wfd_video_formats: 28 00 02 02 00000020 00000000 00000000 00 0000 0000 00 none none
wfd_audio_codecs: LPCM 00000002 00
wfd_presentation_URL: rtsp://192.168.16.40/wfd1.0/streamid=0 none
wfd_client_rtp_ports: RTP/AVP/UDP;unicast 6500 0 mode=play

RTSP/1.0 200 OK
CSeq: 3

SET_PARAMETER rtsp://localhost/wfd1.0 RTSP/1.0
Date: Fri, 08 Mar 2013 12:37:54 +0000
Server: Mine/1.0
CSeq: 4
Content-Type: text/parameters
Content-Length: 27

wfd_trigger_method: SETUP

RTSP/1.0 200 OK
CSeq: 4

SETUP rtsp://192.168.16.40/wfd1.0/streamid=0 RTSP/1.0
CSeq: 2
Transport: RTP/AVP/UDP;unicast;client_port=6500

RTSP/1.0 200 OK
Date: Fri, 08 Mar 2013 12:37:55 +0000
Server: Mine/1.0
CSeq: 2
Session: 1219569791;timeout=30
Transport: RTP/AVP/UDP;unicast;client_port=6500;server_port=15550

PLAY rtsp://192.168.16.40/wfd1.0/streamid=0 RTSP/1.0
CSeq: 3
Session: 1219569791

RTSP/1.0 200 OK
Date: Fri, 08 Mar 2013 12:37:55 +0000
Server: Mine/1.0
CSeq: 3
Session: 1219569791;timeout=30
Range: npt=now-

SET_PARAMETER rtsp://localhost/wfd1.0 RTSP/1.0
Date: Fri, 08 Mar 2013 12:38:07 +0000
Server: Mine/1.0
CSeq: 5
Content-Type: text/parameters
Content-Length: 30

wfd_trigger_method: TEARDOWN
RTSP/1.0 200 OK
CSeq: 5

TEARDOWN rtsp://192.168.16.40/wfd1.0/streamid=0 RTSP/1.0
CSeq: 4
Session: 1219569791

RTSP/1.0 200 OK
Date: Fri, 08 Mar 2013 12:38:09 +0000
Server: Mine/1.0
CSeq: 4
Session: 1219569791;timeout=30
Connection: close


Неправда ли, напоминает обычный RTSP. Итак, часть дела сделана. Остается понять чем отличается Miracast-овская реализация RTSP от стандартной. Для тех, кто никогда не сталкивался с RTSP (Real Time Streaming Protocol) напомню, что он используется для управления мультимедийным потоком с сервера на клиенте. Сиречь — позволяет выдать такие команды как PLAY, PAUSE, TEARDOWN и т.п. Также имеется возможность обменяться опциями и настроить параметры. Именно {GET|SET}_PARAMETER и стали основной моей головной болью при анализе. Не имея под рукой стандарта, я не мог знать, что значат все эти wfd_video_formats, wfd_audio_codecs и т.п. Но мог догадываться!

Поскольку из анализа фреймов MPEG-TS я понял, что использовалось стандартное разрешение 720x480, и кодек H.264 (AVC), то было неплохой идеей создать видеофайл с ровно такими же параметрами, и тогда поля типа wfd_video_formats можно оставить без изменения! Порывшись в DVD-дисках я перекодировал небольшой VOB из телесериала «Cracker», в нужный мне формат посредством ffmpeg. Теперь оставалось только скормить файл серверу. Но для этого нужно найти сервер!

Чтобы не писать RTSP-сервер самостоятельно (что никак не входило в мои планы) я начал просматривать Open Source варианты, которые было бы легко доработать до состояния совместимого с Miracast. Если вы внимательно смотрели на логи из tcpdump-а, то могли заметить несколько странностей. Традиционная клиент-серверная модель RTSP заменена «peer-to-peer» взаимодействием. Это значит, что активность в запросах может исходить не только от клиента (им в данном случае выступает телевизор или проектор), а и от «сервера» (то бишь телефона или компьютера). Зачем понадобилось так делать — непонятно, но факт остается фактом — и «клиент» и «сервер» могут слать запросы когда им вздумается, что сводит на нет их традиционные роли. Тем не менее, сторону которая шлет видеосигнал я буду продолжать именовать сервером (в нашем случае это Linix-PC), а сторону, принимающую и декодирующую видео — клиентом (в нашем случае — это будет проектор).

Итак, после нескольких часов поисков я остановился на live555. Этот сервер написан на С++, распространяется под лицензией LGPL и поддерживает как RTSP, так и вещание в MPEG-TS. Поглядев на обработчик RTSP я понял, что его вполне реально переработать под peer-to-peer специфику Miracast. Но, оставалось еще заставить клиента (т.е. Мiracast-гаджет) соединяться с Linux!

Эта задача была посложней «Фауста» Гёте. Прежде я никогда не настраивал в Linux-е даже обычный Wi-Fi, справедливо полагая, что провода как-то понадежнее. Что уж говорить про Wi-Fi Direct. Однако, прочитав стопку manual-ов, я понял, что надо рыть в направлении загадочного WPA supplicant. Для чего нужен этот supplicant? Именно он обеспечивает аутентификацию при подключении по Wi-Fi к точке доступа или к другому узлу. Как я уже писал выше, Miracast работает в режиме p2p, т.е. устройства связываются напрямую, минуя маршрутизаторы. Эта возможность, к счастью, поддержана в последних версиях wpa_supplicant. Не знаю точно, с какого момента была добавлена поддержка p2p, но в версии 2.1-devel она уже есть.

Однако, обновить supplicant мало! Надо еще иметь конфигурационные файлы для него. С грехом пополам я написал конфигурацию приемлемую для моего устройства (NetGear, WNA1100 Wireless-N 150 [Atheros AR9271]), возможно, она подойдет и вам.

Итак, в файле /etc/wpa_p2p.conf пишем:
ctrl_interface=/var/run/wpa_supplicant
ap_scan=1

device_name=JellyFish
device_type=1-0050F204-1


Далее, нужен shell-скрип для запуска supplicant:

sudo iwconfig wlan0 mode ad-hoc
sudo ip link set wlan0 up

sudo wpa_supplicant -Dnl80211 -c /etc/wpa_p2p.conf -i wlan0 -dt


Вот вроде и все (уточню, что данная конфигурация работает в Ubuntu-based дистрибутиве Linux Mint 13 Maya, версия ядра — 3.2.0-57-generic).

Дальше нужно овладеть такой утилитой как wpa_cli, именно она позволяет управлять соединением «вручную».
После запуска wpa_supplicant через скрипт, нужно открыть отдельную консоль и выдать что-то вроде:

sudo wpa_cli


Это командный интерфейс к supplicant-у. Включив гаджет мы можем командой p2p_find найти все устройства в округе, готовые подключиться к нам в режиме p2p. Далее, используя команду p2p_connect мы производим само подключение.

Вот пример лога для моего устройства:

wpa_cli v2.1-devel
Selected interface 'wlan0'
Interactive mode

> p2p_find
OK
<3>P2P-DEVICE-FOUND 02:90:4c:04:04:04 p2p_dev_addr=02:90:4c:04:04:04 pri_dev_type=7-0050F204-1 name='MLT-52-2123' config_methods=0x4688 dev_capab=0x25 group_capab=0xa
> 
> p2p_connect 02:90:4c:04:04:04 pbc
OK
<3>P2P-FIND-STOPPED                   <--- Тут надо нажать кнопку на устройстве
<3>P2P-GO-NEG-SUCCESS 
<4>Failed to initiate AP scan
<4>Failed to initiate AP scan
<4>Failed to initiate AP scan
<4>Failed to initiate AP scan
<3>CTRL-EVENT-SCAN-RESULTS 
<3>WPS-AP-AVAILABLE-PBC 
<3>SME: Trying to authenticate with 02:90:4c:04:84:04 (SSID='DIRECT-fCMLT-52-2123' freq=2412 MHz)
<3>Trying to associate with 02:90:4c:04:84:04 (SSID='DIRECT-fCMLT-52-2123' freq=2412 MHz)
<3>CTRL-EVENT-SCAN-RESULTS 
<3>WPS-AP-AVAILABLE-PBC 
<3>SME: Trying to authenticate with 02:90:4c:04:84:04 (SSID='DIRECT-fCMLT-52-2123' freq=2412 MHz)
<3>Trying to associate with 02:90:4c:04:84:04 (SSID='DIRECT-fCMLT-52-2123' freq=2412 MHz)
<3>Associated with 02:90:4c:04:84:04
<3>CTRL-EVENT-EAP-STARTED EAP authentication started
<3>CTRL-EVENT-EAP-PROPOSED-METHOD vendor=14122 method=1
<3>CTRL-EVENT-EAP-METHOD EAP vendor 14122 method 1 (WSC) selected
<3>WPS-CRED-RECEIVED 
<3>WPS-SUCCESS 
<3>P2P-GROUP-FORMATION-SUCCESS 
<3>CTRL-EVENT-EAP-FAILURE EAP authentication failed
<3>CTRL-EVENT-DISCONNECTED bssid=02:90:4c:04:84:04 reason=3 locally_generated=1
<3>CTRL-EVENT-SCAN-RESULTS 
<3>WPS-AP-AVAILABLE 
<3>SME: Trying to authenticate with 02:90:4c:04:84:04 (SSID='DIRECT-fCMLT-52-2123' freq=2412 MHz)
<3>Trying to associate with 02:90:4c:04:84:04 (SSID='DIRECT-fCMLT-52-2123' freq=2412 MHz)
<3>Associated with 02:90:4c:04:84:04
<3>WPA: Key negotiation completed with 02:90:4c:04:84:04 [PTK=CCMP GTK=CCMP]
<3>CTRL-EVENT-CONNECTED - Connection to 02:90:4c:04:84:04 completed [id=0 id_str=]
<3>P2P-GROUP-STARTED wlan0 client ssid="DIRECT-fCMLT-52-2123" freq=2412 psk=fd435c6683ae5d7c9e3398dab15cc1b80d7f308b3fe7330db044ea90dcf7ac31 go_dev_addr=02:90:4c:04:04:04 [PERSISTENT]


В принципе, из лога все понятно, кроме разве что загадочного слова 'pbc' в команде p2p_connect после адреса устройства. Что же оно значит? Это один из вариантов аутентификации при подключении по Wi-Fi direct. Означает он — Push Button Control. Это упрощенная аутентификация, не требующая от пользователя ввода пароля или даже pin-кода. Просто в момент соединения нужно нажать кнопку на устройстве, и аутентификаця будет считаться успешной.

Итак, из лога мы видим, что соединение успешно произошло. И теперь мы имеем возможность получить IP-адрес для интерфейса wlan0.
DHCP-сервером в данном случае будет выступать телевизор или проектор. Введем в отдельном терминале:

sudo dhclient wlan0


Если после этого запустить tcpdump, то мы обнаружим попытки посылки SYN-пакета на порт 7236. Этот порт отличается от стандартного порта для RTSP (554), но пугать это нас не должно. Самое главное, что гаджет хочет с нами договориться! Запустив уже слегка доработанный livemedia сервер на этом порту (7236) мы получаем возможность отлаживать собственно «клиент-серверное» взаимодействие.

Я не буду утомлять читателя подробностями отладки протокола, скажу лишь, что все проблемы так или иначе были решены. И вот, наконец, результат налицо — я смог смотреть видео со своего PC через новомодный Miracast!



Нужно ли это вам? Не знаю. Во всяком случае, разобраться в новом стандарте всегда интересно (если конечно это не ASN.1).

Для тех, кому было лень вникать в технические подробности тезисно обрисую процедуру соединения для Miracast-based устройств:

  1. Используя Wi-Fi direct, устройства находят друг друга (обычно — источник видео-данных находит устройство отображения)
  2. Используя ту или иную форму аутентификации (в нашем случае — pbc) устройства объединяются в P2P-группу
  3. Одно из устройств получает IP-адрес по DHCP (в нашем случае — это источник видео-данных)
  4. На источнике данных на порту 7236 запускается RTSP-сервер
  5. Клиент подключается к RTSP-серверу, и запрашивает некий предопределенный URL (/wfd1.0/streamid=0)
  6. RTSP-сервер начинает передавать видео (и, возможно, аудио) данные в форме MPEG-TS упакованных в RTP-пакеты.
  7. Клиент распаковывает данные и отображает их на устройстве вывода.


Из явных недостатков Miracast (не упомянутых в Wiki) я бы отметил следующие:
  • Если вы подключаетесь к Miracast-устройству то теряете возможность работы через обычный (не P2P) Wi-Fi. Чтобы одновременно пользоваться традиционным Wi-Fi и Wi-Fi direct нужен специальный двух-канальный Wi-Fi адаптер. Он имеется далеко не во всех телефонах!
  • Качество картинки на динамичных сценах страдает даже при разрешении 720x480, 30 FPS. Я уж не говорю про Full HD. Разумеется, с появлением более мощных процессоров картина будет меняться, но пока все печально.

Вот собственно и все. Если у вас остались вопросы — задавайте в комментариях.
Andrew Jelly @A_J
карма
14,0
рейтинг 0,1
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Самое читаемое Администрирование

Комментарии (15)

  • +1
    Какова себестоимость такой железки для старого телевизора? Можно ли её стразу встраивать в Android-приставки и насколько это увеличит их цену? Реально ли сделать софтовую реализацию, чтобы гонять Android -> Android или лучше воспользоваться в такой ситуации классикой типа DLNA?
    • 0
      Китайцы отдают свои изделия такого типа ~ по 20$ (и там даже бывают конфигурации сразу с тремя стандартами — AirPlay, DLNA, Miracast). Искать по контексту «HDMI Miracast dongle». Реализация от NetGear, в некотором роде — референсная — PTV3000 стоит аж 60$.

      Софтовая реализация возможна, если имеется аппаратная поддержка кодека для H.264, иначе будет зверски тормозить (на телефоне). Насчет приставок не скажу — не владею предметом. По мне, если уж поддержка классики типа DLNA встроена, то и хорошо. От добра добра не ищут.

    • +1
      Брендированный Prestigio MultiScreen PMD1 стоит от $40 в России. Втыкается в HDMI, требует питание USB, ощутимо греется при использовании. Тестировали со смартфонами на Mediatek MT6589 и MT6589T — звук при воспроизведении 720p видео и игр-бенчмарков похрипывает в определенные моменты, но пока не берусь судить, беда это смартфонов или железки от Prestigio. На самих устройствах ни с картинкой, ни со звуком проблем нет.
  • 0
    Насчет поддержки Miracast в телевизорах вы все же не правы. Насколько я знаю большая часть телевизоров LG и (вроде бы) Samsung 2013 года идут с поддержкой этой технологии. У Sony поддержка этой технологии точно есть в w805 и w905, насчет младших моделей сказать не могу.
    • 0
      Да, так примерно и есть. С 2013 года Miracast начинают массово встраивать. Но на момент моих экспериментов было совсем плохо.
  • 0
    А что такого фатального в WiDi? Вроде даже совместимость с DLNA есть (правда в win81 не работает)
    • 0
      Да вроде ничего фатального.
  • 0
    BTW, в RTSP нет «традиционной клиент-серверной модели», там изначально есть запросы сервер->клиент.
  • 0
    НЕ РЕКЛАМА!
    Но такая штука с поддержкой Mircast и DLNA уже есть в продаже — defender.ru/products/multimedia/smarttvaccessory/smart-transmitter-x1/
    2500 руб
  • 0
    Нужно ли это вам? Не знаю.

    HTPC-гики, да и просто гики на xbmc.org, xda, и т.д с вами не согласятся. К тому же, это почти идеальная технология для показа презентаций — донгл к проектору, в руках смартфон, планшет (а при помощи ваших изыскакий — и ноутбук), и не надо марсианских пультов или специфичного софта.

    Качество картинки на динамичных сценах страдает даже при разрешении 720x480, 30 FPS. Я уж не говорю про Full HD. Разумеется, с появлением более мощных процессоров картина будет меняться, но пока все печально.

    Насколько я понимаю, это решается уже сегодня, если на стороне сервера будет подходящая ОС. Расскажите пожалуйста, как вы видите процесс реверса принимающей видеосигнал части и предполагаемую схему работы «клиентского» ПО, если там тоже будет x86 *nix? Wi-Fi Direct (WPA supplicant, P2P) + DHCP-сервер для установки соединения, RTSP-клиент и demux-decode для H.264 внутри MPEG-TS? Это всё что нужно? RTSP-клиент всегда стучится на порт 7236? Какие еще вам известны ньюансы?

    Вообще автор, вы большой молодец — свежий бесстрашный взгляд на вещи вкупе с прямыми руками. Я много раз видел вопросы про Miracast в сообществах энтузиастов и даже чего-то сам гуглил, но там нет вообще ничего на сантиметр приближающего к реализации. А вы тут одним ударом. Если вы разрешите, и никто не сделает этого раньше, то не позднее ближайшего воскресенья я могу перевести данный лог ваших изысканий на английский и, опять же, с вашего разрешения, закинуть в места где некоторым людям это будет очень интересно. Что скажете?
    • 0
      Да, насколько я понимаю основное применение протокола — удобные презентации.

      Что касается клиента — вроде бы тут нет ничего невозможного. Того что вы описали должно хватить. Разве что я не в курсе приличных клиентов для RTSP которые можно было бы доработать. Сам я делал делал back port сервера на Android 4.0.3, не думаю, что «клиент» сложнее.

      В одном из инженерных sample этого самого miracast dongle я вообще обнаружил полноценный Android. Т.е. выходит забавно — один Android на телефоне жмет поток в H.264, другой разжимает, и все для того, чтоб показать экран телефона. Думаю если кидать jpeg-и screenshot-ов то вышло бы быстрее и проще.

      Касательно нюансов — очень важно чтоб был правильно сформирован Transport Stream. В частности — должен присутствовать корректный PCR и PTS. Без него многие клиенты отказываются отображать что либо. Но если писать клиент, то это не столь важно. Я могу, если интересно, выложить ссылку на полный лог tcpdump-а для успешного соединения и показа маленького ролика.

      Касательно перевода — я не против. Думаю, это было бы полезно сообществу.
      Я сам удивился, что на xda-developers и Stack Overflow практически нет информации по Miracast. Вроде за год должна бы уж появиться.

  • 0
    А какая задержка сигнала примерно, можете сказать?
    • 0
      упс, промахнулся. ответ ниже.
  • +1
    С задержкой конечно не ахти. Минимум, которого мне удавалось добиться — 200 ms. Обычно больше — порядка секунды-двух. Плюс еще неслабый jitter. Я пробовал пользоваться Miracast-ом в режиме VNC — выходило не очень. Как я понимаю, основное маркетинговое назначение протокола — показывать друзьям ролики и фотки с телефона на большом экране. Там, понятное дело, latency не так важна, ведь можно и буферизовать.
    • 0
      Понял, спасибо.

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