MediaSession を介したメディアの制御

最終更新日: 2020 年 9 月 9 日。

動画の再生に対して MediaSession を追加するメリット

メディア セッションは、Android プラットフォームとメディアアプリを結びつけるのに不可欠な要素です。メディアが再生中であることを Android に伝える(これによりメディア アクションを正しいセッションに転送できる)だけでなく、再生中のメディアや制御方法についてプラットフォームに伝えることもできます。

アプリを通じて MediaSession を公開することで、ユーザーがさまざまなメリットを得られます。以下にいくつか例を示します。

Google アシスタント

ユーザーは、「一時停止」、「再開」、「次へ」などの音声コマンドによって、アプリ内のメディアを簡単に操作できます。メディアのメタデータを使用して、現在再生中のメディアに関する情報を得ることもできます。

Android TV

HDMI-CEC 対応の大画面のテレビを使用しているユーザーは、Android TV アプリで従来のリモコンを利用できます。再生と一時停止、停止、次へ、前へのボタンによって発行されたコマンドが、アプリに中継されます。

画面上のメディア コントロール

Android 4.0(API レベル 14)以降では、システムからメディア セッションの再生状態とメタデータへのアクセスが可能です。この機能により、ロック画面にメディア コントロールとアートワークを表示できます。この動作は Android のバージョンによって異なります。

バックグラウンド メディア

メディアを再生するアプリがバックグラウンドで実行されている場合でも、こうしたシナリオのいずれかでメディアを制御できます。

アンビエント コンピューティング

再生中のコンテンツと制御方法に関するデータをメディアに公開することで、デバイス間のブリッジが可能となり、ユーザーはさまざまな方法でメディアを操作できます。

作成するアプリの概要

この Codelab では、既存の Exoplayer サンプルを拡張して、メディア セッションのサポートを追加します。作成するアプリの機能は次のとおりです。

  • メディア セッションのアクティブ状態を正しく反映する
  • メディア コントロールを ExoPlayer に中継する
  • キュー内のアイテムのメタデータをメディア セッションに渡す

学習内容

  • メディア セッションによりユーザーの利便性がより向上する理由
  • メディア セッションを作成してその状態を管理する方法
  • メディア セッションを ExoPlayer に接続する方法
  • メディア セッションの再生キューにアイテムのメタデータを含める方法
  • その他の(カスタム)アクションを追加する方法

この Codelab では、MediaSession SDK を中心に説明します。ExoPlayer の実装に関する詳細など、関連性のない概念やコードブロックについては説明していませんが、そのままコピーして貼り付けられるようにしています。

必要なもの

  • 最新バージョンの Android Studio(3.5 以降)
  • Android アプリの開発に関する基本的な知識

出発点

まずは、ExoPlayer のメインのデモから開始します。このデモでは、画面上のメディア コントロールを示した動画を見ることができますが、メディア セッションをそのまま使用した例ではありません。ぜひ実際に体験してご活用ください。

ExoPlayer サンプルを入手する

ExoPlayer サンプルから始めましょう。下記のリンクから GitHub リポジトリのクローンを作成します。

ExoPlayer サンプルのクローンを作成

デモを開く

Android Studio で、demos/main にあるメインのデモ プロジェクトを開きます。

Android Studio で SDK へのパスの設定を求めるメッセージが表示されます。問題が発生した場合は、IDE と SDK ツールのアップデートに関する推奨事項に従ってください。

10e3b5c652186d57.png

最新バージョンの Gradle を使用するよう求められた場合は、更新してください。

アプリの設計の基本について理解しておきましょう。SampleChooserActivity と PlayerActivity という 2 つのアクティビティがあります。Codelab の残りの部分では、メディアを実際に再生する PlayerActivity を使用するため、このクラスを開いて次のセクションに進みます。

メディア セッションを作成する

PlayerActivity.java を開きます。このクラスは ExoPlayer を作成し、動画を画面にレンダリングする機能などを管理します。このアクティビティでは、ExoPlayer をメディア セッションに接続します。

クラスの先頭で次の 2 つのフィールドを宣言します。このセクション全体を通して、これらのフィールドを使用します。

private MediaSessionCompat mediaSession;
private MediaSessionConnector mediaSessionConnector;

