واجهة Player
هي الأساس في مكتبة ExoPlayer. يعرض Player
وظائف مشغّل الوسائط التقليدية العالية المستوى، مثل القدرة على تخزين الوسائط مؤقتًا والتشغيل والإيقاف المؤقت وتقديمها. تم تصميم طريقة التنفيذ التلقائية ExoPlayer
لوضع بعض الافتراضات حول نوع الوسائط التي يتم تشغيلها (وبالتالي فرض قيود قليلة عليها)، وطريقة تخزينها ومكان تخزينها، وطريقة عرضها. بدلاً من تنفيذ تحميل الوسائط وعرضها مباشرةً، تفوّض تنفيذات ExoPlayer
هذا العمل إلى المكوّنات التي يتم إدراجها عند إنشاء مشغّل أو عند تمرير مصادر وسائط جديدة إلى المشغّل.
في ما يلي المكونات الشائعة لجميع عمليات تنفيذ ExoPlayer
:
- مثيلات
MediaSource
التي تحدّد الوسائط المطلوب تشغيلها وتحمل الوسائط والتي يمكن قراءة الوسائط المحمَّلة منها يتم إنشاء مثيلMediaSource
منMediaItem
بواسطةMediaSource.Factory
داخل المشغّل. ويمكن أيضًا تمريرها مباشرةً إلى المشغّل باستخدام واجهة برمجة تطبيقات قائمة التشغيل المستندة إلى مصدر الوسائط. - مثيل
MediaSource.Factory
يحوّلMediaItem
إلىMediaSource
يتمّ إدراجMediaSource.Factory
عند إنشاء اللاعب. Renderer
مثيلات تعرض مكونات فردية للوسائط. ويتم حقنها عند إنشاء اللاعب.TrackSelector
لاختيار الأغاني التي يوفّرهاMediaSource
لكي يتم استخدامها في كلRenderer
متاح يتمّ إدراجTrackSelector
عند إنشاء المشغّل.LoadControl
للتحكّم في الحالات التي يخزّن فيهاMediaSource
المزيد من الوسائط في ذاكرة التخزين المؤقت، وكمية الوسائط التي يتم تخزينها في ذاكرة التخزين المؤقت يتمّ إدخالLoadControl
عند إنشاء اللاعب.LivePlaybackSpeedControl
للتحكّم في سرعة التشغيل أثناء تشغيل المحتوى المباشر للسماح للمشغّل بالبقاء قريبًا من وقت البث المباشر الذي تم ضبطه يتمّ إدراجLivePlaybackSpeedControl
عند إنشاء اللاعب.
يمكن العثور على مفهوم إدراج مكوّنات تنفِّذ أجزاء من وظائف اللاعب في جميع أنحاء المكتبة. تفوض عمليات التنفيذ التلقائية ل بعض المكوّنات العمل إلى المزيد من المكوّنات المُحقَّقة. يتيح ذلك استبدال العديد من المكوّنات الفرعية بشكلٍ فردي بعمليات التنفيذ التي تم ضبطها بطريقة مخصّصة.
تخصيص اللاعب
في ما يلي بعض الأمثلة الشائعة لتخصيص المشغّل عن طريق إدخال المكوّنات.
ضبط حِزمة الشبكة
لدينا صفحة حول تخصيص حِزمة الشبكة التي يستخدمها ExoPlayer.
تخزين البيانات التي يتم تحميلها من الشبكة
اطّلِع على الأدلة المتعلّقة بالتخزين المؤقت أثناء التنقل وتنزيل الوسائط.
تخصيص التفاعلات مع الخادم
قد تحتاج بعض التطبيقات إلى اعتراض طلبات HTTP واستجاباتها. قد تحتاج إلى إدخال عناوين طلبات مخصصة وقراءة عناوين استجابة الخادم وتعديل معرّفات الموارد المنتظمة (URI) للطلبات وما إلى ذلك. على سبيل المثال، قد يصادق تطبيقك عن طريق إدخال رمز مميز كعنوان عند طلب شرائح الوسائط.
يوضّح المثال التالي كيفية تنفيذ هذه السلوكيات من خلال
إدخال DataSource.Factory
مخصّص في DefaultMediaSourceFactory
:
Kotlin
val dataSourceFactory = DataSource.Factory { val dataSource = httpDataSourceFactory.createDataSource() // Set a custom authentication request header. dataSource.setRequestProperty("Header", "Value") dataSource } val player = ExoPlayer.Builder(context) .setMediaSourceFactory( DefaultMediaSourceFactory(context).setDataSourceFactory(dataSourceFactory) ) .build()
Java
DataSource.Factory dataSourceFactory = () -> { HttpDataSource dataSource = httpDataSourceFactory.createDataSource(); // Set a custom authentication request header. dataSource.setRequestProperty("Header", "Value"); return dataSource; }; ExoPlayer player = new ExoPlayer.Builder(context) .setMediaSourceFactory( new DefaultMediaSourceFactory(context).setDataSourceFactory(dataSourceFactory)) .build();
في مقتطف الرمز أعلاه، يتضمّن HttpDataSource
المُحقَّق العنوان
"Header: Value"
في كل طلب HTTP. هذا السلوك ثابت لكل
تفاعل مع مصدر HTTP.
لاتّباع نهج أكثر دقة، يمكنك إدخال السلوك المناسب في الوقت المناسب باستخدام
ResolvingDataSource
. يوضح مقتطف الرمز التالي كيفية إدخال
عناوين الطلبات قبل التفاعل مع مصدر HTTP مباشرةً:
Kotlin
val dataSourceFactory: DataSource.Factory = ResolvingDataSource.Factory(httpDataSourceFactory) { dataSpec: DataSpec -> // Provide just-in-time request headers. dataSpec.withRequestHeaders(getCustomHeaders(dataSpec.uri)) }
Java
DataSource.Factory dataSourceFactory = new ResolvingDataSource.Factory( httpDataSourceFactory, // Provide just-in-time request headers. dataSpec -> dataSpec.withRequestHeaders(getCustomHeaders(dataSpec.uri)));
يمكنك أيضًا استخدام ResolvingDataSource
لإجراء تعديلات
في الوقت المناسب على عنوان URL، كما هو موضّح في المقتطف التالي:
Kotlin
val dataSourceFactory: DataSource.Factory = ResolvingDataSource.Factory(httpDataSourceFactory) { dataSpec: DataSpec -> // Provide just-in-time URI resolution logic. dataSpec.withUri(resolveUri(dataSpec.uri)) }
Java
DataSource.Factory dataSourceFactory = new ResolvingDataSource.Factory( httpDataSourceFactory, // Provide just-in-time URI resolution logic. dataSpec -> dataSpec.withUri(resolveUri(dataSpec.uri)));
تخصيص معالجة الأخطاء
يتيح تنفيذ LoadErrorHandlingPolicy
مخصّص للتطبيقات تخصيص
طريقة استجابة ExoPlayer لأخطاء التحميل. على سبيل المثال، قد يريد التطبيق إنهاء عملية البث بسرعة بدلاً من إعادة المحاولة عدة مرات، أو قد يريد تخصيص منطق الانتظار الذي يتحكّم في المدة التي ينتظرها المشغّل بين كل محاولة. يوضّح المقتطف التالي
كيفية تنفيذ منطق التراجع المخصّص:
Kotlin
val loadErrorHandlingPolicy: LoadErrorHandlingPolicy = object : DefaultLoadErrorHandlingPolicy() { override fun getRetryDelayMsFor(loadErrorInfo: LoadErrorInfo): Long { // Implement custom back-off logic here. return 0 } } val player = ExoPlayer.Builder(context) .setMediaSourceFactory( DefaultMediaSourceFactory(context).setLoadErrorHandlingPolicy(loadErrorHandlingPolicy) ) .build()
Java
LoadErrorHandlingPolicy loadErrorHandlingPolicy = new DefaultLoadErrorHandlingPolicy() { @Override public long getRetryDelayMsFor(LoadErrorInfo loadErrorInfo) { // Implement custom back-off logic here. return 0; } }; ExoPlayer player = new ExoPlayer.Builder(context) .setMediaSourceFactory( new DefaultMediaSourceFactory(context) .setLoadErrorHandlingPolicy(loadErrorHandlingPolicy)) .build();
تحتوي الوسيطة LoadErrorInfo
على مزيد من المعلومات عن عملية التحميل التي تعذّر إكمالها لأجل
تخصيص المنطق استنادًا إلى نوع الخطأ أو الطلب الذي تعذّر إكماله.
تخصيص علامات المستخرج
يمكن استخدام علامات المستخرج لتخصيص كيفية استخراج التنسيقات الفردية
من الوسائط التدريجية. ويمكن ضبطها في DefaultExtractorsFactory
الذي يتم
تقديمه إلى DefaultMediaSourceFactory
. يُرسِل المثال التالي علامة
تتيح التقديم أو الإيقاف بالاستناد إلى الفهرس في أحداث MP3.
Kotlin
val extractorsFactory = DefaultExtractorsFactory().setMp3ExtractorFlags(Mp3Extractor.FLAG_ENABLE_INDEX_SEEKING) val player = ExoPlayer.Builder(context) .setMediaSourceFactory(DefaultMediaSourceFactory(context, extractorsFactory)) .build()
Java
DefaultExtractorsFactory extractorsFactory = new DefaultExtractorsFactory().setMp3ExtractorFlags(Mp3Extractor.FLAG_ENABLE_INDEX_SEEKING); ExoPlayer player = new ExoPlayer.Builder(context) .setMediaSourceFactory(new DefaultMediaSourceFactory(context, extractorsFactory)) .build();
تفعيل ميزة التقديم أو الإيقاف السريع بمعدل نقل بيانات ثابت
بالنسبة إلى أحداث البث بتنسيقات MP3 وADTS وAMR، يمكنك تفعيل ميزة التقديم/الترجيع التقريبي باستخدام افتراض معدل نقل بيانات ثابت مع علامات FLAG_ENABLE_CONSTANT_BITRATE_SEEKING
.
يمكن ضبط هذه العلامات لأدوات استخراج فردية باستخدام طرق
DefaultExtractorsFactory.setXyzExtractorFlags
الفردية كما هو موضّح أعلاه. ل
تفعيل ميزة التقديم/الترجيع بمعدّل نقل بيانات ثابت لجميع برامج الاستخراج المتوافقة، استخدِم DefaultExtractorsFactory.setConstantBitrateSeekingEnabled
.
Kotlin
val extractorsFactory = DefaultExtractorsFactory().setConstantBitrateSeekingEnabled(true)
Java
DefaultExtractorsFactory extractorsFactory = new DefaultExtractorsFactory().setConstantBitrateSeekingEnabled(true);
يمكن بعد ذلك إدخال ExtractorsFactory
من خلال DefaultMediaSourceFactory
كما هو описан في قسم تخصيص علامات المستخرج أعلاه.
تفعيل وضع "قائمة انتظار التخزين المؤقت غير المتزامن"
"قائمة انتظار الوسائط المؤقتة غير المتزامنة" هي ميزة محسّنة في مسار معالجة التحويل في ExoPlayer، الذي يشغّل MediaCodec
مثيلًا في الوضع غير المتزامن ويستخدم خيوطًا إضافية لجدولة فك ترميز البيانات وعرضها. يمكن أن يؤدي تفعيل هذه الميزة
إلى تقليل عدد اللقطات المفقودة ووقت التوقف المؤقت في الصوت.
تكون ميزة "قائمة انتظار المخزن المؤقت غير المتزامن" مفعّلة تلقائيًا على الأجهزة التي تعمل بنظام التشغيل Android 12 (المستوى 31 من واجهة برمجة التطبيقات) والإصدارات الأحدث، ويمكن تفعيلها يدويًا بدءًا من Android 6.0 (المستوى 23 من واجهة برمجة التطبيقات). ننصحك بتفعيل هذه الميزة على أجهزة معيّنة تلاحظ فيها تقطُّعًا في اللقطات أو تأخُّرًا في عرض الصوت، خاصةً عند تشغيل محتوًى محمي بإدارة الحقوق الرقمية أو محتوًى يتضمن عددًا كبيرًا من اللقطات في الثانية.
في أبسط الحالات، عليك إدراج DefaultRenderersFactory
في
المشغّل على النحو التالي:
Kotlin
val renderersFactory = DefaultRenderersFactory(context).forceEnableMediaCodecAsynchronousQueueing() val exoPlayer = ExoPlayer.Builder(context, renderersFactory).build()
Java
DefaultRenderersFactory renderersFactory = new DefaultRenderersFactory(context).forceEnableMediaCodecAsynchronousQueueing(); ExoPlayer exoPlayer = new ExoPlayer.Builder(context, renderersFactory).build();
في حال إنشاء عناصر عرض مباشرةً، عليك تمرير AsynchronousMediaCodecAdapter.Factory
إلى وظيفتَي الإنشاء MediaCodecVideoRenderer
و
MediaCodecAudioRenderer
.
اعتراض طلبات الإجراءات باستخدام ForwardingPlayer
يمكنك تخصيص بعض سلوك مثيل Player
من خلال تغليفه في
فئة فرعية من ForwardingPlayer
واستبدال الطرق لتنفيذ أي مما يلي:
- يمكنك الوصول إلى المَعلمات قبل تمريرها إلى المفوَّض
Player
. - يمكنك الوصول إلى القيمة المعروضة من المفوَّض
Player
قبل عرضها. - إعادة تنفيذ الطريقة بالكامل
عند إلغاء طرق ForwardingPlayer
، من المهم التأكّد من أنّ
التنفيذ يظلّ متسقًا مع نفسه ومتوافقًا مع Player
واجهة، خاصةً عند التعامل مع الطرق التي من المفترض أن يكون لها
سلوك مماثل أو ذي صلة. مثلاً:
- إذا كنت تريد إلغاء كل عملية "تشغيل"، عليك إلغاء كل من
ForwardingPlayer.play
وForwardingPlayer.setPlayWhenReady
، لأنّه سيتوقع المُرسِل أن يكون سلوك هاتين الطريقتَين متطابقًا عندplayWhenReady = true
. - إذا أردت تغيير نسبة التقديم/الترجيع، عليك إلغاء كل من
ForwardingPlayer.seekForward
لتنفيذ عملية البحث باستخدام الزيادة المخصّصة، وForwardingPlayer.getSeekForwardIncrement
للإبلاغ عن الزيادة المخصّصة الصحيحة إلى المتصل. - إذا أردت التحكّم في ما يعلِن عنه
Player.Commands
من خلال مثيل مشغِّل، عليك إلغاء كل منPlayer.getAvailableCommands()
وPlayer.isCommandAvailable()
، والاستماع أيضًا إلى رمز معاودة الاتصالPlayer.Listener.onAvailableCommandsChanged()
لتلقّي إشعارات بشأن التغييرات الواردة من المشغّل الأساسي.
تخصيص MediaSource
تُدرِج الأمثلة أعلاه مكوّنات مخصّصة لاستخدامها أثناء تشغيل كل العناصر
MediaItem
التي يتم تمريرها إلى المشغّل. وعند الحاجة إلى إجراء تخصيص بالغ الدقة، من الممكن أيضًا إدخال مكوّنات مخصّصة في مثيلات
MediaSource
فردية، ويمكن تمريرها مباشرةً إلى المشغّل. يوضّح المثال أدناه كيفية تخصيص ProgressiveMediaSource
لاستخدام DataSource.Factory
وExtractorsFactory
وLoadErrorHandlingPolicy
مخصّصة:
Kotlin
val mediaSource = ProgressiveMediaSource.Factory(customDataSourceFactory, customExtractorsFactory) .setLoadErrorHandlingPolicy(customLoadErrorHandlingPolicy) .createMediaSource(MediaItem.fromUri(streamUri))
Java
ProgressiveMediaSource mediaSource = new ProgressiveMediaSource.Factory(customDataSourceFactory, customExtractorsFactory) .setLoadErrorHandlingPolicy(customLoadErrorHandlingPolicy) .createMediaSource(MediaItem.fromUri(streamUri));
إنشاء مكوّنات مخصّصة
توفر المكتبة عمليات التنفيذ الافتراضية للمكونات المدرجة أعلى هذه الصفحة لحالات الاستخدام الشائعة. يمكن أن يستخدم ExoPlayer
هذه المكوّنات، ولكن
يمكن أيضًا إنشاؤه لاستخدام عمليات التنفيذ المخصّصة إذا كانت السلوكيات غير العادية
مطلوبة. في ما يلي بعض حالات الاستخدام لعمليات التنفيذ المخصّصة:
Renderer
: قد تحتاج إلى تنفيذRenderer
مخصّص للتعامل مع نوع وسائط غير متوافق مع عمليات التنفيذ التلقائية التي تقدّمها المكتبة.TrackSelector
: يتيح تنفيذTrackSelector
مخصّص لمطوّر التطبيقات تغيير طريقة اختيار الأغاني التي يعرضهاMediaSource
لاستهلاكها من خلال كلRenderer
متاح.-
LoadControl
: يتيح تنفيذLoadControl
مخصّص لمطوّر التطبيقات تغيير سياسة التخزين المؤقت لمشغّل الوسائط. Extractor
– إذا كنت بحاجة إلى إتاحة تنسيق حاوية لا توفّره المكتبة حاليًا، ننصحك بتنفيذ فئةExtractor
مخصّصة.MediaSource
– قد يكون من المناسب تنفيذ فئةMediaSource
مخصّصة إذا كنت تريد الحصول على نماذج وسائط للخلاصة لبرامج العرض بطريقة مخصّصة أو إذا أردت تطبيق سلوكMediaSource
مخصَّص.MediaSource.Factory
: يتيح تنفيذMediaSource.Factory
مخصّص للتطبيق تخصيص طريقة إنشاءMediaSource
منMediaItem
.-
DataSource
: تحتوي حزمة ExoPlayer الأساسية حاليًا على عدد من عمليات تنفيذDataSource
لحالات استخدام مختلفة. يمكنك استخدام فئةDataSource
لتحميل البيانات بطريقة أخرى، مثلاً عبر بروتوكول مخصّص أو باستخدام حزمة HTTP مخصّصة أو من ذاكرة تخزين مؤقت دائمة مخصَّصة.
عند إنشاء مكوّنات مخصّصة، ننصحك بما يلي:
- إذا كان المكوّن المخصّص بحاجة إلى الإبلاغ عن الأحداث إلى التطبيق، ننصحك
بإجراء ذلك باستخدام النموذج نفسه المستخدَم في مكوّنات ExoPlayer الحالية، مثلاً باستخدام فئات
EventDispatcher
أو تمريرHandler
مع مُستمع إلى مُنشئ المكوّن. - ننصحك بأن تستخدم المكوّنات المخصّصة النموذج نفسه المستخدَم في مكوّنات ExoPlayer
الحالية للسماح للتطبيق بإعادة الضبط أثناء التشغيل. لإجراء ذلك، يجب أن تنفِّذ المكونات المخصّصة
PlayerMessage.Target
وتتلقّى تغييرات الإعدادات في طريقةhandleMessage
. يجب أن يمرّر رمز التطبيق تغييرات الإعدادات من خلال استدعاء طريقةcreateMessage
في ExoPlayer وإعداد الرسالة وإرسالها إلى المكوِّن باستخدامPlayerMessage.send
. يضمن إرسال الرسائل ليتم تسليمها في سلسلة محادثات التشغيل تنفيذها بالترتيب مع أي عمليات أخرى تتم على المشغّل.