การเริ่มต้นใช้งาน CastPlayer

CastPlayer เป็นการติดตั้งใช้งาน Player ของ Jetpack Media3 ที่รองรับ ทั้งการเล่นในเครื่องและการแคสต์ไปยังอุปกรณ์ระยะไกลที่พร้อมใช้งาน Cast CastPlayer ช่วยให้การเพิ่มฟังก์ชันการแคสต์ลงในแอปเป็นเรื่องง่ายและมีฟีเจอร์มากมายที่ช่วยให้ สลับระหว่างการเล่นในเครื่องและการเล่นจากระยะไกลได้อย่างราบรื่น คู่มือนี้แสดงวิธี ผสานรวม CastPlayer เข้ากับแอปสื่อ

หากต้องการผสานรวม Cast กับแพลตฟอร์มอื่นๆ โปรดดู Cast SDK

ซื้ออุปกรณ์ที่พร้อมใช้งาน Cast

หากต้องการทดสอบ CastPlayer คุณต้องมีอุปกรณ์ที่พร้อมใช้งาน Cast โดยมีตัวเลือก ได้แก่ Android TV, Chromecast, ลำโพงอัจฉริยะ และจอแสดงผลอัจฉริยะ ตรวจสอบว่าอุปกรณ์ ตั้งค่าและเชื่อมต่อกับเครือข่าย Wi-Fi เดียวกันกับอุปกรณ์เคลื่อนที่ที่ใช้พัฒนาสำหรับการ ค้นพบ

เพิ่มการพึ่งพิงบิวด์

หากต้องการเริ่มใช้ CastPlayer ให้เพิ่มการอ้างอิง AndroidX Media3 และ CastPlayer ลงในไฟล์ build.gradle ของโมดูลแอป

Kotlin

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

Groovy

implementation "androidx.media3:media3-exoplayer:1.9.2"
implementation "androidx.media3:media3-ui:1.9.2"
implementation "androidx.media3:media3-session:1.9.2"
implementation "androidx.media3:media3-cast:1.9.2"

กำหนดค่า CastPlayer

หากต้องการกำหนดค่า CastPlayer ให้อัปเดตไฟล์ AndroidManifest.xml ด้วย ผู้ให้บริการตัวเลือก

ผู้ให้บริการตัวเลือก

CastPlayer กำหนดให้ผู้ให้บริการตัวเลือกต้องกำหนดค่าลักษณะการทำงาน สำหรับการตั้งค่าพื้นฐาน คุณสามารถใช้ DefaultCastOptionsProvider ได้โดยการเพิ่มลงในไฟล์ AndroidManifest.xml การดำเนินการนี้จะใช้การตั้งค่าเริ่มต้น ซึ่งรวมถึงแอปพลิเคชันตัวรับสัญญาณเริ่มต้น

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

หากต้องการปรับแต่งการกำหนดค่า ให้ใช้ OptionsProvider ที่กำหนดเอง ดูวิธีดำเนินการได้ในคำแนะนำเกี่ยวกับ CastOptions

เพิ่มผู้รับสำหรับการโอนสื่อ

การเพิ่ม MediaTransferReceiver ลงในไฟล์ Manifest จะช่วยให้ UI ของระบบ ค้นพบอุปกรณ์ที่พร้อมใช้งาน Cast ในเครือข่ายและเปลี่ยนเส้นทางสื่อได้โดยไม่ต้องเปิด กิจกรรมของแอป เช่น ผู้ใช้สามารถเปลี่ยนอุปกรณ์ที่เล่นสื่อของแอปได้จากการแจ้งเตือนสื่อ

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

สร้าง CastPlayer

สำหรับการเล่นจากระยะไกลด้วย Cast แอปควรจัดการการเล่นได้แม้ว่าผู้ใช้จะไม่ได้โต้ตอบกับกิจกรรมจากแอป เช่น ผ่านการแจ้งเตือนสื่อของระบบ ด้วยเหตุนี้ คุณจึงควรสร้างอินสแตนซ์ ExoPlayer (สำหรับการเล่นในเครื่อง) และ CastPlayer (สำหรับการเล่นจากระยะไกล) ในบริการ เช่น MediaSessionService หรือ MediaLibraryService ก่อนอื่น ให้สร้างอินสแตนซ์ ExoPlayer แล้วเมื่อสร้างอินสแตนซ์ CastPlayer ให้ตั้งค่า ExoPlayer เป็นอินสแตนซ์เครื่องเล่นในเครื่อง จากนั้นคุณจะสลับการเล่นสื่อระหว่างอุปกรณ์เคลื่อนที่กับอุปกรณ์ที่พร้อมใช้งาน Cast ได้จากการแจ้งเตือนสื่อหรือการแจ้งเตือนบนหน้าจอล็อก Media3 ใช้ฟีเจอร์Output Switcher เพื่อจัดการการโอนเพลเยอร์เมื่อเส้นทางการส่งออกเปลี่ยนจาก ภายในเป็นระยะไกล หรือจากระยะไกลเป็นภายใน

