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

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

Android Sender SDK обеспечивает поддержку рекламных пауз и сопутствующих объявлений в заданном медиапотоке.

Дополнительную информацию о том, как работают рекламные паузы, см. в обзоре рекламных пауз Web Receiver .

Хотя перерывы можно указать как для отправителя, так и для получателя, рекомендуется указать их для веб-приемника и приемника 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 подсказки о типе и размере изображения, которое будет выбрано для отображения в пользовательском интерфейсе.

Настройка диалогов Cast

SessionManager — это центральное место для управления жизненным циклом сеанса. SessionManager прослушивает изменения состояния выбора маршрута Android MediaRouter для запуска, возобновления и завершения сеансов. Когда маршрут выбран, SessionManager создаст объект Session и попытается запустить или возобновить его. Когда маршрут не выбран, SessionManager завершит текущий сеанс.

Поэтому, чтобы SessionManager правильно управлял жизненными циклами сеансов, необходимо убедиться, что:

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

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

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

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