Làm quen với CastPlayer

CastPlayer là một phương thức triển khai Player của Jetpack Media3, hỗ trợ cả tính năng phát cục bộ và truyền đến một thiết bị từ xa có hỗ trợ Cast. CastPlayer giúp đơn giản hoá việc thêm chức năng truyền vào ứng dụng của bạn và cung cấp nhiều tính năng để chuyển đổi liền mạch giữa chế độ phát cục bộ và phát từ xa. Hướng dẫn này trình bày cách tích hợp CastPlayer vào ứng dụng đa phương tiện của bạn.

Để tích hợp Cast với các nền tảng khác, hãy xem Cast SDK.

Thêm CastPlayer làm phần phụ thuộc

Để bắt đầu sử dụng CastPlayer, hãy thêm các phần phụ thuộc AndroidX Media3 và CastPlayer cần thiết vào tệp build.gradle của mô-đun ứng dụng.

Kotlin

implementation("androidx.media3:media3-exoplayer:1.9.0-alpha01")
implementation("androidx.media3:media3-ui:1.9.0-alpha01")
implementation("androidx.media3:media3-session:1.9.0-alpha01")
implementation("androidx.media3:media3-cast:1.9.0-alpha01")

Groovy

implementation "androidx.media3:media3-exoplayer:1.9.0-alpha01"
implementation "androidx.media3:media3-ui:1.9.0-alpha01"
implementation "androidx.media3:media3-session:1.9.0-alpha01"
implementation "androidx.media3:media3-cast:1.9.0-alpha01"

Tham khảo ghi chú phát hành Jetpack Media để tìm bản phát hành alpha mới nhất để bạn có thể tích hợp CastPlayer vào ứng dụng của mình. Tất cả các mô-đun phải có cùng phiên bản.

Để biết thêm thông tin về các mô-đun thư viện hiện có, hãy xem trang Google Maven AndroidX Media3.

Định cấu hình CastPlayer

Để định cấu hình CastPlayer, hãy cập nhật tệp AndroidManifest.xml bằng một trình cung cấp lựa chọn.

Nhà cung cấp lựa chọn

CastPlayer yêu cầu một nhà cung cấp tuỳ chọn để định cấu hình hành vi của nó. Đối với chế độ thiết lập cơ bản, bạn có thể sử dụng trình cung cấp lựa chọn mặc định bằng cách thêm trình cung cấp này vào tệp AndroidManifest.xml. Thao tác này sử dụng chế độ cài đặt mặc định, bao gồm cả ứng dụng nhận mặc định.

<application>
  <meta-data
    android:name="com.google.android.gms.cast.framework.OPTIONS_PROVIDER_CLASS_NAME"
    android:value="androidx.media3.cast.DefaultCastOptionsProvider" />
</application>

Để tuỳ chỉnh cấu hình, hãy triển khai OptionsProvider tuỳ chỉnh của riêng bạn. Hãy xem hướng dẫn về CastOptions để tìm hiểu cách thực hiện.

Thêm một receiver để chuyển nội dung nghe nhìn

Việc thêm MediaTransferReceiver vào tệp kê khai cho phép Giao diện người dùng hệ thống định tuyến lại nội dung nghe nhìn mà không cần mở hoạt động của ứng dụng. Ví dụ: người dùng có thể thay đổi thiết bị phát nội dung nghe nhìn của ứng dụng thông qua thông báo về nội dung nghe nhìn.

<application>
  <receiver android:name="androidx.mediarouter.media.MediaTransferReceiver" />
</application>

Tạo CastPlayer

Đối với tính năng phát từ xa bằng Cast, ứng dụng của bạn phải có khả năng quản lý hoạt động phát ngay cả khi người dùng không tương tác với một Hoạt động trong ứng dụng của bạn, chẳng hạn như thông qua thông báo của hệ thống về nội dung nghe nhìn. Vì lý do này, bạn nên tạo các thực thể ExoPlayer (để phát cục bộ) và CastPlayer (để phát từ xa) trong một dịch vụ, chẳng hạn như MediaSessionService hoặc MediaLibraryService. Trước tiên, hãy tạo thực thể ExoPlayer, sau đó khi tạo thực thể CastPlayer, hãy đặt ExoPlayer làm thực thể trình phát cục bộ. Sau đó, Media3 sẽ có thể xử lý các hoạt động chuyển trình phát khi tuyến đầu ra thay đổi từ cục bộ sang từ xa hoặc từ từ xa sang cục bộ.

