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

החל מגרסה Android 8.0 (רמת API‏ 26), MediaPlayer כולל ממשקי API שתומכים בהפעלה של תוכן שמוגן באמצעות DRM. ממשקי ה-API של MediaPlayer DRM דומים לממשק ה-API ברמה נמוכה ש-MediaDrm מספק, אבל הם פועלים ברמה גבוהה יותר ולא חושפים את האובייקטים הבסיסיים של ה-extractor, ה-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().
    • אם יצרתם והרשמתם קריאה חוזרת מסוג OnDrmConfigHelper, היא תתבצע בזמן ההרצה של prepareDrm(). כך תוכלו לבצע הגדרה מותאמת אישית של מאפייני ה-DRM לפני פתיחת הסשן של ה-DRM. פונקציית ה-callback נקראת באופן סינכרוני בשרשור שבו התבצעה הקריאה ל-prepareDrm(). כדי לגשת למאפייני ה-DRM, צריך להפעיל את הפונקציות getDrmPropertyString() ו-setDrmPropertyString(). הימנעו מביצוע פעולות ממושכות.
    • אם המכשיר עדיין לא הוקצה, prepareDrm() ניגש גם לשרת ההקצאה כדי להקצות את המכשיר. התהליך עשוי להימשך זמן משתנה, בהתאם לקישוריות לרשת.
  3. כדי לקבל מערך בייט של בקשת מפתח אטום שאפשר לשלוח לשרת רישיונות, צריך לבצע קריאה ל-getKeyRequest().
  4. כדי להודיע למנוע ה-DRM על תגובת המפתח שהתקבלה משרת הרישיון, צריך לבצע קריאה ל-provideKeyResponse(). התוצאה תלויה בסוג הבקשה למפתח:
    • אם התשובה היא לבקשת מפתח אופליין, התוצאה היא מזהה של קבוצת מפתחות. אפשר להשתמש במזהה של קבוצת המפתחות עם restoreKeys() כדי לשחזר את המפתחות לסשן חדש.
    • אם התשובה היא לבקשת סטרימינג או פרסום, התוצאה היא null.

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

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

מגדירים OnDrmPreparedListener. prepareDrm() מבצע את ההקצאה (אם יש צורך) וההכנה ברקע. בסיום ההקצאה וההכנה, המערכת קוראת למאזין. אל תניחו הנחות לגבי רצף הקריאות או על השרשור שבו ה-listener פועל (אלא אם תירשמו את ה-listener עם שרשור של טיפול). המערכת יכולה להפעיל את המאזין לפני או אחרי שהערך של 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();
}

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

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

מידע נוסף

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

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