מקבצים של רשתות

בדרך כלל משתמשים ב-ExoPlayer כדי להעביר מדיה בסטרימינג דרך האינטרנט. הוא תומך בכמה מקבצי רשת (network stack) כדי לשלוח את הבקשות לאחזור מהרשת. לבחירה של מקבץ הרשת יכולה להיות השפעה משמעותית על ביצועי הסטרימינג.

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

הגדרת ExoPlayer לשימוש במקבץ רשת ספציפי

ExoPlayer טוען נתונים דרך רכיבי DataSource, שאותם הוא מקבל ממופעי DataSource.Factory שמוזרקים מקוד האפליקציה.

אם האפליקציה צריכה להפעיל רק תוכן מסוג http(s), כדי לבחור מקבץ רשת צריך רק לעדכן את כל המופעים של DataSource.Factory שהאפליקציה מוסיפה, כך שיהיו מופעים של HttpDataSource.Factory שתואמים למקבץ הרשת שבו רוצים להשתמש. אם האפליקציה צריכה להפעיל גם תוכן שהוא לא http(s), כמו קבצים מקומיים, צריך להשתמש ב-DefaultDataSource.Factory:

Kotlin

DefaultDataSource.Factory(
  context,
  /* baseDataSourceFactory= */ PreferredHttpDataSource.Factory(context),
)

Java

new DefaultDataSource.Factory(
    context, /* baseDataSourceFactory= */ new PreferredHttpDataSource.Factory(context));

בדוגמה הזו, PreferredHttpDataSource.Factory הוא המפעל שתואם למקבץ הרשת המועדף. השכבה DefaultDataSource.Factory מוסיפה תמיכה במקורות שאינם http(s), כמו קבצים מקומיים.

בדוגמה הבאה מוסבר איך ליצור ExoPlayer שישתמש במקבץ הרשת (network stack) של Cronet וגם יתמוך בהפעלה של תוכן שאינו מסוג http(s).

Kotlin

// Given a CronetEngine and Executor, build a CronetDataSource.Factory.
val cronetDataSourceFactory = CronetDataSource.Factory(cronetEngine, executor)

// Wrap the CronetDataSource.Factory in a DefaultDataSource.Factory, which adds
// in support for requesting data from other sources (such as files, resources,
// etc).
val dataSourceFactory =
  DefaultDataSource.Factory(context, /* baseDataSourceFactory= */ cronetDataSourceFactory)

// Inject the DefaultDataSource.Factory when creating the player.
val player =
  ExoPlayer.Builder(context)
    .setMediaSourceFactory(
      DefaultMediaSourceFactory(context).setDataSourceFactory(dataSourceFactory)
    )
    .build()

Java

// Given a CronetEngine and Executor, build a CronetDataSource.Factory.
CronetDataSource.Factory cronetDataSourceFactory =
    new CronetDataSource.Factory(cronetEngine, executor);

// Wrap the CronetDataSource.Factory in a DefaultDataSource.Factory, which adds
// in support for requesting data from other sources (such as files, resources,
// etc).
DefaultDataSource.Factory dataSourceFactory =
    new DefaultDataSource.Factory(
        context, /* baseDataSourceFactory= */ cronetDataSourceFactory);

// Inject the DefaultDataSource.Factory when creating the player.
ExoPlayer player =
    new ExoPlayer.Builder(context)
        .setMediaSourceFactory(
            new DefaultMediaSourceFactory(context).setDataSourceFactory(dataSourceFactory))
        .build();

מקבצי רשת (network stack) נתמכים

‫ExoPlayer מספק תמיכה ישירה ב-HttpEngine, ב-Cronet, ב-OkHttp ובמקבץ הרשת (network stack) המובנה שמוגדר כברירת מחדל ב-Android. אפשר גם להרחיב את ExoPlayer כדי לתמוך בכל מקבץ רשת אחר שפועל ב-Android.

HttpEngine

‫HttpEngine הוא מקבץ הרשת המומלץ כברירת מחדל ב-Android מ-API 34 (או S extensions 7). ברוב המקרים, הוא משתמש במקבץ הרשת (network stack) של Cronet באופן פנימי, ותומך בפרוטוקולים HTTP,‏ HTTP/2 ו-HTTP/3 דרך QUIC.

ExoPlayer תומך ב-HttpEngine באמצעות HttpEngineDataSource.Factory. אפשר להחדיר את המפעל הזה של מקור הנתונים כמו שמתואר בקטע הגדרת ExoPlayer לשימוש במקבץ רשת ספציפי.

Cronet

