הטמעת ה-Co-Doing API

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

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

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

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

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

כדי להתחיל סשן, צריך להוסיף את withCoDoing ל-builder.

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

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

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

הפעלת תרשים של ממשק 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 של משתתף אחר מקבלת שידור, 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();
    }
  }
}