يشغِّل ExoPlayer معظم أحداث البث المباشر التكيُّفية بطريقة مبتكرة بدون أي إعدادات خاصة. اطّلِع على صفحة التنسيقات المتوافقة للحصول على مزيد من التفاصيل.
تقدّم أحداث البث المباشر التكيُّفية نافذة للوسائط المتاحة يتم تعديلها في فواصل زمنية terature لمتابعة الوقت الفعلي الحالي. وهذا يعني أنّ نقطة بدء التشغيل ستكون دائمًا في مكان ما في هذه النافذة، وفي معظم الحالات ستكون قريبة من الوقت الفعلي الحالي الذي يتم فيه إنشاء البث. يُعرف الفرق بين الوقت الفعلي الحالي ووقت التشغيل باسم التأخُّر في البث المباشر.
رصد عمليات التشغيل المباشرة وتتبُّعها
في كل مرة يتم فيها تعديل نافذة مباشرة، ستتلقّى مثيلات Player.Listener
المسجّلة
حدث onTimelineChanged
. يمكنك استرداد تفاصيل حول
البث المباشر الحالي من خلال البحث عن طُرق Player
وTimeline.Window
مختلفة، كما هو موضّح أدناه وكما هو موضّح في الشكل التالي.
- تشير العلامة
Player.isCurrentWindowLive
إلى ما إذا كان الوسائط التي يتم تشغيلها حاليًا عبارة عن بث مباشر. تظل هذه القيمة صحيحة حتى إذا انتهى البث المباشر. - يشير الرمز
Player.isCurrentWindowDynamic
إلى ما إذا كان يتم تعديل المحتوى المشغّل حاليًا. وينطبق ذلك عادةً على أحداث البث المباشر التي لم تنته بعد. يُرجى العِلم أنّ هذه العلامة صحيحة أيضًا للفيديوهات غير المباشرة في بعض الحالات. - تعرِض
Player.getCurrentLiveOffset
المدة بين الوقت الفعلي الحالي ووقت التشغيل (إذا كان متاحًا). Player.getDuration
تعرِض طول الفترة الزمنية الحالية للبث المباشر.Player.getCurrentPosition
تعرِض موضع التشغيل بالنسبة إلى بداية النافذة المباشرة.- تعرض
Player.getCurrentMediaItem
عنصر الوسائط الحالي، حيث يحتويMediaItem.liveConfiguration
على عمليات إلغاء يوفّرها التطبيق لمَعلمات تعديل المحتوى المباشر المستهدفة وتعديل المحتوى المباشر. - تعرِض
Player.getCurrentTimeline
بنية الوسائط الحالية في ملفTimeline
. يمكن استردادTimeline.Window
الحالي منTimeline
باستخدامPlayer.getCurrentMediaItemIndex
وTimeline.getWindow
. ضمنWindow
:- تحتوي السمة
Window.liveConfiguration
على معاملَي الإزاحة المباشرة المستهدفة وتعديل الإزاحة المباشرة. تستند هذه القيم إلى المعلومات الواردة في الوسائط وأيّ قيم إلغاء يوفّرها التطبيق تم ضبطها فيMediaItem.liveConfiguration
. Window.windowStartTimeMs
هو الوقت الذي تبدأ فيه نافذة Unix Epoch المباشرة.-
Window.getCurrentUnixTimeMs
هو الوقت الذي مضى منذ بدء حساب الفترة الزمنية لقياس الوقت الفعلي الحالي. يمكن تصحيح هذه القيمة من خلال فرق معروف بين الساعة في الخادم والعميل. Window.getDefaultPositionMs
هو الموضع في نافذة البث المباشر الذي سيبدأ فيه المشغّل التشغيل تلقائيًا.
- تحتوي السمة
جارٍ البحث في أحداث البث المباشر
يمكنك الانتقال إلى أي جزء من النافذة المباشرة باستخدام Player.seekTo
. إنّ موضع التقديم/الترجيع الذي تم تمريره نسبي لبداية نافذة البث المباشر. على سبيل المثال، يؤدي النقر على seekTo(0)
إلى ترجيع الفيديو إلى بداية النافذة المباشرة. ويحاول اللاعب الحفاظ على نفس التعويض المباشر مع الموضع المطلوب بعد التقديم/الترجيع.
وتحتوي نافذة البث المباشر أيضًا على الموضع التلقائي الذي من المفترض أن يبدأ عنده التشغيل. ويكون هذا الموضع عادةً في مكان قريب من الحافة النشطة. يمكنك الانتقال إلى الموضع التلقائي من خلال استدعاء Player.seekToDefaultPosition
.
واجهة المستخدم للتشغيل المباشر
تعرِض مكونات واجهة المستخدم التلقائية في ExoPlayer مدة نافذة البث المباشر
وموضع التشغيل الحالي فيها. هذا يعني أن الموضع سيظهر كتحرك للخلف
في كل مرة يتم فيها تحديث النافذة المباشرة. إذا كنت بحاجة إلى سلوك مختلف، على سبيل المثال عرض وقت Unix أو الوقت الحالي للبث المباشر، يمكنك
إنشاء نسخة من PlayerControlView
وتعديلها لتلبية احتياجاتك.
ضبط مَعلمات التشغيل المباشر
يستخدم ExoPlayer بعض المعلمات للتحكّم في إزاحة موضع التشغيل من الحافة المباشرة، ونطاق سرعات التشغيل التي يمكن استخدامها لضبط هذه الإزاحة.
يحصل ExoPlayer على قيم لهذه المَعلمات من ثلاثة مواضع، بترتيب تناقصي للأولوية (يتم استخدام القيمة الأولى التي يتم العثور عليها):
- لكل
MediaItem
قيمة يتم تمريرها إلىMediaItem.Builder.setLiveConfiguration
. - تم ضبط القيم التلقائية العامة على
DefaultMediaSourceFactory
. - القيم المقروءة مباشرةً من الوسائط
Kotlin
// Global settings. val player = ExoPlayer.Builder(context) .setMediaSourceFactory(DefaultMediaSourceFactory(context).setLiveTargetOffsetMs(5000)) .build() // Per MediaItem settings. val mediaItem = MediaItem.Builder() .setUri(mediaUri) .setLiveConfiguration( MediaItem.LiveConfiguration.Builder().setMaxPlaybackSpeed(1.02f).build() ) .build() player.setMediaItem(mediaItem)
Java
// Global settings. ExoPlayer player = new ExoPlayer.Builder(context) .setMediaSourceFactory( new DefaultMediaSourceFactory(context).setLiveTargetOffsetMs(5000)) .build(); // Per MediaItem settings. MediaItem mediaItem = new MediaItem.Builder() .setUri(mediaUri) .setLiveConfiguration( new MediaItem.LiveConfiguration.Builder().setMaxPlaybackSpeed(1.02f).build()) .build(); player.setMediaItem(mediaItem);
قيم الإعدادات المتاحة هي:
targetOffsetMs
: المدة المستهدَفة التي يتم عرض الإعلان خلالها سيحاول المشغّل الاقتراب من هذه المدة المباشرة أثناء التشغيل إن أمكن.minOffsetMs
: الحد الأدنى المسموح به للوقت المُضاف إلى البث المباشر حتى عند ضبط التأخير وفقًا لظروف الشبكة الحالية، لن يحاول المشغّل خفض هذا التأخير أثناء التشغيل.maxOffsetMs
: الحد الأقصى المسموح به للوقت المُضاف إلى البث المباشر حتى عند ضبط التأخير وفقًا لظروف الشبكة الحالية، لن يحاول المشغّل تجاوز هذا التأخير أثناء التشغيل.-
minPlaybackSpeed
: الحد الأدنى لسرعة التشغيل التي يمكن للمشغّل استخدامها للرجوع إليها عند محاولة الوصول إلى الإزاحة المباشرة المستهدَفة maxPlaybackSpeed
: الحد الأقصى لسرعة التشغيل التي يمكن للمشغّل استخدامها للوصول إلى المحتوى المعروض مباشرةً عند محاولة الوصول إلى مدة البث المباشر المستهدَفة.
ضبط سرعة التشغيل
عند تشغيل بث مباشر بوقت استجابة منخفض، يعدّل ExoPlayer مدة البث المباشر من خلال تغيير سرعة التشغيل قليلاً. سيحاول المشغّل مطابقة القيمة المستهدفة للتأخّر المباشر المقدَّمة من الوسائط أو التطبيق، وسيحاول أيضًا الاستجابة لظروف الشبكة المتغيّرة. على سبيل المثال، إذا حدثت عمليات إعادة تخزين أثناء التشغيل، سيبطئ المشغّل التشغيل قليلاً للابتعاد عن حدود البث المباشر. إذا أصبحت الشبكة مستقرة بما يكفي للسماح بتشغيل المحتوى بشكل أقرب إلى حدود البث المباشر مرة أخرى، سيسرّع المشغّل تشغيل المحتوى للعودة إلى وقت البث المباشر المستهدَف.
إذا لم تكن تريد ضبط سرعة التشغيل تلقائيًا، يمكنك إيقاف هذه الميزة من خلال
ضبط السمتَين minPlaybackSpeed
وmaxPlaybackSpeed
على 1.0f
.
وبالمثل، يمكن تفعيل هذه الميزة لأحداث البث المباشر التي لا تتسم بوقت استجابة منخفض من خلال ضبط هذين المقياسين
بشكل صريح على قيم غير 1.0f
. اطّلِع على
قسم الضبط أعلاه للحصول على
مزيد من التفاصيل حول كيفية ضبط هذه السمات.
تخصيص خوارزمية ضبط سرعة التشغيل
في حال تفعيل ميزة "ضبط السرعة"، يحدِّد LivePlaybackSpeedControl
نوع تعديلات السرعة التي يتم إجراؤها. من الممكن تنفيذ علامة LivePlaybackSpeedControl
مخصّصة، أو تخصيص عملية التنفيذ التلقائية، وهي
DefaultLivePlaybackSpeedControl
. في كلتا الحالتَين، يمكن ضبط مثيل عند
إنشاء المشغّل:
Kotlin
val player = ExoPlayer.Builder(context) .setLivePlaybackSpeedControl( DefaultLivePlaybackSpeedControl.Builder().setFallbackMaxPlaybackSpeed(1.04f).build() ) .build()
Java
ExoPlayer player = new ExoPlayer.Builder(context) .setLivePlaybackSpeedControl( new DefaultLivePlaybackSpeedControl.Builder() .setFallbackMaxPlaybackSpeed(1.04f) .build()) .build();
في ما يلي مَعلمات التخصيص ذات الصلة بـ DefaultLivePlaybackSpeedControl
:
-
fallbackMinPlaybackSpeed
وfallbackMaxPlaybackSpeed
: الحد الأدنى والأقصى لسرعات التشغيل التي يمكن استخدامها للضبط إذا لم تحدّد الوسائط أوMediaItem
المقدَّمة من التطبيق حدودًا. -
proportionalControlFactor
: للتحكّم في سلاسة تعديل السرعة. يؤدي تحديد قيمة عالية إلى إجراء التعديلات بشكل مفاجئ وسريع الاستجابة، ولكن من المرجّح أيضًا أن يُسمع صوتها. تؤدي القيمة الأصغر إلى انتقال أكثر سلاسة بين السرعات، ولكن بتكلفة السرعة الأقل. targetLiveOffsetIncrementOnRebufferMs
: تتم إضافة هذه القيمة إلى قيمة الإزاحة المباشرة المستهدفة عند حدوث إعادة تخزين مؤقت، من أجل المتابعة بحذر أكثر. يمكن إيقاف هذه الميزة من خلال ضبط القيمة على 0.-
minPossibleLiveOffsetSmoothingFactor
: عامل تمويه أسي يتم استخدامه للتتبّع أدنى وقت ممكن للبث المباشر استنادًا إلى الوسائط التي يتم تخزينها مؤقتًا حاليًا. تعني القيمة التي تكون قريبة جدًا من 1 أنّ التقدير أكثر حذرًا وقد يستغرق وقتًا أطول للتكيّف مع ظروف الشبكة المحسّنة، في حين تعني القيمة الأقل أنّه سيتم ضبط التقدير بشكل أسرع مع زيادة مخاطر الاصطدام بمستودعات احتياطية.
BehindLiveWindowException وERROR_CODE_BEHIND_LIVE_WINDOW
وقد يظهر موضع التشغيل خلف نافذة البث المباشر، مثلاً إذا تم إيقاف المشغّل مؤقتًا أو في تخزينه مؤقتًا لفترة زمنية كافية. في هذه الحالة، لن تتمكّن من تشغيل الفيديو، وسيتم الإبلاغ عن استثناء بالرقم التعريفي للخطأ
ERROR_CODE_BEHIND_LIVE_WINDOW
من خلال
Player.Listener.onPlayerError
. قد يتعامل رمز التطبيق مع مثل هذه
الأخطاء من خلال استئناف التشغيل في الموضع التلقائي. يوضح PlayerActivity
للتطبيق التجريبي هذا النهج.
Kotlin
override fun onPlayerError(error: PlaybackException) { if (error.errorCode == PlaybackException.ERROR_CODE_BEHIND_LIVE_WINDOW) { // Re-initialize player at the live edge. player.seekToDefaultPosition() player.prepare() } else { // Handle other errors } }
Java
@Override public void onPlayerError(PlaybackException error) { if (error.errorCode == PlaybackException.ERROR_CODE_BEHIND_LIVE_WINDOW) { // Re-initialize player at the live edge. player.seekToDefaultPosition(); player.prepare(); } else { // Handle other errors } }