با استفاده از Media3 ExoPlayer یک برنامه پخش کننده رسانه اولیه ایجاد کنید

Jetpack Media3 یک رابط Player تعریف می کند که عملکردهای اساسی برای پخش فایل های ویدیویی و صوتی را مشخص می کند. ExoPlayer پیاده سازی پیش فرض این رابط در Media3 است. توصیه می‌کنیم از ExoPlayer استفاده کنید، زیرا مجموعه‌ای جامع از ویژگی‌ها را ارائه می‌کند که بیشتر موارد استفاده پخش را پوشش می‌دهد و برای رسیدگی به موارد استفاده اضافی که ممکن است داشته باشید، قابل تنظیم است. ExoPlayer همچنین قطعه قطعه شدن دستگاه و سیستم عامل را انتزاعی می کند تا کد شما به طور مداوم در کل اکوسیستم اندروید کار کند. ExoPlayer شامل:

این صفحه شما را از طریق برخی از مراحل کلیدی ساخت یک برنامه پخش راهنمایی می کند و برای جزئیات بیشتر می توانید به راهنمای کامل ما در Media3 ExoPlayer مراجعه کنید.

شروع کردن

برای شروع، یک وابستگی به ExoPlayer، UI و ماژول های مشترک Jetpack Media3 اضافه کنید:

implementation "androidx.media3:media3-exoplayer:1.4.1"
implementation "androidx.media3:media3-ui:1.4.1"
implementation "androidx.media3:media3-common:1.4.1"

بسته به مورد استفاده شما، ممکن است به ماژول های اضافی از Media3 نیز نیاز داشته باشید، مانند exoplayer-dash برای پخش جریانی در قالب DASH.

مطمئن شوید که 1.4.1 با نسخه دلخواه خود از کتابخانه جایگزین کنید. برای مشاهده آخرین نسخه می توانید به یادداشت های انتشار مراجعه کنید.

ایجاد یک پخش کننده رسانه

با Media3، می توانید از پیاده سازی موجود در رابط Player ، ExoPlayer استفاده کنید، یا می توانید پیاده سازی سفارشی خود را بسازید.

ساخت ExoPlayer

ساده ترین راه برای ایجاد یک نمونه ExoPlayer به شرح زیر است:

کاتلین

val player = ExoPlayer.Builder(context).build()

جاوا

ExoPlayer player = new ExoPlayer.Builder(context).build();

می‌توانید پخش‌کننده رسانه خود را در روش چرخه حیات onCreate() در Activity ، Fragment یا Service که در آن زندگی می‌کند ایجاد کنید.

Builder شامل طیف وسیعی از گزینه های سفارشی سازی است که ممکن است به آنها علاقه مند باشید، مانند:

Media3 یک مؤلفه رابط کاربری PlayerView را ارائه می دهد که می توانید آن را در فایل طرح بندی برنامه خود قرار دهید. این کامپوننت یک PlayerControlView برای کنترل‌های پخش، SubtitleView برای نمایش زیرنویس‌ها و Surface برای رندر کردن ویدیو را در خود جای داده است.

آماده سازی بازیکن

با روش هایی مانند setMediaItem() و addMediaItem() آیتم های رسانه ای را برای پخش به لیست پخش اضافه کنید. سپس، برای شروع بارگذاری رسانه و به دست آوردن منابع لازم، prepare() را فراخوانی کنید.

شما نباید این مراحل را قبل از قرار گرفتن برنامه در پیش زمینه انجام دهید. اگر پخش کننده شما در یک Activity یا Fragment باشد، این به معنای آماده سازی پخش کننده در روش چرخه حیات onStart() در سطح API 24 و بالاتر یا روش چرخه حیات onResume() در سطح API 23 و پایین تر است. برای پخش کننده ای که در یک Service است، می توانید آن را در onCreate() آماده کنید.

پخش کننده را کنترل کنید

پس از آماده شدن پخش کننده، می توانید با فراخوانی روش هایی روی پخش کننده مانند:

