סשנים של מדיה מספקים דרך אוניברסלית לאינטראקציה עם נגן אודיו או וידאו. ב-Media3, נגן ברירת המחדל הוא המחלקה ExoPlayer
, שמטמיעה את הממשק Player
. חיבור של סשן המדיה לנגן מאפשר לאפליקציה לפרסם את הפעלת המדיה באופן חיצוני ולקבל פקודות הפעלה ממקורות חיצוניים.
הפקודות יכולות להגיע מלחצנים פיזיים, כמו לחצן ההפעלה באוזניות או בשלט רחוק של טלוויזיה. יכול להיות שהפקודות יגיעו גם מאפליקציות לקוח שיש להן אמצעי בקרה להפעלת מדיה, כמו פקודה להשהיה של Google Assistant. הפקודות האלה מועברות על ידי סשן המדיה לנגן של אפליקציית המדיה.
מתי כדאי לבחור סשן מדיה
כשמטמיעים את MediaSession
, המשתמשים יכולים לשלוט בהפעלה:
- באמצעות האוזניות שלהם. לרוב יש באוזניות לחצנים או אפשרויות מגע שמאפשרות למשתמש להפעיל או להשהות את המדיה, או לעבור לטראק הבא או הקודם.
- לדבר אל Google Assistant. דוגמה נפוצה היא לומר "OK Google, pause" כדי להשהות מדיה שמופעלת כרגע במכשיר.
- דרך שעון Wear OS. כך קל יותר לגשת לפקדי ההפעלה הנפוצים ביותר בזמן המשחק בטלפון.
- באמצעות אמצעי הבקרה למדיה. בסרגל הזה מוצגים אמצעי בקרה לכל סשן מדיה שפועל.
- בטלוויזיה. מאפשר פעולות באמצעות לחצני הפעלה פיזיים, שליטה בהפעלה בפלטפורמה וניהול צריכת חשמל (לדוגמה, אם הטלוויזיה, מקרן הקול או מקלט האודיו/וידאו כבויים או שהקלט הוחלף, ההפעלה צריכה להיפסק באפליקציה).
- באמצעות כפתורי המדיה של Android Auto. כך אפשר לשלוט בהפעלה בצורה בטוחה בזמן הנהיגה.
- וכל תהליך חיצוני אחר שצריך להשפיע על ההפעלה.
זה מצוין להרבה תרחישי שימוש. במיוחד, מומלץ מאוד להשתמש ב-MediaSession
במקרים הבאים:
- אתם צופים בסטרימינג של תוכן וידאו ארוך, כמו סרטים או טלוויזיה בשידור חי.
- אתם צופים בסטרימינג של תוכן אודיו ארוך, כמו פודקאסטים או פלייליסטים של מוזיקה.
- אתם מפתחים אפליקציה לטלוויזיה.
עם זאת, לא כל תרחישי השימוש מתאימים ל-MediaSession
. כדאי להשתמש רק ב-Player
במקרים הבאים:
- אתם מציגים תוכן קצר שלא דורש אמצעי בקרה חיצוניים או הפעלה ברקע.
- אין סרטון פעיל אחד, למשל משתמש גולל ברשימה וכמה סרטונים מוצגים על המסך בו-זמנית.
- אתם מפעילים סרטון מבוא או הסבר חד-פעמי, ואתם מצפים שהמשתמש יצפה בו באופן פעיל בלי שיהיה צורך ברכיבי בקרה חיצוניים להפעלה.
- התוכן שלכם רגיש מבחינת פרטיות ואתם לא רוצים שתהיה גישה לתהליכים חיצוניים למטא-נתונים של המדיה (לדוגמה, מצב פרטי בדפדפן).
אם תרחיש השימוש שלכם לא מתאים לאף אחת מהאפשרויות שצוינו למעלה, כדאי לשקול אם אתם מסכימים שההפעלה באפליקציה תימשך גם כשהמשתמש לא מקיים אינטראקציה פעילה עם התוכן. אם התשובה היא כן, כדאי לבחור באפשרות MediaSession
. אם התשובה היא לא, כדאי להשתמש ב-Player
במקום זאת.
יצירת סשן מדיה
סשן מדיה מתקיים לצד הנגן שהוא מנהל. אפשר ליצור סשן מדיה עם אובייקט Context
ואובייקט Player
. מומלץ ליצור ולהפעיל סשן מדיה כשצריך, למשל בשיטת מחזור החיים onStart()
או onResume()
של Activity
או Fragment
, או בשיטה onCreate()
של Service
שבבעלותו סשן המדיה והנגן המשויך.
כדי ליצור סשן מדיה, מאתחלים Player
ומספקים אותו ל-MediaSession.Builder
באופן הבא:
Kotlin
val player = ExoPlayer.Builder(context).build() val mediaSession = MediaSession.Builder(context, player).build()
Java
ExoPlayer player = new ExoPlayer.Builder(context).build(); MediaSession mediaSession = new MediaSession.Builder(context, player).build();
טיפול אוטומטי במצבים
הספרייה Media3 מעדכנת אוטומטית את סשן המדיה באמצעות מצב הנגן. לכן, לא צריך לטפל באופן ידני במיפוי מהנגן לסשן.
זה שונה מהפלטפורמה של סשן המדיה, שבה היה צריך ליצור ולתחזק PlaybackState
בנפרד מהנגן עצמו, למשל כדי לציין שגיאות.
מזהה סשן ייחודי
כברירת מחדל, MediaSession.Builder
יוצר סשן עם מחרוזת ריקה כמזהה הסשן. זה מספיק אם האפליקציה מתכוונת ליצור רק מופע אחד של סשן, וזה המקרה הנפוץ ביותר.
אם אפליקציה רוצה לנהל כמה מופעים של סשנים בו-זמנית, היא צריכה לוודא שמזהה הסשן של כל סשן הוא ייחודי. אפשר להגדיר את מזהה הסשן כשיוצרים את הסשן באמצעות MediaSession.Builder.setId(String id)
.
אם אתם רואים את השגיאה IllegalStateException
שגורמת לקריסת האפליקציה עם הודעת השגיאה IllegalStateException: Session ID must be unique. ID=
, סביר להניח שנוצר סשן באופן לא צפוי לפני שמופע שנוצר קודם עם אותו מזהה שוחרר. כדי למנוע דליפה של סשנים בגלל שגיאת תכנות, המערכת מזהה מקרים כאלה ושולחת התראה על ידי הפעלת חריגה.
מתן שליטה ללקוחות אחרים
סשן המדיה הוא המפתח לשליטה בהפעלה. היא מאפשרת לכם לנתב פקודות ממקורות חיצוניים לנגן שמבצע את הפעולה של הפעלת המדיה. המקורות האלה יכולים להיות כפתורים פיזיים, כמו כפתור ההפעלה באוזניות או בשלט רחוק של טלוויזיה, או פקודות עקיפות, כמו "השהיה" ל-Google Assistant. באופן דומה, יכול להיות שתרצו להעניק גישה למערכת Android כדי להקל על השליטה בהתראות ובמסך הנעילה, או לשעון Wear OS כדי שתוכלו לשלוט בהפעלה מלוח השעון. לקוחות חיצוניים יכולים להשתמש באמצעי בקרה של מדיה כדי להנפיק פקודות הפעלה לאפליקציית המדיה. הפקודות האלה מתקבלות על ידי סשן המדיה, ובסופו של דבר מועברות לנגן המדיה.

