حِزم الشبكة

يُستخدَم ExoPlayer عادةً لبث الوسائط عبر الإنترنت. وهي تتيح استخدام حِزم شبكات متعددة لتقديم طلبات الشبكة الأساسية. يمكن أن يؤثر اختيارك لمجموعة بروتوكولات الشبكة بشكل كبير في أداء البث.

توضّح هذه الصفحة كيفية ضبط ExoPlayer لاستخدام حزمة الشبكة التي تختارها، وتدرج الخيارات المتاحة، وتقدّم بعض الإرشادات حول كيفية اختيار حزمة شبكة لتطبيقك، وتوضّح كيفية تفعيل التخزين المؤقت للوسائط التي يتم بثها.

ضبط ExoPlayer لاستخدام حزمة شبكة معيّنة

يحمّل ExoPlayer البيانات من خلال مكوّنات DataSource التي يحصل عليها من مثيلات DataSource.Factory التي يتم إدخالها من رمز التطبيق.

إذا كان تطبيقك يحتاج فقط إلى تشغيل محتوى http(s)، فإنّ اختيار حزمة شبكة يكون بسيطًا مثل تعديل أي مثيلات DataSource.Factory يدرجها تطبيقك لتكون مثيلات HttpDataSource.Factory التي تتوافق مع حزمة الشبكة التي تريد استخدامها. إذا كان تطبيقك يحتاج أيضًا إلى تشغيل محتوى غير http(s)، مثل الملفات المحلية، استخدِم DefaultDataSource.Factory:

Kotlin

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

Java

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

في هذا المثال، PreferredHttpDataSource.Factory هو المصنع الذي يتوافق مع حزمة الشبكة المفضّلة لديك. تضيف طبقة DefaultDataSource.Factory إمكانية استخدام مصادر غير http(s)‎ مثل الملفات المحلية.

يوضّح المثال التالي كيفية إنشاء ExoPlayer سيستخدم حزمة شبكة 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();

حِزم الشبكات المتوافقة

يتوافق ExoPlayer مباشرةً مع HttpEngine وCronet وOkHttp وحزمة الشبكة التلقائية المضمّنة في Android. يمكن أيضًا توسيع نطاق ExoPlayer ليشمل أي حزمة شبكة أخرى تعمل على Android.

HttpEngine

HttpEngine هي حزمة الشبكة التلقائية المقترَحة على Android بدءًا من المستوى 34 لواجهة برمجة التطبيقات (أو الإصدار 7 من حزمة S extensions). في معظم الحالات، تستخدم هذه المكتبة حزمة شبكة Cronet داخليًا، وهي تتوافق مع بروتوكولات HTTP وHTTP/2 وHTTP/3 عبر بروتوكولات QUIC.

يتوافق ExoPlayer مع HttpEngine من خلال HttpEngineDataSource.Factory. يمكنك إدخال مصدر البيانات هذا على النحو الموضّح في ضبط ExoPlayer لاستخدام حزمة شبكة محدّدة.

Cronet

Cronet هي حزمة شبكة Chromium التي تتوفّر لتطبيقات Android كمكتبة. تستفيد Cronet من تقنيات متعدّدة تقلّل وقت الاستجابة وتزيد معدّل نقل البيانات لطلبات الشبكة التي يحتاجها تطبيقك ليعمل، بما في ذلك الطلبات التي يرسلها ExoPlayer. يتوافق بشكل أساسي مع بروتوكولات HTTP وHTTP/2 وHTTP/3 عبر QUIC. يتم استخدام Cronet من قِبل بعض أكبر تطبيقات البث المباشر في العالم، بما في ذلك YouTube.

يتوافق ExoPlayer مع Cronet من خلال مكتبة Cronet. اطّلِع على README.md في المكتبة للحصول على تعليمات مفصّلة حول كيفية استخدامها. يُرجى العِلم أنّ مكتبة Cronet يمكنها استخدام ثلاث عمليات تنفيذ أساسية لـ Cronet، وهي:

  1. خدمات Google Play: ننصح باستخدام هذه الطريقة في معظم الحالات، والرجوع إلى حزمة الشبكة المضمّنة في Android (DefaultHttpDataSource) إذا لم تكن "خدمات Google Play" متاحة.
  2. Cronet Embedded: قد يكون خيارًا جيدًا إذا كان عدد كبير من المستخدمين في الأسواق التي لا تتوفّر فيها "خدمات Google Play" على نطاق واسع، أو إذا كنت تريد التحكّم في الإصدار الدقيق من تنفيذ Cronet المستخدَم. العيب الرئيسي في Cronet Embedded هو أنّه يضيف حوالي 8 ميغابايت إلى تطبيقك.
  3. الخيار الاحتياطي في Cronet: ينفّذ الخيار الاحتياطي في Cronet واجهة برمجة التطبيقات الخاصة بـ Cronet كبرنامج تضمين حول حزمة الشبكة المضمّنة في Android. يجب عدم استخدامها مع ExoPlayer، لأنّ استخدام حزمة الشبكة المضمّنة في Android مباشرةً (من خلال استخدام DefaultHttpDataSource) أكثر فعالية.

OkHttp

OkHttp هي حزمة شبكة حديثة أخرى يستخدمها العديد من تطبيقات Android الشائعة. يتوافق مع HTTP وHTTP/2، ولكنّه لا يتوافق بعد مع HTTP/3 عبر QUIC.

