Jetpack Media3 xác định giao diện Player trình bày chức năng cơ bản để phát tệp video và tệp âm thanh. ExoPlayer là phương thức triển khai mặc định
của giao diện này trong Media3. Bạn nên sử dụng ExoPlayer vì trình phát này cung cấp một bộ tính năng toàn diện, đáp ứng hầu hết các trường hợp sử dụng phát nội dung và có thể tuỳ chỉnh để xử lý mọi trường hợp sử dụng khác mà bạn có thể gặp phải. ExoPlayer cũng
loại bỏ 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 truyền trực tuyến thích ứng và tăng dần
- Hỗ trợ cả tính năng chèn quảng cáo phía máy khách và phía máy chủ
- 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 quan trọng trong việc xây dựng ứng dụng phát, đồng thời bạn có thể xem hướng dẫn đầy đủ của chúng tôi về Media3 ExoPlayer để biết thêm thông tin chi tiết.
Bắt đầu
Để bắt đầu, hãy thêm phần phụ thuộc vào các mô-đun ExoPlayer, Giao diện người dùng và Common của Jetpack Media3:
Kotlin
implementation("androidx.media3:media3-exoplayer:1.11.1")
implementation("androidx.media3:media3-ui:1.11.1")
implementation("androidx.media3:media3-common:1.11.1")
Groovy
implementation "androidx.media3:media3-exoplayer:1.11.1"
implementation "androidx.media3:media3-ui:1.11.1"
implementation "androidx.media3:media3-common:1.11.1"
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 các luồng ở định dạng DASH.
Hãy nhớ thay thế 1.11.1 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 phương thức triển khai có sẵn của giao diện Player, ExoPlayer hoặc bạn có thể tạo phương thức triển khai tuỳ chỉnh của riêng mình.
Tạo ExoPlayer
Cách đơn giản nhất để tạo một thực thể ExoPlayer 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 đa phương tiện trong phương thức vòng đời onCreate() của Activity, Fragment hoặc Service nơi trình phát đó hoạt động.
Builder có nhiều lựa chọn tuỳ chỉnh mà bạn có thể quan tâm, chẳng hạn như:
setAudioAttributes()để định cấu hình cách xử lý quyền phát âm thanhsetHandleAudioBecomingNoisy()để định cấu hình hành vi phát khi thiết bị đầu ra âm thanh bị ngắt kết nốisetTrackSelector()để định cấu hình lựa chọn kênh
Media3 cung cấp một thành phầ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 chế độ phát, SubtitleView để hiển thị phụ đề và Surface để kết xuất video.
Đang chuẩn bị trình phát
Thêm mục nội dung nghe nhìn vào danh sách phát để phát bằng các phương thức như setMediaItem() và addMediaItem(). Sau đó, hãy gọi prepare() để bắt đầu tải nội dung nghe nhìn và lấy 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 chạy trên nền trước. Nếu trình phát của bạn nằm trong Activity hoặc Fragment, thì tức là bạn cần chuẩn bị trình phát trong phương thức vòng đời onStart() trên cấp độ API 24 trở lên hoặc phương thức vòng đời onResume() trên cấp độ API 23 trở xuống. Đối với trình phát đang ở trạng thái Service,
bạn có thể chuẩn bị trình phát đó trong onCreate(). Hãy tham khảo lớp học lập trình về ExoPlayer để xem ví dụ về cách triển khai các phương thức trong 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 quá trình 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ư:
play()vàpause()để bắt đầu và tạm dừng phátseekTo()để tua đến một vị trí trong mục nội dung nghe nhìn hiện tạiseekToNextMediaItem()vàseekToPreviousMediaItem()để di chuyển trong danh sách phát
Các thành phần giao diện người dùng như PlayerView hoặc PlayerControlView sẽ cập nhật tương ứng khi liên kết với một trình phát.
Thả cầu thủ
Quá trình 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 đến trình phát nữa.
Nếu trình phát của bạn đang ở trạng thái 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 cấp độ API 24 trở lên hoặc phương thức onPause() trên cấp độ API 23 trở xuống. Đối với người chơi đang ở trong Service, bạn có thể giải phóng người chơi đó trong onDestroy(). Tham khảo lớp học lập trình về ExoPlayer để xem ví dụ về cách triển khai các phương thức trong vòng đời.
Quản lý việc phát bằng phiên 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 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 nội dung nghe nhìn đang phát ra bên ngoài và nhận 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 đa phương tiện, hãy thêm một phần phụ thuộc vào mô-đun Phiên Media3:
Kotlin
implementation("androidx.media3:media3-session:1.11.1")
Groovy
implementation "androidx.media3:media3-session:1.11.1"
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. Phương thức này hoạt động với mọi phương thức triển khai Player, bao gồm cả ExoPlayer, CastPlayer hoặc phương thức triển khai tuỳ chỉnh.
Cấp quyền kiểm soát cho các ứng dụng khác
Ứng dụng khách có thể triển khai trình điều khiển nội dung nghe nhìn để điều khiển việc phát phiên nội dung nghe nhìn. Để nhận các yêu cầu này, hãy đặt đối tượng callback khi tạo MediaSession.
Khi một bộ đ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, phương thức onConnect() sẽ được gọi. Bạn có thể sử dụng ControllerInfo được cung cấp để quyết định xem nên chấp nhận hay từ chối yêu cầu. Xem ví dụ về vấn đề này trong ứng dụng minh hoạ phiên Media3.
Sau khi kết nối, bộ điều khiển có thể gửi lệnh phát đến phiên. Sau đó, phiên sẽ uỷ quyền 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ẽ tự động được phiên xử lý.
Các phương thức gọi lại khác cho phép bạn xử lý, ví dụ: yêu cầu về lệnh phát tuỳ chỉnh và sửa đổi danh sách phát. Tương tự, các lệnh gọi lại này bao gồm một đối tượng ControllerInfo để bạn có thể xác định quyền kiểm soát truy cập theo 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 không chạy ở nền trước, chẳng hạn như phát nhạc, sách nói hoặc podcast ngay cả khi người dùng không mở ứng dụng, bạn nên đóng gói Player và MediaSession 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ể cho 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 khai báo lớp Service bằng bộ lọc ý định MediaSessionService và yêu cầu quyền FOREGROUND_SERVICE để chạy dịch vụ 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 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 đa phương tiện của bạ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;
}
Đang 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 tách biệt với Activity hoặc Fragment nơi có giao diện người dùng của trình phát, 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 một SessionToken cho MediaSession, sau đó sử dụng SessionToken để tạo MediaController. Quá trình tạo 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() và pause() để điều khiển quá trình 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 đến nữa trong 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
Dịch vụ nền trước phải đăng thông báo khi đang hoạt động. MediaSessionService sẽ tự động tạo một MediaStyle thông báo cho bạn dưới dạng MediaNotification. Để cung cấp thông báo tuỳ chỉnh, hãy tạo một MediaNotification.Provider bằng DefaultMediaNotificationProvider.Builder hoặc bằng cách tạo một phương thức 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
MediaLibraryService được xây dựng dựa trên MediaSessionService bằng cách cho phép các ứng dụng khách duyệt xem nội dung nghe nhìn do ứng dụng của bạn cung cấp. Các ứng dụng khách triển khai MediaBrowser để tương tác với MediaLibraryService của bạn.
Việc triển khai MediaLibraryService cũng tương tự như 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 trình duyệt điều hướng 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 một bộ lọc ý định cho cả MediaLibraryService và MediaBrowserService cũ để đảm bảo khả năng tương thích ngược. Bộ lọc ý định bổ sung cho phép các ứng dụng khách sử dụng API MediaBrowserCompat nhận ra Service của bạn.
MediaLibrarySession cho phép bạn phân phát thư viện nội dung theo cấu trúc cây, với một MediaItem gốc duy nhất. Mỗi MediaItem trong cây có thể có số lượng nút MediaItem con bất kỳ. 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 khách. Ví dụ: cây mà bạn trả về cho một ứng dụng khách đang tìm danh sách các mục nội dung nghe nhìn được đề xuất có thể chỉ chứa nút MediaItem gốc và một cấp nút MediaItem con, trong khi cây mà bạn trả về cho một ứng dụng khách khác có thể đại diện cho một thư viện nội dung hoàn chỉnh hơn.
Đang tạo MediaLibrarySession
MediaLibrarySession mở rộng API MediaSession để thêm các API duyệt nội dung. So với lệnh gọi lại MediaSession, lệnh gọi lại MediaLibrarySession thêm các phương thức như:
onGetLibraryRoot()khi ứng dụng yêu cầu gốcMediaItemcủa cây nội dungonGetChildren()khi ứng dụng yêu cầu các phần tử con của mộtMediaItemtrong cây nội dungonGetSearchResult()khi ứ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 một đối tượng LibraryParams có
các tín hiệu bổ sung về loại cây nội dung mà ứng dụng khách
quan tâm.