مؤلفه‌های رابط کاربری مانند PlayerView یا PlayerControlView در صورت اتصال به پخش‌کننده، بر این اساس به‌روزرسانی می‌شوند.

پخش کننده را رها کنید

پخش می‌تواند به منابع محدودی مانند رمزگشای ویدیو نیاز داشته باشد، بنابراین مهم است که release() در پخش‌کننده خود فراخوانی کنید تا زمانی که دیگر به پخش‌کننده نیازی ندارید، منابع را آزاد کنید.

اگر پخش کننده شما در یک Activity یا Fragment است، پخش کننده را در روش چرخه حیات onStop() در سطح API 24 و بالاتر یا روش onPause() در سطح API 23 و پایین تر رها کنید. برای بازیکنی که در یک Service است، می توانید آن را در onDestroy() منتشر کنید.

مدیریت پخش با یک جلسه رسانه

در Android، جلسات رسانه راهی استاندارد شده برای تعامل با یک پخش کننده رسانه در سراسر مرزهای فرآیند ارائه می دهد. اتصال یک جلسه رسانه به پخش کننده به شما امکان می دهد پخش رسانه خود را به صورت خارجی تبلیغ کنید و دستورات پخش را از منابع خارجی دریافت کنید، به عنوان مثال برای ادغام با کنترل های رسانه سیستم در دستگاه های تلفن همراه و صفحه بزرگ.

برای استفاده از جلسات رسانه، یک وابستگی به ماژول Media3 Session اضافه کنید:

implementation "androidx.media3:media3-session:1.4.1"

یک جلسه رسانه ای ایجاد کنید

شما می توانید پس از مقداردهی اولیه پخش کننده به صورت زیر یک MediaSession ایجاد کنید:

کاتلین

val player = ExoPlayer.Builder(context).build()
val mediaSession = MediaSession.Builder(context, player).build()

جاوا

ExoPlayer player = new ExoPlayer.Builder(context).build();
MediaSession mediaSession = new MediaSession.Builder(context, player).build();

Media3 به طور خودکار وضعیت Player را با وضعیت MediaSession همگام می کند. این با هر پیاده سازی Player ، از جمله ExoPlayer ، CastPlayer ، یا یک پیاده سازی سفارشی کار می کند.

اعطای کنترل به سایر مشتریان

برنامه های سرویس گیرنده می توانند یک کنترلر رسانه برای کنترل پخش جلسه رسانه شما پیاده سازی کنند. برای دریافت این درخواست‌ها، هنگام ساخت MediaSession یک شیء برگشتی تنظیم کنید.

هنگامی که یک کنترلر می خواهد به جلسه رسانه شما متصل شود، متد onConnect() فراخوانی می شود. می توانید از ControllerInfo ارائه شده برای تصمیم گیری در مورد پذیرش یا رد درخواست استفاده کنید. نمونه ای از این را در برنامه نمایشی Media3 Session ببینید.

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

سایر روش‌های پاسخ به تماس به شما این امکان را می‌دهند که به عنوان مثال، درخواست‌های دستورات پخش سفارشی و اصلاح فهرست پخش را مدیریت کنید. این تماس‌های برگشتی به طور مشابه شامل یک شی ControllerInfo هستند تا بتوانید کنترل دسترسی را بر اساس درخواست به درخواست تعیین کنید.

پخش رسانه در پس زمینه

برای ادامه پخش رسانه زمانی که برنامه شما در پیش زمینه نیست، به عنوان مثال برای پخش موسیقی، کتاب های صوتی یا پادکست، حتی زمانی که کاربر برنامه شما را باز نکرده است، Player و MediaSession شما باید در یک سرویس پیش زمینه محصور شوند. Media3 رابط MediaSessionService را برای این منظور فراهم می کند.

پیاده سازی MediaSessionService

کلاسی ایجاد کنید که MediaSessionService را گسترش دهد و MediaSession شما را در متد چرخه حیات onCreate() نمونه سازی کنید.

کاتلین

class PlaybackService : MediaSessionService() {
    private var mediaSession: MediaSession? = null

