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

管理远程状态

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

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