گوش دادن به رویدادهای پخش
رویدادهایی مانند تغییر در وضعیت و خطاهای پخش، به نمونه های ثبت شده 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
است -
playWhenReady
true
است - پخش به دلیلی که توسط
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
دسترسی داشته باشد تا رویدادهای بعدی را راه اندازی کند، برای مثال به دنبال انتقال آیتم رسانه ای باشد. - شنونده قصد دارد از مقادیر چندگانه حالتی استفاده کند که از طریق تماس های مجزا با هم یا در ترکیب با روش های
Player
Getter گزارش می شوند. به عنوان مثال، استفاده از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();