สร้างแอปมีเดียเพลเยอร์พื้นฐานโดยใช้ Media3 ExoPlayer

Jetpack Media3 กำหนดอินเทอร์เฟซ Player ที่แสดงฟังก์ชันการทำงานพื้นฐาน สำหรับการเล่นไฟล์วิดีโอและไฟล์เสียง ExoPlayer เป็นการใช้งานเริ่มต้น ของอินเทอร์เฟซนี้ใน Media3 เราขอแนะนำให้ใช้ ExoPlayer เนื่องจากมี ชุดคุณลักษณะที่ครอบคลุมซึ่งครอบคลุมกรณีการใช้งานส่วนใหญ่ของการเล่นและ สามารถปรับแต่งให้รองรับ Use Case อื่นๆ เพิ่มเติม ExoPlayer ด้วย แยกส่วนของอุปกรณ์และระบบปฏิบัติการออกเพื่อให้โค้ดทำงานได้อย่างราบรื่น ทั่วทั้งระบบนิเวศของ Android ExoPlayer ประกอบด้วย

หน้านี้จะแนะนำขั้นตอนสำคัญในการสร้างการเล่นวิดีโอ และดูรายละเอียดเพิ่มเติมได้ในคู่มือฉบับเต็ม Media3 ExoPlayer

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

หากต้องการเริ่มต้นใช้งาน ให้เพิ่มทรัพยากร Dependency ใน ExoPlayer, UI และโมดูลทั่วไปของ Jetpack Media3:

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

คุณอาจต้องการโมดูลเพิ่มเติมจาก Media3 ด้วย ทั้งนี้ขึ้นอยู่กับกรณีการใช้งานของคุณ เช่น exoplayer-dash เพื่อเล่นสตรีมในรูปแบบ DASH

โปรดแทนที่ 1.4.0 ด้วยเวอร์ชันที่ต้องการ ไลบรารี คุณดูบันทึกประจำรุ่นได้ เพื่อดูเวอร์ชันล่าสุด

การสร้างมีเดียเพลเยอร์

เมื่อใช้ Media3 คุณจะสามารถใช้การติดตั้งใช้งาน Player ที่รวมอยู่ด้วย อินเทอร์เฟซExoPlayer หรือคุณจะสร้างการใช้งานที่กำหนดเองก็ได้

การสร้าง ExoPlayer

วิธีที่ง่ายที่สุดในการสร้างอินสแตนซ์ ExoPlayer มีดังนี้

Kotlin

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

Java

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

คุณสามารถสร้างมีเดียเพลเยอร์ได้ในเมธอดวงจร onCreate() ของ Activity, Fragment หรือ Service ที่พำนัก

Builder ประกอบด้วย ตัวเลือกต่างๆ ของการปรับแต่งที่คุณอาจสนใจ เช่น

Media3 มีคอมโพเนนต์ UI ของ PlayerView ที่คุณรวมไว้ในแอป ใหม่ คอมโพเนนต์นี้จะสรุป PlayerControlView สำหรับการเล่น ตัวควบคุม, SubtitleView สำหรับการแสดงคำบรรยาย และ Surface สำหรับการแสดงภาพ ในการสร้างสรรค์วิดีโอ

กำลังเตรียมโปรแกรมเล่น

เพิ่มรายการสื่อลงในเพลย์ลิสต์สำหรับ โดยใช้วิธีการเช่น setMediaItem() และ addMediaItem() จากนั้นโทรหา prepare() เพื่อ เริ่มโหลดสื่อและรับทรัพยากรที่จำเป็น

คุณไม่ควรทำตามขั้นตอนเหล่านี้ก่อนที่แอปจะทำงานในส่วนหน้า หาก ผู้เล่นอยู่ใน Activity หรือ Fragment ซึ่งหมายถึงการเตรียมโปรแกรมเล่นใน เมธอดอายุการใช้งาน onStart() ใน API ระดับ 24 ขึ้นไปหรือ onResume() เมธอดตลอดอายุการใช้งานใน API ระดับ 23 หรือต่ำกว่า สำหรับผู้เล่นที่อยู่ใน Service คุณสามารถเตรียมการได้ในonCreate()

ควบคุมโปรแกรมเล่น

หลังจากเตรียมโปรแกรมเล่นแล้ว คุณสามารถควบคุมการเล่นได้โดยวิธีการโทร ในโปรแกรมเล่น เช่น

  • play() และ pause() เพื่อเริ่มเล่นและหยุดเล่นชั่วคราว
  • seekTo() เพื่อค้นหา ตำแหน่งภายในรายการสื่อปัจจุบัน
  • seekToNextMediaItem() และ seekToPreviousMediaItem() เพื่อไปยังส่วนต่างๆ ในเพลย์ลิสต์

