广告插播时间点
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); } } }
支持自动播放
替换用户体验 widget 的图片选择
框架的各个组件(即“投射”对话框、迷你
控制器,而 UIMediaController(如果已配置)将显示海报图片
。图片海报图片的网址通常为
包含在媒体的 MediaMetadata
中,但发送器应用可能有
这些网址的备用来源
通过
ImagePicker
类定义了一种从图片列表中选择适当图片的方法。
在 MediaMetadata
中,具体取决于图片的使用方式,例如通知
缩略图或全屏背景默认的 ImagePicker
实现
则始终选择第一张图片,或者如果
MediaMetadata
。您的应用可以创建 ImagePicker
的子类并替换
onPickImage(MediaMetadata, ImageHints)
方法提供备用实现,然后选择该子类
替换为
setImagePicker
CastMediaOptions.Builder
的方法。
ImageHints
用于向 ImagePicker
提供有关要
选择在界面中显示
自定义 Cast 对话框
管理会话生命周期
SessionManager
是管理会话生命周期的中心位置。SessionManager
次收听
到 Android
MediaRouter
路由选择状态会更改为启动、恢复和结束会话。如果某个路线
已选择,SessionManager
将创建
Session
对象并尝试启动或恢复它。取消选中某个路线后
SessionManager
会结束当前会话。
因此,为确保 SessionManager
正确管理会话生命周期,您需要
必须确保:
- 在路由选择器对话框中,
致电
MediaRouter.selectRoute(MediaRouter.RouteInfo)
当用户选择设备时触发。 - 在路由控制器对话框(位于已连接
state 或
投放
状态),
致电
MediaRouter.unselect(int)
当用户停止投射时触发。
根据您创建 Cast 对话框的方式,您可能还需要执行其他操作 完成:
- 如果您使用
MediaRouteChooserDialog
和MediaRouteControllerDialog
, 然后,这些对话框将自动更新MediaRouter
中的路线选择, 因此无需执行任何操作 - 如果您使用
CastButtonFactory.setUpMediaRouteButton(Context, Menu, int)
或CastButtonFactory.setUpMediaRouteButton(Context, MediaRouteButton)
, 对话框实际上 使用MediaRouteChooserDialog
和MediaRouteControllerDialog
创建, 也无需执行任何操作 - 在其他情况下,您需要创建自定义 Cast 对话框,因此您需要
按照上述说明在
MediaRouter
。
零设备状态
如果您创建自定义 Cast 对话框,您的自定义
MediaRouteChooserDialog
应正确处理设备未连接的情况
找到。该对话框中应包含指示标志,以便用户清楚地了解
应用仍在尝试查找设备,且未尝试查找
。
如果您使用的是默认 MediaRouteChooserDialog
,则零设备状态
已处理。
后续步骤
以上就是可以向 Android 发送者应用中添加的功能。 您现在可以针对其他平台构建发送者应用 (iOS 或网站),或 构建 Web Receiver 应用。