实现 Co-Watching API

本页介绍了如何使用 Co-Watching API 支持“一起看”场景。

初始设置

如需准备该库以供使用,实时分享应用应初始化一个表示一起观看会话的 CoWatchingClient 对象。

如需使用 Meet 实时共享 SDK,请调用 AddonClientFactory.getClient 方法。这将返回一个 AddonClient,用作“一起看”会话的入口点。

如需使用该客户端,请从 AddonClient 调用 newSessionBuilder 方法,为新的 AddonSession 返回构建器。newSessionBuilder 会实现 AddonSessionHandler 接口,以处理插件为会话提供的回调。

如需启动会话,请将 withCoWatching 方法添加到构建器上。

以下代码示例展示了共同观看客户端对象的基本初始化:

Java

class AwesomeVideoAddonSessionHandler implements AddonSessionHandler {}

// For sample implementation, see the "Manage remote state" section below.
class AwesomeVideoCoWatchingHandler implements CoWatchingHandler {}

public ListenableFuture<AddonSession> initialSetup() {
  AddonClient meetClient = AddonClientFactory.getClient();
  return meetClient
      .newSessionBuilder(
          new AwesomeVideoAddonSessionHandler())
      .withCoWatching(new AwesomeVideoCoWatchingHandler())
      .begin();
}

有用户操作时发出通知

当本地用户执行操作(例如,暂停或跳转其设备上的媒体播放)时,必须通知库,以便将这些操作镜像到一起观看体验中的其他参与者。如需查看如何针对多种状态向库发出通知的示例,请参阅使用入门

您可以通过以下方式控制“一起看”状态:

以下代码示例展示了如何通知用户:

Java

public void onVideoPaused(Duration currentTimestamp) {
  // Use Meet to broadcast the pause state to ensure other participants also pause.
  this.session.getCoWatching().notifyPauseState(/* paused= */ true, currentTimestamp);
};

管理远程状态

如需应用远程参与者传入的更新,您必须为 Meet 提供一种使用 CoWatchingHandler.onCoWatchingStateChanged() 回调直接管理本地媒体播放状态的方法。

Meet 还需要通过调用 CoWatchingHandler.onStateQuery() 回调来检索媒体播放的当前位置。系统会定期调用此函数,因此应将其写入为高性能(例如,小于 100 毫秒)。

以下代码示例展示了 CoWatchingHandler 的实现:

Java

class AwesomeVideoCoWatchingHandler implements CoWatchingHandler {
  /** Applies incoming playback state to the local video. */
  public void onCoWatchingStateChanged(CoWatchingState newState) {
    // Handle transition to new video.
    if (!newState.mediaId().equals(this.videoPlayer.videoUrl)) {
      this.videoPlayer.loadVideo(newState.mediaId());
    }

    // Only adjust the local video playout if it's sufficiently diverged from the timestamp in the
    // applied update.
    if (newState
            .mediaPlayoutPosition()
            .minus(this.videoPlayer.videoTimestamp)
            .compareTo(Duration.ofMillis(500))
        > 0) {
      this.videoPlayer.seek(newState.mediaPlayoutPosition());
    }

    // Update pause state, if necessary.
    if (newState.playbackState().equals(PLAY) && this.videoPlayer.isPaused) {
      this.videoPlayer.unpause();
    } else if (newState.playbackState().equals(PAUSE) && !this.videoPlayer.isPaused) {
      this.videoPlayer.pause();
    }
  }

  /** Returns local video playback state. */
  public Optional<QueriedCoWatchingState> onStateQuery() {
    return Optional.of(QueriedCoWatchingState.of(
      /* mediaPlayoutPosition= */ this.videoPlayer.videoTimestamp));
  }
}