يشغّل ExoPlayer معظم أحداث البث المباشر التكيُّفية بدون أي إعدادات خاصة. لمزيد من التفاصيل، يُرجى الاطّلاع على صفحة التنسيقات المتوافقة.
توفّر أحداث البث المباشر التكيُّفية نافذة للوسائط المتاحة التي يتم تعديلها على فترات منتظمة لتتماشى مع الوقت الفعلي الحالي. وهذا يعني أنّ موضع التشغيل سيكون دائمًا في مكان ما في هذه النافذة، وفي معظم الحالات يكون قريبًا من الوقت الفعلي الحالي الذي يتم فيه إنتاج البث. يُعرف الفرق بين الوقت الفعلي الحالي وموضع التشغيل باسم الإزاحة المباشرة.
رصد عمليات التشغيل المباشرة ومراقبتها
في كل مرة يتم فيها تعديل نافذة بث مباشر، ستتلقّى مثيلات 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إلى الوقت المنقضي منذ بداية حقبة يونكس الذي تبدأ فيه نافذة البث المباشر. -
Window.getCurrentUnixTimeMsهو الوقت المنقضي منذ بداية حقبة يونكس للوقت الفعلي الحالي. يمكن تصحيح هذه القيمة من خلال فرق معروف في الساعة بين الخادم والعميل. -
Window.getDefaultPositionMsهو الموضع في النافذة المباشرة الذي سيبدأ المشغّل منه التشغيل تلقائيًا.
- يحتوي
التقديم السريع أو الترجيع في أحداث البث المباشر
يمكنك الانتقال إلى أي مكان في النافذة المباشرة باستخدام Player.seekTo. ويكون موضع البحث الذي تم تمريره مرتبطًا ببداية نافذة البث المباشر. على سبيل المثال،
سيؤدي استخدام seekTo(0) إلى الانتقال إلى بداية نافذة البث المباشر. سيحاول المشغّل الحفاظ على الإزاحة المباشرة نفسها التي تم البحث عنها بعد عملية البحث.
تحتوي نافذة البث المباشر أيضًا على موضع تلقائي من المفترض أن يبدأ التشغيل منه. ويكون هذا الموضع عادةً قريبًا من نقطة البث المباشر. يمكنك الانتقال إلى الموضع التلقائي
من خلال استدعاء Player.seekToDefaultPosition.
واجهة مستخدم تشغيل البث المباشر
تعرض مكوّنات واجهة المستخدم التلقائية في ExoPlayer مدة نافذة البث المباشر وموضع التشغيل الحالي ضمنها. وهذا يعني أنّ الموضع يبدو وكأنّه يقفز
للخلف في كل مرة يتم فيها تعديل النافذة المباشرة. إذا كنت بحاجة إلى سلوك مختلف،
مثل عرض وقت حقبة يونكس أو الإزاحة المباشرة الحالية، يمكنك إنشاء نسخة من
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 } }