Kotlin

override fun onCreate() {
  super.onCreate()

  val exoPlayer = ExoPlayer.Builder(context).build()
  val castPlayer = CastPlayer.Builder(context)
      .setLocalPlayer(exoPlayer)
      .build()

  mediaSession = MediaSession.Builder(context, castPlayer).build()
}

Java

@Override
public void onCreate() {
  super.onCreate();

  ExoPlayer exoPlayer = new ExoPlayer.Builder(context).build();
  CastPlayer castPlayer = new CastPlayer.Builder(context)
      .setLocalPlayer(exoPlayer)
      .build();

  mediaSession = new MediaSession.Builder(
    /* context= */ context, /* player= */ castPlayer).build();
}

Thêm các phần tử trên giao diện người dùng

Thêm một MediaRouteButton vào giao diện người dùng của ứng dụng để cho phép người dùng chọn một thiết bị truyền. Phần này hướng dẫn bạn cách thêm nút và theo dõi các sự kiện để cập nhật giao diện người dùng khi chế độ phát chuyển đổi giữa thiết bị cục bộ và thiết bị từ xa.

Đặt MediaRouteButton

Có 4 phương thức có thể dùng để thêm MediaRouteButton vào giao diện người dùng của hoạt động để người dùng tương tác. Lựa chọn này sẽ phụ thuộc vào cách bạn muốn giao diện người dùng cho hoạt động của trình phát xuất hiện và hoạt động.

Thêm nút tuyến đường nội dung nghe nhìn có thể kết hợp vào Trình phát

Bạn có thể thêm thành phần kết hợp MediaRouteButton vào giao diện người dùng của trình phát. Để biết thêm thông tin, hãy xem hướng dẫn về Compose.

Kotlin

import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.media3.cast.MediaRouteButton

@Composable
fun PlayerComposeView(player: Player, modifier: Modifier = Modifier) {
  var controlsVisible by remember { mutableStateOf(false) }

  Box(
    modifier = modifier.clickable { controlsVisible = true },
    contentAlignment = Alignment.Center,
  ) {
    PlayerSurface(player = player, modifier = modifier)
    AnimatedVisibility(visible = controlsVisible, enter = fadeIn(), exit = fadeOut()) {
      Box(modifier = Modifier.fillMaxSize()) {
        MediaRouteButton(modifier = Modifier.align(Alignment.TopEnd))
        PrimaryControls(player = player, modifier = Modifier.align(Alignment.Center))
      }
    }
  }
}

@Composable
fun PrimaryControls(player: Player, modifier: Modifier = Modifier) {
  ...
}

Thêm nút tuyến phát nội dung nghe nhìn vào PlayerView

Bạn có thể thêm MediaRouteButton ngay trong các chế độ điều khiển giao diện người dùng của PlayerView. Sau khi đặt MediaController làm trình phát cho PlayerView, hãy cung cấp một MediaRouteButtonViewProvider để hiển thị nút Truyền trên Trình phát.

Kotlin

override fun onStart() {
  super.onStart()

  playerView.player = mediaController
  playerView.setMediaRouteButtonViewProvider(MediaRouteButtonViewProvider())
}

Java

@Override
public void onStart() {
  super.onStart();

  playerView.setPlayer(mediaController);
  playerView.setMediaRouteButtonViewProvider(new MediaRouteButtonViewProvider());
}

Thêm nút tuyến đường truyền nội dung nghe nhìn vào trình đơn thanh ứng dụng

Phương thức này thiết lập một nút tuyến đường truyền thông trong trình đơn thanh ứng dụng. Bạn cần cập nhật cả tệp kê khai và Activity để hiển thị kiểu nút này.

<menu xmlns:android="http://schemas.android.com/apk/res/android"
         xmlns:app="http://schemas.android.com/apk/res-auto">
  <item android:id="@+id/media_route_menu_item"
    android:title="@string/media_route_menu_title"
    app:showAsAction="always"
    app:actionProviderClass="androidx.mediarouter.app.MediaRouteActionProvider"/>
</menu>

Kotlin