‫Cronet הוא מקבץ הרשת (network stack) של Chromium שזמין לאפליקציות ל-Android כספרייה. ‫Cronet משתמש בכמה טכנולוגיות שמפחיתות את זמן האחזור ומגדילות את הקיבולת של הבקשות לאחזור מהרשת שהאפליקציה צריכה כדי לפעול, כולל אלה שנוצרו על ידי ExoPlayer. הוא תומך באופן מובנה בפרוטוקולים HTTP,‏ HTTP/2 ו-HTTP/3 over QUIC. אפליקציות הסטרימינג הגדולות בעולם, כולל YouTube, משתמשות ב-Cronet.

ExoPlayer תומך ב-Cronet באמצעות ספריית Cronet. בREADME.md של הספרייה מוסבר איך להשתמש בה. שימו לב: ספריית Cronet יכולה להשתמש בשלוש הטמעות בסיסיות של Cronet:

  1. Google Play Services: מומלץ להשתמש בהטמעה הזו ברוב המקרים, ולחזור למקבץ הרשת המובנה של Android‏ (DefaultHttpDataSource) אם Google Play Services לא זמין.
  2. ‫Cronet Embedded: יכול להיות בחירה טובה אם אחוז גדול מהמשתמשים נמצאים בשווקים שבהם Google Play Services לא זמינה באופן נרחב, או אם רוצים לשלוט בגרסה המדויקת של הטמעת Cronet שבה משתמשים. החיסרון העיקרי של Cronet Embedded הוא שהיא מוסיפה כ-8MB לאפליקציה.
  3. Cronet Fallback: הטמעת ה-fallback של Cronet מטמיעה את ה-API של Cronet כמעטפת סביב מקבץ הרשת (network stack) המובנה של Android. לא כדאי להשתמש בו עם ExoPlayer, כי יעיל יותר להשתמש ישירות במקבץ הרשת (network stack) המובנה של Android (באמצעות DefaultHttpDataSource).

OkHttp

‫OkHttp הוא מקבץ רשת מודרני נוסף שנמצא בשימוש נרחב בהרבה אפליקציות פופולריות ל-Android. הוא תומך ב-HTTP וב-HTTP/2, אבל עדיין לא תומך ב-HTTP/3 דרך QUIC.

ExoPlayer תומך ב-OkHttp באמצעות ספריית OkHttp. בREADME.md של הספרייה מוסבר איך להשתמש בה. כשמשתמשים בספריית OkHttp, מקבץ הרשת מוטמע באפליקציה. זה דומה ל-Cronet Embedded, אבל OkHttp קטן משמעותית ומוסיף פחות מ-1MB לאפליקציה.

מקבץ הרשת (network stack) המובנה של Android

ExoPlayer תומך בשימוש במקבץ הרשת המובנה של Android עם DefaultHttpDataSource ו-DefaultHttpDataSource.Factory, שהם חלק מספריית הליבה של ExoPlayer.

ההטמעה המדויקת של מקבץ הרשת תלויה בתוכנה שפועלת במכשיר הבסיסי. ברוב המכשירים יש תמיכה רק ב-HTTP (כלומר, אין תמיכה ב-HTTP/2 וב-HTTP/3 דרך QUIC).

מקבצי רשת אחרים

אפליקציות יכולות גם לשלב מקבצי רשת אחרים עם ExoPlayer. כדי לעשות את זה, מטמיעים HttpDataSource שעוטף את מקבץ הרשת (network stack), יחד עם HttpDataSource.Factory תואם. הספריות Cronet ו-OkHttp של ExoPlayer הן דוגמאות טובות לאופן שבו אפשר לעשות זאת.

כשמבצעים שילוב עם מקבץ רשת (network stack) של Java בלבד, מומלץ להטמיע DataSourceContractTest כדי לבדוק שההטמעה של HttpDataSource פועלת בצורה תקינה. OkHttpDataSourceContractTest בספריית OkHttp היא דוגמה טובה לאיך לעשות את זה.

בחירת מקבץ רשת (network stack)

בטבלה הבאה מפורטים היתרונות והחסרונות של מקבצי הרשת שנתמכים ב-ExoPlayer.

מקבץ רשת (network stack) פרוטוקולים ההשפעה על גודל ה-APK הערות
HttpEngine ‫HTTP
HTTP/2
HTTP/3 over QUIC
ללא זמין רק ב-API 34 או ב-S Extensions 7
‫Cronet‏ (Google Play Services) ‫HTTP
HTTP/2
HTTP/3 over QUIC
קטן
(פחות מ-100KB)
נדרש Google Play Services. גרסת Cronet מתעדכנת אוטומטית
‫Cronet (מוטמע) ‫HTTP
HTTP/2
HTTP/3 over QUIC
גדול
(כ-8MB)
גרסת Cronet שנשלטת על ידי מפתח האפליקציה
‫Cronet (חלופי) HTTP
(משתנה לפי המכשיר)
קטן
(פחות מ-100KB)
לא מומלץ ל-ExoPlayer
OkHttp HTTP
HTTP/2
קטן
(פחות מ-1MB)
מקבץ רשת (network stack) מובנה HTTP
(משתנה לפי המכשיר)
ללא ההטמעה משתנה בהתאם למכשיר

