מדיה זורמת

ב-ExpoPlayer נהנים מרוב השידורים החיים המותאמים באופן מיידי, ללא צורך בתוספות מיוחדות הגדרה אישית. מידע נוסף זמין בדף 'פורמטים נתמכים'.

בשידורים חיים בהתאמה אישית יש חלון של מדיה זמינה שמתעדכנת במרווחי זמן קבועים שנקבעו בזמן אמת. המשמעות היא שההפעלה יהיה תמיד במקום כלשהו בחלון, ברוב המקרים קרוב בזמן אמת שבו משודר השידור. ההבדל בין הזמן הנוכחי בזמן אמת ומיקום ההפעלה נקראים היסט בזמן אמת.

זיהוי של הפעלות בשידור חי ומעקב אחריהן

בכל פעם שחלון פעיל מתעדכן, מתועדים Player.Listener מופעים יקבל אירוע onTimelineChanged. אפשר לאחזר פרטים על ההפעלה הנוכחית בשידור חי על ידי שליחת שאילתה לגבי Player ו-Timeline.Window שונים השיטות שמפורטות בהמשך ומוצג באיור הבא.

חלון השידור החי

  • Player.isCurrentWindowLive מציין אם המדיה שמופעלת כרגע הפריט הוא שידור חי. הערך הזה עדיין רלוונטי גם אם לשידור החי הסתיים.
  • Player.isCurrentWindowDynamic מציין אם המדיה שמופעלת כרגע עדיין מתבצע עדכון של הפריט. זה נכון בדרך כלל לגבי שידורים חיים עדיין לא הסתיים. שימו לב שהסימון הזה נכון גם בשידורים שאינם בשידור חי בחלק במקרים שונים.
  • הפונקציה Player.getCurrentLiveOffset מחזירה את הקיזוז בין הריאל הנוכחי השעה ואת מיקום ההפעלה (אם זמין).
  • הפונקציה Player.getDuration מחזירה את משך הזמן של חלון השידור החי הנוכחי.
  • Player.getCurrentPosition מחזיר את נקודת ההפעלה ביחס ההתחלה של חלון השידור החי.
  • Player.getCurrentMediaItem מחזיר את פריט המדיה הנוכחי, שבו השדה MediaItem.liveConfiguration מכיל שינויים שסופקו על ידי האפליקציה לצורך היעד פרמטרים של התאמת היסט בזמן אמת והתאמת היסט בזמן אמת.
  • Player.getCurrentTimeline מחזירה את מבנה המדיה הנוכחי Timeline. אפשר לאחזר את הערך הנוכחי של Timeline.Window מהTimeline באמצעות Player.getCurrentWindowIndex ו-Timeline.getWindow. בתוך Window:
    • Window.liveConfiguration מכיל את יעד ההיסט בזמן אמת וההיסט בזמן אמת של פרמטרים להתאמה אישית. הערכים האלה מבוססים על מידע בתקשורת וכל ההגדרות החלופיות שסופקו על ידי האפליקציה שהוגדרו ב-MediaItem.liveConfiguration.
    • Window.windowStartTimeMs הוא הזמן שעבר מאז נקודת יוניקס (Unix epoch) שבה חלון השידור החי מתחיל.
    • Window.getCurrentUnixTimeMs הוא הזמן שעבר מאז תקופת יוניקס (Unix epoch) בזמן אמת. יכול להיות שהערך יתוקן בגלל הבדל ידוע בשעון בין השרת ללקוח.
    • Window.getDefaultPositionMs הוא המיקום בחלון השידור החי שבו הנגן יתחיל את ההפעלה כברירת מחדל.

חיפוש בשידורים חיים

אפשר לדלג לכל מקום בחלון השידור החי באמצעות Player.seekTo. הדילוג המיקום שהועבר הוא ביחס לתחילת החלון הפעיל. לדוגמה, הפעולה seekTo(0) תריץ את הסמן לתחילת חלון השידור החי. הנגן ינסה לשמור על אותה קיזוז פעיל כמו המיקום המבוקש אחרי הדילוג.