คอมโพเนนต์ UI เช่น PlayerView หรือ PlayerControlView จะอัปเดต ให้สอดคล้องเมื่อเชื่อมโยงกับโปรแกรมเล่น

ปล่อยโปรแกรมเล่น

การเล่นอาจต้องใช้ทรัพยากรที่มีจำกัด เช่น วิดีโอ ตัวถอดรหัส คุณจึงควรเรียกใช้ release() บนโปรแกรมเล่นของคุณเพื่อเพิ่มพื้นที่ว่าง เมื่อไม่จำเป็นต้องใช้โปรแกรมเล่นแล้ว

หากโปรแกรมเล่นของคุณอยู่ใน Activity หรือ Fragment ให้ปล่อยโปรแกรมเล่นนั้นใน เมธอดอายุการใช้งาน onStop() ใน API ระดับ 24 ขึ้นไปหรือ onPause() ใน API ระดับ 23 และต่ำกว่า สำหรับผู้เล่นที่อยู่ใน Service คุณสามารถ เผยแพร่ใน onDestroy()

การจัดการการเล่นด้วยเซสชันสื่อ

ใน Android เซสชันสื่อจะเป็นวิธีมาตรฐานในการโต้ตอบกับสื่อ ข้ามขอบเขตของกระบวนการ การเชื่อมต่อเซสชันสื่อกับโปรแกรมเล่น อนุญาตให้คุณโฆษณาการเล่นสื่อของคุณภายนอกและเพื่อรับการเล่น จากแหล่งที่มาภายนอก เช่น เพื่อผสานรวมกับ การควบคุมสื่อของระบบในอุปกรณ์เคลื่อนที่และขนาดใหญ่ อุปกรณ์หน้าจออื่นๆ

หากต้องการใช้เซสชันสื่อ ให้เพิ่มทรัพยากร Dependency ในโมดูลเซสชัน Media3 ดังนี้

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

สร้างเซสชันสื่อ

คุณสามารถสร้าง MediaSession หลังจากเริ่มต้นโปรแกรมเล่นด้วยวิธีต่อไปนี้

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 จะซิงค์สถานะของ Player กับสถานะของ MediaSession ซึ่งใช้งานได้กับการติดตั้งใช้งาน Player ทั้งหมด ได้แก่ ExoPlayer, CastPlayer หรือ แบบกำหนดเองได้

ให้สิทธิ์ควบคุมกับลูกค้ารายอื่น

แอปไคลเอ็นต์ใช้ตัวควบคุมสื่อได้ เพื่อควบคุมการเล่นเซสชันสื่อของคุณ หากต้องการรับคำขอเหล่านี้ ให้ตั้งค่า callback ออบเจ็กต์เมื่อ เพื่อก่อสร้างMediaSession

เมื่อตัวควบคุมกำลังจะเชื่อมต่อกับเซสชันสื่อของคุณ onConnect() เมธอด คุณสามารถใช้ControllerInfo ในการตัดสินใจว่าจะยอมรับ หรือปฏิเสธ คำขอ ดูตัวอย่างได้ในแอปเดโมเซสชัน Media3

เมื่อเชื่อมต่อแล้ว ตัวควบคุมจะส่งคำสั่งการเล่นไปยังเซสชันได้ แล้วจะมอบหมายคำสั่งเหล่านั้นให้โปรแกรมเล่น การเล่นและเพลย์ลิสต์ คำสั่งที่กำหนดในอินเทอร์เฟซ Player ได้รับการจัดการโดยอัตโนมัติโดย เซสชัน

คุณสามารถใช้วิธีอื่นๆ ในการติดต่อกลับได้ เช่น คําขอ คำสั่งการเล่นแบบกำหนดเอง และการแก้ไขเพลย์ลิสต์ Callback เหล่านี้ก็รวมออบเจ็กต์ ControllerInfo ด้วย คุณจึง สามารถกำหนดการควบคุมการเข้าถึงตามคำขอได้

การเล่นสื่อขณะล็อกหน้าจอหรือขณะใช้แอปอื่น

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

การติดตั้งใช้งาน MediaSessionService

สร้างชั้นเรียนที่ขยาย MediaSessionService และสร้างอินสแตนซ์ MediaSession ในเมธอดอายุการใช้งาน 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();
    }
}

ไฟล์ Manifest คลาส Service ที่มี Intent 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 เพื่อปฏิเสธคำขอ

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

กำลังเชื่อมต่อกับ UI