הפרוטוקולים HTTP/2 ו-HTTP/3 over QUIC יכולים לשפר משמעותית את הביצועים של סטרימינג של מדיה. במיוחד כשמדובר בסטרימינג של מדיה מותאמת שמופצת באמצעות רשת להעברת תוכן (CDN), יש מקרים שבהם השימוש בפרוטוקולים האלה יכול לאפשר לרשתות CDN לפעול בצורה הרבה יותר יעילה. לכן, התמיכה של HttpEngine ו-Cronet ב-HTTP/2 וב-HTTP/3 דרך QUIC (והתמיכה של OkHttp ב-HTTP/2) היא יתרון משמעותי בהשוואה לשימוש במקבץ הרשת המובנה של Android, בתנאי שהשרתים שבהם התוכן מתארח תומכים גם בפרוטוקולים האלה.

כשמדובר בסטרימינג של מדיה בלבד, מומלץ להשתמש ב-HttpEngine או ב-Cronet שסופקו על ידי Google Play Services, ולחזור ל-DefaultHttpDataSource אם Google Play Services לא זמין. ההמלצה הזו מאזנת בין האפשרות להשתמש ב-HTTP/2 וב-HTTP/3 דרך QUIC ברוב המכשירים, לבין הימנעות מהגדלה משמעותית של קובץ ה-APK. יש כמה חריגים להמלצה הזו. אם סביר להניח ש-Google Play Services לא יהיה זמין בחלק משמעותי מהמכשירים שבהם האפליקציה תפעל, יכול להיות שעדיף להשתמש ב-Cronet Embedded או ב-OkHttp. אם גודל ה-APK הוא שיקול קריטי, או אם סטרימינג של מדיה הוא רק חלק קטן מהפונקציונליות של האפליקציה, יכול להיות ששימוש במקבץ הרשת המובנה יהיה מקובל.

מעבר למדיה, בדרך כלל מומלץ לבחור מקבץ רשת (network stack) אחד לכל פעולות הרשת שהאפליקציה מבצעת. כך אפשר לאסוף ביעילות משאבים (כמו שקעים) ולשתף אותם בין ExoPlayer לבין רכיבים אחרים באפליקציה.

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

שמירת מדיה במטמון

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

כדי לשמור במטמון, צריך מכונה של SimpleCache שמפנה לספריית מטמון ייעודית ו-CacheDataSource.Factory:

Kotlin

// Note: This should be a singleton in your app.
val databaseProvider = StandaloneDatabaseProvider(context)

// An on-the-fly cache should evict media when reaching a maximum disk space limit.
val cache =
  SimpleCache(downloadDirectory, LeastRecentlyUsedCacheEvictor(maxBytes), databaseProvider)

// Configure the DataSource.Factory with the cache and factory for the desired HTTP stack.
val cacheDataSourceFactory =
  CacheDataSource.Factory().setCache(cache).setUpstreamDataSourceFactory(httpDataSourceFactory)

// Inject the DefaultDataSource.Factory when creating the player.
val player =
  ExoPlayer.Builder(context)
    .setMediaSourceFactory(
      DefaultMediaSourceFactory(context).setDataSourceFactory(cacheDataSourceFactory)
    )
    .build()

Java

// Note: This should be a singleton in your app.
DatabaseProvider databaseProvider = new StandaloneDatabaseProvider(context);

// An on-the-fly cache should evict media when reaching a maximum disk space limit.
Cache cache =
    new SimpleCache(
        downloadDirectory, new LeastRecentlyUsedCacheEvictor(maxBytes), databaseProvider);

// Configure the DataSource.Factory with the cache and factory for the desired HTTP stack.
DataSource.Factory cacheDataSourceFactory =
    new CacheDataSource.Factory()
        .setCache(cache)
        .setUpstreamDataSourceFactory(httpDataSourceFactory);

// Inject the DefaultDataSource.Factory when creating the player.
ExoPlayer player =
    new ExoPlayer.Builder(context)
        .setMediaSourceFactory(
            new DefaultMediaSourceFactory(context).setDataSourceFactory(cacheDataSourceFactory))
        .build();