プレーヤー イベント

再生イベントをリッスンする

状態の変更や再生エラーなどのイベントは、登録済みの Player.Listener インスタンス。このようなイベントを受信するようにリスナーを登録し、 events:

Kotlin

// Add a listener to receive events from the player.
player.addListener(listener)

Java

// Add a listener to receive events from the player.
player.addListener(listener);

Player.Listener には空のデフォルト メソッドがあるので、実装する必要があるのは 確認することもできます。詳細については、Javadoc をご覧ください。 呼び出されるタイミングを指定できます。その中でも特に重要なのは、 以下で詳しく説明します。

リスナーは、個々のイベント コールバックを実装するか、 1 つ以上のイベントが発生した後に呼び出される汎用の onEvents コールバック 説明します。どちらを選択するかについては、Individual callbacks vs onEvents をご覧ください。 適切なオプションを選択することをおすすめします

再生状態の変更

プレーヤーの状態の変化は、次を実装することで受け取れます。 onPlaybackStateChanged(@State int state)(登録済み) Player.Listener。プレーヤーは、次の 4 つの再生状態のいずれかになります。

  • Player.STATE_IDLE: これは初期状態です。プレーヤーが 再生に失敗した場合などですプレーヤーは限られたリソースしか持っていない 必要があります。
  • Player.STATE_BUFFERING: プレーヤーはすぐに再生できない 表示できます。これはほとんどの場合、より多くのデータを読み込む必要があるために発生します。
  • Player.STATE_READY: プレーヤーは現在の状態からすぐに再生できる なります。
  • Player.STATE_ENDED: プレーヤーがすべてのメディアの再生を終了しました。

プレーヤーには、これらの状態に加えて、状態を示す playWhenReady フラグがあります。 示します。このフラグの変更は、 onPlayWhenReadyChanged(playWhenReady, @PlayWhenReadyChangeReason int reason)

プレーヤーが再生中(位置が進行していて、メディアが進行している) 次の 3 つの条件がすべて満たされている場合:

  • プレーヤーが Player.STATE_READY 状態である
  • playWhenReady の場合は true
  • から返された理由により再生が抑制されていない Player.getPlaybackSuppressionReason

これらのプロパティを個別に確認する必要はありません。Player.isPlaying 呼び出すことができます。この状態の変更を受け取るには、 onIsPlayingChanged(boolean isPlaying):

Kotlin

player.addListener(
  object : Player.Listener {
    override fun onIsPlayingChanged(isPlaying: Boolean) {
      if (isPlaying) {
        // Active playback.
      } else {
        // Not playing because playback is paused, ended, suppressed, or the player
        // is buffering, stopped or failed. Check player.playWhenReady,
        // player.playbackState, player.playbackSuppressionReason and
        // player.playerError for details.
      }
    }
  }
)

Java

player.addListener(
    new Player.Listener() {
      @Override
      public void onIsPlayingChanged(boolean isPlaying) {
        if (isPlaying) {
          // Active playback.
        } else {
          // Not playing because playback is paused, ended, suppressed, or the player
          // is buffering, stopped or failed. Check player.getPlayWhenReady,
          // player.getPlaybackState, player.getPlaybackSuppressionReason and
          // player.getPlaybackError for details.
        }
      }
    });

再生エラー

再生が失敗する原因となるエラーは、 onPlayerError(PlaybackException error)(登録済み) Player.Listener。エラーが発生すると、このメソッドが呼び出されます。 再生状態が Player.STATE_IDLE に移行する直前にトリガーされます。 失敗または停止した再生を再試行するには、ExoPlayer.prepare を呼び出します。

一部の Player 実装では、 PlaybackException に失敗に関する追加情報を提供します。対象 たとえば、ExoPlayerExoPlaybackException を渡します。これには type が含まれています。 rendererIndex、その他の ExoPlayer 固有のフィールド。

次の例は、エラーが原因で再生が失敗したことを検出し、 HTTP ネットワークの問題:

Kotlin

player.addListener(
  object : Player.Listener {
    override fun onPlayerError(error: PlaybackException) {
      val cause = error.cause
      if (cause is HttpDataSourceException) {
        // An HTTP error occurred.
        val httpError = cause
        // It's possible to find out more about the error both by casting and by querying
        // the cause.
        if (httpError is InvalidResponseCodeException) {
          // Cast to InvalidResponseCodeException and retrieve the response code, message
          // and headers.
        } else {
          // Try calling httpError.getCause() to retrieve the underlying cause, although
          // note that it may be null.
        }
      }
    }
  }
)

Java

player.addListener(
    new Player.Listener() {
      @Override
      public void onPlayerError(PlaybackException error) {
        @Nullable Throwable cause = error.getCause();
        if (cause instanceof HttpDataSourceException) {
          // An HTTP error occurred.
          HttpDataSourceException httpError = (HttpDataSourceException) cause;
          // It's possible to find out more about the error both by casting and by querying
          // the cause.
          if (httpError instanceof HttpDataSource.InvalidResponseCodeException) {
            // Cast to InvalidResponseCodeException and retrieve the response code, message
            // and headers.
          } else {
            // Try calling httpError.getCause() to retrieve the underlying cause, although
            // note that it may be null.
          }
        }
      }
    });

再生リストの切り替え

プレーヤーが再生リスト内の新しいメディア アイテムに変更したとき onMediaItemTransition(MediaItem mediaItem, @MediaItemTransitionReason int reason) が登録済みで呼び出されます Player.Listener オブジェクト。自動停止であるかどうかを示します。 遷移、シーク(player.next() の呼び出し後など)、 再生リストの変更が原因(たとえば、 削除されます)。

メタデータ

