Tạo một ứng dụng trình phát nội dung đa phương tiện cơ bản bằng Media3 ExoPlayer

Jetpack Media3 xác định giao diện Player nêu ra chức năng cơ bản để phát tệp video và âm thanh. ExoPlayer là cách triển khai mặc định của giao diện này trong Media3. Bạn nên sử dụng ExoPlayer vì nó cung cấp một bộ tính năng toàn diện bao gồm hầu hết các trường hợp sử dụng phát và có thể tuỳ chỉnh để xử lý mọi trường hợp sử dụng bổ sung mà bạn có thể có. ExoPlayer cũng trừu tượng hoá sự phân mảnh của thiết bị và hệ điều hành để mã của bạn hoạt động nhất quán trên toàn bộ hệ sinh thái Android. ExoPlayer bao gồm:

  • Hỗ trợ danh sách phát
  • Hỗ trợ nhiều định dạng phát trực tuyến thích ứng và tiến bộ formats
  • Hỗ trợ chèn quảng cáo ở cả phía máy khách và phía máy chủ ad insertion
  • Hỗ trợ phát nội dung được bảo vệ bằng DRM

Trang này hướng dẫn bạn một số bước chính trong việc xây dựng ứng dụng phát . Để biết thêm thông tin chi tiết, bạn có thể xem hướng dẫn đầy đủ của chúng tôi về Media3 ExoPlayer.

Bắt đầu

Để bắt đầu, hãy thêm một phần phụ thuộc vào các mô-đun ExoPlayer, UI và Common của Jetpack Media3:

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

Tuỳ thuộc vào trường hợp sử dụng, bạn cũng có thể cần thêm các mô-đun khác từ Media3, chẳng hạn như exoplayer-dash để phát luồng ở định dạng DASH.

Hãy nhớ thay thế 1.9.2 bằng phiên bản thư viện mà bạn muốn. Bạn có thể tham khảo ghi chú phát hành để xem phiên bản mới nhất.

Tạo trình phát nội dung nghe nhìn

Với Media3, bạn có thể sử dụng cách triển khai giao diện Player có sẵn, ExoPlayer, hoặc tự xây dựng cách triển khai tuỳ chỉnh của riêng mình.

Tạo ExoPlayer

Cách đơn giản nhất để tạo thực thể ExoPlayer là như sau:

Kotlin

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

Java

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

Bạn có thể tạo trình phát nội dung nghe nhìn trong phương thức vòng đời onCreate() của Activity, Fragment, hoặc Service nơi trình phát này tồn tại.

Builder bao gồm một loạt các tuỳ chọn tuỳ chỉnh mà bạn có thể quan tâm, chẳng hạn như:

Media3 cung cấp thành phần trên giao diện người dùng PlayerView mà bạn có thể đưa vào tệp bố cục của ứng dụng. Thành phần này đóng gói PlayerControlView cho các nút điều khiển phát , SubtitleView để hiển thị phụ đề và Surface để kết xuất video.

Chuẩn bị trình phát

Thêm mục nội dung đa phương tiện vào danh sách phát để phát bằng các phương thức như setMediaItem()addMediaItem(). Sau đó, gọi prepare() để bắt đầu tải nội dung đa phương tiện và thu thập các tài nguyên cần thiết.

Bạn không nên thực hiện các bước này trước khi ứng dụng ở nền trước. Nếu trình phát của bạn ở trong Activity hoặc Fragment, điều này có nghĩa là bạn cần chuẩn bị trình phát trong phương thức vòng đời onStart() trên API cấp 24 trở lên hoặc phương thức vòng đời onResume() trên API cấp 23 trở xuống. Đối với trình phát ở trong Service, bạn có thể chuẩn bị trình phát đó trong onCreate(). Tham khảo lớp học lập trình Exoplayer để biết ví dụ về cách triển khai các phương thức vòng đời.

Điều khiển trình phát

Sau khi chuẩn bị trình phát, bạn có thể điều khiển việc phát bằng cách gọi các phương thức trên trình phát, chẳng hạn như:

Các thành phần trên giao diện người dùng như PlayerView hoặc PlayerControlView sẽ cập nhật cho phù hợp khi được liên kết với một trình phát.

Giải phóng trình phát

Việc phát có thể yêu cầu các tài nguyên có nguồn cung hạn chế, chẳng hạn như bộ giải mã video . Vì vậy, bạn cần gọi release() trên trình phát để giải phóng tài nguyên khi không còn cần trình phát nữa.

