فهرست‌های پخش

میانای برنامه‌سازی کاربردی فهرست پخش توسط رابط Player تعریف می‌شود که توسط همه پیاده‌سازی‌های ExoPlayer پیاده‌سازی می‌شود. فهرست‌های پخش امکان پخش متوالی چندین مورد رسانه‌ای را فراهم می‌کنند. مثال زیر نحوه شروع بازپخش یک فهرست پخش حاوی دو ویدیو را نشان می‌دهد:

کاتلین

// Build the media items.
val firstItem = MediaItem.fromUri(firstVideoUri)
val secondItem = MediaItem.fromUri(secondVideoUri)
// Add the media items to be played.
player.addMediaItem(firstItem)
player.addMediaItem(secondItem)
// Prepare the player.
player.prepare()
// Start the playback.
player.play()

جاوا

// Build the media items.
MediaItem firstItem = MediaItem.fromUri(firstVideoUri);
MediaItem secondItem = MediaItem.fromUri(secondVideoUri);
// Add the media items to be played.
player.addMediaItem(firstItem);
player.addMediaItem(secondItem);
// Prepare the player.
player.prepare();
// Start the playback.
player.play();

گذار بین موارد در فهرست پخش یکپارچه است. هیچ الزامی وجود ندارد که آن‌ها از یک قالب باشند (برای مثال، فهرست پخش می‌تواند شامل ویدیوهای H264 و VP9 باشد). حتی ممکن است از انواع مختلف باشند (یعنی، مشکلی ندارد که یک فهرست پخش شامل ویدیوها، تصاویر، و جاری‌سازی‌های فقط صوتی باشد). می‌توانید از همان MediaItem چندین بار در یک فهرست پخش استفاده کنید.

درحال تغییر دادن فهرست پخش

می‌توانید با افزودن، جابه‌جا کردن، برداشتن، یا جایگزین کردن عناصر رسانه‌ای، فهرست پخش را به‌صورت پویا تغییر دهید. این کار را می‌توان هم قبل و هم درحین پخش با فراخوانی روش‌های API فهرست پخش مربوطه انجام داد:

کاتلین

// Adds a media item at position 1 in the playlist.
player.addMediaItem(/* index= */ 1, MediaItem.fromUri(thirdUri))
// Moves the third media item from position 2 to the start of the playlist.
player.moveMediaItem(/* currentIndex= */ 2, /* newIndex= */ 0)
// Removes the first item from the playlist.
player.removeMediaItem(/* index= */ 0)
// Replace the second item in the playlist.
player.replaceMediaItem(/* index= */ 1, MediaItem.fromUri(newUri))

جاوا

// Adds a media item at position 1 in the playlist.
player.addMediaItem(/* index= */ 1, MediaItem.fromUri(thirdUri));
// Moves the third media item from position 2 to the start of the playlist.
player.moveMediaItem(/* currentIndex= */ 2, /* newIndex= */ 0);
// Removes the first item from the playlist.
player.removeMediaItem(/* index= */ 0);
// Replace the second item in the playlist.
player.replaceMediaItem(/* index= */ 1, MediaItem.fromUri(newUri));

جایگزینی و پاک کردن کل فهرست پخش نیز پشتیبانی می‌شود:

کاتلین

// Replaces the playlist with a new one.
val newItems: List<MediaItem> =
  listOf(MediaItem.fromUri(fourthUri), MediaItem.fromUri(fifthUri))
player.setMediaItems(newItems, /* resetPosition= */ true)
// Clears the playlist. If prepared, the player transitions to the ended state.
player.clearMediaItems()

جاوا

// Replaces the playlist with a new one.
ImmutableList<MediaItem> newItems =
    ImmutableList.of(MediaItem.fromUri(fourthUri), MediaItem.fromUri(fifthUri));
player.setMediaItems(newItems, /* resetPosition= */ true);
// Clears the playlist. If prepared, the player transitions to the ended state.
player.clearMediaItems();

پخش‌کننده به‌طور خودکار تغییرات را درحین پخش به روش صحیح مدیریت می‌کند:

  • اگر MediaItem درحال پخش جابه‌جا شود، بازپخش قطع نمی‌شود و پس‌از تکمیل، جانشین جدید آن پخش خواهد شد.
  • اگر MediaItem درحال پخش برداشته شود، پخش‌کننده به‌طور خودکار اولین جانشین باقی‌مانده را پخش می‌کند یا اگر چنین جانشینی وجود نداشته باشد، به حالت پایان‌یافته منتقل می‌شود.
  • اگر MediaItem درحال پخش فعلی جایگزین شود، بازپخش قطع نمی‌شود اگر هیچ‌یک از ویژگی‌های MediaItem مربوط به بازپخش تغییر نکرده باشد. برای مثال، در اکثر موارد می‌توان MediaItem.MediaMetadata فیلدها را بدون تأثیر بر بازپخش به‌روزرسانی کرد.