override fun onCreateOptionsMenu(menu: Menu): Boolean {
    ...
    menuInflater.inflate(R.menu.sample_media_route_button_menu, menu)
    val menuItemFuture: ListenableFuture<MenuItem> =
        MediaRouteButtonFactory.setUpMediaRouteButton(
            context, menu, R.id.media_route_menu_item)
    Futures.addCallback(
        menuItemFuture,
        object : FutureCallback<MenuItem> {
            override fun onSuccess(menuItem: MenuItem?) {
                // Do something with the menu item.
            }

            override fun onFailure(t: Throwable) {
                // Handle the failure.
            }
        },
        executor)
    ...
}

Java

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    ...
    getMenuInflater().inflate(R.menu.sample_media_route_button_menu, menu);
    ListenableFuture<MenuItem> menuItemFuture =
        MediaRouteButtonFactory.setUpMediaRouteButton(
          context, menu, R.id.media_route_menu_item);
    Futures.addCallback(
        menuItemFuture,
        new FutureCallback<MenuItem>() {
          @Override
          public void onSuccess(MenuItem menuItem) {
            // Do something with the menu item.
          }

          @Override
          public void onFailure(Throwable t) {
            // Handle the failure.
          }
        },
        executor);
    ...
}

Thêm nút tuyến đường truyền phát nội dung nghe nhìn dưới dạng một View

Ngoài ra, bạn có thể thiết lập một MediaRouteButton trong activity layout.xml. Để hoàn tất quá trình thiết lập cho MediaRouteButton, hãy sử dụng MediaRouteButtonFactory Media3 Cast trong mã Activity của bạn.

Kotlin

override fun onCreate(savedInstanceState: Bundle?) {
  super.onCreate(savedInstanceState)

  findViewById<MediaRouteButton>(R.id.media_route_button)?.also {
    val unused = MediaRouteButtonFactory.setUpMediaRouteButton(context, it)
  }
}

Java

@Override
public void onCreate(Bundle savedInstanceState) {
    ...
    MediaRouteButton button = findViewById(R.id.media_route_button);
    ListenableFuture<Void> setUpFuture =
        MediaRouteButtonFactory.setUpMediaRouteButton(context, button);
}

Trình nghe hoạt động

Tạo một Player.Listener trong Activity để theo dõi các thay đổi về vị trí phát nội dung nghe nhìn. Khi playbackType thay đổi giữa PLAYBACK_TYPE_LOCALPLAYBACK_TYPE_REMOTE, bạn có thể điều chỉnh giao diện người dùng nếu cần. Để ngăn chặn tình trạng rò rỉ bộ nhớ và giới hạn hoạt động của trình nghe chỉ khi ứng dụng của bạn hiển thị, hãy đăng ký trình nghe trong onStart và huỷ đăng ký trong onStop:

Kotlin

import androidx.media3.common.DeviceInfo
import androidx.media3.common.Player

private val playerListener: Player.Listener =
  object : Player.Listener {
    override fun onDeviceInfoChanged(deviceInfo: DeviceInfo) {
      if (deviceInfo.playbackType == DeviceInfo.PLAYBACK_TYPE_LOCAL) {
        // Add UI changes for local playback.
      } else if (deviceInfo.playbackType == DeviceInfo.PLAYBACK_TYPE_REMOTE) {
        // Add UI changes for remote playback.
      }
    }
  }

override fun onStart() {
  super.onStart()
  mediaController.addListener(playerListener)
}

override fun onStop() {
  super.onStop()
  mediaController.removeListener(playerListener)
}

Java

import androidx.media3.common.DeviceInfo;
import androidx.media3.common.Player;

private Player.Listener playerListener =
    new Player.Listener() {
      @Override
      public void onDeviceInfoChanged(DeviceInfo deviceInfo) {
        if (deviceInfo.playbackType == DeviceInfo.PLAYBACK_TYPE_LOCAL) {
          // Add UI changes for local playback.
        } else if (deviceInfo.playbackType == DeviceInfo.PLAYBACK_TYPE_REMOTE) {
          // Add UI changes for remote playback.
        }
      }
    };

@Override
protected void onStart() {
  super.onStart();
  mediaController.addListener(playerListener);
}

@Override
protected void onStop() {
  super.onStop();
  mediaController.removeListener(playerListener);
}

Để biết thêm thông tin về cách theo dõi và phản hồi các sự kiện phát, hãy xem hướng dẫn về sự kiện của trình phát.