Nếu trình phát của bạn ở trong Activity hoặc Fragment, hãy giải phóng trình phát trong phương thức vòng đời onStop() trên API cấp 24 trở lên hoặc phương thức onPause() trên API cấp 23 trở xuống. Đối với trình phát ở trong Service, bạn có thể giải phóng trình phát đó trong onDestroy(). Tham khảo lớp học lập trình Exoplayer để biết ví dụ về cách triển khai các phương thức vòng đời.

Quản lý việc phát bằng phiên phát nội dung nghe nhìn

Trên Android, phiên phát nội dung nghe nhìn cung cấp một cách thức tiêu chuẩn hoá để tương tác với trình phát nội dung nghe nhìn trên các ranh giới quy trình. Việc kết nối phiên phát nội dung nghe nhìn với trình phát cho phép bạn quảng cáo việc phát nội dung nghe nhìn bên ngoài và nhận các lệnh phát từ các nguồn bên ngoài, chẳng hạn như tích hợp với các nút điều khiển nội dung nghe nhìn của hệ thống trên thiết bị di động và thiết bị màn hình lớn.

Để sử dụng phiên phát nội dung nghe nhìn, hãy thêm một phần phụ thuộc vào mô-đun Phiên của Media3:

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

Tạo phiên phát nội dung nghe nhìn

Bạn có thể tạo MediaSession sau khi khởi chạy trình phát như sau:

Kotlin

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

Java

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

Media3 tự động đồng bộ hoá trạng thái của Player với trạng thái của MediaSession. Tính năng này hoạt động với mọi Player cách triển khai, bao gồm ExoPlayer, CastPlayer hoặc cách triển khai tuỳ chỉnh.

Cấp quyền kiểm soát cho các ứng dụng khác

Các ứng dụng có thể triển khai trình điều khiển nội dung nghe nhìn để kiểm soát việc phát phiên phát nội dung nghe nhìn của bạn. Để nhận các yêu cầu này, hãy đặt một đối tượng gọi lại khi xây dựng MediaSession.

Khi một trình điều khiển sắp kết nối với phiên phát nội dung nghe nhìn của bạn, onConnect() phương thức sẽ được gọi. Bạn có thể sử dụng ControllerInfo để quyết định chấp nhận hay từ chối yêu cầu. Xem ví dụ về việc này trong ứng dụng minh hoạ Phiên của Media3.

Sau khi kết nối, trình điều khiển có thể gửi các lệnh phát đến phiên. Sau đó, phiên sẽ uỷ thác các lệnh đó cho trình phát. Các lệnh phát và danh sách phát được xác định trong giao diện Player sẽ được phiên tự động xử lý.

Các phương thức gọi lại khác cho phép bạn xử lý, chẳng hạn như các yêu cầu về lệnh phát tuỳ chỉnhsửa đổi danh sách phát. Các lệnh gọi lại này cũng bao gồm đối tượng ControllerInfo để bạn có thể xác định quyền kiểm soát truy cập trên cơ sở từng yêu cầu.

Phát nội dung nghe nhìn trong nền

Để tiếp tục phát nội dung nghe nhìn khi ứng dụng của bạn không ở nền trước (ví dụ: để phát nhạc, sách nói hoặc podcast ngay cả khi người dùng không mở ứng dụng của bạn ), PlayerMediaSession phải được đóng gói trong một dịch vụ trên nền trước. Media3 cung cấp giao diện MediaSessionService cho mục đích này.

Triển khai MediaSessionService

Tạo một lớp mở rộng MediaSessionService và tạo thực thể MediaSession trong phương thức vòng đời onCreate().

Kotlin

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()
    }
}

Java

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();
    }
}

Trong tệp kê khai, hãy thêm lớp Service bằng bộ lọc ý định MediaSessionService và yêu cầu quyền FOREGROUND_SERVICE để chạy dịch vụ trên nền trước:

<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" />

Cuối cùng, trong lớp mà bạn đã tạo, hãy ghi đè phương thức onGetSession() để kiểm soát quyền truy cập của ứng dụng vào phiên phát nội dung nghe nhìn. Trả về MediaSession để chấp nhận yêu cầu kết nối hoặc trả về null để từ chối yêu cầu.

Kotlin

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