    // Create your Player and MediaSession in the onCreate lifecycle event
    override fun onCreate() {
        super.onCreate()
        val player = ExoPlayer.Builder(this).build()
        mediaSession = MediaSession.Builder(this, player).build()
    }

    // Remember to release the player and media session in onDestroy
    override fun onDestroy() {
        mediaSession?.run {
            player.release()
            release()
            mediaSession = null
        }
        super.onDestroy()
    }
}

جاوا

public class PlaybackService extends MediaSessionService {
    private MediaSession mediaSession = null;

    @Override
    public void onCreate() {
        super.onCreate();
        ExoPlayer player = new ExoPlayer.Builder(this).build();
        mediaSession = new MediaSession.Builder(this, player).build();
    }

    @Override
    public void onDestroy() {
        mediaSession.getPlayer().release();
        mediaSession.release();
        mediaSession = null;
        super.onDestroy();
    }
}

در مانیفست شما، کلاس Service شما با هدف MediaSessionService فیلتر شده و اجازه FOREGROUND_SERVICE را برای اجرای یک سرویس پیش زمینه درخواست کنید:

<service
    android:name=".PlaybackService"
    android:foregroundServiceType="mediaPlayback"
    android:exported="true">
    <intent-filter>
        <action android:name="androidx.media3.session.MediaSessionService"/>
    </intent-filter>
</service>

<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

در نهایت، در کلاسی که ایجاد کردید، متد onGetSession() را برای کنترل دسترسی مشتری به جلسه رسانه خود لغو کنید. برای پذیرش درخواست اتصال، MediaSession را برگردانید یا برای رد درخواست، null برگردانید.

کاتلین

// This example always accepts the connection request
override fun onGetSession(
    controllerInfo: MediaSession.ControllerInfo
): MediaSession? = mediaSession

جاوا

@Override
public MediaSession onGetSession(MediaSession.ControllerInfo controllerInfo) {
  // This example always accepts the connection request
  return mediaSession;
}

در حال اتصال به UI شما

اکنون که جلسه رسانه شما در Service جدا از Activity یا Fragment است که رابط کاربری پخش کننده شما در آن زندگی می کند، می توانید از MediaController برای پیوند دادن آنها به یکدیگر استفاده کنید. در متد onStart() از Activity یا Fragment با رابط کاربری خود، یک SessionToken برای MediaSession خود ایجاد کنید، سپس از SessionToken برای ساخت MediaController استفاده کنید. ساخت MediaController به صورت ناهمزمان اتفاق می افتد.

کاتلین

override fun onStart() {
  val sessionToken = SessionToken(this, ComponentName(this, PlaybackService::class.java))
  val controllerFuture = MediaController.Builder(this, sessionToken).buildAsync()
  controllerFuture.addListener(
    {
        // Call controllerFuture.get() to retrieve the MediaController.
        // MediaController implements the Player interface, so it can be
        // attached to the PlayerView UI component.
        playerView.setPlayer(controllerFuture.get())
      },
    MoreExecutors.directExecutor()
  )
}

جاوا

@Override
public void onStart() {
  SessionToken sessionToken =
    new SessionToken(this, new ComponentName(this, PlaybackService.class));
  ListenableFuture<MediaController> controllerFuture =
    new MediaController.Builder(this, sessionToken).buildAsync();
  controllerFuture.addListener(() -> {
    // Call controllerFuture.get() to retrieve the MediaController.
    // MediaController implements the Player interface, so it can be
    // attached to the PlayerView UI component.
    playerView.setPlayer(controllerFuture.get());
  }, MoreExecutors.directExecutor())
}

MediaController رابط Player را پیاده سازی می کند، بنابراین می توانید از روش های مشابهی مانند play() و pause() برای کنترل پخش استفاده کنید. مشابه سایر مؤلفه‌ها، به یاد داشته باشید که MediaController را زمانی که دیگر مورد نیاز نیست، مانند متد چرخه حیات onStop() یک Activity ، با فراخوانی MediaController.releaseFuture() آزاد کنید.

