حِزم الشبكة

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

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

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

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

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

Kotlin

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

Java

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

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

يوضّح المثال التالي كيفية إنشاء ExoPlayer يستخدم حزمة شبكة Cronet ويتيح أيضًا تشغيل محتوى غير عناوين http.

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 دعمًا مباشرًا لحزمة شبكة Cronet وOkHttp وحزمة الشبكات المدمجة في Android. ويمكن أيضًا توسيع منصة ExoPlayer لتتوافق مع أي حزمة شبكة أخرى تعمل على Android.

كرونيت

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

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

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

OkHttp

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

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

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

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

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

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

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

عند الدمج مع حزمة شبكة Java فقط، من الأفضل تنفيذ DataSourceContractTest للتحقّق من أنّ عملية تنفيذ HttpDataSource تعمل على نحو صحيح. يُعد OkHttpDataSourceContractTest في مكتبة OkHttp مثالاً جيدًا على كيفية إجراء ذلك.

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

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

حزم الشبكات البروتوكولات تأثير حجم حِزم APK Notes
Cronet (خدمات Google Play) HTTP
HTTP/2
HTTP/3 عبر QUIC
صغيرة
(<100 كيلوبايت)
تتطلب هذه الميزة استخدام "خدمات Google Play". تم تعديل إصدار Cronet تلقائيًا.
Cronet (مضمّن) HTTP
HTTP/2
HTTP/3 عبر QUIC
كبير
(حوالي 8 ميغابايت)
إصدار Cronet الذي يتحكّم فيه مطوِّر التطبيق
Cronet (احتياطي) HTTP
(يختلف حسب الجهاز)
صغيرة
(<100 كيلوبايت)
لا يُنصَح به مع ExoPlayer
OkHttp HTTP
HTTP/2
صغيرة
(<1 ميغابايت)
يجب استخدام وقت تشغيل Kotlin.
حزم الشبكة المدمجة HTTP
(يختلف حسب الجهاز)
بدون تحديد نمط تختلف عملية التنفيذ حسب الجهاز.

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

عند التفكير في بث الوسائط بشكل منعزل، ننصح باستخدام Cronet الذي توفِّره "خدمات Google Play" واستخدام DefaultHttpDataSource في حال عدم توفُّر "خدمات Google Play". يحقق هذا الاقتراح توازنًا جيدًا بين تفعيل استخدام HTTP/2 وHTTP/3 عبر QUIC على معظم الأجهزة، وتجنُّب زيادة كبيرة في حجم APK. هناك استثناءات لهذه التوصية. بالنسبة إلى الحالات التي يكون فيها استخدام خدمات Google Play غير متاح على جزء كبير من الأجهزة التي ستشغّل تطبيقك، قد يكون من الأفضل استخدام Cronet inline أو 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();