הטמעת ממשק ה-API לצפייה משותפת

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

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

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

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

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

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

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

Java

class AwesomeVideoAddonSessionHandler implements AddonSessionHandler {}

// For sample implementation, see the "Manage remote state" section below.
class AwesomeVideoCoWatchingHandler implements CoWatchingHandler {}

public ListenableFuture<AddonSession> initialSetup() {
  AddonClient meetClient = AddonClientFactory.getClient();
  return meetClient
      .newSessionBuilder(
          new AwesomeVideoAddonSessionHandler())
      .withCoWatching(new AwesomeVideoCoWatchingHandler())
      .begin();
}

התראות על פעולות משתמשים

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

אתם יכולים לשלוט במצב הצפייה המשותפת באמצעות השיטות האלה:

  • CoWatchingClient.notifyBuffering: מודיע ל-Meet שמדיה לא מוכנה להפעלה בגלל אחסון זמני, בגלל מעבר קודם למדיה, חיפוש מדיה או עומס רגיל ברשת.
  • CoWatchingClient.notifyEnded: מודיעה ל-Meet שנגן המדיה הגיע לסוף המדיה הנוכחית.
  • CoWatchingClient.notifyPauseState שליחת התראה ל-Meet שהמשתמש השהה או ביטל את ההשהיה של הפעלת המדיה, כדי שיוכלו לשקף למשתמשים אחרים את הפעולה הזו ב-Meet.
  • CoWatchingClient.notifyPlayoutRate: מודיעה ל-Meet שהמשתמש עדכן את קצב ההפעלה של המדיה לערך חדש (לדוגמה, 1.25x).
  • CoWatchingClient.notifyQueueUpdate: מודיעה ל-Meet שהתור השתנה, כדי ש-Meet יכול לשקף את כך אצל משתמשים אחרים.
  • CoWatchingClient.notifyReady: מודיע ל-Meet שמאגר הנתונים הזמני הושלם, והמדיה מוכנה להפעלה, החל מחותמת הזמן שצוינה.
  • CoWatchingClient.notifySeekToTimestamp: מודיעה ל-Meet שהמשתמש חיפש את נקודת ההפעלה של המדיה, כדי שניתן יהיה לשקף את הפעולה הזו ב-Meet אצל משתמשים אחרים.
  • CoWatchingClient.notifySwitchedToMedia: מודיעה ל-Meet שהמשתמש החליף מדיה, כדי ש-Meet תוכל להעביר את זה למשתמשים אחרים. יש גם אפשרות לעדכון תור בו-זמנית.

דוגמת הקוד הבאה מציגה איך ליידע את המשתמשים:

Java

public void onVideoPaused(Duration currentTimestamp) {
  // Use Meet to broadcast the pause state to ensure other participants also pause.
  this.session.getCoWatching().notifyPauseState(/* paused= */ true, currentTimestamp);
};

ניהול שמירת המצב ביעד מרוחק

כדי להחיל עדכונים נכנסים מהמשתתפים מרחוק, צריך להציע ל-Meet דרך לנהל ישירות את המצב המקומי להפעלת מדיה באמצעות הקריאה החוזרת CoWatchingHandler.onCoWatchingStateChanged().

בנוסף, ב-Meet צריך להפעיל את הקריאה החוזרת (callback) CoWatchingHandler.onStateQuery() כדי לשחזר את המיקום הנוכחי של הקראת המדיה. קוראים לזה באופן קבוע, ולכן צריך לכתוב אותו כביצועים (לדוגמה, <100 אלפיות שנייה).

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

Java

class AwesomeVideoCoWatchingHandler implements CoWatchingHandler {
  /** Applies incoming playback state to the local video. */
  public void onCoWatchingStateChanged(CoWatchingState newState) {
    // Handle transition to new video.
    if (!newState.mediaId().equals(this.videoPlayer.videoUrl)) {
      this.videoPlayer.loadVideo(newState.mediaId());
    }

    // Only adjust the local video playout if it's sufficiently diverged from the timestamp in the
    // applied update.
    if (newState
            .mediaPlayoutPosition()
            .minus(this.videoPlayer.videoTimestamp)
            .compareTo(Duration.ofMillis(500))
        > 0) {
      this.videoPlayer.seek(newState.mediaPlayoutPosition());
    }

    // Update pause state, if necessary.
    if (newState.playbackState().equals(PLAY) && this.videoPlayer.isPaused) {
      this.videoPlayer.unpause();
    } else if (newState.playbackState().equals(PAUSE) && !this.videoPlayer.isPaused) {
      this.videoPlayer.pause();
    }
  }

  /** Returns local video playback state. */
  public Optional<QueriedCoWatchingState> onStateQuery() {
    return Optional.of(QueriedCoWatchingState.of(
      /* mediaPlayoutPosition= */ this.videoPlayer.videoTimestamp));
  }
}