הטמעת ה-Co-Doing API

בדף הזה נסביר איך להשתמש ב-Co-Doing API כדי לתמוך בתרחיש של ביצוע משותף.

הגדרה ראשונית

כדי להכין את הספרייה לשימוש, אפליקציית השיתוף בזמן אמת צריכה לאתחל אובייקט CoDoingClient שמייצג פעילות משותפת.

כדי להשתמש ב-SDK לשיתוף בזמן אמת ב-Meet, צריך להפעיל את השיטה AddonClientFactory.getClient. כך מתקבל AddonClient שמשמש כנקודת הכניסה לסשן של שיתוף פעולה.

כדי להשתמש בלקוח, קוראים לשיטה newSessionBuilder מה-AddonClient כדי להחזיר builder עבור AddonSession חדש. newSessionBuilder מטמיע את הממשק של AddonSessionHandler כדי לטפל בקריאות החוזרות (callback) שהתוסף בסשן מספק.

כדי להתחיל סשן, מוסיפים את השיטה withCoDoing ל-builder.

דוגמת הקוד הבאה מציגה אתחול בסיסי של אובייקט הלקוח לביצוע פעולה משותפת:

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 שמשתתפים בחוויית השיתוף בזמן אמת. בקטע טיפול בעדכונים נכנסים מוסבר איך מקבלים עדכונים בשידור ממשתתפים אחרים.

בתרשים הבא מתואר רצף האירועים אחרי שפעולת ההשהיה מופעלת:

הפעלת התרשים של Live Share API.

ביטול ההשהיה של הסרטון

כמו במקרה של השהיית הסרטון, אם משתמש מבטל את ההשהיה של הסרטון באפליקציה המקומית, צריך לשדר את הפעולה הזו ב-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 של משתתף אחר מקבלת שידור, מופעלת הקריאה החוזרת (callback) 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();
    }
  }
}