앱이 포그라운드에 있지 않을 때 미디어를 재생하는 것이 바람직한 경우가 많습니다. 대상 예를 들어 음악 플레이어는 일반적으로 사용자가 기기를 잠그면 다른 앱을 사용하고 있는지 확인할 수 있습니다. Media3 라이브러리는 이 인터페이스를 통해 백그라운드 재생을 지원할 수 있습니다.
MediaSessionService 사용
백그라운드 재생을 사용 설정하려면 Player
및
별도의 Service 내 MediaSession
이렇게 하면 앱이
있습니다.
서비스 내에서 플레이어를 호스팅할 때는 MediaSessionService
를 사용해야 합니다.
이렇게 하려면 MediaSessionService
` 를 확장하는 클래스를 만들고
찾을 수 있습니다.
MediaSessionService
를 사용하면 Google과 같은 외부 클라이언트가 가능합니다.
어시스턴트, 시스템 미디어 컨트롤 또는 Wear OS와 같은 호환 기기
연결하고, 연결하고, 재생을 제어할 수 있습니다.
UI 활동이 전혀 없습니다. 실제로 여러 개의 클라이언트 앱이
같은 MediaSessionService
에 동시에 연결할 수 있으며, 각 앱은 자체적인
MediaController
서비스 수명 주기 구현
서비스의 세 가지 수명 주기 메서드를 구현해야 합니다.
- 첫 번째 컨트롤러가 연결되려고 할 때
onCreate()
가 호출되고 시작됩니다 Kubernetes는Player
및MediaSession
onTaskRemoved(Intent)
는 사용자가 최근 할 일 목록을 표시합니다. 재생이 진행 중인 경우 앱에서 서비스를 유지하도록 선택할 수 있습니다. 포그라운드에서 실행되는 것을 볼 수 있습니다 플레이어가 일시중지되면 서비스는 중지되어야 합니다.onDestroy()
는 서비스가 중지되는 동안 호출됩니다. 모든 리소스 해제해야 합니다.
Kotlin
class PlaybackService : MediaSessionService() { private var mediaSession: MediaSession? = null // Create your player and media session in the onCreate lifecycle event override fun onCreate() { super.onCreate() val player = ExoPlayer.Builder(this).build() mediaSession = MediaSession.Builder(this, player).build() } // The user dismissed the app from the recent tasks override fun onTaskRemoved(rootIntent: Intent?) { val player = mediaSession?.player!! if (!player.playWhenReady || player.mediaItemCount == 0 || player.playbackState == Player.STATE_ENDED) { // Stop the service if not playing, continue playing in the background // otherwise. stopSelf() } } // Remember to release the player and media session in onDestroy override fun onDestroy() { mediaSession?.run { player.release() release() mediaSession = null } super.onDestroy() } }
자바
public class PlaybackService extends MediaSessionService { private MediaSession mediaSession = null; // Create your Player and MediaSession in the onCreate lifecycle event @Override public void onCreate() { super.onCreate(); ExoPlayer player = new ExoPlayer.Builder(this).build(); mediaSession = new MediaSession.Builder(this, player).build(); } // The user dismissed the app from the recent tasks @Override public void onTaskRemoved(@Nullable Intent rootIntent) { Player player = mediaSession.getPlayer(); if (!player.getPlayWhenReady() || player.getMediaItemCount() == 0 || player.getPlaybackState() == Player.STATE_ENDED) { // Stop the service if not playing, continue playing in the background // otherwise. stopSelf(); } } // Remember to release the player and media session in onDestroy @Override public void onDestroy() { mediaSession.getPlayer().release(); mediaSession.release(); mediaSession = null; super.onDestroy(); } }
백그라운드에서 재생을 계속 진행하는 대신 앱에서 사용자가 앱을 닫을 때 서비스를 중지합니다.
Kotlin
override fun onTaskRemoved(rootIntent: Intent?) { val player = mediaSession.player if (player.playWhenReady) { // Make sure the service is not in foreground. player.pause() } stopSelf() }
자바
@Override public void onTaskRemoved(@Nullable Intent rootIntent) { Player player = mediaSession.getPlayer(); if (player.getPlayWhenReady()) { // Make sure the service is not in foreground. player.pause(); } stopSelf(); }
미디어 세션에 대한 액세스 제공
onGetSession()
메서드를 재정의하여 다른 클라이언트에 미디어 액세스 권한을 부여합니다.
기본 세션을 제공합니다.
Kotlin
class PlaybackService : MediaSessionService() { private var mediaSession: MediaSession? = null // [...] lifecycle methods omitted override fun onGetSession(controllerInfo: MediaSession.ControllerInfo): MediaSession? = mediaSession }
자바
public class PlaybackService extends MediaSessionService { private MediaSession mediaSession = null; // [...] lifecycle methods omitted @Override public MediaSession onGetSession(MediaSession.ControllerInfo controllerInfo) { return mediaSession; } }
매니페스트에서 서비스 선언
앱에 포그라운드 서비스를 실행하려면 권한이 필요합니다.
FOREGROUND_SERVICE
권한이 있어야 하며, API 34 및
위 FOREGROUND_SERVICE_MEDIA_PLAYBACK
:
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />
매니페스트에서 인텐트 필터를 사용하여 Service
클래스도 선언해야 합니다.
총 MediaSessionService
페이지입니다.
<service
android:name=".PlaybackService"
android:foregroundServiceType="mediaPlayback"
android:exported="true">
<intent-filter>
<action android:name="androidx.media3.session.MediaSessionService"/>
</intent-filter>
</service>
먼저
foregroundServiceType
드림
앱이 Android가 설치된 기기에서 실행될 때 mediaPlayback
가 포함됩니다.
10 (API 수준 29) 이상
MediaController
를 사용하여 재생 제어
플레이어 UI가 포함된 활동 또는 프래그먼트에서 링크를 설정할 수 있습니다.
MediaController
를 사용하여 UI와 미디어 세션 간 UI 사용
미디어 컨트롤러를 사용하여 UI에서 플레이어로 명령을 보낼 수 있습니다.
세션입니다. 자세한 내용은
MediaController
만들기
MediaController
생성 및 사용에 관한 자세한 내용은 가이드를 참고하세요.
UI 명령어 처리
MediaSession
는
MediaSession.Callback
MediaSession
를 초기화하면 기본값이 생성됨
모든 코드를 자동으로 처리하는 MediaSession.Callback
구현
MediaController
가 플레이어에 전송하는 명령어를 실행합니다.
알림
MediaSessionService
는 자동으로 MediaNotification
를 생성합니다.
대부분의 경우 잘 작동합니다. 기본적으로 게시된 알림은
MediaStyle
알림
항상 최신 정보를
재생 컨트롤을 표시합니다. MediaNotification
에서 세션을 인식하고 다른 앱의 재생을 제어하는 데 사용될 수 있습니다.
동일한 세션에 연결된
여러 광고 그룹을 만듭니다
예를 들어 MediaSessionService
를 사용하는 음악 스트리밍 앱은
MediaNotification
- 다음의 제목, 아티스트, 앨범아트를 표시합니다.
현재 미디어 항목을 재생 컨트롤과 함께 재생 중인
MediaSession
구성
필수 메타데이터는 미디어에 제공되거나 미디어 항목을 호출합니다.
Kotlin
val mediaItem = MediaItem.Builder() .setMediaId("media-1") .setUri(mediaUri) .setMediaMetadata( MediaMetadata.Builder() .setArtist("David Bowie") .setTitle("Heroes") .setArtworkUri(artworkUri) .build() ) .build() mediaController.setMediaItem(mediaItem) mediaController.prepare() mediaController.play()
자바
MediaItem mediaItem = new MediaItem.Builder() .setMediaId("media-1") .setUri(mediaUri) .setMediaMetadata( new MediaMetadata.Builder() .setArtist("David Bowie") .setTitle("Heroes") .setArtworkUri(artworkUri) .build()) .build(); mediaController.setMediaItem(mediaItem); mediaController.prepare(); mediaController.play();
앱은 Android 미디어 컨트롤의 명령 버튼을 맞춤설정할 수 있습니다. 자세히 알아보기 Android 미디어 맞춤설정에 관한 컨트롤을 참고하세요.
알림 맞춤설정
알림을 맞춤설정하려면
MediaNotification.Provider
드림
대상: DefaultMediaNotificationProvider.Builder
또는 제공자 인터페이스의 맞춤형 구현을 생성하여 제공할 수 있습니다.
제공업체를 MediaSessionService
에 제공합니다.
setMediaNotificationProvider
재생 재개
미디어 버튼은 Android 기기 및 기타 주변기기에서 볼 수 있는 하드웨어 버튼입니다. (예: 블루투스 헤드셋의 재생 또는 일시중지 버튼) 미디어3 서비스가 실행 중일 때 미디어 버튼 입력을 자동으로 처리합니다.
Media3 미디어 버튼 수신기 선언
Media3에는 사용자가 재개할 수 있는 API가 포함되어 있습니다.
앱이 종료된 후, 심지어 기기가 종료된 후에도
시작됩니다 기본적으로 재생 재개는 사용 중지되어 있습니다. 즉, 사용자는
서비스가 실행되고 있지 않을 때는 재생을 다시 시작할 수 없습니다. 선택하려면 먼저
매니페스트에서 MediaButtonReceiver
을 선언합니다.
<receiver android:name="androidx.media3.session.MediaButtonReceiver"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MEDIA_BUTTON" />
</intent-filter>
</receiver>
재생 재개 콜백 구현
블루투스 기기 또는 재생 재개를 요청하는 경우
Android 시스템 UI 재개 기능
onPlaybackResumption()
콜백 메서드가 호출됩니다.
Kotlin
override fun onPlaybackResumption( mediaSession: MediaSession, controller: ControllerInfo ): ListenableFuture<MediaItemsWithStartPosition> { val settable = SettableFuture.create<MediaItemsWithStartPosition>() scope.launch { // Your app is responsible for storing the playlist and the start position // to use here val resumptionPlaylist = restorePlaylist() settable.set(resumptionPlaylist) } return settable }
자바
@Override public ListenableFuture<MediaItemsWithStartPosition> onPlaybackResumption( MediaSession mediaSession, ControllerInfo controller ) { SettableFuture<MediaItemsWithStartPosition> settableFuture = SettableFuture.create(); settableFuture.addListener(() -> { // Your app is responsible for storing the playlist and the start position // to use here MediaItemsWithStartPosition resumptionPlaylist = restorePlaylist(); settableFuture.set(resumptionPlaylist); }, MoreExecutors.directExecutor()); return settableFuture; }
재생 속도, 반복 모드 또는
셔플 모드인 경우 onPlaybackResumption()
를 사용하여 플레이어를 구성하는 것이 좋습니다.
이러한 매개변수로 Media3이 플레이어를 준비하고
콜백이 완료됩니다.
고급 컨트롤러 구성 및 이전 버전과의 호환성
일반적인 시나리오는 앱 UI에서 MediaController
를 사용하여
표시됩니다. 동시에 세션은
모바일 또는 TV의 어시스턴트, Android 미디어 컨트롤과 같은 외부 클라이언트와
시계용 Wear OS와 자동차용 Android Auto Media3 세션 데모 앱
은 이러한 시나리오를 구현하는 앱의 예입니다.
이러한 외부 클라이언트는 기존 API의 MediaControllerCompat
와 같은 API를 사용할 수 있습니다.
AndroidX 라이브러리 또는 Android의 android.media.session.MediaController
프레임워크입니다 Media3은 기존 라이브러리와 완전히 호환되며
Android 프레임워크 API와의 상호운용성을 제공합니다.
미디어 알림 컨트롤러 사용
이러한 레거시 또는 프레임워크 컨트롤러는
PlaybackState.getActions()
프레임워크의 동일한 값
PlaybackState.getCustomActions()
다음에 대한 작업 및 맞춤 작업을 결정하기 위해
프레임워크 세션에서 앱은 미디어 알림 컨트롤러를 사용할 수 있음
사용 가능한 명령어와 맞춤 레이아웃을 설정합니다. 서비스가 미디어를 연결함
알림을 보내고, 이 세션에서는
구성을 위해 콜백의 onConnect()
에서 ConnectionResult
를 반환함
작업 및 사용자 지정 작업을 모두 수행할 수 있습니다.
모바일 전용 시나리오에서는 앱이
MediaSession.Callback.onConnect()
: 사용 가능한 명령어 설정
맞춤 레이아웃을 설정하는 것입니다.
Kotlin
override fun onConnect( session: MediaSession, controller: MediaSession.ControllerInfo ): ConnectionResult { if (session.isMediaNotificationController(controller)) { val sessionCommands = ConnectionResult.DEFAULT_SESSION_COMMANDS.buildUpon() .add(customCommandSeekBackward) .add(customCommandSeekForward) .build() val playerCommands = ConnectionResult.DEFAULT_PLAYER_COMMANDS.buildUpon() .remove(COMMAND_SEEK_TO_PREVIOUS) .remove(COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM) .remove(COMMAND_SEEK_TO_NEXT) .remove(COMMAND_SEEK_TO_NEXT_MEDIA_ITEM) .build() // Custom layout and available commands to configure the legacy/framework session. return AcceptedResultBuilder(session) .setCustomLayout( ImmutableList.of( createSeekBackwardButton(customCommandSeekBackward), createSeekForwardButton(customCommandSeekForward)) ) .setAvailablePlayerCommands(playerCommands) .setAvailableSessionCommands(sessionCommands) .build() } // Default commands with default custom layout for all other controllers. return AcceptedResultBuilder(session).build() }
자바
@Override public ConnectionResult onConnect( MediaSession session, MediaSession.ControllerInfo controller) { if (session.isMediaNotificationController(controller)) { SessionCommands sessionCommands = ConnectionResult.DEFAULT_SESSION_COMMANDS .buildUpon() .add(customCommandSeekBackward) .add(customCommandSeekForward) .build(); Player.Commands playerCommands = ConnectionResult.DEFAULT_PLAYER_COMMANDS .buildUpon() .remove(COMMAND_SEEK_TO_PREVIOUS) .remove(COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM) .remove(COMMAND_SEEK_TO_NEXT) .remove(COMMAND_SEEK_TO_NEXT_MEDIA_ITEM) .build(); // Custom layout and available commands to configure the legacy/framework session. return new AcceptedResultBuilder(session) .setCustomLayout( ImmutableList.of( createSeekBackwardButton(customCommandSeekBackward), createSeekForwardButton(customCommandSeekForward))) .setAvailablePlayerCommands(playerCommands) .setAvailableSessionCommands(sessionCommands) .build(); } // Default commands without default custom layout for all other controllers. return new AcceptedResultBuilder(session).build(); }
Android Auto에서 맞춤 명령을 전송하도록 승인
MediaLibraryService
를 사용하는 경우
모바일 앱에서 Android Auto를 지원하기 위해
필요한 명령어가 필요하며, 그러지 않으면 Media3에서 이를 거부
해당 컨트롤러에서 수신되는 커스텀 명령어를
Kotlin
override fun onConnect( session: MediaSession, controller: MediaSession.ControllerInfo ): ConnectionResult { val sessionCommands = ConnectionResult.DEFAULT_SESSION_AND_LIBRARY_COMMANDS.buildUpon() .add(customCommandSeekBackward) .add(customCommandSeekForward) .build() if (session.isMediaNotificationController(controller)) { // [...] See above. } else if (session.isAutoCompanionController(controller)) { // Available session commands to accept incoming custom commands from Auto. return AcceptedResultBuilder(session) .setAvailableSessionCommands(sessionCommands) .build() } // Default commands with default custom layout for all other controllers. return AcceptedResultBuilder(session).build() }
자바
@Override public ConnectionResult onConnect( MediaSession session, MediaSession.ControllerInfo controller) { SessionCommands sessionCommands = ConnectionResult.DEFAULT_SESSION_COMMANDS .buildUpon() .add(customCommandSeekBackward) .add(customCommandSeekForward) .build(); if (session.isMediaNotificationController(controller)) { // [...] See above. } else if (session.isAutoCompanionController(controller)) { // Available commands to accept incoming custom commands from Auto. return new AcceptedResultBuilder(session) .setAvailableSessionCommands(sessionCommands) .build(); } // Default commands without default custom layout for all other controllers. return new AcceptedResultBuilder(session).build(); }
세션 데모 앱에는 자동차 모듈 는 별도의 APK가 필요한 Automotive OS 지원을 보여줍니다.