Рекламные паузы
Android Sender SDK обеспечивает поддержку рекламных пауз и сопутствующих рекламных объявлений в заданном медиапотоке.
Дополнительную информацию о том, как работают рекламные паузы, см. в обзоре рекламных пауз в веб-приемнике .
Хотя перерывы можно указать как для отправителя, так и для получателя, рекомендуется указывать их в веб-приемнике и приемнике Android TV для обеспечения единообразного поведения на разных платформах.
В Android укажите рекламные паузы в команде загрузки, используя AdBreakClipInfo
и AdBreakInfo
:
val breakClip1: AdBreakClipInfo = AdBreakClipInfo.Builder("bc0") .setTitle("Clip title") .setPosterUrl("https://www.some.url") .setDuration(60000) .setWhenSkippableInMs(5000) // Set this field so that the ad is skippable .build() val breakClip2: AdBreakClipInfo = … val breakClip3: AdBreakClipInfo = … val break1: AdBreakClipInfo = AdBreakInfo.Builder(/* playbackPositionInMs= */ 10000) .setId("b0") .setBreakClipIds({"bc0","bc1","bc2"}) … .build() val mediaInfo: MediaInfo = MediaInfo.Builder() … .setAdBreaks({break1}) .setAdBreakClips({breakClip1, breakClip2, breakClip3}) .build() val mediaLoadRequestData: MediaLoadRequestData = MediaInfo.Builder() … .setMediaInfo(mediaInfo) .build() remoteMediaClient.load(mediaLoadRequestData)
AdBreakClipInfo breakClip1 = new AdBreakClipInfo.Builder("bc0") .setTitle("Clip title") .setPosterUrl("https://www.some.url") .setDuration(60000) .setWhenSkippableInMs(5000) // Set this field so that the ad is skippable .build(); AdBreakClipInfo breakClip2 = … AdBreakClipInfo breakClip3 = … AdBreakInfo break1 = new AdBreakInfo.Builder(/* playbackPositionInMs= */ 10000) .setId("b0") .setBreakClipIds({"bc0","bc1","bc2"}) … .build(); MediaInfo mediaInfo = new MediaInfo.Builder() … .setAdBreaks({break1}) .setAdBreakClips({breakClip1, breakClip2, breakClip3}) .build(); MediaLoadRequestData mediaLoadRequestData = new MediaInfo.Builder() … .setMediaInfo(mediaInfo) .build(); remoteMediaClient.load(mediaLoadRequestData);
Добавить специальные действия
Приложение-отправитель может расширить MediaIntentReceiver
для обработки пользовательских действий или переопределить его поведение. Если вы реализовали свой собственный MediaIntentReceiver
, вам необходимо добавить его в манифест, а также задать его имя в CastMediaOptions
. В этом примере представлены пользовательские действия, которые переопределяют переключение удаленного воспроизведения мультимедиа, нажатие кнопки мультимедиа и другие типы действий.
// In AndroidManifest.xml
<receiver android:name="com.example.MyMediaIntentReceiver" />
// In your OptionsProvider var mediaOptions = CastMediaOptions.Builder() .setMediaIntentReceiverClassName(MyMediaIntentReceiver::class.java.name) .build() // Implementation of MyMediaIntentReceiver internal class MyMediaIntentReceiver : MediaIntentReceiver() { override fun onReceiveActionTogglePlayback(currentSession: Session) { } override fun onReceiveActionMediaButton(currentSession: Session, intent: Intent) { } override fun onReceiveOtherAction(context: Context?, action: String, intent: Intent) { } }
// In your OptionsProvider CastMediaOptions mediaOptions = new CastMediaOptions.Builder() .setMediaIntentReceiverClassName(MyMediaIntentReceiver.class.getName()) .build(); // Implementation of MyMediaIntentReceiver class MyMediaIntentReceiver extends MediaIntentReceiver { @Override protected void onReceiveActionTogglePlayback(Session currentSession) { } @Override protected void onReceiveActionMediaButton(Session currentSession, Intent intent) { } @Override protected void onReceiveOtherAction(Context context, String action, Intent intent) { } }
Добавить клиентский канал
Чтобы приложение-отправитель могло взаимодействовать с приложением-получателем, вашему приложению необходимо создать собственный канал. Отправитель может использовать собственный канал для отправки строковых сообщений получателю. Каждый пользовательский канал определяется уникальным пространством имен и должен начинаться с префикса urn:x-cast:
, например urn:x-cast:com.example.custom
. Можно иметь несколько пользовательских каналов, каждый из которых имеет уникальное пространство имен. Приложение-получатель также может отправлять и получать сообщения, используя то же пространство имен.
Пользовательский канал реализуется с помощью интерфейса Cast.MessageReceivedCallback
:
class HelloWorldChannel : MessageReceivedCallback { val namespace: String get() = "urn:x-cast:com.example.custom" override fun onMessageReceived(castDevice: CastDevice, namespace: String, message: String) { Log.d(TAG, "onMessageReceived: $message") } }
class HelloWorldChannel implements Cast.MessageReceivedCallback { public String getNamespace() { return "urn:x-cast:com.example.custom"; } @Override public void onMessageReceived(CastDevice castDevice, String namespace, String message) { Log.d(TAG, "onMessageReceived: " + message); } }
Как только приложение-отправитель подключено к приложению-получателю, можно создать пользовательский канал с помощью метода setMessageReceivedCallbacks
:
try { mCastSession.setMessageReceivedCallbacks( mHelloWorldChannel.namespace, mHelloWorldChannel) } catch (e: IOException) { Log.e(TAG, "Exception while creating channel", e) }
try { mCastSession.setMessageReceivedCallbacks( mHelloWorldChannel.getNamespace(), mHelloWorldChannel); } catch (IOException e) { Log.e(TAG, "Exception while creating channel", e); }
После создания пользовательского канала отправитель может использовать метод sendMessage
для отправки строковых сообщений получателю по этому каналу:
private fun sendMessage(message: String) { if (mHelloWorldChannel != null) { try { mCastSession.sendMessage(mHelloWorldChannel.namespace, message) .setResultCallback { status -> if (!status.isSuccess) { Log.e(TAG, "Sending message failed") } } } catch (e: Exception) { Log.e(TAG, "Exception while sending message", e) } } }
private void sendMessage(String message) { if (mHelloWorldChannel != null) { try { mCastSession.sendMessage(mHelloWorldChannel.getNamespace(), message) .setResultCallback( status -> { if (!status.isSuccess()) { Log.e(TAG, "Sending message failed"); } }); } catch (Exception e) { Log.e(TAG, "Exception while sending message", e); } } }
Поддержка автозапуска
См. раздел API автозапуска и организации очередей .
Переопределить выбор изображения для UX-виджетов
Различные компоненты платформы (а именно диалоговое окно Cast, мини-контроллер и UIMediaController, если так настроено) будут отображать обложку для текущего медиафайла, транслируемого в данный момент. URL-адреса изображений обычно включаются в MediaMetadata
для мультимедиа, но приложение-отправитель может иметь альтернативный источник URL-адресов.
Класс ImagePicker
определяет средство выбора соответствующего изображения из списка изображений в MediaMetadata
на основе использования изображения, например миниатюры уведомления или полноэкранного фона. Реализация ImagePicker
по умолчанию всегда выбирает первое изображение или возвращает значение null, если в MediaMetadata
нет изображения. Ваше приложение может создать подкласс ImagePicker
и переопределить метод onPickImage(MediaMetadata, ImageHints)
чтобы предоставить альтернативную реализацию, а затем выбрать этот подкласс с помощью метода setImagePicker
из CastMediaOptions.Builder
. ImageHints
предоставляет ImagePicker
подсказки о типе и размере изображения, которое должно быть выбрано для отображения в пользовательском интерфейсе.
Настройка диалогов трансляции
Управление жизненным циклом сеанса
SessionManager
— это центральное место для управления жизненным циклом сеанса. SessionManager
прослушивает изменения состояния выбора маршрута Android MediaRouter
для запуска, возобновления и завершения сеансов. Когда маршрут выбран, SessionManager
создаст объект Session
и попытается запустить или возобновить его. Если маршрут не выбран, SessionManager
завершит текущий сеанс.
Таким образом, чтобы обеспечить правильное управление жизненными циклами сеансов SessionManager
, вы должны убедиться, что:
- В диалоговом окне выбора маршрута вызовите
MediaRouter.selectRoute(MediaRouter.RouteInfo)
когда пользователь выбирает устройство. - В диалоговом окне контроллера маршрута (либо в состоянии подключения , либо в состоянии приведения ) вызовите
MediaRouter.unselect(int)
когда пользователь прекращает приведение.
В зависимости от того, как вы создаете диалоги трансляции, возможно, потребуется выполнить дополнительные действия:
- Если вы создаете диалоговые окна Cast с помощью
MediaRouteChooserDialog
иMediaRouteControllerDialog
, эти диалоговые окна будут автоматически обновлять выбор маршрута вMediaRouter
, поэтому ничего делать не нужно. - Если вы настроили кнопку Cast с помощью
CastButtonFactory.setUpMediaRouteButton(Context, Menu, int)
илиCastButtonFactory.setUpMediaRouteButton(Context, MediaRouteButton)
, то диалоги фактически создаются с помощьюMediaRouteChooserDialog
иMediaRouteControllerDialog
, поэтому ничего делать тоже не нужно. - В других случаях вы будете создавать собственные диалоговые окна Cast, поэтому вам необходимо следовать приведенным выше инструкциям, чтобы обновить состояние выбора маршрута в
MediaRouter
.
Состояние нулевого устройства
Если вы создаете пользовательские диалоговые окна Cast, ваш пользовательский MediaRouteChooserDialog
должен правильно обрабатывать случай, когда не обнаружено ни одного устройства. В диалоговом окне должны быть индикаторы, показывающие пользователям, когда ваше приложение все еще пытается найти устройства и когда попытка обнаружения больше не активна.
Если вы используете MediaRouteChooserDialog
по умолчанию, состояние нулевого устройства уже обрабатывается.
Следующие шаги
На этом завершаются функции, которые вы можете добавить в свое приложение Android Sender. Теперь вы можете создать приложение-отправитель для другой платформы ( iOS или Интернет ) или создать приложение веб-получателя .