ב-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 } }