לחלון השידור החי יש גם מיקום ברירת מחדל שבו ההפעלה אמורה הפעלה. לרוב, המיקום הזה קרוב לקצה הפעיל. אפשר להריץ למיקום ברירת המחדל באמצעות קריאה ל-Player.seekToDefaultPosition.

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

ברכיבי ברירת המחדל של ממשק המשתמש של ExoPlayer מוצגים משך הזמן של חלון השידור החי את מיקום ההפעלה הנוכחי בתוכו. משמעות הדבר היא שהמיקום לדלג אחורה בכל פעם שחלון השידור החי מתעדכן. אם צריך התנהגות מסוימת. לדוגמה, כדי להציג את זמן ה-Unix או את ההיסט הנוכחי של השידור החי, אפשר אפשר לחבר את PlayerControlView ולשנות אותו בהתאם לצרכים שלך.

הגדרת הפרמטרים של הפעלה בשידור חי

ExoPlayer משתמש בפרמטרים מסוימים כדי לשלוט בהיסט של מיקום ההפעלה מהקצה של השידור החי, ושל טווח מהירויות ההפעלה שניתן להשתמש בהן מתאימים את ההיסט הזה.

ExoPlayer מקבל ערכים לפרמטרים האלה משלושה מקומות, בסדר יורד סדר עדיפות (נעשה שימוש בערך הראשון שנמצא):

  • לכל MediaItem ערכים שמועברים אל MediaItem.Builder.setLiveConfiguration.
  • ערכי ברירת המחדל הכלליים הוגדרו בתאריך DefaultMediaSourceFactory.
  • הערכים שנקראים ישירות מהמדיה.

Kotlin

// Global settings.
val player =
  ExoPlayer.Builder(context)
    .setMediaSourceFactory(DefaultMediaSourceFactory(context).setLiveTargetOffsetMs(5000))
    .build()

// Per MediaItem settings.
val mediaItem =
  MediaItem.Builder()
    .setUri(mediaUri)
    .setLiveConfiguration(
      MediaItem.LiveConfiguration.Builder().setMaxPlaybackSpeed(1.02f).build()
    )
    .build()
player.setMediaItem(mediaItem)

Java

// Global settings.
ExoPlayer player =
    new ExoPlayer.Builder(context)
        .setMediaSourceFactory(
            new DefaultMediaSourceFactory(context).setLiveTargetOffsetMs(5000))
        .build();

// Per MediaItem settings.
MediaItem mediaItem =
    new MediaItem.Builder()
        .setUri(mediaUri)
        .setLiveConfiguration(
            new MediaItem.LiveConfiguration.Builder().setMaxPlaybackSpeed(1.02f).build())
        .build();
player.setMediaItem(mediaItem);

ערכי ההגדרות הזמינים הם:

  • targetOffsetMs: קיזוז היעד בזמן אמת. השחקן ינסה להשיג קרוב להיסט הזה של השידור החי במהלך ההפעלה, אם אפשר.
  • minOffsetMs: הסטייה המינימלית המותרת בזמן אמת. גם כאשר מכווננים את לקזז בהתאם לתנאי הרשת הנוכחיים, הנגן לא ינסה להוריד את הנתונים ההיסט הזה במהלך ההפעלה.
  • maxOffsetMs: המרבי המותר של הסטייה בזמן אמת. גם כאשר מכווננים את לקזז בהתאם לתנאי הרשת הנוכחיים, הנגן לא ינסה להשיג מעל ההיסט הזה במהלך ההפעלה.
  • minPlaybackSpeed: מהירות ההפעלה המינימלית שהנגן יכול להשתמש בה כדי לחזור אחורה כשמנסים להגיע לקיזוז היעד בזמן אמת.
  • maxPlaybackSpeed: מהירות ההפעלה המקסימלית שהנגן יכול להשתמש בה כדי להתעדכן כשמנסים להגיע לקיזוז היעד בזמן אמת.

כוונון מהירות ההפעלה

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

אם לא רוצים לכוונן את מהירות ההפעלה האוטומטית, אפשר להשבית אותה על ידי הגדרה של minPlaybackSpeed ו-maxPlaybackSpeed כ-1.0f. באופן דומה, אפשר להפעיל את התכונה לשידורים חיים עם זמן אחזור קצר באופן מפורש לערכים שאינם 1.0f. צפייה בקטע בנושא הגדרות אישיות על האופן שבו ניתן להגדיר את המאפיינים האלה.

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