この場合、「Module: demo」のモジュール レベルの build.gradle に「extension-mediasession」プロジェクト依存関係を追加する必要があります。

implementation project(path: ':extension-mediasession')

Android Studio では、MediaSessionConnector の解決でエラーにカーソルを合わせると、この依存関係を自動的に追加できます。

60055e4ad54fbb97.png

最後に、次の行を追加してクラスのインポートを解決します。

import android.support.v4.media.session.MediaSessionCompat;
import com.google.android.exoplayer2.ext.mediasession.MediaSessionConnector;

アクティビティを作成したら、メディア セッションとメディア セッション コネクタ(メディア セッションと ExoPlayer の仲介として機能)を作成します。

これを挿入する理想的な場所は、ExoPlayer が作成される場所でもあります。デモアプリでは、initializePlayer() の最後にコードを追加できます。このロジックは必ず、プレーヤーをインスタンス化したに追加してください。

private void initializePlayer() {
  if (player == null) {
    ...
    player = ...
    ...
    mediaSession = new MediaSessionCompat(this, "sample");
    mediaSessionConnector = new MediaSessionConnector(mediaSession);
    mediaSessionConnector.setPlayer(player);
  }
  ...
}

メディア セッションを解放する

不要になったメディア セッションを解放します。releasePlayer() で ExoPlayer を解放するときに、次のコードを含めることができます。

private void releasePlayer() {
  if (mediaSession != null) {
    mediaSession.release();
  }
  ...
}

メディア セッションの状態を管理する

メディア セッションをインスタンス化したら、ユーザーがアクティビティを操作したときに、その状態が正しく反映されるようにする必要があります。

ユーザーがアクティビティを開始すると、メディア セッションがアクティブになります。

@Override
public void onStart() {
  ...
  if (mediaSession != null) {
    mediaSession.setActive(true);
  }
}

アプリはバックグラウンドでメディアを再生しないため、ユーザーがアクティビティを離れたときに、メディア セッションが非アクティブになるようにする必要があります。

@Override
public void onStop() {
  super.onStop();
  if (mediaSession != null) {
    mediaSession.setActive(false);
  }
  ...
}

デモを実行してみる

  1. Android デバイスを接続するか、エミュレータを起動します。
  2. Android Studio のツールバーから実行するために「demo」cb1ec4e50886874f.png が選択されていることを確認します。
  3. Android Studio のツールバーで 9d8fb3a9ddf12827.png をクリックします。
  4. デバイスでアプリが起動したら、再生する動画ストリームを選択します。
  5. 再生が開始されたら、adb コマンド「adb shell media dispatch pauseadb shell media dispatch playadb shell media dispatch play-pauseadb shell media dispatch fast-forwardadb shell media dispatch rewind」を使用してメディア セッションを制御します。
  1. また、adb shell dumpsys media_session を実行して、Android がメディア セッションをどのように認識しているかについても確認します。
  2. マイク付きの物理デバイスを使用する場合は、Google アシスタントを呼び出して、「一時停止」「再開」「1 分早送り」のような音声コマンドを発行します。

b8dda02a6fb0f6a4.pngAndroid TV で動作する ExoPlayer のサンプル。

以前に initializePlayer() で MediaSessionConnector を作成したメディア セッションのサポート対象となる機能を拡張できるようになりました。

TimelineQueueNavigator の追加

ExoPlayer は、メディアの構造をタイムラインとして表します。この仕組みの詳細については、ExoPlayer の Timeline オブジェクトをご覧ください。この構造を利用することで、コンテンツが変更されたときに通知を受け、必要に応じて現在再生中のメディアのメタデータを公開できます。

そのためには、TimelineQueueNavigator を定義します。initializePlayer() で MediaSessionConnector のインスタンス化を見つけて、mediaSession を初期化したに TimelineQueueNavigator の実装を追加します。

mediaSessionConnector.setQueueNavigator(new TimelineQueueNavigator(mediaSession) {
  @Override
  public MediaDescriptionCompat getMediaDescription(Player player, int windowIndex) {
    return new MediaDescriptionCompat.Builder()
            .setTitle("MediaDescription title")
            .setDescription("MediaDescription description for " + windowIndex)
            .setSubtitle("MediaDescription subtitle")
            .build();
  }
});