درحال پُرسمان فهرست پخش

فهرست پخش را می‌توان بااستفاده از Player.getMediaItemCount و Player.getMediaItemAt پُرسمان کرد. با فراخوانی Player.getCurrentMediaItem می‌توانید مورد رسانه‌ای درحال پخش را پُرسمان کنید. روش‌های راحت دیگری مانند Player.hasNextMediaItem یا Player.getNextMediaItemIndex نیز برای ساده کردن ناوبری در فهرست پخش وجود دارد.

حالت‌های تکرار

بازیکن از ۳ حالت تکرار پشتیبانی می‌کند که در هر زمان با Player.setRepeatMode قابل تنظیم است:

  • Player.REPEAT_MODE_OFF: فهرست پخش تکرار نمی‌شود و پس‌از پخش آخرین مورد در فهرست پخش، پخش‌کننده به Player.STATE_ENDED منتقل می‌شود.
  • ‫Player.REPEAT_MODE_ONE: مورد فعلی در یک حلقه بی‌پایان تکرار می‌شود. روش‌هایی مثل Player.seekToNextMediaItem این را نادیده می‌گیرند و به‌دنبال مورد بعدی در فهرست می‌گردند، که سپس در یک حلقه بی‌نهایت تکرار می‌شود.
  • Player.REPEAT_MODE_ALL: کل فهرست پخش در یک حلقه بی‌پایان تکرار می‌شود.

حالت پخش درهم

هرزمان بخواهید می‌توانید حالت پخش درهم را با Player.setShuffleModeEnabled فعال یا غیرفعال کنید. وقتی در حالت درهم‌سازی هستید، پخش‌کننده فهرست پخش را به‌ترتیب تصادفی ازپیش محاسبه‌شده پخش می‌کند. همه موارد یک‌بار پخش خواهند شد و حالت درهم‌سازی را می‌توان با Player.REPEAT_MODE_ALL ترکیب کرد تا همان ترتیب تصادفی در یک حلقه بی‌نهایت تکرار شود. وقتی حالت مختلط خاموش باشد، بازپخش از مورد فعلی در موقعیت اصلی آن در فهرست پخش ادامه می‌یابد.

توجه داشته باشید که شاخص‌های برگشت‌داده‌شده توسط روش‌هایی مانند Player.getCurrentMediaItemIndex همیشه به ترتیب اصلی و بدون درهم‌آمیزی اشاره دارند. به‌همین ترتیب، Player.seekToNextMediaItem مورد را در player.getCurrentMediaItemIndex() + 1 پخش نخواهد کرد، بلکه مورد بعدی را براساس ترتیب درهم پخش خواهد کرد. درج موارد جدید در فهرست پخش یا برداشتن موارد تا حد امکان ترتیب درهم موجود را بدون تغییر نگه می‌دارد.

تنظیم ترتیب درهم‌سازی سفارشی

به‌طور پیش‌فرض، پخش‌کننده از درهم کردن بااستفاده از DefaultShuffleOrder پشتیبانی می‌کند. این مورد را می‌توان با ارائه یک پیاده‌سازی ترتیب درهم‌سازی سفارشی، یا با تنظیم یک ترتیب سفارشی در سازنده DefaultShuffleOrder سفارشی‌سازی کرد:

کاتلین

// Set a custom shuffle order for the 5 items currently in the playlist:
exoPlayer.setShuffleOrder(DefaultShuffleOrder(intArrayOf(3, 1, 0, 4, 2), randomSeed))
// Enable shuffle mode.
exoPlayer.shuffleModeEnabled = true

جاوا

// Set a custom shuffle order for the 5 items currently in the playlist:
exoPlayer.setShuffleOrder(new DefaultShuffleOrder(new int[] {3, 1, 0, 4, 2}, randomSeed));
// Enable shuffle mode.
exoPlayer.setShuffleModeEnabled(/* shuffleModeEnabled= */ true);

درحال شناسایی موارد فهرست پخش

برای شناسایی عناصر فهرست پخش، هنگام ساختن عنصر، MediaItem.mediaId را می‌توان تنظیم کرد:

کاتلین

// Build a media item with a media ID.
val mediaItem = MediaItem.Builder().setUri(uri).setMediaId(mediaId).build()

جاوا

// Build a media item with a media ID.
MediaItem mediaItem = new MediaItem.Builder().setUri(uri).setMediaId(mediaId).build();