אם התאמת המהירות מופעלת, LivePlaybackSpeedControl מגדיר יתבצעו התאמות. אפשר ליישם LivePlaybackSpeedControl, או להתאים אישית את הטמעת ברירת המחדל, DefaultLivePlaybackSpeedControl. בשני המקרים, אפשר להגדיר מכונה כאשר בניית הנגן:

Kotlin

val player =
  ExoPlayer.Builder(context)
    .setLivePlaybackSpeedControl(
      DefaultLivePlaybackSpeedControl.Builder().setFallbackMaxPlaybackSpeed(1.04f).build()
    )
    .build()

Java

ExoPlayer player =
    new ExoPlayer.Builder(context)
        .setLivePlaybackSpeedControl(
            new DefaultLivePlaybackSpeedControl.Builder()
                .setFallbackMaxPlaybackSpeed(1.04f)
                .build())
        .build();

הפרמטרים הרלוונטיים להתאמה אישית של DefaultLivePlaybackSpeedControl הם:

  • fallbackMinPlaybackSpeed ו-fallbackMaxPlaybackSpeed: ערכי המינימום וגם מהירויות הפעלה מקסימליות שאפשר להשתמש בהן להתאמה אם אף מדיה לא או MediaItem שסופקה על ידי האפליקציה מגדירות מגבלות.
  • proportionalControlFactor: המדיניות קובעת עד כמה התאמת המהירות תהיה חלקה. א' ערך גבוה מבצע התאמות פתאומיות ותגובתיות יותר, אך גם סביר יותר יהיו חייב להיות עוצמתי. ערך קטן יותר יגרום למעבר חלק יותר בין מהירויות, במחיר של איטיות יותר.
  • targetLiveOffsetIncrementOnRebufferMs: הערך הזה נוסף ליעד היסט בזמן אמת בכל פעם שמתרחש מאגר נתונים זמני, כדי להמשיך בזהירות רבה יותר. אפשר להשבית את התכונה הזו על ידי הגדרת הערך כ-0.
  • minPossibleLiveOffsetSmoothingFactor: גורם החלקה מעריכי משמש למעקב אחר ההיסט המינימלי האפשרי בשידור חי, לפי מדיה ששמורה במאגר נתונים זמני. ערך קרוב מאוד ל-1 פירושו שההערכה גבוהה יותר זהירותי וייתכן שיידרש זמן רב יותר להסתגלות לתנאי רשת משופרים, בעוד ערך נמוך יותר פירושו שההערכה תתאים מהר יותר בסיכון גבוה יותר בתהליך של אגירת נתונים.

BehindLiveWindowאפס ו-ERROR_CODE_BEHIND_LIVE_WINDOW

מיקום ההפעלה עשוי להיות מאחורי חלון השידור החי, לדוגמה אם הנגן נמצא בהשהיה או בתהליך אגירת נתונים למשך תקופה ארוכה מספיק. אם זה יקרה, ההפעלה תיכשל וחריגה עם קוד שגיאה הדיווח על ERROR_CODE_BEHIND_LIVE_WINDOW יתבצע דרך Player.Listener.onPlayerError. ייתכן שקוד האפליקציה יטפל שגיאות על ידי המשך ההפעלה במיקום ברירת המחדל. PlayerActivity של אפליקציית ההדגמה ממחישה את הגישה הזו.

Kotlin

override fun onPlayerError(error: PlaybackException) {
  if (error.errorCode == PlaybackException.ERROR_CODE_BEHIND_LIVE_WINDOW) {
    // Re-initialize player at the live edge.
    player.seekToDefaultPosition()
    player.prepare()
  } else {
    // Handle other errors
  }
}

Java

@Override
public void onPlayerError(PlaybackException error) {
  if (error.errorCode == PlaybackException.ERROR_CODE_BEHIND_LIVE_WINDOW) {
    // Re-initialize player at the live edge.
    player.seekToDefaultPosition();
    player.prepare();
  } else {
    // Handle other errors
  }
}