Java

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

Kết nối với giao diện người dùng

Giờ đây, phiên phát nội dung nghe nhìn của bạn nằm trong một Service riêng biệt với Activity hoặc Fragment nơi giao diện người dùng trình phát của bạn tồn tại. Bạn có thể sử dụng MediaController để liên kết chúng với nhau. Trong phương thức onStart() của Activity hoặc Fragment có giao diện người dùng, hãy tạo SessionToken cho MediaSession, sau đó sử dụng SessionToken để xây dựng MediaController. Việc xây dựng MediaController diễn ra không đồng bộ.

Kotlin

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()
  )
}

Java

@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 triển khai giao diện Player, vì vậy, bạn có thể sử dụng các phương thức tương tự như play()pause() để điều khiển việc phát. Tương tự như các thành phần khác, hãy nhớ giải phóng MediaController khi không còn cần nữa, chẳng hạn như phương thức vòng đời onStop() của Activity, bằng cách gọi MediaController.releaseFuture().

Xuất bản thông báo

Các dịch vụ trên nền trước phải xuất bản thông báo khi đang hoạt động. A MediaSessionService sẽ tự động tạo thông báo cho bạn ở dạng MediaNotification.MediaStyle Để cung cấp thông báo tuỳ chỉnh, hãy tạo MediaNotification.Provider bằng DefaultMediaNotificationProvider.Builder hoặc bằng cách tạo cách triển khai tuỳ chỉnh của giao diện nhà cung cấp. Thêm nhà cung cấp vào MediaSession bằng setMediaNotificationProvider.

Quảng cáo thư viện nội dung của bạn

A MediaLibraryService xây dựng dựa trên a MediaSessionService bằng cách cho phép client apps duyệt xem nội dung đa phương tiện do ứng dụng của bạn cung cấp. Client apps triển khai a MediaBrowser để tương tác với MediaLibraryService.

Việc triển khai MediaLibraryService tương tự như việc triển khai MediaSessionService, ngoại trừ việc trong onGetSession(), bạn nên trả về MediaLibrarySession thay vì MediaSession. So với MediaSession.Callback, MediaLibrarySession.Callback bao gồm các phương thức bổ sung cho phép ứng dụng duyệt xem nội dung do dịch vụ thư viện của bạn cung cấp.

Tương tự như MediaSessionService, hãy khai báo MediaLibraryService trong tệp kê khai và yêu cầu quyền FOREGROUND_SERVICE để chạy dịch vụ trên nền trước:

<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" />

Ví dụ trên bao gồm bộ lọc ý định cho cả MediaLibraryService và (để tương thích ngược) MediaBrowserService cũ. Bộ lọc ý định bổ sung cho phép các ứng dụng sử dụng API MediaBrowserCompat nhận dạng Service của bạn.

Một MediaLibrarySession cho phép bạn phân phát thư viện nội dung của mình theo cấu trúc cây, với một gốc MediaItem duy nhất. Mỗi MediaItem trong cây có thể có bất kỳ số lượng nút MediaItem con nào. Bạn có thể phân phát một gốc khác hoặc một cây khác dựa trên yêu cầu của ứng dụng. Ví dụ: cây mà bạn trả về cho một ứng dụng đang tìm kiếm danh sách các mục nội dung đa phương tiện được đề xuất có thể chỉ chứa gốc MediaItem và một cấp độ duy nhất của các nút MediaItem con, trong khi cây mà bạn trả về cho một ứng dụng khác có thể đại diện cho một thư viện nội dung đầy đủ hơn.

Tạo MediaLibrarySession

A MediaLibrarySession mở rộng API MediaSession để thêm các API duyệt xem nội dung. So với lệnh gọi lại MediaSession, lệnh gọi lại MediaLibrarySession sẽ thêm các phương thức như:

  • onGetLibraryRoot() cho trường hợp ứng dụng yêu cầu gốc MediaItem của cây nội dung
  • onGetChildren() cho trường hợp ứng dụng yêu cầu các phần tử con của MediaItem trong cây nội dung
  • onGetSearchResult() cho trường hợp ứng dụng yêu cầu kết quả tìm kiếm từ cây nội dung cho một truy vấn nhất định

Các phương thức gọi lại có liên quan sẽ bao gồm đối tượng LibraryParams với các tín hiệu bổ sung về loại cây nội dung mà ứng dụng quan tâm.