次の行を追加してクラスのインポートを解決します。

import android.support.v4.media.MediaDescriptionCompat;
import com.google.android.exoplayer2.ext.mediasession.TimelineQueueNavigator;

windowIndex パラメータが、再生キュー内の該当するインデックスのアイテムに対応していることを確認します。

メタデータを追加したので、再生中のコンテンツをアシスタントが認識するかどうかをテストできます。Android TV で動画を再生しているときにアシスタントを起動し、「何を再生してる?」と尋ねます。

6c7fc0cb853cbc38.png

プレーヤーが一部のアクションをサポートしていない場合や、サポートを追加したい場合は、以前に initializePlayer() で MediaSessionConnector を作成したメディア セッションについて、詳しく見ていきましょう。

サポートされているアクションの宣言

mediaSessionConnector.setEnabledPlaybackActions() を使用して、メディア セッションでサポートするアクションをカスタマイズしてみます。

完全なセットは次のとおりです。

mediaSessionConnector.setEnabledPlaybackActions(
        PlaybackStateCompat.ACTION_PLAY_PAUSE
                | PlaybackStateCompat.ACTION_PLAY
                | PlaybackStateCompat.ACTION_PAUSE
                | PlaybackStateCompat.ACTION_SEEK_TO
                | PlaybackStateCompat.ACTION_FAST_FORWARD
                | PlaybackStateCompat.ACTION_REWIND
                | PlaybackStateCompat.ACTION_STOP
                | PlaybackStateCompat.ACTION_SET_REPEAT_MODE
                | PlaybackStateCompat.ACTION_SET_SHUFFLE_MODE
);

ここで、このデータがプラットフォームにどのように公開されるかをもう一度見てみましょう。

  1. 以前と同じように動画を開始します。
  2. adb shell dumpsys media_session を実行して、メディア セッションのメタデータが Android でどのように認識されるかを確認します。
  3. メタデータを含む行を探し、タイトルと説明が含まれていて com.google.android.exoplayer2.demo/sample に関連付けられていることを確認します。

その他のアクションの追加

メディア セッションは、追加のアクションをいくつか使用して拡張できます。このセクションでは、字幕のサポートのみを追加します。

字幕のサポート

メディア セッションに字幕のサポートを追加すると、ユーザーは音声で字幕を切り替えることができます。メディア セッション コネクタを初期化したら、次の行を追加します。

mediaSessionConnector.setCaptionCallback(new MediaSessionConnector.CaptionCallback() {
      @Override
      public void onSetCaptioningEnabled(Player player, boolean enabled) {
        Log.d("MediaSession", "onSetCaptioningEnabled: enabled=" + enabled);
      }

      @Override
      public boolean hasCaptions(Player player) {
        return true;
      }

      @Override
      public boolean onCommand(Player player, ControlDispatcher controlDispatcher, String command, Bundle extras, ResultReceiver cb) {
        return false;
      }
    }
);

最後に、不足しているインポートを解決します。

これをテストするには、Android TV で Google アシスタントを呼び出し、「字幕を有効にして」と言います。Logcat でメッセージを調べて、どのようにしてコードに呼び出されるかを確認します。

これで、メディア セッションをサンプルに追加できました。

次の方法で、多くの機能を提供できます。

  • メディア セッションを追加する
  • メディア セッションを ExoPlayer のインスタンスに接続する
  • メタデータとその他のアクションを追加する

ここでは、メディアアプリを充実させ、ユーザーに多彩な機能を提供するために必要な主な手順について確認しました。

おわりに

この Codelab は、ExoPlayer ソースコードのサンプルを基に作成されています。ExoPlayer をソースから利用する必要はありません。代わりに、ExoPlayer と MediaSessionConnector の依存関係を pull することをおすすめします。最新のリリースを把握しやすくなります。

そのためには、次のようにプロジェクトの依存関係を置き換えて、

implementation project(modulePrefix + 'library-core')
implementation project(path: ':extension-mediasession')

次のように Maven リポジトリから pull します。

implementation 'com.google.android.exoplayer:exoplayer-core:2.+'
implementation 'com.google.android.exoplayer:extension-mediasession:2.+'

リファレンス ドキュメント