Добавьте расширенные функции в свое приложение для Android

Рекламные паузы

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 , вы должны убедиться, что:

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

  • Если вы создаете диалоговые окна Cast с помощью MediaRouteChooserDialog и MediaRouteControllerDialog , эти диалоговые окна будут автоматически обновлять выбор маршрута в MediaRouter , поэтому ничего делать не нужно.
  • Если вы настроили кнопку Cast с помощью CastButtonFactory.setUpMediaRouteButton(Context, Menu, int) или CastButtonFactory.setUpMediaRouteButton(Context, MediaRouteButton) , то диалоги фактически создаются с помощью MediaRouteChooserDialog и MediaRouteControllerDialog , поэтому ничего делать тоже не нужно.
  • В других случаях вы будете создавать собственные диалоговые окна Cast, поэтому вам необходимо следовать приведенным выше инструкциям, чтобы обновить состояние выбора маршрута в MediaRouter .

Состояние нулевого устройства

Если вы создаете пользовательские диалоговые окна Cast, ваш пользовательский MediaRouteChooserDialog должен правильно обрабатывать случай, когда не обнаружено ни одного устройства. В диалоговом окне должны быть индикаторы, показывающие пользователям, когда ваше приложение все еще пытается найти устройства и когда попытка обнаружения больше не активна.

Если вы используете MediaRouteChooserDialog по умолчанию, состояние нулевого устройства уже обрабатывается.

Следующие шаги

На этом завершаются функции, которые вы можете добавить в свое приложение Android Sender. Теперь вы можете создать приложение-отправитель для другой платформы ( iOS или Интернет ) или создать приложение веб-получателя .