انتشار اطلاعیه

خدمات پیش زمینه برای انتشار اعلان در حین فعال بودن الزامی است. یک MediaSessionService به طور خودکار یک اعلان MediaStyle را در قالب MediaNotification برای شما ایجاد می کند. برای ارائه یک اعلان سفارشی، یک MediaNotification.Provider با DefaultMediaNotificationProvider.Builder یا با ایجاد یک پیاده سازی سفارشی از رابط ارائه دهنده ایجاد کنید. ارائه دهنده خود را با setMediaNotificationProvider به MediaSession خود اضافه کنید.

کتابخانه محتوای خود را تبلیغ کنید

MediaLibraryService بر روی MediaSessionService ایجاد می‌شود و به برنامه‌های مشتری اجازه می‌دهد محتوای رسانه‌ای ارائه شده توسط برنامه شما را مرور کنند. برنامه های سرویس گیرنده یک MediaBrowser برای تعامل با MediaLibraryService شما پیاده سازی می کنند.

پیاده‌سازی MediaLibraryService شبیه اجرای MediaSessionService است، با این تفاوت که در onGetSession() باید یک MediaLibrarySession به جای MediaSession برگردانید. در مقایسه با MediaSession.Callback ، MediaLibrarySession.Callback شامل روش‌های دیگری است که به مشتری مرورگر اجازه می‌دهد محتوای ارائه شده توسط سرویس کتابخانه شما را پیمایش کند.

مشابه MediaSessionService ، MediaLibraryService در مانیفست خود اعلام کنید و مجوز FOREGROUND_SERVICE را برای اجرای یک سرویس پیش زمینه درخواست کنید:

<service
    android:name=".PlaybackService"
    android:foregroundServiceType="mediaPlayback"
    android:exported="true">
    <intent-filter>
        <action android:name="androidx.media3.session.MediaLibraryService"/>
        <action android:name="android.media.browse.MediaBrowserService"/>
    </intent-filter>
</service>

<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

مثال بالا شامل یک فیلتر هدف هم برای MediaLibraryService و هم برای سازگاری با گذشته، MediaBrowserService قدیمی است. فیلتر قصد اضافی به برنامه های سرویس گیرنده با استفاده از MediaBrowserCompat API قادر می سازد تا Service شما را شناسایی کنند.

MediaLibrarySession به شما امکان می دهد کتابخانه محتوای خود را در یک ساختار درختی، با یک MediaItem ریشه واحد ارائه دهید. هر MediaItem در درخت می تواند هر تعداد گره MediaItem فرزند داشته باشد. بر اساس درخواست برنامه مشتری، می‌توانید ریشه یا درخت متفاوتی را ارائه دهید. به عنوان مثال، درختی که به مشتری برمی‌گردانید و به دنبال فهرستی از آیتم‌های رسانه توصیه‌شده است، ممکن است فقط حاوی ریشه MediaItem و یک سطح از گره‌های MediaItem فرزند باشد، در حالی که درختی که به یک برنامه مشتری دیگر برمی‌گردانید ممکن است یک کتابخانه کامل‌تر از آن را نشان دهد. محتوا

ایجاد MediaLibrarySession

MediaLibrarySession API MediaSession را برای افزودن APIهای مرور محتوا گسترش می دهد. در مقایسه با فراخوان MediaSession ، MediaLibrarySession متدهایی مانند:

  • onGetLibraryRoot() برای زمانی که یک کلاینت، MediaItem ریشه درخت محتوا را درخواست می کند
  • onGetChildren() برای زمانی که مشتری از فرزندان یک MediaItem در درخت محتوا درخواست می کند
  • onGetSearchResult() برای زمانی که یک کلاینت نتایج جستجو را از درخت محتوا برای یک پرس و جو داده شده درخواست می کند.

روش‌های برگشت تماس مربوطه شامل یک شی LibraryParams با سیگنال‌های اضافی در مورد نوع درخت محتوایی است که برنامه مشتری به آن علاقه دارد.