يتوافق ExoPlayer مع OkHttp من خلال مكتبة OkHttp. اطّلِع على README.md في المكتبة للحصول على تعليمات مفصّلة حول كيفية استخدامها. عند استخدام مكتبة OkHttp، يتم تضمين حزمة الشبكة في التطبيق. ويشبه ذلك Cronet Embedded، ولكن حجم OkHttp أصغر بكثير، حيث يضيف أقل من ميغابايت واحد إلى تطبيقك.

حزمة الشبكات المدمَجة في Android

يتيح ExoPlayer استخدام حزمة الشبكة المضمّنة في Android مع DefaultHttpDataSource وDefaultHttpDataSource.Factory، وهما جزء من مكتبة ExoPlayer الأساسية.

يعتمد التنفيذ الدقيق لمجموعة بروتوكولات الشبكة على البرنامج الذي يعمل على الجهاز الأساسي. لا تتوافق معظم الأجهزة إلا مع HTTP (أي أنّها لا تتوافق مع HTTP/2 وHTTP/3 عبر QUIC).

حزم الشبكات الأخرى

يمكن للتطبيقات أيضًا دمج حِزم الشبكة الأخرى مع ExoPlayer. لإجراء ذلك، عليك تنفيذ HttpDataSource يغلّف حزمة الشبكة، بالإضافة إلى HttpDataSource.Factory مطابق. تُعدّ مكتبتا Cronet وOkHttp في ExoPlayer مثالَين جيدَين على كيفية إجراء ذلك.

عند الدمج مع حزمة شبكة Java خالصة، من المستحسن تنفيذ DataSourceContractTest للتحقّق من أنّ عملية تنفيذ HttpDataSource تعمل بشكل صحيح. OkHttpDataSourceContractTest في مكتبة OkHttp هو مثال جيد على كيفية تنفيذ ذلك.

اختيار حزمة الشبكات

يوضّح الجدول التالي مزايا وعيوب حزم الشبكة المتوافقة مع ExoPlayer.

حزم الشبكات البروتوكولات تأثير حجم حزمة APK الملاحظات
HttpEngine ‫HTTP
HTTP/2
HTTP/3 عبر QUIC
بدون يتوفّر فقط على الإصدار 34 من واجهة برمجة التطبيقات أو الإصدار 7 من حزمة S Extensions
Cronet (خدمات Google Play) ‫HTTP
HTTP/2
HTTP/3 عبر QUIC
صغير
(<100 كيلوبايت)
يتطلّب استخدام "خدمات Google Play". تحديث إصدار Cronet تلقائيًا
Cronet (مضمّنة) ‫HTTP
HTTP/2
HTTP/3 عبر QUIC
كبير
(~8MB)
يتحكّم مطوّر التطبيق في إصدار Cronet
Cronet (احتياطي) ‫HTTP
(يختلف حسب الجهاز)
صغير
(<100 كيلوبايت)
لا يُنصح باستخدامها مع ExoPlayer
OkHttp HTTP
HTTP/2
صغيرة
(<1MB)
حزمة الشبكات المضمّنة ‫HTTP
(يختلف حسب الجهاز)
بدون تختلف عملية الإعداد حسب الجهاز

يمكن أن يؤدي استخدام بروتوكولَي HTTP/2 وHTTP/3 عبر QUIC إلى تحسين أداء بث الوسائط بشكل كبير. على وجه الخصوص، عند بث وسائط متكيّفة يتم توزيعها باستخدام شبكة توصيل المحتوى (CDN)، هناك حالات يمكن أن يتيح فيها استخدام هذه البروتوكولات لشبكات توصيل المحتوى العمل بكفاءة أكبر بكثير. لهذا السبب، يُعدّ توفير HttpEngine وCronet لإمكانية استخدام كل من HTTP/2 وHTTP/3 عبر QUIC (وتوفير OkHttp لإمكانية استخدام HTTP/2) ميزة كبيرة مقارنةً باستخدام حزمة الشبكة المضمّنة في Android، شرط أن توفّر الخوادم التي تستضيف المحتوى إمكانية استخدام هذه البروتوكولات أيضًا.

عند التفكير في بث الوسائط بشكل منفصل، ننصح باستخدام HttpEngine أو Cronet المقدَّمَين من &quot;خدمات Google Play&quot; مع الرجوع إلى DefaultHttpDataSource في حال عدم توفّر &quot;خدمات Google Play&quot;. يقدّم هذا الاقتراح توازنًا جيدًا بين إتاحة استخدام HTTP/2 وHTTP/3 عبر QUIC على معظم الأجهزة وتجنُّب زيادة كبيرة في حجم حزمة APK. هناك استثناءات لهذه التوصية. في الحالات التي من المحتمل ألا تتوفّر فيها "خدمات Google Play" على جزء كبير من الأجهزة التي سيتم تشغيل تطبيقك عليها، قد يكون استخدام Cronet Embedded أو OkHttp أكثر ملاءمةً. قد يكون استخدام حزمة الشبكة المضمّنة مقبولاً إذا كان حجم حزمة APK يمثّل مشكلة كبيرة، أو إذا كان بث الوسائط جزءًا ثانويًا من وظائف تطبيقك.

بالإضافة إلى الوسائط، من المستحسن عادةً اختيار حزمة شبكة واحدة لجميع عمليات الشبكات التي ينفّذها تطبيقك، ما يتيح تجميع الموارد (مثل مآخذ التوصيل) ومشاركتها بكفاءة بين 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();