گوش دادن به رویدادهای پخش
رویدادهایی مانند تغییر در وضعیت و خطاهای پخش، به نمونه های ثبت شده Player.Listener گزارش می شود. برای ثبت نام شنونده برای دریافت چنین رویدادهایی:
کاتلین
// Add a listener to receive events from the player. player.addListener(listener)
جاوا
// Add a listener to receive events from the player. player.addListener(listener);
Player.Listener متدهای پیشفرض خالی دارد، بنابراین شما فقط باید روشهایی را که به آنها علاقه دارید پیادهسازی کنید. برای توضیح کامل متدها و زمان فراخوانی آنها به Javadoc مراجعه کنید. برخی از مهم ترین روش ها در زیر با جزئیات بیشتر توضیح داده شده است.
شنوندگان میتوانند بین اجرای تماسهای رویداد فردی یا یک فراخوان عمومی onEvents که پس از وقوع یک یا چند رویداد با هم فراخوانی میشوند، انتخاب کنند. برای توضیحی که باید برای موارد استفاده مختلف ترجیح داده شود، به Individual callbacks vs onEvents مراجعه کنید.
وضعیت پخش تغییر می کند
تغییرات در وضعیت پخش کننده را می توان با پیاده سازی onPlaybackStateChanged(@State int state) در یک Player.Listener ثبت شده دریافت کرد. بازیکن می تواند در یکی از چهار حالت پخش باشد:
-
Player.STATE_IDLE: این حالت اولیه است، وضعیت زمانی که پخش کننده متوقف می شود و زمانی که پخش با شکست مواجه می شود. بازیکن فقط منابع محدودی را در این حالت نگه خواهد داشت. -
Player.STATE_BUFFERING: بازیکن نمی تواند بلافاصله از موقعیت فعلی خود بازی کند. این بیشتر به این دلیل اتفاق می افتد که داده های بیشتری باید بارگذاری شوند. -
Player.STATE_READY: بازیکن می تواند بلافاصله از موقعیت فعلی خود بازی کند. -
Player.STATE_ENDED: پخش کننده پخش تمام رسانه ها را به پایان رساند.
علاوه بر این حالت ها، بازیکن دارای یک پرچم playWhenReady برای نشان دادن قصد کاربر برای بازی است. تغییرات در این پرچم را می توان با پیاده سازی onPlayWhenReadyChanged(playWhenReady, @PlayWhenReadyChangeReason int reason) دریافت کرد.
یک بازیکن در حال بازی است (یعنی موقعیت آن در حال پیشرفت است و رسانه در حال ارائه به کاربر است) زمانی که هر سه شرط زیر برآورده شود:
- پخش کننده در وضعیت
Player.STATE_READYاست -
playWhenReadytrueاست - پخش به دلیلی که توسط
Player.getPlaybackSuppressionReasonبازگردانده شده است، متوقف نمی شود
به جای بررسی جداگانه این ویژگی ها، می توان Player.isPlaying را فراخوانی کرد. تغییرات این حالت را می توان با پیاده سازی onIsPlayingChanged(boolean isPlaying) دریافت کرد:
کاتلین
player.addListener( object : Player.Listener { override fun onIsPlayingChanged(isPlaying: Boolean) { if (isPlaying) { // Active playback. } else { // Not playing because playback is paused, ended, suppressed, or the player // is buffering, stopped or failed. Check player.playWhenReady, // player.playbackState, player.playbackSuppressionReason and // player.playerError for details. } } } )
جاوا
player.addListener( new Player.Listener() { @Override public void onIsPlayingChanged(boolean isPlaying) { if (isPlaying) { // Active playback. } else { // Not playing because playback is paused, ended, suppressed, or the player // is buffering, stopped or failed. Check player.getPlayWhenReady, // player.getPlaybackState, player.getPlaybackSuppressionReason and // player.getPlaybackError for details. } } });
خطاهای پخش
خطاهایی که باعث شکست پخش می شوند را می توان با اجرای onPlayerError(PlaybackException error) در یک Player.Listener ثبت شده دریافت کرد. هنگامی که مشکلی رخ می دهد، این روش بلافاصله قبل از انتقال حالت پخش به Player.STATE_IDLE فراخوانی می شود. با فراخوانی ExoPlayer.prepare میتوانید پخشهای ناموفق یا متوقف شده را دوباره امتحان کنید.
توجه داشته باشید که برخی از پیادهسازیهای Player نمونههایی از زیرکلاسهای PlaybackException را برای ارائه اطلاعات اضافی درباره خرابی ارسال میکنند. به عنوان مثال، ExoPlayer ExoPlaybackException را پاس می کند که دارای type ، rendererIndex و سایر فیلدهای خاص ExoPlayer است.
مثال زیر نشان می دهد که چگونه می توان تشخیص داد که یک پخش به دلیل مشکل شبکه HTTP شکست خورده است:
کاتلین
player.addListener( object : Player.Listener { override fun onPlayerError(error: PlaybackException) { val cause = error.cause if (cause is HttpDataSourceException) { // An HTTP error occurred. val httpError = cause // It's possible to find out more about the error both by casting and by querying // the cause. if (httpError is InvalidResponseCodeException) { // Cast to InvalidResponseCodeException and retrieve the response code, message // and headers. } else { // Try calling httpError.getCause() to retrieve the underlying cause, although // note that it may be null. } } } } )
جاوا
player.addListener( new Player.Listener() { @Override public void onPlayerError(PlaybackException error) { @Nullable Throwable cause = error.getCause(); if (cause instanceof HttpDataSourceException) { // An HTTP error occurred. HttpDataSourceException httpError = (HttpDataSourceException) cause; // It's possible to find out more about the error both by casting and by querying // the cause. if (httpError instanceof HttpDataSource.InvalidResponseCodeException) { // Cast to InvalidResponseCodeException and retrieve the response code, message // and headers. } else { // Try calling httpError.getCause() to retrieve the underlying cause, although // note that it may be null. } } } });
انتقال لیست پخش
هر زمان که پخش کننده به یک آیتم رسانه جدید در لیست پخش تغییر کند onMediaItemTransition(MediaItem mediaItem, @MediaItemTransitionReason int reason) روی اشیاء ثبت شده Player.Listener فراخوانی می شود. دلیل نشان میدهد که آیا این یک انتقال خودکار، جستجو (به عنوان مثال پس از فراخوانی player.next() )، تکرار همان آیتم، یا ناشی از تغییر فهرست پخش (مثلاً اگر آیتم در حال پخش فعلی حذف شود) بوده است.
فراداده
ابردادههای بازگرداندهشده از player.getCurrentMediaMetadata() میتوانند به دلایل زیادی تغییر کنند: انتقال فهرست پخش، بهروزرسانیهای فراداده در جریان یا بهروزرسانی MediaItem فعلی در اواسط پخش.
اگر به تغییرات ابرداده علاقه مند هستید، به عنوان مثال برای به روز رسانی رابط کاربری که عنوان فعلی را نشان می دهد، می توانید به onMediaMetadataChanged گوش دهید.
به دنبال
فراخوانی روشهای Player.seekTo منجر به یک سری تماسهای برگشتی به نمونههای ثبتشده Player.Listener میشود:
-
onPositionDiscontinuityباreason=DISCONTINUITY_REASON_SEEK. این نتیجه مستقیم فراخوانیPlayer.seekToاست. پاسخ تماس دارای فیلدهایPositionInfoبرای موقعیت قبل و بعد از جستجو است. -
onPlaybackStateChangedبا هر تغییر وضعیت فوری مربوط به جستجو تغییر کرد. توجه داشته باشید که ممکن است چنین تغییری وجود نداشته باشد.
تماسهای فردی در مقابل onEvents
شنوندگان میتوانند بین اجرای تماسهای فردی مانند onIsPlayingChanged(boolean isPlaying) و پاسخ به تماس عمومی onEvents(Player player, Events events) یکی را انتخاب کنند. فراخوان عمومی دسترسی به شی Player را فراهم می کند و مجموعه events که با هم اتفاق افتاده اند را مشخص می کند. این callback همیشه پس از تماس هایی که با رویدادهای فردی مطابقت دارند فراخوانی می شود.
کاتلین
override fun onEvents(player: Player, events: Player.Events) { if ( events.contains(Player.EVENT_PLAYBACK_STATE_CHANGED) || events.contains(Player.EVENT_PLAY_WHEN_READY_CHANGED) ) { uiModule.updateUi(player) } }
جاوا
@Override public void onEvents(Player player, Events events) { if (events.contains(Player.EVENT_PLAYBACK_STATE_CHANGED) || events.contains(Player.EVENT_PLAY_WHEN_READY_CHANGED)) { uiModule.updateUi(player); } }
رویدادهای فردی باید در موارد زیر ترجیح داده شوند:
- شنونده به دلایل تغییرات علاقه مند است. به عنوان مثال، دلایل ارائه شده برای
onPlayWhenReadyChangedیاonMediaItemTransition. - شنونده فقط بر روی مقادیر جدید ارائه شده از طریق پارامترهای پاسخ به تماس عمل می کند یا چیز دیگری را فعال می کند که به پارامترهای برگشت به تماس بستگی ندارد.
- پیاده سازی شنونده ترجیح می دهد یک نشانه قابل خواندن واضح از آنچه باعث ایجاد رویداد در نام روش شده است.
- شنونده به یک سیستم تحلیلی گزارش می دهد که باید در مورد همه رویدادهای فردی و تغییرات حالت بداند.
کلی onEvents(Player player, Events events) باید در موارد زیر ترجیح داده شود:
- شنونده می خواهد منطق یکسانی را برای چندین رویداد راه اندازی کند. بهعنوان مثال، بهروزرسانی یک رابط کاربری هم برای
onPlaybackStateChangedو همonPlayWhenReadyChanged. - شنونده باید به شی
Playerدسترسی داشته باشد تا رویدادهای بعدی را راه اندازی کند، برای مثال به دنبال انتقال آیتم رسانه ای باشد. - شنونده قصد دارد از مقادیر چندگانه حالتی استفاده کند که از طریق تماس های مجزا با هم یا در ترکیب با روش های
PlayerGetter گزارش می شوند. به عنوان مثال، استفاده ازPlayer.getCurrentWindowIndex()باTimelineارائه شده درonTimelineChangedفقط از طریق پاسخ به تماسonEventsایمن است. - شنونده علاقه مند است که آیا رویدادها به طور منطقی با هم اتفاق افتاده اند یا خیر. به عنوان مثال،
onPlaybackStateChangedبه دلیل انتقال آیتم رسانه بهSTATE_BUFFERINGتغییر کرد.
در برخی موارد، شنوندگان ممکن است نیاز داشته باشند که تماسهای فردی را با تماس کلی onEvents ترکیب کنند، به عنوان مثال برای ضبط دلایل تغییر آیتم رسانه با onMediaItemTransition ، اما فقط زمانی اقدام کنند که بتوان از همه تغییرات حالت با هم در onEvents استفاده کرد.
با استفاده از AnalyticsListener
هنگام استفاده از ExoPlayer ، یک AnalyticsListener را می توان با فراخوانی addAnalyticsListener در پخش کننده ثبت کرد. پیاده سازی AnalyticsListener قادر به گوش دادن به رویدادهای دقیق است که ممکن است برای اهداف تجزیه و تحلیل و گزارش گیری مفید باشد. لطفا برای جزئیات بیشتر به صفحه تجزیه و تحلیل مراجعه کنید.
با استفاده از EventLogger
EventLogger یک AnalyticsListener است که مستقیماً توسط کتابخانه برای اهداف ورود به سیستم ارائه می شود. EventLogger را به ExoPlayer اضافه کنید تا با یک خط لاگ اضافی مفید را فعال کنید:
کاتلین
player.addAnalyticsListener(EventLogger())
جاوا
player.addAnalyticsListener(new EventLogger());
برای جزئیات بیشتر به صفحه ثبت اشکال زدایی مراجعه کنید.
شلیک رویدادها در موقعیت های پخش مشخص شده
برخی از موارد استفاده به رویدادهای شلیک در موقعیت های پخش مشخص شده نیاز دارند. این با استفاده از PlayerMessage پشتیبانی می شود. یک PlayerMessage می توان با استفاده از ExoPlayer.createMessage ایجاد کرد. موقعیت پخشی که باید در آن اجرا شود را می توان با استفاده از PlayerMessage.setPosition تنظیم کرد. پیامها بهطور پیشفرض در رشته پخش اجرا میشوند، اما میتوان آن را با استفاده از PlayerMessage.setLooper سفارشی کرد. PlayerMessage.setDeleteAfterDelivery را می توان برای کنترل اینکه آیا هر بار با موقعیت پخش مشخص شده مواجه می شود (این ممکن است چندین بار به دلیل حالت های جستجو و تکرار اتفاق بیفتد) یا فقط برای اولین بار، اجرا شود یا خیر استفاده شود. هنگامی که PlayerMessage پیکربندی شد، می توان آن را با استفاده از PlayerMessage.send برنامه ریزی کرد.
کاتلین
player .createMessage { messageType: Int, payload: Any? -> } .setLooper(Looper.getMainLooper()) .setPosition(/* mediaItemIndex= */ 0, /* positionMs= */ 120000) .setPayload(customPayloadData) .setDeleteAfterDelivery(false) .send()
جاوا
player .createMessage( (messageType, payload) -> { // Do something at the specified playback position. }) .setLooper(Looper.getMainLooper()) .setPosition(/* mediaItemIndex= */ 0, /* positionMs= */ 120_000) .setPayload(customPayloadData) .setDeleteAfterDelivery(false) .send();