Agrega funciones avanzadas a tu app para Android

Pausas publicitarias

El SDK de Android Sender proporciona compatibilidad con pausas publicitarias y anuncios complementarios en una transmisión de contenido multimedia determinada.

Consulta la Descripción general de las pausas publicitarias del receptor web para obtener más información sobre cómo funcionan.

Si bien se pueden especificar pausas en el remitente y en el receptor, se recomienda que se especifiquen en el receptor web y en el receptor de Android TV para mantener un comportamiento coherente en todas las plataformas.

En Android, especifica las pausas publicitarias en un comando de carga con AdBreakClipInfo y AdBreakInfo:

Kotlin
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)
Java
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);

Agrega acciones personalizadas

Una app emisora puede extender MediaIntentReceiver para controlar acciones personalizadas o anular su comportamiento. Si implementaste tu propio MediaIntentReceiver, debes agregarlo al manifiesto y también establecer su nombre en CastMediaOptions. En este ejemplo, se proporcionan acciones personalizadas que anulan la activación de la reproducción multimedia remota, presionar el botón multimedia y otros tipos de acciones.

// In AndroidManifest.xml
<receiver android:name="com.example.MyMediaIntentReceiver" />
Kotlin
// 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) {
    }
}
Java
// 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) {
    }
}

Agregar un canal personalizado

Para que la app emisora se comunique con la app receptora, la tuya debe crear un canal personalizado. El remitente puede usar el canal personalizado para enviar mensajes de string al receptor. Cada canal personalizado se define con un espacio de nombres único y debe comenzar con el prefijo urn:x-cast:, por ejemplo, urn:x-cast:com.example.custom. Es posible tener varios canales personalizados, cada uno con un espacio de nombres único. La app receptora también puede enviar y recibir mensajes con el mismo espacio de nombres.

El canal personalizado se implementa con la interfaz Cast.MessageReceivedCallback:

Kotlin
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")
    }
}
Java
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);
    }
}

Una vez que la app emisora se conecta a la app receptora, se puede crear el canal personalizado con el método setMessageReceivedCallbacks:

Kotlin
try {
    mCastSession.setMessageReceivedCallbacks(
        mHelloWorldChannel.namespace,
        mHelloWorldChannel)
} catch (e: IOException) {
    Log.e(TAG, "Exception while creating channel", e)
}
Java
try {
    mCastSession.setMessageReceivedCallbacks(
            mHelloWorldChannel.getNamespace(),
            mHelloWorldChannel);
} catch (IOException e) {
    Log.e(TAG, "Exception while creating channel", e);
}

Una vez que se crea el canal personalizado, el remitente puede usar el método sendMessage para enviar mensajes de string al receptor a través de ese canal:

Kotlin
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)
        }
    }
}
Java
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);
        }
    }
}

Cómo admitir la reproducción automática

Consulta la sección Autoplay & Queueing APIs.

Anular la selección de imágenes para los widgets de UX

Varios componentes del framework (es decir, el diálogo Cast, el minicontrolador y el UIMediaController, si están configurados) mostrarán el material gráfico del contenido multimedia que se transmite en ese momento. Por lo general, las URLs del material gráfico de imágenes se incluyen en MediaMetadata para los medios, pero la app emisora puede tener una fuente alternativa para las URLs.

La clase ImagePicker define un medio para seleccionar una imagen adecuada de la lista de imágenes de un objeto MediaMetadata, según el uso de la imagen, como una miniatura de notificación o un fondo de pantalla completa. La implementación predeterminada de ImagePicker siempre elige la primera imagen o muestra un valor nulo si no hay ninguna imagen disponible en MediaMetadata. Tu app puede crear subclases de ImagePicker y anular el método onPickImage(MediaMetadata, ImageHints) para proporcionar una implementación alternativa, y luego seleccionar esa subclase con el método setImagePicker de CastMediaOptions.Builder. ImageHints proporciona sugerencias a un elemento ImagePicker sobre el tipo y el tamaño de una imagen que se seleccionará para mostrarse en la IU.

Cómo personalizar los diálogos de transmisión

SessionManager es el lugar central para administrar el ciclo de vida de la sesión. SessionManager escucha los cambios de estado de la selección de ruta de MediaRouter de Android para iniciar, reanudar y finalizar sesiones. Cuando se selecciona una ruta, SessionManager creará un objeto Session y tratará de iniciarlo o reanudarlo. Si no seleccionas una ruta, SessionManager finalizará la sesión actual.

Por lo tanto, para garantizar que SessionManager administre los ciclos de vida de las sesiones de forma correcta, debes asegurarte de lo siguiente:

Según cómo crees los diálogos de Cast, es posible que debas realizar acciones adicionales:

Próximos pasos

Con esto concluye las funciones que puedes agregar a tu app de Android Sender. Ahora puedes compilar una app emisora para otra plataforma (iOS o Web) o una app receptora web.