本页介绍了如何使用 Co-Doing API 支持协同操作 场景。
初始设置
要准备库以供使用,实时共享应用应初始化
CoDoingClient
对象。
要使用 Meet 实时共享 SDK,请调用
AddonClientFactory.getClient
方法。这将返回一个
AddonClient
作为共同操作会话的入口点
要使用客户端,请调用
newSessionBuilder
AddonClient
方法返回新
AddonSession
。
newSessionBuilder
会实现
AddonSessionHandler
用于处理由 API 提供的
插件
要开始会话,请添加
withCoDoing
添加到构建器上。
以下代码示例展示了协作操作客户端的基本初始化 对象:
Java
class AwesomeVideoAddonSessionHandler implements AddonSessionHandler {}
//For sample implementation, see the "Handle incoming updates" section.
class AwesomeVideoCoDoingHandler implements CoDoingHandler {}
public ListenableFuture<AddonSession> initialSetup() {
AddonClient meetClient = AddonClientFactory.getClient();
return meetClient
.newSessionBuilder(
new AwesomeVideoAddonSessionHandler())
.withCoDoing(new AwesomeVideoCoDoingHandler())
.begin();
}
暂停视频
参与实时共享体验时,如果用户暂停了播放 进行直播,那么您必须确保所有参与者都能 也会暂停视频
为此,请制作一个
CoDoingState
显示视频已暂停的消息,并指示 Google Meet 向该视频广播
其他所有使用
setGlobalState
方法。共享的全局状态会成为所有参与者的默认状态,
现有状态或新的状态,直到设置新状态。
以下代码示例展示了如何通知用户已暂停状态:
Java
public void onVideoPaused(String videoUrl, Instant currentTimestamp) {
// Create an internal state object to share with other participants. Note: It's
// good practice to encode all metadata—even seemingly irrelevant data—into
// ActivityState updates to guard against race conditions and other subtle
// failures.
AwesomeVideoState videoState = AwesomeVideoState
.builder()
.videoUrl(videoUrl)
.videoTimestamp(currentTimestamp)
.isPaused(true)
.build();
// Create the CoDoingState object to wrap the internal state
CoDoingState coDoingState = new CoDoingState();
coDoingState.state = SerializationUtils.serialize(videoState);
// Use Meet to broadcast internal state update to all other participants
this.coDoingClient.setGlobalState(coDoingState);
};
此代码示例触发要广播到的序列化 videoState
对象
参与实时共享的所有其他 Meet 实例
体验。详细了解如何从其他
请参阅处理传入更新
部分。
下图描述了暂停操作触发后的事件序列, 已触发:
取消暂停视频
与暂停视频类似,如果用户在自己的设备上 则 Meet 必须将此操作广播到其他直播 共享参与者。
在发送方(即取消暂停视频的用户)方面,
暂停示例是 isPaused
状态已更新。
以下代码示例展示了如何从 发送方:
Java
public void onVideoUnpaused(String videoUrl, Instant currentTimestamp) {
AwesomeVideoState videoState = AwesomeVideoState
.builder()
.videoUrl(videoUrl)
.videoTimestamp(currentTimestamp)
.isPaused(false)
.build();
CoDoingState coDoingState = new CoDoingState();
coDoingState.state = SerializationUtils.serialize(videoState);
this.coDoingClient.setGlobalState(coDoingState);
}
跳转视频
就像暂停视频和取消暂停视频一样, 如果用户将本地应用上的时间轴拖动到新的时间戳, Meet 必须向所有参与者广播此操作。
以下代码示例展示了如何通知用户时间戳已更新 :
Java
public void onVideoSeeked(String videoUrl, Instant currentTimestamp, bool isPaused) {
AwesomeVideoState videoState = AwesomeVideoState
.builder()
.videoUrl(videoUrl)
.videoTimestamp(currentTimestamp)
.isPaused(isPaused)
.build();
CoDoingState coDoingState = new CoDoingState();
coDoingState.state = SerializationUtils.serialize(videoState);
this.coDoingClient.setGlobalState(coDoingState);
}
播放其他视频
如果用户还通过选择
Meet 必须播放新视频才能进行所有实时共享
参与者。更改后的视频存储在 videoState.videoUrl
中。
以下代码示例展示了如何通知用户视频网址已更新:
Java
public void onVideoChanged(String videoUrl, Duration currentTimestamp, bool isPaused) {
AwesomeVideoState videoState = AwesomeVideoState
.builder()
.videoUrl(videoUrl)
.videoTimestamp(currentTimestamp)
.isPaused(isPaused)
.build();
CoDoingState coDoingState = new CoDoingState();
coDoingState.state = SerializationUtils.serialize(videoState);
this.coDoingClient.setGlobalState(coDoingState);
}
结束共享操作
当用户选择结束 Activity 时,
endSession
方法与 Meet 应用断开连接。这并不强制
Meet 结束会议,且不会导致用户退出会议
会议。
以下代码示例展示了如何通知用户会话已停止:
Java
public void endCoDoing() {
this.session.endSession();
}
处理传入的更新
当其他参与者的 Meet 应用收到广播时,
onGlobalStateChanged()
触发回调函数。通常情况下,在决定要采用哪种方法
对传入更新执行的操作(例如,仅匹配传入的
视频时间戳(如果它们与本地时间戳明显不同)。
以下代码示例展示了如何处理不同的传入更新:
Java
class AwesomeVideoCoDoingHandler implements CoDoingHandler {
public void onGlobalStateChanged(CoDoingState update) {
AwesomeVideoState videoState = SerializationUtils.deserialize(update.state());
// Handle transition to new video.
if (!videoState.videoUrl.equals(this.videoPlayer.videoUrl)) {
this.videoPlayer.loadVideo(videoState.videoUrl);
}
// If the timestamp in the arriving update has sufficiently diverged, adjust
// the local video playout.
if (videoState.videoTimestamp.minus(this.videoPlayer.videoTimestamp).abs() >
Duration.ofSeconds(2)) {
this.videoPlayer.seek(videoState.videoTimestamp);
}
// Update pause state, if necessary.
if (!videoState.isPaused && this.videoPlayer.isPaused) {
this.videoPlayer.unpause();
} else if (videoState.isPaused && !this.videoPlayer.isPaused) {
this.videoPlayer.pause();
}
}
}