player.getCurrentMediaMetadata() から返されるメタデータは、 再生リストの切り替え、インストリーム メタデータの更新、 現在の MediaItem の再生中。

メタデータの変更に関心がある場合(たとえば、次を表示する UI の更新など)は、 onMediaMetadataChangedを再生します。

シークしています

Player.seekTo メソッドを呼び出すと、登録された一連のコールバックが呼び出されます。 Player.Listener 個のインスタンス:

  1. onPositionDiscontinuityreason=DISCONTINUITY_REASON_SEEK に置き換えます。これは、 Player.seekTo を呼び出した直接的な結果。コールバックに PositionInfo が含まれている フィールドを返します。
  2. onPlaybackStateChanged は、シークに関連する即時の状態変更に置き換えます。 そのような変更がない場合もあります。

個別のコールバックと onEvents

リスナーは、次のように個別のコールバックの実装を選択できます。 onIsPlayingChanged(boolean isPlaying)、汎用 onEvents(Player player, Events events) コールバック。汎用のコールバックでは、 Player オブジェクトにアクセスし、発生した events のセットを指定します。 説明します。このコールバックは常に、対応するコールバックの 個別に選択できます。

Kotlin

override fun onEvents(player: Player, events: Player.Events) {
  if (
    events.contains(Player.EVENT_PLAYBACK_STATE_CHANGED) ||
      events.contains(Player.EVENT_PLAY_WHEN_READY_CHANGED)
  ) {
    uiModule.updateUi(player)
  }
}

Java

@Override
public void onEvents(Player player, Events events) {
  if (events.contains(Player.EVENT_PLAYBACK_STATE_CHANGED)
      || events.contains(Player.EVENT_PLAY_WHEN_READY_CHANGED)) {
    uiModule.updateUi(player);
  }
}

次の場合は、個別のイベントをおすすめします。

  • リスナーは変更の理由に関心を持っています。たとえば、 onPlayWhenReadyChanged または onMediaItemTransition に対して指定された理由。
  • リスナーは、コールバック パラメータを通じて提供される新しい値に対してのみ動作します。 コールバックのパラメータに依存しない別の処理をトリガーします。
  • リスナー実装では、何であるかをわかりやすく メソッド名のイベントをトリガーします
  • リスナーはアナリティクス システムにレポートを送信します。このシステムは、 状態変化をモニタリングできます。

カテゴリでは、汎用の onEvents(Player player, Events events) が優先されます。 次のようなケースがあります。

  • リスナーは、複数のイベントに対して同じロジックをトリガーしたいと考えています。対象 たとえば、onPlaybackStateChanged と両方の UI を更新するとします。 onPlayWhenReadyChanged
  • リスナーは、以降のイベントをトリガーするために Player オブジェクトにアクセスする必要があります。 たとえばメディア アイテムの遷移後にシークします
  • リスナーは、報告される複数の状態値を使用することを意図しています。 個別のコールバックを一緒に使用することも、Player ゲッターと組み合わせて使用することもできます。 あります。たとえば、Player.getCurrentWindowIndex()onTimelineChanged で指定された Timeline は、 onEvents コールバック。
  • リスナーは、イベントが一緒に発生したかどうかを調べます。対象 メディア アイテムによる onPlaybackStateChanged から STATE_BUFFERING など 説明します。

場合によっては、リスナーは個々のコールバックを 汎用の onEvents コールバック(メディア アイテムの変更理由を記録する場合など) onMediaItemTransition を使用。ただし、すべての状態変化が使用可能になった場合にのみ動作 onEvents で一緒にプレイします。

AnalyticsListener の使用

ExoPlayer を使用する場合は、AnalyticsListener をプレーヤーに登録できる。 addAnalyticsListener を呼び出します。AnalyticsListener 個の実装で可能 分析やロギングに役立つ可能性のある詳細なイベントをリッスンする あります。詳しくは、アナリティクス ページをご覧ください。

EventLogger の使用

EventLogger は、ライブラリから直接提供される AnalyticsListener です。 使用します。EventLoggerExoPlayer に追加して利便性を高める 次のように 1 行で追加します。

Kotlin

player.addAnalyticsListener(EventLogger())

Java

player.addAnalyticsListener(new EventLogger());

詳細については、デバッグ ロギングのページをご覧ください。

指定した再生位置でイベントを発生させる

ユースケースによっては、指定した再生位置でイベントを発生させる必要があります。これは、 PlayerMessage を使用してサポートされます。PlayerMessage は、次のコマンドを使用して作成できます。 ExoPlayer.createMessage。実行する再生位置 PlayerMessage.setPosition を使用して設定できます。メッセージは、 デフォルトですが、次のコマンドを使用してカスタマイズできます。 PlayerMessage.setLooperPlayerMessage.setDeleteAfterDelivery を使用できます。 指定した日時のたびにメッセージを実行するかどうかを 再生位置に到達した(これは再生位置の移動が原因で複数回発生する場合がある) リピート モードなど)、または初回のみに設定できます。PlayerMessage の設定が完了したら、 PlayerMessage.send を使用してスケジュールできます。

Kotlin

player
  .createMessage { messageType: Int, payload: Any? -> }
  .setLooper(Looper.getMainLooper())
  .setPosition(/* mediaItemIndex= */ 0, /* positionMs= */ 120000)
  .setPayload(customPayloadData)
  .setDeleteAfterDelivery(false)
  .send()

Java

player
    .createMessage(
        (messageType, payload) -> {
          // Do something at the specified playback position.
        })
    .setLooper(Looper.getMainLooper())
    .setPosition(/* mediaItemIndex= */ 0, /* positionMs= */ 120_000)
    .setPayload(customPayloadData)
    .setDeleteAfterDelivery(false)
    .send();