עבודה עם MediaPlayer ועם ניהול זכויות דיגיטלי (DRM)

החל מ-Android 8.0 (רמת API‏ 26), ‏ MediaPlayer כולל ממשקי API שתומכים בהפעלה של חומרים שמוגנים באמצעות DRM. ממשקי ה-API של MediaPlayer DRM דומים לממשק ה-API ברמה נמוכה שמוצע על ידי MediaDrm, אבל הם פועלים ברמה גבוהה יותר ולא חושפים את האובייקטים הבסיסיים של החילוץ, ה-DRM וההצפנה.

למרות ש-MediaPlayer DRM API לא מספק את הפונקציונליות המלאה של MediaDrm, הוא תומך בתרחישי השימוש הנפוצים ביותר. ההטמעה הנוכחית יכולה לטפל בסוגי התוכן הבאים:

  • קבצים מקומיים של מדיה שמוגנים על ידי Widevine
  • קבצים של מדיה מרוחקת או סטרימינג של מדיה שמוגנים על ידי Widevine

בקטע הקוד הבא אפשר לראות איך משתמשים בשיטות החדשות של DRM MediaPlayerבהטמעה סינכרונית.

כדי לנהל מדיה שנשלטת על ידי DRM, צריך לכלול את השיטות החדשות לצד התהליך הרגיל של קריאות MediaPlayer, כמו בדוגמה הזו:

Kotlin

mediaPlayer?.apply {
    setDataSource()
    setOnDrmConfigHelper() // optional, for custom configuration
    prepare()
    drmInfo?.also {
        prepareDrm()
        getKeyRequest()
        provideKeyResponse()
    }

    // MediaPlayer is now ready to use
    start()
    // ...play/pause/resume...
    stop()
    releaseDrm()
}

Java

setDataSource();
setOnDrmConfigHelper(); // optional, for custom configuration
prepare();
if (getDrmInfo() != null) {
  prepareDrm();
  getKeyRequest();
  provideKeyResponse();
}

// MediaPlayer is now ready to use
start();
// ...play/pause/resume...
stop();
releaseDrm();

מתחילים באתחול האובייקט MediaPlayer והגדרת המקור שלו באמצעות setDataSource(), כרגיל. לאחר מכן, כדי להשתמש ב-DRM, מבצעים את השלבים הבאים:

  1. אם רוצים שהאפליקציה תבצע הגדרה בהתאמה אישית, צריך להגדיר ממשק OnDrmConfigHelper ולצרף אותו לנגן באמצעות setOnDrmConfigHelper().
  2. קוראים לפונקציה prepare().
  3. קוראים לפונקציה getDrmInfo(). אם המקור מכיל תוכן עם DRM, הפונקציה מחזירה ערך MediaPlayer.DrmInfo שאינו null.

אם הסמל MediaPlayer.DrmInfo מופיע:

  1. בודקים את המפה של ה-UUID הזמינים ובוחרים אחד מהם.
  2. מכינים את הגדרת ה-DRM למקור הנוכחי על ידי קריאה ל-prepareDrm().
    • אם יצרתם ורשמתם קריאה חוזרת (callback) של OnDrmConfigHelper, היא מופעלת בזמן ש-prepareDrm() פועל. כך תוכלו לבצע הגדרה בהתאמה אישית של מאפייני ה-DRM לפני פתיחת סשן ה-DRM. הקריאה החוזרת מתבצעת באופן סינכרוני בשרשור שקרא ל-prepareDrm(). כדי לגשת למאפייני ה-DRM, קוראים לפונקציות getDrmPropertyString() ו-setDrmPropertyString(). מומלץ להימנע מביצוע פעולות ארוכות.
    • אם עדיין לא הוקצו הרשאות למכשיר, prepareDrm() גם ניגש לשרת הקצאת ההרשאות כדי להקצות הרשאות למכשיר. משך הזמן של הפעולה הזו משתנה בהתאם לחיבור לרשת.
  3. כדי לקבל מערך בייטים של בקשת מפתח אטום לשליחה לשרת רישיונות, קוראים ל-getKeyRequest().
  4. כדי לעדכן את מנוע ה-DRM לגבי תגובת המפתח שהתקבלה משרת הרישיונות, צריך להתקשר אל provideKeyResponse(). התוצאה משתנה בהתאם לסוג בקשת המפתח:
    • אם התשובה היא לבקשת מפתח אופליין, התוצאה היא מזהה של קבוצת מפתחות. אפשר להשתמש במזהה של קבוצת המפתחות עם restoreKeys() כדי לשחזר את המפתחות לסשן חדש.
    • אם התשובה היא לבקשה להפצה או להזרמה, התוצאה היא null.

הכנת DRM באופן אסינכרוני

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

מגדירים OnDrmPreparedListener. ‫prepareDrm() מבצע את ההקצאה (אם צריך) ואת ההכנה ברקע. כשההקצאה וההכנה מסתיימות, המערכת מתקשרת למאזין. אל תניחו הנחות לגבי רצף הקריאות או ה-thread שבו ה-listener פועל (אלא אם רשמתם את ה-listener עם handler thread). המערכת יכולה להתקשר למאזין לפני או אחרי שהפונקציה prepareDrm() מחזירה ערך.

הגדרה של DRM באופן אסינכרוני

אפשר להפעיל את ה-DRM באופן אסינכרוני על ידי יצירה ורישום של MediaPlayer.OnDrmInfoListener להכנת ה-DRM ושל MediaPlayer.OnDrmPreparedListener להפעלת הנגן. הם פועלים בשילוב עם prepareAsync(), כמו בדוגמה הזו:

Kotlin

setOnPreparedListener()
setOnDrmInfoListener()
setDataSource()
prepareAsync()
// ...

// If the data source content is protected you receive a call to the onDrmInfo() callback.
override fun onDrmInfo(mediaPlayer: MediaPlayer, drmInfo: MediaPlayer.DrmInfo) {
    mediaPlayer.apply {
        prepareDrm()
        getKeyRequest()
        provideKeyResponse()
    }
}

// When prepareAsync() finishes, you receive a call to the onPrepared() callback.
// If there is a DRM, onDrmInfo() sets it up before executing this callback,
// so you can start the player.
override fun onPrepared(mediaPlayer: MediaPlayer) {
    mediaPlayer.start()
}

Java

setOnPreparedListener();
setOnDrmInfoListener();
setDataSource();
prepareAsync();
// ...

// If the data source content is protected you receive a call to the onDrmInfo() callback.
onDrmInfo() {
  prepareDrm();
  getKeyRequest();
  provideKeyResponse();
}

// When prepareAsync() finishes, you receive a call to the onPrepared() callback.
// If there is a DRM, onDrmInfo() sets it up before executing this callback,
// so you can start the player.
onPrepared() {

start();
}

טיפול במדיה מוצפנת

החל מ-Android 8.0 (רמת API‏ 26),‏ MediaPlayer יכול גם לפענח Common Encryption Scheme‏ (CENC) ומדיה מוצפנת ברמת הדגימה של HLS‏ (METHOD=SAMPLE-AES) עבור סוגי הזרם הבסיסיים H.264 ו-AAC. בעבר הייתה תמיכה במדיה מוצפנת של פלח מלא (METHOD=AES-128).

מידע נוסף

‫Jetpack Media3 הוא הפתרון המומלץ להפעלת מדיה באפליקציה. מידע נוסף

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