Pausas publicitarias
El SDK de Android Sender proporciona compatibilidad con pausas publicitarias y anuncios complementarios dentro de una transmisión multimedia determinada.
Consulta la Descripción general de las pausas publicitarias de los Receptores web para obtener más información sobre su funcionamiento.
Si bien se pueden especificar pausas tanto en el emisor como en el receptor, se recomienda que se especifiquen en Web Receiver y en Android TV Receiver para mantener un comportamiento coherente en todas las plataformas.
En Android, especifica las pausas publicitarias en un comando de carga con AdBreakClipInfo
y 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);
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 establecer su nombre en el CastMediaOptions
. En este ejemplo, se proporcionan acciones personalizadas que anulan la activación o desactivación de la reproducción multimedia remota, cuando se presiona el botón multimedia y otros tipos de acciones.
// 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) { } }
Agregar un canal personalizado
Para que la app emisora se comunique con la app receptora, tu app debe crear un canal personalizado. El remitente puede usar el canal personalizado para enviar mensajes de cadena al receptor. Cada canal personalizado se define mediante 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
:
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); } }
Una vez que la app emisora se conecte a la app receptora, se puede crear el canal personalizado con el método 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); }
Una vez que se crea el canal personalizado, el remitente puede usar el método sendMessage
para enviar mensajes de cadena al receptor a través de ese canal:
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); } } }
Compatibilidad con reproducción automática
Consulta la sección APIs de reproducción automática y de fila.
Cómo anular la selección de imágenes para widgets de UX
Varios componentes del framework (es decir, el diálogo de transmisión, el minicontrolador y el UIMediaController, si se configura) mostrarán el material gráfico del contenido multimedia de transmisión actual. Por lo general, las URLs del material gráfico de la imagen se incluyen en el archivo MediaMetadata
del contenido multimedia, 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 en un MediaMetadata
, según el uso de la imagen, por ejemplo, miniatura de notificación o 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 el MediaMetadata
. Tu app puede subclasificar 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 objeto ImagePicker
sobre el tipo y el tamaño de una imagen que se seleccionará para mostrarla 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 selección de ruta de MediaRouter
de Android para iniciar, reanudar y finalizar sesiones. Cuando se selecciona una ruta, SessionManager
crea un objeto Session
y trata de iniciarla o reanudarla. Si no se selecciona una ruta, SessionManager
finalizará la sesión actual.
Por lo tanto, para asegurarte de que SessionManager
administre los ciclos de vida de la sesión de forma correcta, debes asegurarte de lo siguiente:
- En el diálogo del selector de ruta, llama a
MediaRouter.selectRoute(MediaRouter.RouteInfo)
cuando un usuario seleccione un dispositivo. - En el diálogo del controlador de ruta (ya sea en estado conectado o en estado de transmisión), llama a
MediaRouter.unselect(int)
cuando el usuario deje de transmitir.
Según cómo crees los diálogos de transmisión, es posible que se deban realizar acciones adicionales:
- Si creas diálogos de transmisión con
MediaRouteChooserDialog
yMediaRouteControllerDialog
, estos actualizarán automáticamente la selección de ruta enMediaRouter
, por lo que no es necesario hacer nada. - Si configuras el botón para transmitir con
CastButtonFactory.setUpMediaRouteButton(Context, Menu, int)
oCastButtonFactory.setUpMediaRouteButton(Context, MediaRouteButton)
, los diálogos se crean conMediaRouteChooserDialog
yMediaRouteControllerDialog
, por lo que no es necesario hacer nada. - En otros casos, crearás diálogos de transmisión personalizados, por lo que deberás seguir las instrucciones anteriores para actualizar el estado de selección de ruta en
MediaRouter
.
Próximos pasos
De esta manera, 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 compilar una app receptora web.