本页介绍了如何使用 Co-Doing API 支持协作处理场景。
初始设置
如需准备该库以供使用,实时共享应用应初始化一个代表共同处理会话的 CoDoingClient
对象。
如需使用 Meet 实时共享 SDK,请调用 AddonClientFactory.getClient
方法。这将返回一个 AddonClient
,作为共同处理会话的入口点。
如需使用该客户端,请从 AddonClient
调用 newSessionBuilder
方法,为新的 AddonSession
返回构建器。newSessionBuilder
会实现 AddonSessionHandler
接口,以处理插件为会话提供的回调。
如需启动会话,请将 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
消息,显示视频已暂停,并使用 setGlobalState
方法让 Google Meet 向所有其他参与者广播消息。共享全局状态将成为所有参与者(包括现有参与者还是新参与者)的默认状态,直到设置了新状态为止。
以下代码示例展示了如何将暂停状态通知用户:
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();
}
}
}