手順4: Fire TVのUIで再生する
ライブTVには、ユーザーが閲覧の行にあるいずれかのタイルにフォーカスしたときにプレビュー再生できる機能があります。これにより、コンテンツをすばやく簡単にプレビューできます。
TvInputService.Session
の作成- 正しいチャンネルの特定
- プレビューでのチャンネルコンテンツの再生
- チェックポイント - 閲覧時のプレビューの再生
- トラブルシューティング
- 次のステップ
プレビュー再生を統合する場合は、ライブTVアプリから提供されるSurfaceの使用が可能なプレーヤー内でチャンネルコンテンツを再生する必要があります。
TvInputService.Session
の作成
ユーザーが特定のチャンネルを選択すると、TvInputService
クラスが呼び出されてSessionが作成されます。Sessionでは、コンテンツの選択、プレーヤーの準備、チャンネルコンテンツのレンダリングを行うことができます。これをTvInputServiceクラス(RichTvInputService)
に追加します。
実際のSessionクラスの例を以下に示します。
private class PreviewSession extends TvInputService.Session {
PreviewSession(Context context) {
super(context);
Log.d(Utils.DEBUG_TAG, "セッションが作成されました。");
}
@Override
public boolean onTune(Uri channelUri) {
Log.d(Utils.DEBUG_TAG, "onTune " + channelUri);
...
return false;
}
@Override
public boolean onSetSurface(@Nullable Surface surface) {
Log.d(Utils.DEBUG_TAG, "onSetSurface");
...
return false;
}
}
import android.content.Context
import android.media.tv.TvInputService
import android.net.Uri
import android.util.Log
import android.view.Surface
private const val TAG = "MyTag"
private class PreviewSession(context: Context) : TvInputService.Session(context) {
init {
Log.d(TAG, "セッションが作成されました。")
}
override fun onTune(channelUri: Uri): Boolean {
Log.d(TAG, "onTune $channelUri")
return false
}
override fun onSetSurface(surface: Surface?): Boolean {
Log.d(TAG, "onSetSurface")
return false
}
override fun onSetCaptionEnabled(enabled: Boolean) {
TODO("まだ実装されていません")
}
override fun onRelease() {
TODO("まだ実装されていません")
}
override fun onSetStreamVolume(volume: Float) {
TODO("まだ実装されていません")
}
}
正しいチャンネルの特定
onTune()
コールバックでchannelId
を使用して、ユーザーが現在選択しているチャンネルを特定できます。
channelUri
からチャンネルIDを取得する方法の例を以下に示します。
long channelId = Long.parseLong(channelUri.getLastPathSegment());
import android.net.Uri
val channelUri: Uri = TODO()
var channelId: Long? = channelUri.lastPathSegment?.toLong()
チャンネルIDは、AndroidのTVデータベースにチャンネルを挿入する際にAndroidから自動的に割り当てられるIDです。チャンネルがTVデータベースに挿入されたときにAndroidから割り当てられるチャンネルIDと、使用するチャンネルIDとの間のマップは必ず維持してください。こうすることで、チャンネルIDを使用して、いつでも正しいチャンネルコンテンツを見つけることができます。
プレビューでのチャンネルコンテンツの再生
構成可能なサーフェスでTVフィードを再生できるメディアプレーヤーを実装します。
ユーザーが閲覧中に特定のチャンネルカードにフォーカスすると、前の手順で作成したSessionがライブアプリで使用されます。これは、アプリによってTvInputService.Session
クラスの一部として定義され、リクエストされたチャンネルへの変更やコンテンツの再生に使用されます。
メディアプレーヤーの作成
メディアプレーヤーの実装にはいくつかのオプションがあります。直接使用できるメディアプレーヤーがアプリ内であらかじめ明確に定義されている必要があります。プレーヤーでTVフィードを再生でき、カスタマイズしたSurfaceクラスを使用するようにプレーヤーを構成できさえすれば、使用するメディアプレーヤーについては厳しい要件はありません(次の手順を参照)。このようにプレーヤーの実装はケースバイケースとなるため、ここでは参考としてオプションの一部のみを示します。
ExoPlayer:基盤となるメディアプレーヤーの候補として適しています。
SampleTvAppのDemoPlayer:TVチャンネルの変更をサポートするメディアプレーヤーを作成するためにExoPlayerを使用している例です。
SampleTvAppのTvInputService内のDemoPlayer:カスタマイズしたメディアプレーヤーをTvInputService
で定義する方法の例です。
onSetSurface
チャンネル変更プロセス中に、AndroidのTIFフレームワークによってonSetSurface(@Nullable Surface surface)
コールバックが呼び出されます。このコールバックはTvInputService.Session
で定義されています(前の手順を参照)。提供されたSurfaceインスタンスは、開発者がメディアプレーヤーに設定する必要があります。メディアプレーヤーはプレビューの再生に使用されます。
onTune
次に、onTune(Uri channelUri)
コールバックが呼び出されます。ここで正しいチャンネルを特定し(正しいチャンネルの特定を参照)、対応するチャンネルフィードを取得し、準備ができたらフィードを再生するようにメディアプレーヤーを準備する必要があります。
onTune
が再度呼び出されることはありません。2回目の再生でonTune()
を呼び出さない場合の一般的なシナリオには、次のようなものがあります。
- ユーザーがチャンネルカードにフォーカスした場合。onTuneからプレビューの再生が呼び出されます。
- ユーザーが現在のカードをクリックして全画面再生を開始した場合。
- 全画面再生がシームレスに全画面で表示された場合。この場合、別の
onTune()
は受け取りません。
チャンネル変更ステータスの通知
プレーヤーの読み込みステータスに基づいて、最新のチャンネル変更ステータスをTvInputService
に通知する必要があります。Fire TVのライブアプリは、このステータスを参照して、プレビューUIを調整します。
以下は、チャンネル変更ステータスを通知する例を示しています。この場合、ステータスは「一時的に利用不可」になります。 このコードはTvInputService.Session
に配置します。
@Override
public boolean onTune(Uri channelUri) {
Log.d(Utils.DEBUG_TAG, "onTune " + channelUri);
// ビデオが読み込まれていることをTvInputServiceに知らせます。
notifyVideoUnavailable(VIDEO_UNAVAILABLE_REASON_TUNING);
}
override fun onTune(channelUri: Uri): Boolean {
Log.d(TAG, "onTune $channelUri")
notifyVideoUnavailable(VIDEO_UNAVAILABLE_REASON_TUNING)
return true
}
以下は、ビデオの利用可能ステータスを通知する例を示しています。
notifyTracksChanged(getAllTracks());
String audioId = getTrackId(TvTrackInfo.TYPE_AUDIO,
mPlayer.getSelectedTrack(TvTrackInfo.TYPE_AUDIO));
String videoId = getTrackId(TvTrackInfo.TYPE_VIDEO,
mPlayer.getSelectedTrack(TvTrackInfo.TYPE_VIDEO));
String textId = getTrackId(TvTrackInfo.TYPE_SUBTITLE,
mPlayer.getSelectedTrack(TvTrackInfo.TYPE_SUBTITLE));
notifyTrackSelected(TvTrackInfo.TYPE_AUDIO, audioId);
notifyTrackSelected(TvTrackInfo.TYPE_VIDEO, videoId);
notifyTrackSelected(TvTrackInfo.TYPE_SUBTITLE, textId);
notifyVideoAvailable();
val audioId: String = getTrackId(
TvTrackInfo.TYPE_AUDIO,
mPlayer.getSelectedTrack(TvTrackInfo.TYPE_AUDIO)
)
val videoId: String = getTrackId(
TvTrackInfo.TYPE_VIDEO,
mPlayer.getSelectedTrack(TvTrackInfo.TYPE_VIDEO)
)
val textId: String = getTrackId(
TvTrackInfo.TYPE_SUBTITLE,
mPlayer.getSelectedTrack(TvTrackInfo.TYPE_SUBTITLE)
)
notifyTrackSelected(TvTrackInfo.TYPE_AUDIO, audioId)
notifyTrackSelected(TvTrackInfo.TYPE_VIDEO, videoId)
notifyTrackSelected(TvTrackInfo.TYPE_SUBTITLE, textId)
notifyVideoAvailable()
機能制限
商品の要件に従って、機能制限(PCON)が有効になっている場合は、プレビュー再生でビデオを再生しないようにする必要があります。
以下は、ライブプレビューやネイティブの全画面再生に関して、機能制限をリッスンする方法の例を示しています。
private TvContentRating mBlockedRating = null;
@Override
public boolean onTune(final Uri channelUri) {
...
if (mTvInputManager.isParentalControlsEnabled()) {
// サーフェスで音声や画像が再生されないようにします
mBlockedRating = < content_rating > ;
notifyContentBlocked(mBlockedRating);
} else {
// 再生が開始されます
notifyContentAllowed();
}
...
}
@Override
public void onUnblockContent(final TvContentRating unblockedRating) {
// ユーザーのPIN入力により、指定のレーティングに該当するコンテンツのブロックが
// 正常に解除されました
if (unblockedRating.unblockContent(mBlockedRating)) {
// 再生が開始されます
notifyContentAllowed();
}
}
import android.content.Context
import android.media.tv.TvContentRating
import android.media.tv.TvInputManager
import android.media.tv.TvInputService
import android.net.Uri
import android.view.Surface
private const val TAG = "MyTag"
private class PreviewSession(context: Context) : TvInputService.Session(context) {
private val tvInputManager: TvInputManager = TODO()
override fun onTune(channelUri: Uri): Boolean {
if (tvInputManager.isParentalControlsEnabled) {
// サーフェスで音声や画像が再生されないようにします
val blockedRating = getContentRating(channelUri)
notifyContentBlocked(blockedRating)
} else {
// 再生が開始されます
notifyContentAllowed()
}
return true
}
override fun onUnblockContent(unblockedRating: TvContentRating) {
// ユーザーのPIN入力により、指定のレーティングに該当するコンテンツのブロックが
// 正常に解除されました
if (unblockedRating.unblockContent(blockedRating)) { // <-- これは何か?
// 再生が開始されます
notifyContentAllowed()
}
}
}
private fun getContentRating(channelUri: Uri): TvContentRating = TODO()
アクティビティ | 必須・任意 | 備考 |
---|---|---|
mTvInputManager.isParentalControlsEnabled() |
必須 | このメソッドはPCONステータスを確認するために呼び出されます。 |
notifyContentBlocked() |
状況依存 | このメソッドはPCONによりビデオの再生がブロックされた場合に呼び出されます。 |
notifyContentAllowed() |
状況依存 | このメソッドはビデオの再生が可能な場合に呼び出されます。 |
チェックポイント - 閲覧時のプレビューの再生
- APKをビルドしてFire TVにインストールします。
- [放映中のチャンネル] 行に移動し、チャンネルカードにフォーカスすると、画面の右上隅でプレビューの再生が開始されます。
- ディープリンクを使用しない場合:チャンネルカードを選択すると、全画面で再生が続行されます。
- [機能制限] メニューに移動して、機能制限を有効にします。
- [放映中のチャンネル] 行に戻り、チャンネルカードにフォーカスすると、プレビューの再生が開始されなくなります。ただし、ポスターアートがある場合は、ポスターアートが閲覧画面に表示されます。
- ディープリンクを使用しない場合:チャンネルカードを選択すると、PINの入力を求めるプロンプトが表示されます。PINを入力すると、全画面再生が開始されます。
トラブルシューティング
チャンネルカードにフォーカスしてもonTune()
コールバックがトリガーされない
チャンネルのinputIdを再度確認してください。InputId
が正しくない場合、AndroidはTvInputService
を識別して呼び出すことができません。
onTune()
が呼び出されているのにプレビューの再生が開始されない
- プレーヤーがフィードを再生できるよう正しく実装されているかどうかを確認します。
notifyVideoAvailable()
を呼び出して「準備完了」のチャンネル変更ステータスを通知していることを確認します。
PCONを有効にしても閲覧セクションで引き続きプレビューが再生される
TvInputService
に機能制限のコードが正しく実装されていることを再度確認してください。PCONが有効になっている場合はプレーヤーを停止し、notifyContentBlocked()
を使用してUIに通知します。詳細については、ライブTVのリソースを参照してください。
PCONを有効にするとプレビュー再生だけでなくポスター画像も表示されなくなる(黒い背景のみが表示される)
チャンネルで表示できる有効なポスターアートがあることを確認してください。一般的には現在放送中の番組の画像が考えられます。
画像がある場合は、notifyContentBlocked()
を呼び出していることを再度確認してください。PCONのステータスに関する通知を送信していない場合、UIは更新されず、ポスター画像は使用されません。
次のステップ
プロセスの詳細については、ライブTVのリソースを参照してください。
Last updated: 2024年7月2日