เมื่อเซสชันสื่ออยู่ใน Service แยกจาก Activity หรือ Fragment ที่มี UI ของโปรแกรมเล่นอยู่ คุณสามารถใช้ MediaController เพื่อลิงก์ได้ ไว้ด้วยกัน ในเมธอด onStart() ของ Activity หรือ Fragment ด้วย UI ให้สร้าง SessionToken สำหรับ MediaSession แล้วใช้ SessionToken เพื่อสร้าง MediaController การสร้าง MediaController เกิดขึ้น แบบไม่พร้อมกัน

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 จะใช้อินเทอร์เฟซ Player คุณจึงใช้อินเทอร์เฟซ เช่น play() และ pause() เพื่อควบคุมการเล่น คล้ายกับรายการอื่น คอมโพเนนต์ อย่าลืมปล่อย MediaController เมื่อไม่เผยแพร่แล้ว เช่น วิธีวงจร onStop() ของ Activity โดยการเรียกใช้ MediaController.releaseFuture()

การเผยแพร่การแจ้งเตือน

ต้องใช้บริการที่ทำงานอยู่เบื้องหน้าเพื่อเผยแพร่การแจ้งเตือนขณะใช้งาน ต MediaSessionService จะสร้าง การแจ้งเตือน MediaStyle รายการสำหรับ ในรูปแบบ MediaNotification หากต้องการระบุการแจ้งเตือนที่กำหนดเอง ให้สร้าง MediaNotification.Provider กับ DefaultMediaNotificationProvider.Builder หรือโดยการสร้างการติดตั้งใช้งานอินเทอร์เฟซผู้ให้บริการแบบกำหนดเอง เพิ่ม เป็นผู้ให้บริการ MediaSession ของคุณกับ setMediaNotificationProvider

การโฆษณาไลบรารีเนื้อหาของคุณ

MediaLibraryService สร้างจาก MediaSessionService โดยอนุญาตให้ไคลเอ็นต์ แอปสำหรับเรียกดูเนื้อหาสื่อที่แอปของคุณให้มา แอปไคลเอ็นต์ใช้ MediaBrowser เพื่อโต้ตอบ ด้วย MediaLibraryService

การใช้ MediaLibraryService คล้ายกับการติดตั้งใช้งาน MediaSessionService เว้นแต่ว่าใน onGetSession() คุณควรแสดงผล MediaLibrarySession แทนที่จะเป็น MediaSession เทียบกับ MediaSession.Callback MediaLibrarySession.Callback ประกอบด้วย ที่ช่วยให้ไคลเอ็นต์เบราว์เซอร์สำรวจเนื้อหาที่เสนอโดย บริการห้องสมุด

เช่นเดียวกับ MediaSessionService ให้ประกาศ MediaLibraryService ใน ไฟล์ Manifest และขอสิทธิ์ 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" />

ตัวอย่างด้านบนมีตัวกรอง Intent สำหรับทั้ง MediaLibraryService และ MediaBrowserService เดิมสำหรับความเข้ากันได้แบบย้อนหลัง ตัวกรอง Intent เพิ่มเติมจะเปิดใช้แอปไคลเอ็นต์โดยใช้ API ของ MediaBrowserCompat เพื่อจดจำ Service ของคุณ

MediaLibrarySession ช่วยให้คุณแสดงคลังเนื้อหาแบบต้นไม้ได้ ที่มี MediaItem รากเดียว MediaItem แต่ละรายการในโครงสร้างมีได้ โหนดย่อยจำนวนเท่าใดก็ได้ MediaItem โหนด คุณสามารถแสดงรูทที่แตกต่างกัน หรือ โครงสร้างต้นไม้ที่แตกต่างกัน โดยอิงตามคำขอของแอปไคลเอ็นต์ เช่น ต้นไม้ที่คุณ กลับไปยังลูกค้าที่มองหารายการสื่อที่แนะนำอาจ มีรูท MediaItem และโหนดย่อย MediaItem โหนด ขณะที่แผนผังที่คุณกลับไปยังแอปไคลเอ็นต์อื่นอาจแสดง คลังเนื้อหาทั้งหมด

กำลังสร้าง MediaLibrarySession

MediaLibrarySession ขยาย MediaSession API เพื่อเพิ่ม API การเรียกดูเนื้อหา เทียบกับ MediaSession Callback, การติดต่อกลับของ MediaLibrarySession เพิ่มเมธอด เช่น

  • onGetLibraryRoot() สำหรับเวลาที่ไคลเอ็นต์ขอรูท MediaItem ของโครงสร้างเนื้อหา
  • onGetChildren() สำหรับเมื่อลูกค้าขอองค์ประกอบย่อยของ MediaItem ในโครงสร้างเนื้อหา
  • onGetSearchResult() สำหรับเวลาที่ลูกค้าขอผลการค้นหาจากโครงสร้างเนื้อหาของ คำถาม

วิธีการโทรกลับที่เกี่ยวข้องจะมี LibraryParams ที่มีสัญญาณเพิ่มเติมเกี่ยวกับประเภทโครงสร้างเนื้อหาที่แอปไคลเอ็นต์ สนใจ