ממשק הנגן

נגן הוא הרכיב באפליקציה שמאפשר הפעלה של פריטי מדיה. ממשק Media3 Player מגדיר תוכנית לפונקציונליות שמטופלת בדרך כלל על ידי נגן. למשל:

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

‫Media3 מספק גם הטמעה של הממשק Player, שנקרא ExoPlayer.

ממשק משותף בין רכיבים

כמה רכיבים ב-Media3 מטמיעים את ממשק Player, למשל:

רכיב תיאור והערות לגבי ההתנהגות
ExoPlayer ממשק API של נגן מדיה וההטמעה שמוגדרת כברירת מחדל של הממשק Player.
MediaController אינטראקציה עם MediaSession כדי לשלוח פקודות הפעלה. אם הרכיבים Player ו-MediaSession נמצאים ב-Service נפרד מ-Activity או מ-Fragment שבו נמצא ממשק המשתמש של הנגן, אפשר להקצות את MediaController כנגן לרכיב ממשק המשתמש כמו PlayerView או Player Composable. הקריאות לשיטות של הפלייליסט וההפעלה נשלחות אל Player דרך MediaSession.
MediaBrowser בנוסף לפונקציונליות שמוצעת על ידי MediaController, מתקיימת אינטראקציה עם MediaLibrarySession כדי לעיין בתוכן מדיה זמין.
SimpleBasePlayer הטמעה של Player שמצמצמת את מספר השיטות להטמעה למינימום. התג הזה שימושי כשמשתמשים בנגן מותאם אישית שרוצים לקשר ל-MediaSession.
ForwardingSimpleBasePlayer מחלקת משנה SimpleBasePlayer שנועדה להעביר פעולות הפעלה קדימה אל Player אחרת, תוך שמירה על אותן התאמות אישיות עקביות כמו SimpleBasePlayer. אפשר להשתמש במחלקה הזו כדי להשבית או לשנות פעולות הפעלה ספציפיות.
RemoteCastPlayer הטמעה של Player לשליטה בהפעלה באפליקציית מקלט Cast מרחוק.
CastPlayer הטמעה של Player לשליטה בהפעלה של Cast מקומית ומרחוק.

למרות ש-MediaSession לא מיישם את הממשק Player, הוא דורש Player כשיוצרים אותו. המטרה שלו היא לספק גישה ל-Player מתהליכים או משרשורים אחרים.

ארכיטקטורה של הפעלת מדיה ב-Media3

אם יש לכם גישה ל-Player, אתם צריכים להפעיל את השיטות שלו ישירות כדי להנפיק פקודות הפעלה. אתם יכולים לפרסם את ההפעלה ולהעניק למקורות חיצוניים שליטה בהפעלה על ידי הטמעה של MediaSession. המקורות החיצוניים האלה מטמיעים MediaController, שמקל על החיבור להפעלת מדיה ועל שליחת בקשות להפעלת פקודות.

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

תרשים שמראה איך רכיבי ההפעלה של Media3 משתלבים בארכיטקטורה של אפליקציית מדיה.
איור 1: לממשק Player יש תפקיד מרכזי בארכיטקטורה של Media3.

מצב השחקן

המצב של נגן מדיה שמטמיע את הממשק Player מורכב בעיקר מ-4 קטגוריות של מידע:

  1. מצב ההפעלה
  2. פלייליסט של פריטי מדיה
  3. מאפייני הפעלה/השהיה, כמו:
    • playWhenReady: ציון של האם המשתמש רוצה שהמדיה תופעל כשאפשר או שהיא תישאר בהשהיה
    • הסיבה להשבתת ההפעלה: ציון הסיבה להשבתת ההפעלה, אם רלוונטי, גם אם הערך של playWhenReady הוא true
    • isPlaying: אינדיקציה אם הנגן פועל כרגע, שתהיה true רק אם מצב ההפעלה הוא STATE_READY, הערך של playWhenReady הוא true וההפעלה לא מושבתת
  4. מיקום ההפעלה, כולל:

בנוסף, הממשק של Player מאפשר גישה לרצועות הזמינות, למטא נתונים של המדיה, למהירות ההפעלה, לעוצמת הקול ולמאפיינים נוספים של ההפעלה.

האזנה לשינויים

משתמשים ב-Player.Listener כדי לחפש שינויים ב-Player. במאמר Player events (אירועים של נגן) בתיעוד של ExoPlayer מוסבר איך ליצור listener ולהשתמש בו.

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

Kotlin

fun checkPlaybackPosition(delayMs: Long): Boolean =
  handler.postDelayed(
    {
      val currentPosition = player.currentPosition
      // Update UI based on currentPosition
      checkPlaybackPosition(delayMs)
    },
    delayMs,
  )

Java

boolean checkPlaybackPosition(long delayMs) {
  return handler.postDelayed(
      () -> {
        long currentPosition = player.getCurrentPosition();
        // Update UI based on currentPosition
        checkPlaybackPosition(delayMs);
      },
      delayMs);
}

שליטה בהפעלה

בממשק Player יש הרבה דרכים לשנות את המצב ולשלוט בהפעלה:

הטמעות מותאמות אישית של Player

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

מתחילים בהחלפת השיטה getState(). ה-method הזו צריכה לאכלס את מצב השחקן הנוכחי כשהיא מופעלת, כולל:

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

Kotlin

class CustomPlayer(looper: Looper) : SimpleBasePlayer(looper) {
  override fun getState(): State {
    return State.Builder()
      .setAvailableCommands(Commands.EMPTY) // Set which playback commands the player can handle
      // Configure additional playback properties
      .setPlayWhenReady(true, PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST)
      .setCurrentMediaItemIndex(0)
      .setContentPositionMs(0)
      .build()
  }
}

Java

private static final class CustomPlayer extends SimpleBasePlayer {
  public CustomPlayer(Looper looper) {
    super(looper);
  }

  @Override
  protected State getState() {
    return new State.Builder()
        .setAvailableCommands(Commands.EMPTY) // Set which playback commands the player can handle
        // Configure additional playback properties
        .setPlayWhenReady(true, PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST)
        .setCurrentMediaItemIndex(0)
        .setContentPositionMs(0)
        .build();
  }
}

SimpleBasePlayer יבטיח ש-State נוצר עם שילוב תקף של ערכי מצב. הוא גם יטפל במאזינים ויעדכן אותם לגבי שינויים במצב. אם צריך להפעיל עדכון של מצב באופן ידני, צריך להתקשר אל invalidateState().

בנוסף ל-method‏ getState(), צריך להטמיע רק את ה-methods שמשמשים לפקודות שהנגן מצהיר שהן זמינות. מאתרים את שיטת הטיפול שאפשר לבטל שמתאימה לפונקציונליות שרוצים להטמיע. לדוגמה, אפשר לשנות את השיטה handleSeek() כדי לתמוך בפעולות כמו COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM ו-COMMAND_SEEK_TO_NEXT_MEDIA_ITEM.

שינוי הטמעות של Player

במקום ליצור Player בהתאמה אישית מלאה, אפשר להשתמש ב-ForwardingSimpleBasePlayer כדי לשנות את המצב וההתנהגות של Player קיים. פרטים נוספים זמינים במדריך בנושא דף ההתאמה האישית.