ภาพหน้าจอแสดง UI ตัวสลับเอาต์พุตในการแจ้งเตือน
รูปที่ 1: (ก) ชิปอุปกรณ์ในการแจ้งเตือนสื่อ (ข) อุปกรณ์ที่พร้อมแคสต์ซึ่งแสดงเมื่อแตะชิปอุปกรณ์ (ค) ชิปอุปกรณ์ในการแจ้งเตือนบนหน้าจอล็อก

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

เพิ่มองค์ประกอบ UI

เพิ่ม MediaRouteButton ลงใน UI ของแอป การแตะ MediaRouteButton จะเปิดกล่องโต้ตอบที่แสดงรายการอุปกรณ์ที่พร้อมใช้งาน Cast ที่ใช้ได้ใน เครือข่าย เมื่อผู้ใช้เลือกอุปกรณ์ ระบบจะโอนการเล่นสื่อจาก อุปกรณ์เคลื่อนที่ไปยังอุปกรณ์รับที่เลือก ส่วนนี้จะแสดงวิธีเพิ่มปุ่มและรอรับเหตุการณ์เพื่ออัปเดต UI เมื่อการเล่นเปลี่ยนไปมาระหว่างอุปกรณ์ในพื้นที่และอุปกรณ์ระยะไกล

ตั้งค่า MediaRouteButton

คุณเพิ่ม MediaRouteButton ลงใน UI ของกิจกรรมได้ 4 วิธี ตัวเลือกที่ดีที่สุดจะขึ้นอยู่กับการออกแบบและข้อกำหนดของแอป

  • Compose UI: เพิ่ม Composable ของปุ่ม
  • UI ของยอดดู
    • เพิ่มปุ่มลงในเมนูแถบแอป
    • เพิ่มปุ่มภายใน PlayerView
    • เพิ่มปุ่มเป็น View มาตรฐาน
ภาพหน้าจอแสดงปุ่ม MediaRouteButton ใน UI
รูปที่ 2: (ก) MediaRouteButton ในแถบเมนู (ข) เป็น View (ค) ใน PlayerView และ (ง) กล่องโต้ตอบของอุปกรณ์ที่พร้อมใช้งาน Cast

เพิ่ม Composable MediaRouteButton ลงในเพลเยอร์

คุณเพิ่ม MediaRouteButton Composable ลงใน UI ของเพลเยอร์ได้ ดูข้อมูลเพิ่มเติมได้ที่คู่มือ Compose

@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) {
  // ...
}

เพิ่ม MediaRouteButton ลงใน PlayerView

คุณเพิ่ม MediaRouteButton ได้โดยตรงภายใน UI ของ PlayerView controls หลังจากตั้งค่า MediaController เป็นเพลเยอร์สำหรับ PlayerView แล้ว ให้ระบุ MediaRouteButtonViewProvider เพื่อแสดงปุ่มแคสต์ ในเพลเยอร์

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

เพิ่ม MediaRouteButton ลงในเมนูแถบแอป

หากต้องการตั้งค่า MediaRouteButton ในเมนูแถบแอป ให้สร้างเมนู XML แล้ว ลบล้าง onCreateOptionsMenu ใน Activity

<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,
  )
  // ...
  return true
}

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);
  // ...
  return true;
}

เพิ่ม MediaRouteButton เป็นมุมมอง

คุณตั้งค่า MediaRouteButton ได้ใน activity_layout.xml

  <androidx.mediarouter.app.MediaRouteButton
      android:id="@+id/media_route_button"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      app:mediaRouteButtonTint="@android:color/white" />

หากต้องการตั้งค่า MediaRouteButton ให้เสร็จสมบูรณ์ ให้ใช้ Media3 Cast MediaRouteButtonFactory ในโค้ด Activity

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) {
  super.onCreate(savedInstanceState);
  // ...
  MediaRouteButton button = findViewById(R.id.media_route_button);
  ListenableFuture<Void> setUpFuture =
      MediaRouteButtonFactory.setUpMediaRouteButton(context, button);
}

Activity Listener

สร้าง Player.Listener ใน Activity เพื่อฟังการเปลี่ยนแปลงตำแหน่งการเล่นสื่อ เมื่อplaybackTypeเปลี่ยนระหว่าง PLAYBACK_TYPE_LOCAL กับ PLAYBACK_TYPE_REMOTE คุณจะปรับ UI ได้ตามต้องการ หากต้องการป้องกันหน่วยความจำรั่วและจำกัดกิจกรรมของ Listener เฉพาะเมื่อแอปของคุณปรากฏ ให้ลงทะเบียน Listener ใน onStart และยกเลิกการลงทะเบียนใน onStop

Kotlin

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

private final 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);
}

ดูข้อมูลเพิ่มเติมเกี่ยวกับการฟังและการตอบสนองต่อเหตุการณ์การเล่นได้ในคู่มือเหตุการณ์ของเพลเยอร์