AirPlay и HDMI

This post is also available in: Английский

Если вы разработчик игровых или мультимедиа-приложений для iOS, тогда вы просто не сможете обойтись без технологии AirPlay, которая в данной области стала уже почти стандартом. В самом деле, что может быть лучше для пользователя, чем наблюдать любимые видео или фотографии на большом экране плазменного ТВ или играть на нем в современные игры, при этом держа iPhone/iPad/iPod в руках в качестве мультитач-джойстика? AirPlay предназначен именно для этого.

Как, вы до сих пор не знаете, что такое AirPlay? Не беда! В этой статье мы расскажем вам про это интереснейшее нововведение iOS 4.3, а также поведаем о том, как добавить к вашему приложению его функционал и приведём несколько полезных советов по его использованию.

Немного истории

Итак, что же такое AirPlay? AirPlay — это появившаяся начиная с версии iOS 4.3 возможность передачи видео-, фото- и аудиоконтента на внешние устройства по Wi-Fi. Таким образом любое устройство с установленной операционной системой iOS 4.3 и выше может выступать передатчиком медиаконтента. При этом приемниками для него будут служить — либо специально предназначенные для этого Apple TV и AirPort, затем передающие контент на видео- и аудиоустройства, — либо сами устройства, если они поддерживают эту функцию по умолчанию и находятся в домашней сети Wi-Fi. Сама технология чрезвычайно проста в использовании. Для того, чтобы прослушать вашу любимую песню с iPod Touch на домашней аудиосистеме, достаточно включить AirPlay на iPod, в появившемся списке выбрать нужное устройство-приёмник и нажать кнопку Play в плеере. Далее останется только наслаждаться музыкой, передающейся с плеера на аудиосистему прямо по воздуху. С видео и фотографиями ситуация абсолютно идентична.

Надо отметить, что AirPlay работает не только с контентом, воспроизводимом при помощи плеера на устройстве, но также поддерживается и в UIWebView, и может передавать видео и музыку непосредственно из Интернета.

Технология AirPlay появилась не на пустом месте. Ее предком являлась технология AirTunes, появившаяся в 2004 году, которая только лишь позволяла пользователям приложения iTunes передавать треки по Wi-Fi на внешние аудиоустройства, подключённые к сети. К 2010 году технология была усовершенствована и впервые продемонстрирована на презентации 1 сентября 2010 года. Начиная с этого момента, по сети также могут передаваться фотографии и видео.

Конечно, в первоначальном варианте с точки зрения разработчиков технология была несколько ограниченной. Единственное место её применения — это плеер, к которому можно было подключить кнопку AirPlay и в выпадающем меню выбрать устройство-приёмник для передачи. Однако уже в iOS 5 компания Apple порадовала разработчиков новым, по-настоящему полезным, расширением — функцией Mirroring (в российской версии интерфейса она называется «видеоповтор»). Этот функционал позволяет передавать на экран, подключенный по AirPlay, уже не просто видео из плеера, но и всё, происходящее на экране устройства. Такая возможность существенно расширяет область применения технологии AirPlay, так как с её помощью становится возможным создание самых разнообразных приложений с двумя экранами, в которых на внешнем дисплее мы увидим полную версию интерфейса какого-либо сложного приложения, а устройство с iOS будет играть роль управляющего устройства. Такой подход широко используется в играх. Например, это могут быть гонки, где основное действие происходит на большом экране, а iPad может являться рулём с картой трассы и интерфейсом.

У Mirroring есть и одна существенная неприятность. По внутренней сети Wi-Fi видеопоток передаётся в несжатом виде, что приводит к необходимости иметь довольно мощный домашний роутер для комфортной работы «без тормозов».

Добавление кнопки AirPlay в интерфейс вашего плеера

Итак, вы уже заинтересовались и хотите побыстрее добавить кнопку AirPlay в плеер своего приложения? Нет ничего проще. API iOS предоставляет для этой цели отдельный view-класс — MPVolumeView. Как следует из названия, функционал этого класса каким-то образом связан с громкостью воспроизведения, и действительно — это стандартный слайдер громкости. Каким образом он связан с AirPlay? Дело в том, что нет отдельного класса кнопки AirPlay. Она встроена в класс MPVolumeView. Задаем значение YES для свойства showsRouteButton и справа от слайдера появляется заветная кнопка. Далее требуется только добавить MPVolumeView в интерфейс плеера и вы увидите стандартную белую кнопку AirPlay, по нажатию на которую появляется список доступных для передачи данных устройств. Если вам нужна только кнопка, без слайдера (например, у вас кастомный плеер и уже есть собственный слайдер), то из вида MPVolumeView необходимо убрать слайдер присвоением значения NO свойству showsVolumeSlider. Здесь приведён пример добавления кнопки в интерфейс плеера.

Код, иллюстрирующий вставку кнопки в интерфейс:

[gist id=4274801 bump=1]

Нужно отметить, что поддержка AirPlay не является функционалом, инкапсулированным в класс плеера. Это функционал, который действует на уровне всей системы. Если вы выбираете устройство-приёмник, то система тут же будет знать, что к ней подключено устройство и включённый после плеер будет вести себя правильным образом — передавать видео на устройство.

Изменение внешнего вида кнопки

У вас мог возникнуть вопрос, что делать в том случае, если нужно изменить вид кнопки. Может быть, у вас свой собственный плеер, и вы не хотите делать его похожим на стандартный. В таком случае можно из массива subviews класса MPVolumeView получить ссылку на кнопку AirPlay. Кнопка включения AirPlay является обычной кнопкой класса UIButton, поэтому при наличии ссылки на неё вам становятся доступны все стандартные методы изменения её внешнего вида. Получить ссылку на кнопку весьма просто в соответствии с тем, что описано здесь. Пример кода получения ссылки приведен ниже:

[gist id=4274836]

Однако если все, что вам нужно, это изменить картинку кнопки, то начиная с iOS 6 разработчикам предоставлен удобный метод класса MPVolumeView. Это метод

-(void)setRouteButtonImage:(UIImage *)image forState:(UIControlState)state

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

Отслеживание доступности функции AirPlay

Теперь вы знаете, как добавить кнопку в интерфейс плеера и даже как настроить её внешний вид. Однако вы можете пойти ещё дальше и захотеть получать оповещения в моменты, когда в сети нет ни одного устройства для AirPlay и кнопка становится неактивной. Тогда имеет смысл и вовсе убрать кнопку, чтобы высвободить свободное место и не загружать интерфейс неактивными элементами. Если при этом нужно сдвинуть остальные элементы, то придётся как-то вычислять момент для вызова метода setNeedsLayout.

К сожалению, ни у класса MPVolumeView, ни у плеера нет никаких оповещений, связанных с кнопкой. Поэтому нет прямого способа получить оповещение о доступности или недоступности устройств. Однако в этом обсуждении предлагается хитрость, призванная помочь вам выйти из положения. Суть способа в том, что когда кнопка AirPlay становится неактивной, она затемняется, — а значит, у неё меняется значение alpha. Значит, можно через механизм Key-Value Observing подписаться на изменение свойства alpha, таким образом отслеживая момент, в который кнопка затемнится или наоборот, посветлеет.

[gist id=4274864]

Кстати говоря, поддержку функции AirPlay для плеера можно и отключить насовсем. Для этого достаточно установить в NO свойство allowsAirPlayVideo в AVPlayer, либо свойство allowsAirPlay у MPMoviePlayerController. Также его можно отключить у UIWebView, присвоив NO свойству mediaPlaybackAllowsAirplay. Помимо этого, в MPMoviePlayerController  можно подписаться на оповещения MPMoviePlayerIsAirPlayVideoActiveDidChangeNotification. Эти оповещения сообщают о том, что статус проигрывания видео по AirPlay изменился. Чтобы уточнить, началось или закончилось вещание по AirPlay, необходимо проверять свойство airPlayVideoActive.

Изменения в iOS 6

В документации к API шестой версии iOS, свойства класса AVPlayer, касающиеся AirPlay, помечены как устаревшие (deprecated), однако в документации не помечено, какие свойства использовать вместо них. При ближайшем рассмотрении заголовочного файла AVPlayer.h было отмечено наличие новых свойств, предназначенных для использования только в iOS 6, названия которых в точности повторяют старые, только слово AirPlay в них заменено на ExternalPlayback.

Внешний дисплей. AirPlay и HDMI

У вас, наверное, уже созрел вопрос — почему в статье, которая называется «AirPlay и HDMI» так много написано про AirPlay, но до сих пор ничего не сказано про HDMI? Заполняем этот пробел.

Передача изображения с устройства на экран возможна не только через сеть Wi-Fi, но и через HDMI-адаптер. Такое подключение аналогично функции Mirroring при использовании AirPlay: на экран внешнего дисплея передаётся в точности то же самое, что находится на экране передающего устройства.

Отображение содержимого устройства на экране является поведением по умолчанию. Однако возможно, что вам захочется выводить на внешний дисплей другое изображение, либо он до определённого момента не должен отображать никакого контента вообще. В Q&A QA1738 и в документации описаны действия по определению внешнего дисплея и отображению на нём альтернативной информации.

Существенным вопросом является определение наличия подключенных по AirPlay Mirroring или HDMI внешних дисплеев, а также получение оповещений при подключении нового дисплея или отключении старого.

В обоих случаях довольно просто достичь желаемого результата. Для определения наличия подключённых дисплеев нужно обратить внимание на статический массив screens класса UIScreen. Он хранит в себе ссылки на все экраны, подключённые к устройству. Экран самого устройства всегда находится в этом массиве на нулевом индексе. Стоит заметить, что подключение внешних дисплеев возможно только на устройствах, которые появились после iPhone 3GS. Дополнительно можно определить факт того, что на дисплей передаётся mirroring-контент. Для этого существует свойство mirroredScreen у объектов класса UIScreen. В соответствии с документацией, оно содержит в себе ссылку на mainScreen передающего устройства, если Mirroring доступен и включён, — либо, во всех остальных случаях, значение nil.

Код, иллюстрирующий определение экранов из массива screens и определение наличия в них Mirroring, представлен ниже.

[gist id=4274892]

Чтобы получать оповещения о подключении/удалении внешних экранов, необходимо использовать оповещения UIScreenDidConnectNotification и UIScreenDidDisconnectNotification, соответственно. Ниже приведён пример кода, обрабатывающего оповещения.

[gist id=4274903 bump=2]

Возможности Private API

Все методы, описанные в статье до настоящего момента, являются разрешенными: их использование не возбраняется со стороны Apple. Однако некоторые действия, к которым тоже хотелось бы иметь публичный API, все же запрещены. Например, невозможно программно включить Mirroring или программно выбрать устройство из списка доступных для подключения по AirPlay. В этой статье подробно описано, как вызвать меню выбора устройства-приёмника без задействования кнопки AirPlay (закрытый класс MPAudioVideoRoutingPopoverController), а также как получить список устройств, доступных для подключения и подключиться к любому из них по AirPlay Mirroring (закрытый класс MPAudioDeviceController).

* * *

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