Android アプリに高度な機能を追加する

ミッドロール挿入点

Android Sender SDK は、特定のメディア ストリーム内のミッドロール挿入点とコンパニオン広告をサポートしています。

ミッドロール挿入点の仕組みについて詳しくは、ウェブ レシーバーのミッドロール挿入点の概要をご覧ください。

休憩は送信者と受信者の両方で指定できますが、プラットフォーム間で一貫した動作を維持するには、ウェブ レシーバーAndroid TV レシーバーで指定することをおすすめします。

Android では、AdBreakClipInfoAdBreakInfo を使用して、読み込みコマンドでミッドロール挿入点を指定します。

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

カスタム アクションを追加する

送信元アプリは MediaIntentReceiver を拡張して、カスタム アクションを処理したり、その動作をオーバーライドしたりできます。独自の MediaIntentReceiver を実装した場合は、それをマニフェストに追加し、CastMediaOptions でその名前を設定する必要があります。この例では、リモコンでのメディア再生の切り替え、メディアボタンの押下、その他のタイプのアクションをオーバーライドするカスタム アクションを指定します。

// 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) {
    }
}

カスタム チャネルを追加する

送信側のアプリが受信側のアプリと通信するには、アプリでカスタム チャネルを作成する必要があります。送信者はカスタム チャネルを使用して、受信者に文字列メッセージを送信できます。各カスタム チャネルは一意の Namespace で定義され、接頭辞 urn:x-cast:urn:x-cast:com.example.custom など)で始まる必要があります。複数のカスタム チャネルを作成して、それぞれに一意の名前空間を設定できます。レシーバ アプリは、同じ Namespace を使用してメッセージを送受信することもできます。

カスタム チャネルは 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);
    }
}

送信側のアプリが受信側のアプリに接続されたら、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);
}

カスタム チャネルを作成したら、送信側は sendMessage メソッドを使用して、そのチャネルを介して受信側に文字列メッセージを送信できます。

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

自動再生のサポート

Autoplay & Queueing API セクションをご覧ください。

UX ウィジェットの画像選択をオーバーライドする

フレームワークのさまざまなコンポーネント(キャスト ダイアログ、ミニ コントローラ、UIMediaController(設定されている場合))に、現在キャストされているメディアのアートワークが表示されます。画像アートワークの URL は通常、メディアの MediaMetadata に含まれますが、送信元アプリに URL の代替ソースがある場合があります。

ImagePicker クラスは、通知のサムネイルや全画面の背景など、画像の用途に基づいて、MediaMetadata の画像リストから適切な画像を選択する手段を定義します。デフォルトの ImagePicker 実装では、常に最初の画像が選択されます。MediaMetadata に画像がない場合、null が返されます。アプリは ImagePicker のサブクラスを作成し、onPickImage(MediaMetadata, ImageHints) メソッドをオーバーライドして代替の実装を提供できます。その後、CastMediaOptions.BuildersetImagePicker メソッドでそのサブクラスを選択します。ImageHints は、UI に表示するために選択する画像のタイプとサイズに関するヒントを ImagePicker に提供します。

キャスト ダイアログのカスタマイズ

セッション ライフサイクルの管理

SessionManager は、セッションのライフサイクルを管理するための中心的な場所です。SessionManager は、Android MediaRouter ルート選択状態の変化をリッスンして、セッションの開始、再開、終了を行います。ルートを選択すると、SessionManagerSession オブジェクトを作成し、そのオブジェクトの開始または再開を試みます。ルートが選択されていない場合、SessionManager は現在のセッションを終了します。

したがって、SessionManager がセッションのライフサイクルを適切に管理するには、次のことを確認する必要があります。

Cast ダイアログの作成方法によっては、追加の操作が必要になる場合があります。

ゼロデバイスの状態

カスタム Cast ダイアログを作成する場合は、カスタム MediaRouteChooserDialog で、デバイスが検出されなかった場合を適切に処理する必要があります。ダイアログには、アプリがデバイスの検出をまだ試行しているときと、検出の試行がアクティブでなくなったときをユーザーに明確に示すインジケーターが必要です。

デフォルトの MediaRouteChooserDialog を使用している場合、ゼロデバイスの状態はすでに処理されています。

次のステップ

これで、Android 送信アプリに追加できる機能はすべて説明しました。これで、別のプラットフォーム(iOS または ウェブ)の送信アプリを構築するか、ウェブ受信アプリを構築できます。