اگر برنامه‌ای به‌طور صریح شناسه رسانه‌ای برای عنصر رسانه‌ای تعریف نکند، از نمایش رشته‌ای نشانی وب استفاده می‌شود.

مرتبط کردن داده‌های برنامه با موارد فهرست پخش

علاوه‌بر شناسه، هر عنصر رسانه‌ای را می‌توان با برچسب سفارشی نیز پیکربندی کرد، که می‌تواند هر شیء ارائه‌شده توسط برنامه باشد. یکی از کاربردهای برچسب‌های سفارشی، پیوست کردن فراداده به هر عنصر رسانه‌ای است:

کاتلین

// Build a media item with a custom tag.
val mediaItem = MediaItem.Builder().setUri(uri).setTag(metadata).build()

جاوا

// Build a media item with a custom tag.
MediaItem mediaItem = new MediaItem.Builder().setUri(uri).setTag(metadata).build();

تشخیص زمانی که بازپخش به یک مورد رسانه‌ای دیگر منتقل می‌شود

وقتی بازپخش به یک مورد رسانه‌ای دیگر منتقل می‌شود، یا همان مورد رسانه‌ای شروع به تکرار می‌کند، Listener.onMediaItemTransition(MediaItem, @MediaItemTransitionReason) فراخوانده می‌شود. این برگشتی مورد رسانه‌ای جدید را به‌همراه @MediaItemTransitionReason که نشان می‌دهد چرا انتقال رخ داده است دریافت می‌کند. یک مورد استفاده رایج برای onMediaItemTransition به‌روزرسانی رابط کاربری برنامه برای عنصر رسانه‌ای جدید است:

کاتلین

override fun onMediaItemTransition(
  mediaItem: MediaItem?,
  @MediaItemTransitionReason reason: Int,
) {
  updateUiForPlayingMediaItem(mediaItem)
}

جاوا

@Override
public void onMediaItemTransition(
    @Nullable MediaItem mediaItem, @MediaItemTransitionReason int reason) {
  updateUiForPlayingMediaItem(mediaItem);
}

اگر فراداده موردنیاز برای به‌روزرسانی واسط کاربر بااستفاده از برچسب‌های سفارشی به هر عنصر رسانه‌ای پیوست شده باشد، پیاده‌سازی ممکن است به این شکل باشد:

کاتلین

override fun onMediaItemTransition(
  mediaItem: MediaItem?,
  @MediaItemTransitionReason reason: Int,
) {
  var metadata: CustomMetadata? = null
  mediaItem?.localConfiguration?.let { localConfiguration ->
    metadata = localConfiguration.tag as? CustomMetadata
  }
  updateUiForPlayingMediaItem(metadata)
}

جاوا

@Override
public void onMediaItemTransition(
    @Nullable MediaItem mediaItem, @MediaItemTransitionReason int reason) {
  @Nullable CustomMetadata metadata = null;
  if (mediaItem != null && mediaItem.localConfiguration != null) {
    metadata = (CustomMetadata) mediaItem.localConfiguration.tag;
  }
  updateUiForPlayingMediaItem(metadata);
}

درحال تشخیص تغییر فهرست پخش

وقتی یک مورد رسانه‌ای اضافه، حذف، یا منتقل می‌شود، Listener.onTimelineChanged(Timeline, @TimelineChangeReason) بلافاصله با TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED فراخوانده می‌شود. این برگشتی حتی زمانی که پخش‌کننده هنوز آماده نشده است، فراخوانی می‌شود.

کاتلین

override fun onTimelineChanged(timeline: Timeline, @TimelineChangeReason reason: Int) {
  if (reason == Player.TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED) {
    // Update the UI according to the modified playlist (add, move or remove).
    updateUiForPlaylist(timeline)
  }
}

جاوا

@Override
public void onTimelineChanged(Timeline timeline, @TimelineChangeReason int reason) {
  if (reason == TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED) {
    // Update the UI according to the modified playlist (add, move or remove).
    updateUiForPlaylist(timeline);
  }
}

وقتی اطلاعاتی مثل مدت زمان یک عنصر رسانه‌ای در فهرست پخش دردسترس قرار می‌گیرد، Timeline به‌روزرسانی می‌شود و onTimelineChanged با TIMELINE_CHANGE_REASON_SOURCE_UPDATE فراخوانی می‌شود. دلایل دیگری که می‌تواند باعث به‌روزرسانی خط زمان شود عبارت‌اند از:

  • مانیفستی که پس‌از آماده‌سازی عنصر رسانه‌ای تطبیقی دردسترس قرار می‌گیرد.
  • مانیفستی که به‌صورت دوره‌ای درطول پخش جاری‌سازی زنده به‌روزرسانی می‌شود.