يُستخدَم ExoPlayer عادةً لبث الوسائط عبر الإنترنت. وهي تتيح استخدام حزم شبكات متعددة لإرسال طلبات الشبكة الأساسية. يمكن أن يؤثر اختيارك لحزمة الشبكة بشكل كبير في أداء البث.
توضّح هذه الصفحة كيفية ضبط 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 يستخدم حزمة شبكات 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 لواجهة برمجة التطبيقات (أو S
extensions 7). في معظم الحالات، تستخدم هذه المكتبة حزمة شبكة 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 الأساسية:
- خدمات Google Play: ننصح باستخدام هذا التنفيذ في معظم الحالات، والرجوع إلى حزمة الشبكة المضمّنة في Android (
DefaultHttpDataSource) إذا لم تكن "خدمات Google Play" متاحة. - Cronet المضمَّنة: قد تكون خيارًا جيدًا إذا كانت نسبة كبيرة من المستخدمين في أسواق لا تتوفّر فيها "خدمات Google Play" على نطاق واسع، أو إذا كنت تريد التحكّم في الإصدار الدقيق من تنفيذ Cronet المستخدَم. يتمثّل العيب الرئيسي في Cronet Embedded في أنّه يضيف حوالي 8 ميغابايت إلى تطبيقك.
- Cronet Fallback: هو تنفيذ احتياطي لواجهة برمجة تطبيقات Cronet كبرنامج تضمين حول حزمة الشبكات المضمّنة في Android. ولا يجب استخدامها مع ExoPlayer، لأنّ استخدام حزمة الشبكة المضمّنة في Android مباشرةً (من خلال
DefaultHttpDataSource) يكون أكثر كفاءة.
OkHttp
OkHttp هي حزمة شبكات حديثة أخرى تُستخدم على نطاق واسع في العديد من تطبيقات Android الشائعة. وهو متوافق مع بروتوكولَي HTTP وHTTP/2، ولكنه غير متوافق بعد مع بروتوكول HTTP/3 عبر QUIC.
يتوافق ExoPlayer مع OkHttp من خلال
مكتبة OkHttp.
يُرجى الاطّلاع على README.md الخاص بالمكتبة للحصول على تعليمات مفصّلة حول كيفية استخدامها. عند استخدام مكتبة OkHttp، يتم تضمين حزمة الشبكة داخل التطبيق، وهو ما يشبه Cronet Embedded، إلا أنّ OkHttp أصغر حجمًا بكثير، إذ يضيف أقل من 1 ميغابايت إلى تطبيقك.
حزم الشبكات المُدمَجة في 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 أو S Extensions 7 |
| 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 ميغابايت) |
|
| حزم الشبكات المضمّنة | HTTP (يختلف حسب الجهاز) |
بدون | تختلف عملية التنفيذ حسب الجهاز |
يمكن أن يؤدي استخدام بروتوكولَي HTTP/2 وHTTP/3 عبر بروتوكول QUIC إلى تحسين أداء بث الوسائط بشكل كبير. على وجه الخصوص، عند بث وسائط تكيُّفية يتم توزيعها باستخدام شبكة توزيع المحتوى (CDN)، هناك حالات يمكن أن يؤدي فيها استخدام هذه البروتوكولات إلى السماح لشبكات توزيع المحتوى بالعمل بكفاءة أكبر. لهذا السبب، فإنّ توافق HttpEngine وCronet مع كل من HTTP/2 وHTTP/3 عبر QUIC (وتوافق OkHttp مع HTTP/2) يُعدّ ميزة رئيسية مقارنةً باستخدام حزمة الشبكات المدمجة في Android، بشرط أن تكون الخوادم التي تستضيف المحتوى متوافقة أيضًا مع هذه البروتوكولات.
عند النظر في بث الوسائط بشكل منفصل، ننصح باستخدام HttpEngine أو
Cronet المقدَّم من "خدمات Google Play" والرجوع إلى DefaultHttpDataSource
إذا لم تكن "خدمات Google Play" متاحة. تحقّق هذه التوصية توازنًا جيدًا بين إتاحة استخدام 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();