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

-
Player.isCurrentWindowLiveמציין אם פריט המדיה שמופעל כרגע הוא שידור חי. הערך הזה נכון גם אם השידור החי הסתיים. Player.isCurrentWindowDynamicמציין אם פריט המדיה שמופעל כרגע עדיין מתעדכן. זה נכון בדרך כלל לשידורים חיים שעדיין לא הסתיימו. הערה: הדגל הזה מוגדר כ-true גם לשידורים שהם לא בשידור חי במקרים מסוימים.- הפונקציה
Player.getCurrentLiveOffsetמחזירה את ההפרש בין הזמן הנוכחי בזמן אמת לבין מיקום ההפעלה (אם הוא זמין). -
Player.getDurationמחזירה את האורך של חלון השידור החי הנוכחי. -
Player.getCurrentPositionמחזירה את מיקום ההפעלה ביחס לתחילת חלון השידור החי. -
Player.getCurrentMediaItemמחזירה את פריט המדיה הנוכחי, כאשרMediaItem.liveConfigurationמכילה שינויים שסופקו על ידי האפליקציה לפרמטרים של היעד של ההזזה בשידור חי והתאמת ההזזה בשידור חי. -
Player.getCurrentTimelineמחזירה את מבנה המדיה הנוכחי ב-Timeline. אפשר לאחזר אתTimeline.Windowהנוכחי מ-TimelineבאמצעותPlayer.getCurrentMediaItemIndexו-Timeline.getWindow. בתוך התגWindow:-
Window.liveConfigurationמכיל את הפרמטרים של היעד של ההזחה בשידור חי והתאמת ההזחה בשידור חי. הערכים האלה מבוססים על מידע במדיה ועל כל שינוי שסופק על ידי האפליקציה והוגדר ב-MediaItem.liveConfiguration. -
Window.windowStartTimeMsהוא הזמן מאז ראשית זמן יוניקס (Unix epoch) שבו מתחיל חלון השידור החי. -
Window.getCurrentUnixTimeMsהוא הזמן מאז ראשית זמן יוניקס של הזמן הנוכחי בזמן אמת. יכול להיות שהערך הזה יתוקן על ידי הפרש ידוע בשעון בין השרת לבין הלקוח. -
Window.getDefaultPositionMsהוא המיקום בחלון השידור החי שבו הנגן יתחיל את ההפעלה כברירת מחדל.
-
חיפוש בשידורים חיים
אפשר להשתמש בלחצן Player.seekTo כדי לעבור לכל נקודה בחלון השידור החי. המיקום שצוין בפעולת הדילוג
הוא יחסי לתחילת חלון השידור החי. לדוגמה, אם תלחצו על seekTo(0), תועברו לתחילת חלון השידור החי. הנגן ינסה לשמור על אותו היסט של שידור חי כמו המיקום שאליו בוצע החיפוש אחרי החיפוש.
לחלון השידור החי יש גם מיקום ברירת מחדל שבו ההפעלה אמורה להתחיל. המיקום הזה הוא בדרך כלל איפשהו קרוב לקצה החי. אפשר להגיע למיקום ברירת המחדל באמצעות הקריאה Player.seekToDefaultPosition.
ממשק משתמש להפעלה בשידור חי
רכיבי ברירת המחדל של ממשק המשתמש של ExoPlayer מציגים את משך הזמן של חלון השידור החי ואת מיקום ההפעלה הנוכחי בתוכו. כלומר, בכל פעם שחלון השידור החי מתעדכן, נראה שהמיקום קופץ אחורה. אם אתם צריכים התנהגות שונה, למשל הצגת זמן יוניקס או ההיסט הנוכחי של השידור החי, אתם יכולים ליצור מזלג 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 מצביע על כך שההערכה זהירה יותר, ויכול להיות שיעבור זמן רב יותר עד שהיא תותאם לתנאי רשת משופרים. לעומת זאת, ערך נמוך יותר מצביע על כך שההערכה תותאם מהר יותר, אבל יש סיכון גבוה יותר להיתקל בטעינה מחדש של מאגר הנתונים הזמני.
BehindLiveWindowException ו-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 } }