تصف هذه الصفحة كيفية استخدام Co-Doing API لإتاحة سيناريو مشترك.
عملية الإعداد الأوّلية
لإعداد المكتبة للاستخدام، يجب أن يضبط تطبيق المشاركة المباشرة عنصر CoDoingClient
الذي يمثّل جلسة مشتركة.
لاستخدام حزمة تطوير البرامج (SDK) لميزة "المشاركة المباشرة في Meet"، عليك طلب الطريقة
AddonClientFactory.getClient
. يؤدي ذلك إلى عرض رمز
AddonClient
يعمل كنقطة دخول لجلسة العمل المشترَك.
لاستخدام البرنامج، يمكنك استدعاء الطريقة
newSessionBuilder
من AddonClient
لعرض أداة إنشاء
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
توضح أنّ الفيديو متوقف مؤقتًا، واطلب من 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
".
يعرض نموذج الرمز البرمجي التالي كيفية إشعار المستخدمين بعنوان URL المعدّل الخاص بالفيديو:
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);
}
إنهاء المشاركة في اللعب
عندما يختار المستخدم إنهاء النشاط، يتم إلغاء ربط الطريقة
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();
}
}
}