כשבקר עומד להתחבר להפעלת המדיה, מתבצעת קריאה לשיטה
onConnect()
. אפשר להשתמש בControllerInfo
שסופק כדי להחליט אם לאשר או לדחות את הבקשה. אפשר לראות דוגמה לאישור בקשת חיבור בקטע הצהרה על פקודות מותאמות אישית.
אחרי החיבור, הבקר יכול לשלוח פקודות הפעלה לסשן. לאחר מכן, ההפעלה מעבירה את הפקודות האלה לנגן. הפעלת פקודות ופקודות של פלייליסט שמוגדרות בממשק Player
מטופלות באופן אוטומטי על ידי הסשן.
שיטות אחרות של קריאה חוזרת מאפשרות לכם לטפל, למשל, בבקשות לפקודות מותאמות אישית ובשינוי הפלייליסט. גם הקריאות החוזרות האלה כוללות אובייקט ControllerInfo
, כך שאפשר לשנות את אופן התגובה לכל בקשה על בסיס כל בקר.
שינוי הפלייליסט
אפשר לשנות ישירות את הפלייליסט של הנגן באמצעות סשן מדיה, כמו שמוסבר במדריך ExoPlayer לפלייליסטים.
לבעלי הרשאת ניהול יש גם אפשרות לשנות את הפלייליסט אם אחת מההרשאות COMMAND_SET_MEDIA_ITEM
או COMMAND_CHANGE_MEDIA_ITEMS
זמינה להם.
כשמוסיפים פריטים חדשים לפלייליסט, בדרך כלל נדרשים MediaItem
מופעים עם URI מוגדר כדי שהפריטים יוכלו לפעול. כברירת מחדל, פריטים חדשים שנוספים מועברים אוטומטית לשיטות של נגן כמו player.addMediaItem
אם מוגדר להם URI.
אם רוצים להתאים אישית את המופעים של MediaItem
שנוספו לנגן, אפשר לבטל את ההגדרה של onAddMediaItems()
.
השלב הזה נדרש כשרוצים לתמוך בבקשות של בקרי מדיה ללא URI מוגדר. במקום זאת, בדרך כלל MediaItem
כולל שדה אחד או יותר מהשדות הבאים שמוגדרים לתיאור המדיה המבוקשת:
-
MediaItem.id
: מזהה כללי שמציין את המדיה. -
MediaItem.RequestMetadata.mediaUri
: URI של בקשה שעשוי להשתמש בסכימה מותאמת אישית, ולא בהכרח ניתן להפעלה ישירה על ידי הנגן. -
MediaItem.RequestMetadata.searchQuery
: שאילתת חיפוש טקסטואלית, למשל מ-Google Assistant. -
MediaItem.MediaMetadata
: מטא-נתונים מובְנים כמו 'שם' או 'אומן'.
כדי לקבל אפשרויות נוספות להתאמה אישית של פלייליסטים חדשים לגמרי, אפשר גם להגדיר onSetMediaItems()
, שמאפשר להגדיר את פריט ההתחלה והמיקום בפלייליסט. לדוגמה, אפשר להרחיב פריט יחיד שביקשתם לפלייליסט שלם, ולהנחות את נגן המוזיקה להתחיל מהאינדקס של הפריט המקורי שביקשתם. דוגמה להטמעה של onSetMediaItems()
עם התכונה הזו מופיעה באפליקציית ההדגמה של הסשן.
ניהול ההעדפות של כפתור המדיה
כל אמצעי בקרה, למשל ממשק המשתמש של המערכת, Android Auto או Wear OS, יכול לקבל החלטות משלו לגבי הלחצנים שיוצגו למשתמש. כדי לציין אילו אמצעי בקרה להפעלה רוצים להציג למשתמש, אפשר להגדיר העדפות של לחצני מדיה ב-MediaSession
. ההעדפות האלה מורכבות מרשימה מסודרת של מקרים של CommandButton
, שכל אחד מהם מגדיר העדפה ללחצן בממשק המשתמש.
הגדרת כפתורי פקודות
מופעים של CommandButton
משמשים להגדרת העדפות של לחצני מדיה. כל לחצן מגדיר שלושה היבטים של רכיב ממשק המשתמש הרצוי:
- הסמל, שמגדיר את המראה החזותי. כשיוצרים
CommandButton.Builder
, צריך להגדיר את הסמל לאחת מהקבועים המוגדרים מראש. שימו לב שזה לא משאב Bitmap או תמונה בפועל. קבוע גנרי עוזר לבקרי משאבים לבחור משאב מתאים כדי ליצור מראה ותחושה עקביים בממשק המשתמש שלהם. אם אף אחת מהקבועים של הסמלים המוגדרים מראש לא מתאימה לתרחיש השימוש שלכם, אתם יכולים להשתמש ב-setCustomIconResId
. - הפקודה Command, שמגדירה את הפעולה שמופעלת כשהמשתמש יוצר אינטראקציה עם הלחצן. אפשר להשתמש ב-
setPlayerCommand
בשבילPlayer.Command
, או ב-setSessionCommand
בשבילSessionCommand
מוגדר מראש או מותאם אישית. - העמודה Slot, שבה מגדירים את המיקום של הכפתור בממשק המשתמש של בקר המשחק. השדה הזה הוא אופציונלי והוא מוגדר באופן אוטומטי על סמך הסמל והפקודה. לדוגמה, אפשר לציין שכפתור יוצג באזור הניווט 'קדימה' בממשק המשתמש במקום באזור ברירת המחדל 'overflow'.
Kotlin
val button = CommandButton.Builder(CommandButton.ICON_SKIP_FORWARD_15) .setSessionCommand(SessionCommand(CUSTOM_ACTION_ID, Bundle.EMPTY)) .setSlots(CommandButton.SLOT_FORWARD) .build()
Java
CommandButton button = new CommandButton.Builder(CommandButton.ICON_SKIP_FORWARD_15) .setSessionCommand(new SessionCommand(CUSTOM_ACTION_ID, Bundle.EMPTY)) .setSlots(CommandButton.SLOT_FORWARD) .build();
כשמערכת Android קובעת את ההעדפות של לחצני המדיה, היא משתמשת באלגוריתם הבא:
- לכל
CommandButton
בהעדפות של לחצן המדיה, מציבים את הלחצן במשבצת הראשונה שזמינה ומותרת. - אם אחד מהמיקומים המרכזיים, הקדמיים או האחוריים לא מאוכלס בלחצן, מוסיפים לחצני ברירת מחדל למיקום הזה.
אפשר להשתמש ב-CommandButton.DisplayConstraints
כדי ליצור תצוגה מקדימה של האופן שבו יוחלט על העדפות לחצני המדיה בהתאם למגבלות התצוגה של ממשק המשתמש.
הגדרת העדפות לכפתור המדיה
הדרך הקלה ביותר להגדיר את ההעדפות של לחצן המדיה היא להגדיר את הרשימה כשיוצרים את MediaSession
. לחלופין, אפשר לבטל את ההגדרה של MediaSession.Callback.onConnect
כדי להתאים אישית את ההעדפות של לחצן המדיה לכל בקר מחובר.
Kotlin
val mediaSession = MediaSession.Builder(context, player) .setMediaButtonPreferences(ImmutableList.of(likeButton, favoriteButton)) .build()
Java
MediaSession mediaSession = new MediaSession.Builder(context, player) .setMediaButtonPreferences(ImmutableList.of(likeButton, favoriteButton)) .build();
עדכון ההעדפות של כפתורי המדיה אחרי אינטראקציה של משתמש
אחרי טיפול באינטראקציה עם הנגן, יכול להיות שתרצו לעדכן את הלחצנים שמוצגים בממשק המשתמש של בקר המשחקים. דוגמה טיפוסית היא מתג שמשנה את הסמל והפעולה שלו אחרי הפעלת הפעולה שמשויכת לכפתור הזה. כדי לעדכן את ההעדפות של לחצן המדיה, אפשר להשתמש ב-MediaSession.setMediaButtonPreferences
כדי לעדכן את ההעדפות של כל אמצעי הבקרה או של אמצעי בקרה ספציפי:
Kotlin
// Handle "favoritesButton" action, replace by opposite button mediaSession.setMediaButtonPreferences( ImmutableList.of(likeButton, removeFromFavoritesButton))
Java
// Handle "favoritesButton" action, replace by opposite button mediaSession.setMediaButtonPreferences( ImmutableList.of(likeButton, removeFromFavoritesButton));
הוספת פקודות מותאמות אישית והתאמה אישית של התנהגות ברירת המחדל
אפשר להרחיב את הפקודות הזמינות בנגן באמצעות פקודות מותאמות אישית. אפשר גם ליירט פקודות נכנסות של הנגן ולחצני מדיה כדי לשנות את התנהגות ברירת המחדל.
הצהרה על פקודות מותאמות אישית וטיפול בהן
אפליקציות מדיה יכולות להגדיר פקודות מותאמות אישית שאפשר להשתמש בהן, למשל, בהעדפות של לחצני מדיה. לדוגמה, אפשר להוסיף לחצנים שיאפשרו למשתמש לשמור פריט מדיה ברשימת פריטים מועדפים. ה-MediaController
שולח פקודות מותאמות אישית וה-MediaSession.Callback
מקבל אותן.
כדי להגדיר פקודות מותאמות אישית, צריך לבטל את ברירת המחדל של MediaSession.Callback.onConnect()
כדי להגדיר את הפקודות המותאמות אישית הזמינות לכל בקר מחובר.
Kotlin
private class CustomMediaSessionCallback: MediaSession.Callback { // Configure commands available to the controller in onConnect() override fun onConnect( session: MediaSession, controller: MediaSession.ControllerInfo ): MediaSession.ConnectionResult { val sessionCommands = ConnectionResult.DEFAULT_SESSION_COMMANDS.buildUpon() .add(SessionCommand(SAVE_TO_FAVORITES, Bundle.EMPTY)) .build() return AcceptedResultBuilder(session) .setAvailableSessionCommands(sessionCommands) .build() } }
Java
class CustomMediaSessionCallback implements MediaSession.Callback { // Configure commands available to the controller in onConnect() @Override public ConnectionResult onConnect( MediaSession session, ControllerInfo controller) { SessionCommands sessionCommands = ConnectionResult.DEFAULT_SESSION_COMMANDS.buildUpon() .add(new SessionCommand(SAVE_TO_FAVORITES, new Bundle())) .build(); return new AcceptedResultBuilder(session) .setAvailableSessionCommands(sessionCommands) .build(); } }
כדי לקבל בקשות לפקודות מותאמות אישית מ-MediaController
, צריך לבטל את השיטה onCustomCommand()
ב-Callback
.
Kotlin
private class CustomMediaSessionCallback: MediaSession.Callback { ... override fun onCustomCommand( session: MediaSession, controller: MediaSession.ControllerInfo, customCommand: SessionCommand, args: Bundle ): ListenableFuture<SessionResult> { if (customCommand.customAction == SAVE_TO_FAVORITES) { // Do custom logic here saveToFavorites(session.player.currentMediaItem) return Futures.immediateFuture( SessionResult(SessionResult.RESULT_SUCCESS) ) } ... } }
Java
class CustomMediaSessionCallback implements MediaSession.Callback { ... @Override public ListenableFuture<SessionResult> onCustomCommand( MediaSession session, ControllerInfo controller, SessionCommand customCommand, Bundle args ) { if(customCommand.customAction.equals(SAVE_TO_FAVORITES)) { // Do custom logic here saveToFavorites(session.getPlayer().getCurrentMediaItem()); return Futures.immediateFuture( new SessionResult(SessionResult.RESULT_SUCCESS) ); } ... } }
כדי לעקוב אחרי הבקשה של בקר המדיה, אפשר להשתמש במאפיין packageName
של אובייקט MediaSession.ControllerInfo
שמועבר לשיטות Callback
. כך תוכלו להתאים את ההתנהגות של האפליקציה בתגובה לפקודה מסוימת, אם היא מגיעה מהמערכת, מהאפליקציה שלכם או מאפליקציות לקוח אחרות.
התאמה אישית של פקודות ברירת המחדל של הנגן
כל פקודות ברירת המחדל וניהול המצב מוקצים ל-Player
שנמצא ב-MediaSession
. כדי להתאים אישית את ההתנהגות של פקודה שמוגדרת בממשק Player
, כמו play()
או seekToNext()
, עוטפים את Player
ב-ForwardingSimpleBasePlayer
לפני שמעבירים אותה אל MediaSession
:
Kotlin
val player = (logic to build a Player instance) val forwardingPlayer = object : ForwardingSimpleBasePlayer(player) { // Customizations } val mediaSession = MediaSession.Builder(context, forwardingPlayer).build()
Java
ExoPlayer player = (logic to build a Player instance) ForwardingSimpleBasePlayer forwardingPlayer = new ForwardingSimpleBasePlayer(player) { // Customizations }; MediaSession mediaSession = new MediaSession.Builder(context, forwardingPlayer).build();
מידע נוסף על ForwardingSimpleBasePlayer
אפשר למצוא במדריך ExoPlayer בנושא התאמה אישית.
זיהוי הבקר ששולח בקשה לפקודה של נגן
כששיחה לשיטת Player
מגיעה מ-MediaController
, אפשר לזהות את מקור השיחה באמצעות MediaSession.controllerForCurrentRequest
ולקבל את ControllerInfo
של הבקשה הנוכחית:
Kotlin
class CallerAwarePlayer(player: Player) : ForwardingSimpleBasePlayer(player) { override fun handleSeek( mediaItemIndex: Int, positionMs: Long, seekCommand: Int, ): ListenableFuture<*> { Log.d( "caller", "seek operation from package ${session.controllerForCurrentRequest?.packageName}", ) return super.handleSeek(mediaItemIndex, positionMs, seekCommand) } }
Java
public class CallerAwarePlayer extends ForwardingSimpleBasePlayer { public CallerAwarePlayer(Player player) { super(player); } @Override protected ListenableFuture<?> handleSeek( int mediaItemIndex, long positionMs, int seekCommand) { Log.d( "caller", "seek operation from package: " + session.getControllerForCurrentRequest().getPackageName()); return super.handleSeek(mediaItemIndex, positionMs, seekCommand); } }
התאמה אישית של הטיפול בכפתורי מדיה
לחצני מדיה הם לחצני חומרה שנמצאים במכשירי Android ובמכשירים היקפיים אחרים, כמו לחצן ההפעלה/ההשהיה באוזניות Bluetooth. Media3 מטפל באירועים של לחצני מדיה כשהם מגיעים לסשן, ומפעיל את שיטת Player
המתאימה בנגן הסשן.
מומלץ לטפל בכל האירועים של לחצני המדיה הנכנסים בשיטה המתאימה Player
. לתרחישי שימוש מתקדמים יותר, אפשר ליירט את האירועים של לחצן המדיה ב-MediaSession.Callback.onMediaButtonEvent(Intent)
.
טיפול בשגיאות ודיווח עליהן
יש שני סוגים של שגיאות שסשן פולט ומדווח לבקרי הסשן. שגיאות קריטיות מצביעות על כשל טכני בהפעלה של נגן הסשן שגורם להפרעה בהפעלה. שגיאות קריטיות מדווחות לבקר באופן אוטומטי כשהן מתרחשות. שגיאות לא קריטיות הן שגיאות לא טכניות או שגיאות שקשורות למדיניות שלא מפריעות להשמעה ונשלחות לבקרי המערכת על ידי האפליקציה באופן ידני.
שגיאות קריטיות בהפעלה
הנגן מדווח על שגיאת הפעלה קריטית לסשן, ואז מדווח על כך לבקרי המדיה כדי להפעיל את Player.Listener.onPlayerError(PlaybackException)
ואת Player.Listener.onPlayerErrorChanged(@Nullable PlaybackException)
.
במקרה כזה, מצב ההפעלה משתנה ל-STATE_IDLE
והפונקציה MediaController.getPlaybackError()
מחזירה את הערך PlaybackException
שגרם למעבר. בקר יכול לבדוק את PlayerException.errorCode
כדי לקבל מידע על הסיבה לשגיאה.
לצורך פעולה הדדית, שגיאה קריטית משוכפלת לסשן הפלטפורמה על ידי שינוי הסטטוס שלה ל-STATE_ERROR
והגדרת קוד השגיאה וההודעה בהתאם ל-PlaybackException
.
התאמה אישית של שגיאות קריטיות
כדי לספק למשתמש מידע מותאם לשפה שלו ומשמעותי, אפשר להתאים אישית את קוד השגיאה, הודעת השגיאה ותוספות השגיאה של שגיאת הפעלה קריטית באמצעות ForwardingPlayer
כשיוצרים את הסשן:
Kotlin
val forwardingPlayer = ErrorForwardingPlayer(player) val session = MediaSession.Builder(context, forwardingPlayer).build()
Java
Player forwardingPlayer = new ErrorForwardingPlayer(player); MediaSession session = new MediaSession.Builder(context, forwardingPlayer).build();
הנגן להעברה יכול להשתמש ב-ForwardingSimpleBasePlayer
כדי ליירט את השגיאה ולהתאים אישית את קוד השגיאה, ההודעה או התוספים. באותו אופן, אפשר גם ליצור שגיאות חדשות שלא קיימות בנגן המקורי:
Kotlin
class ErrorForwardingPlayer (private val context: Context, player: Player) : ForwardingSimpleBasePlayer(player) { override fun getState(): State { var state = super.getState() if (state.playerError != null) { state = state.buildUpon() .setPlayerError(customizePlaybackException(state.playerError!!)) .build() } return state } fun customizePlaybackException(error: PlaybackException): PlaybackException { val buttonLabel: String val errorMessage: String when (error.errorCode) { PlaybackException.ERROR_CODE_BEHIND_LIVE_WINDOW -> { buttonLabel = context.getString(R.string.err_button_label_restart_stream) errorMessage = context.getString(R.string.err_msg_behind_live_window) } else -> { buttonLabel = context.getString(R.string.err_button_label_ok) errorMessage = context.getString(R.string.err_message_default) } } val extras = Bundle() extras.putString("button_label", buttonLabel) return PlaybackException(errorMessage, error.cause, error.errorCode, extras) } }
Java
class ErrorForwardingPlayer extends ForwardingSimpleBasePlayer { private final Context context; public ErrorForwardingPlayer(Context context, Player player) { super(player); this.context = context; } @Override protected State getState() { State state = super.getState(); if (state.playerError != null) { state = state.buildUpon() .setPlayerError(customizePlaybackException(state.playerError)) .build(); } return state; } private PlaybackException customizePlaybackException(PlaybackException error) { String buttonLabel; String errorMessage; switch (error.errorCode) { case PlaybackException.ERROR_CODE_BEHIND_LIVE_WINDOW: buttonLabel = context.getString(R.string.err_button_label_restart_stream); errorMessage = context.getString(R.string.err_msg_behind_live_window); break; default: buttonLabel = context.getString(R.string.err_button_label_ok); errorMessage = context.getString(R.string.err_message_default); break; } Bundle extras = new Bundle(); extras.putString("button_label", buttonLabel); return new PlaybackException(errorMessage, error.getCause(), error.errorCode, extras); } }
שגיאות לא קריטיות
אפליקציה יכולה לשלוח שגיאות לא קריטיות שלא נובעות מחריגה טכנית לכל הבקרים או לבקר ספציפי:
Kotlin
val sessionError = SessionError( SessionError.ERROR_SESSION_AUTHENTICATION_EXPIRED, context.getString(R.string.error_message_authentication_expired), ) // Option 1: Sending a nonfatal error to all controllers. mediaSession.sendError(sessionError) // Option 2: Sending a nonfatal error to the media notification controller only // to set the error code and error message in the playback state of the platform // media session. mediaSession.mediaNotificationControllerInfo?.let { mediaSession.sendError(it, sessionError) }
Java
SessionError sessionError = new SessionError( SessionError.ERROR_SESSION_AUTHENTICATION_EXPIRED, context.getString(R.string.error_message_authentication_expired)); // Option 1: Sending a nonfatal error to all controllers. mediaSession.sendError(sessionError); // Option 2: Sending a nonfatal error to the media notification controller only // to set the error code and error message in the playback state of the platform // media session. ControllerInfo mediaNotificationControllerInfo = mediaSession.getMediaNotificationControllerInfo(); if (mediaNotificationControllerInfo != null) { mediaSession.sendError(mediaNotificationControllerInfo, sessionError); }
כששגיאה לא קריטית נשלחת לבקר של התראות המדיה, קוד השגיאה והודעת השגיאה משוכפלים לסשן המדיה של הפלטפורמה, אבל הערך של PlaybackState.state
לא משתנה ל-STATE_ERROR
.
קבלת שגיאות לא קריטיות
אפליקציה MediaController
מקבלת שגיאה לא קריטית על ידי הטמעה של MediaController.Listener.onError
:
Kotlin
val future = MediaController.Builder(context, sessionToken) .setListener(object : MediaController.Listener { override fun onError(controller: MediaController, sessionError: SessionError) { // Handle nonfatal error. } }) .buildAsync()
Java
MediaController.Builder future = new MediaController.Builder(context, sessionToken) .setListener( new MediaController.Listener() { @Override public void onError(MediaController controller, SessionError sessionError) { // Handle nonfatal error. } });