Cast 지원 Android TV 앱

컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요.

1. 개요

Google Cast 로고

이 Codelab에서는 기존 Cast 발신기 앱의 전송 및 통신을 지원하도록 기존 Android TV 앱을 수정하는 방법을 알아봅니다.

Google Cast와 Cast Connect란 무엇인가요?

사용자는 Google Cast를 통해 휴대기기에서 TV로 콘텐츠를 전송할 수 있습니다. 일반적인 Google Cast 세션은 두 가지 요소 즉, 발신기수신기 애플리케이션으로 구성되어 있습니다. 모바일 앱이나 웹사이트(예: YouTube.com)와 같은 발신기 애플리케이션은 Cast 수신기 애플리케이션의 재생을 시작하고 제어합니다. Cast 수신기 애플리케이션은 Chromecast 및 Android TV 기기에서 실행되는 HTML 5 앱입니다.

Cast 세션의 거의 모든 상태는 수신기 애플리케이션에 저장됩니다. 예를 들어 새 미디어 항목이 로드되어 상태가 업데이트되면 미디어 상태가 모든 발신기에 브로드캐스트됩니다. 이러한 브로드캐스트에는 Cast 세션의 현재 상태가 포함됩니다. 발신기 애플리케이션은 이 미디어 상태를 사용하여 UI에 재생 정보를 표시합니다.

Cast Connect는 이러한 인프라 위에 빌드되며, 이때 Android TV 앱은 수신기 역할을 합니다. Cast Connect 라이브러리를 사용하면 Android TV 앱이 Cast 수신기 애플리케이션인 것처럼 메시지를 수신하고 미디어 상태를 브로드캐스트할 수 있습니다.

무엇을 빌드하게 되나요?

이 Codelab을 완료하면 Cast 발신기 앱을 사용하여 Android TV 앱으로 동영상을 전송할 수 있습니다. Android TV 앱은 Cast 프로토콜을 통해 발신기 앱과 통신할 수도 있습니다.

학습할 내용

  • Cast Connect 라이브러리를 샘플 ATV 앱에 추가하는 방법
  • Cast 발신기를 연결하고 ATV 앱을 실행하는 방법
  • Cast 발신기 앱의 미디어 재생을 ATV 앱에서 시작하는 방법
  • ATV 앱에서 Cast 발신기 앱으로 미디어 상태를 전송하는 방법

필요한 항목

2. 샘플 코드 가져오기

모든 샘플 코드를 컴퓨터에 다운로드할 수 있습니다.

다운로드한 ZIP 파일의 압축을 풉니다.

3. 샘플 앱 실행

먼저 완성된 샘플 앱이 어떤 모습인지 살펴보겠습니다. Android TV 앱에서는 Leanback UI와 기본 동영상 플레이어를 사용합니다. 사용자가 목록에서 동영상을 선택할 수 있으며, 선택한 동영상은 TV에서 재생됩니다. 사용자는 함께 제공되는 모바일 발신기 앱을 통해 Android TV 앱에 동영상을 전송할 수도 있습니다.

동영상의 전체 화면 미리보기를 오버레이한 일련의 동영상 썸네일 이미지 (이 중 하나는 강조표시됨). 오른쪽 상단에 'Cast Connect'라는 단어가 표시되어 있습니다.

개발자 기기 등록

애플리케이션 개발을 위해 Cast Connect 기능을 사용 설정하려면 Cast 개발자 콘솔에서 사용하고자 하는 Android TV 기기에 내장된 Chromecast의 일련번호를 등록해야 합니다. 일련번호는 Android TV에서 설정 > 기기 환경설정 > Chromecast 내장 > 일련번호로 이동하여 확인할 수 있습니다. 실제 기기의 일련번호와는 다르므로 위에서 설명한 방법으로 가져와야 합니다.

'Chromecast 내장' 화면, 버전 번호, 일련번호가 표시된 Android TV 화면 이미지

등록하지 않으면 보안상의 이유로 Cast Connect가 Google Play 스토어에서 설치된 앱에서만 작동합니다. 등록 프로세스를 시작하고 15분 후에 기기를 다시 시작합니다.

Android 발신기 앱 설치

휴대기기에서의 전송 요청을 테스트하기 위해 소스 코드 ZIP 다운로드에 Cast 동영상이라는 mobile-sender-0629.apk 파일을 간단한 발신자 애플리케이션으로 제공합니다. ADB를 활용하여 APK를 설치합니다. 이미 다른 버전의 Cast 동영상을 설치했다면 계속 진행하기 전에 설치한 버전을 기기에 있는 모든 프로필에서 제거하세요.

  1. Android 휴대전화에서 개발자 옵션과 USB 디버깅을 사용 설정합니다.
  2. USB 데이터 케이블을 연결하여 Android 휴대전화와 개발용 컴퓨터를 연결합니다.
  3. mobile-sender-0629.apk를 Android 휴대전화에 설치합니다.

mobile-sender.apk를 설치하기 위해 adb 설치 명령어를 실행하는 터미널 창 이미지

  1. Android 휴대전화에서 Cast 동영상 발신자 앱을 찾을 수 있습니다. Cast 동영상 발신자 앱 아이콘

Android 휴대전화 화면에서 실행되는 Cast 동영상 발신자 앱 이미지

Android TV 앱 설치

다음 안내에서는 Android 스튜디오에서 완성된 샘플 앱을 열고 실행하는 방법을 설명합니다.

  1. 시작 화면에서 Import Project 또는 File > New > Import Project... 메뉴 옵션을 선택합니다.
  2. 샘플 코드 폴더에서 폴더 아이콘app-done 디렉터리를 선택하고 OK를 클릭합니다.
  3. File > Android App Studio의 Gradle과 프로젝트 동기화 버튼 Sync Project with Gradle Files를 클릭합니다.
  4. Android TV 기기에서 개발자 옵션과 USB 디버깅을 사용 설정합니다.
  5. ADB가 Android TV 기기와 연결되면 기기가 Android 스튜디오에 표시됩니다. Android 스튜디오 툴바에 표시되는 Android TV 기기를 보여주는 이미지
  6. Android 스튜디오 실행 버튼, 오른쪽을 가리키는 녹색 삼각형Run 버튼을 클릭하면 몇 초 후 Cast Connect Codelab이라는 ATV 앱이 표시됩니다.

ATV 앱으로 Cast Connect 재생

  1. Android TV 홈 화면으로 이동합니다.
  2. Android 휴대전화에서 Cast 동영상 발신기 앱을 엽니다. 전송 버튼 전송 버튼 아이콘을 클릭하고 ATV 기기를 선택합니다.
  3. Cast Connect Codelab ATV 앱이 ATV에서 실행되고 발신자의 전송 버튼이 전송 버튼 아이콘 색상 반전에 연결되어 있다고 표시합니다.
  4. ATV 앱에서 동영상을 선택하면 동영상이 ATV에서 재생되기 시작합니다.
  5. 휴대전화에서 이제 미니 컨트롤러가 발신기 앱 하단에 표시됩니다. 재생/일시중지 버튼을 사용하여 재생을 제어할 수 있습니다.
  6. 휴대전화에서 동영상을 선택하여 재생합니다. 동영상이 ATV에서 재생되기 시작하며 확장 컨트롤러가 모바일 발신기에 표시됩니다.
  7. 휴대전화를 잠갔다 잠금 해제하면 미디어 재생을 제어하거나 전송을 중단하기 위한 알림이 잠금 화면에 표시됩니다.

소형 플레이어가 동영상을 재생하는 Android 휴대전화 화면 섹션 이미지

4. 시작 프로젝트 준비

이제 완성된 앱의 Cast Connect 통합을 확인했으므로 다운로드한 시작 앱에 Cast Connect 지원을 추가해야 합니다. 이제 Android 스튜디오를 사용하여 시작 프로젝트를 토대로 빌드할 준비가 되었습니다.

  1. 시작 화면에서 Import Project 또는 File > New > Import Project... 메뉴 옵션을 선택합니다.
  2. 샘플 코드 폴더에서 폴더 아이콘app-start 디렉터리를 선택하고 OK를 클릭합니다.
  3. File > Android 스튜디오의 Gradle과 프로젝트 동기화 버튼 Sync Project with Gradle Files를 클릭합니다.
  4. ATV 기기를 선택하고 Android 스튜디오의 Run 버튼(오른쪽을 가리키는 녹색 삼각형)Run 버튼을 클릭하여 앱을 실행하고 UI를 살펴봅니다. 선택한 Android TV 기기가 표시된 Android 스튜디오 툴바

동영상의 전체 화면 미리보기를 오버레이한 일련의 동영상 썸네일 이미지 (이 중 하나는 강조표시됨). 오른쪽 상단에 'Cast Connect'라는 단어가 표시되어 있습니다.

앱 디자인

앱에서는 사용자가 둘러볼 수 있는 동영상 목록을 제공합니다. 사용자는 Android TV에서 재생할 동영상을 선택할 수 있습니다. 앱은 두 가지 기본 활동 MainActivityPlaybackActivity로 구성됩니다.

MainActivity

이 활동에는 프래그먼트(MainFragment)가 포함되어 있습니다. 동영상 및 동영상 관련 메타데이터 목록은 MovieList 클래스에서 구성되고 setupMovies() 메서드는 Movie 객체 목록을 빌드하는 데 호출됩니다.

Movie 객체는 제목, 설명, 미리보기 이미지, 동영상 URL이 있는 동영상 항목을 나타냅니다. 각 Movie 객체는 CardPresenter에 바인딩되어 제목 및 스튜디오와 함께 동영상 미리보기 이미지를 표시하고 ArrayObjectAdapter에 전달됩니다.

항목을 선택하면 상응하는 Movie 객체가 PlaybackActivity에 전달됩니다.

PlaybackActivity

이 활동에는 ExoPlayer가 있는 VideoView, 일부 미디어 컨트롤, 선택한 동영상의 설명을 표시하는 텍스트 영역을 호스팅하고 사용자가 Android TV에서 동영상을 재생하도록 허용하는 프래그먼트(PlaybackVideoFragment)가 포함되어 있습니다. 사용자는 리모컨을 사용하여 동영상을 재생/일시중지하거나 동영상 재생을 탐색할 수 있습니다.

Cast Connect 기본 요건

Cast Connect는 AndroidX 네임스페이스를 사용하도록 ATV 앱을 업데이트해야 하는 새로운 버전의 Google Play 서비스를 사용합니다.

Android TV 앱에서 Cast Connect를 지원하려면 미디어 세션에서 이벤트를 만들고 지원해야 합니다. Cast Connect 라이브러리는 미디어 세션 상태에 기반하여 미디어 상태를 생성합니다. Cast Connect 라이브러리에서도 미디어 세션을 사용하여 일시중지와 같은 특정 메시지를 발신기에서 수신했을 때 신호를 보냅니다.

5. Cast 지원 구성

종속 항목

필요한 라이브러리 종속 항목을 포함하도록 앱 build.gradle 파일을 업데이트합니다.

dependencies {
    ....

    // Cast Connect libraries
    implementation 'com.google.android.gms:play-services-cast-tv:20.0.0'
    implementation 'com.google.android.gms:play-services-cast:21.1.0'
}

프로젝트를 동기화하여 오류 없이 프로젝트가 빌드되는지 확인합니다.

초기화

CastReceiverContext는 모든 Cast 상호작용을 조정하는 싱글톤 객체입니다. CastReceiverContext가 초기화될 때 ReceiverOptionsProvider 인터페이스를 구현하여 CastReceiverOptions를 제공해야 합니다.

CastReceiverOptionsProvider.kt 파일을 만들고 다음 클래스를 프로젝트에 추가합니다.

package com.google.sample.cast.castconnect

import android.content.Context
import com.google.android.gms.cast.tv.ReceiverOptionsProvider
import com.google.android.gms.cast.tv.CastReceiverOptions

class CastReceiverOptionsProvider : ReceiverOptionsProvider {
    override fun getOptions(context: Context): CastReceiverOptions {
        return CastReceiverOptions.Builder(context)
                .setStatusText("Cast Connect Codelab")
                .build()
    }
}

그런 다음 앱 AndroidManifest.xml 파일의 <application> 태그 내에 수신기 옵션 제공자를 지정합니다.

<application>
  ...
  <meta-data
    android:name="com.google.android.gms.cast.tv.RECEIVER_OPTIONS_PROVIDER_CLASS_NAME"
    android:value="com.google.sample.cast.castconnect.CastReceiverOptionsProvider" />
</application>

Cast 발신기에서 ATV 앱과 연결하려면 실행하려는 활동을 선택합니다. 이 Codelab에서는 전송 세션이 시작될 때 앱의 MainActivity를 시작합니다. AndroidManifest.xml 파일의 MainActivity에 시작 인텐트 필터를 추가합니다.

<activity android:name=".MainActivity">
  ...
  <intent-filter>
    <action android:name="com.google.android.gms.cast.tv.action.LAUNCH" />
    <category android:name="android.intent.category.DEFAULT" />
  </intent-filter>
</activity>

Cast 수신기 컨텍스트 수명 주기

앱이 실행될 때 CastReceiverContext를 시작하고 앱이 백그라운드로 이동할 때 CastReceiverContext를 중지해야 합니다. androidx.lifecycle 라이브러리LifecycleObserver를 사용하여 CastReceiverContext.start()CastReceiverContext.stop() 호출을 관리하는 것이 좋습니다.

MyApplication.kt 파일을 열고 애플리케이션의 onCreate 메서드에서 initInstance()를 호출하여 전송 컨텍스트를 초기화합니다. AppLifeCycleObserver 클래스에서 애플리케이션이 재개되면 CastReceiverContextstart()하고 애플리케이션이 일시중지되면 stop()합니다.

package com.google.sample.cast.castconnect

import com.google.android.gms.cast.tv.CastReceiverContext
...

class MyApplication : Application() {
    override fun onCreate() {
        super.onCreate()
        CastReceiverContext.initInstance(this)
        ProcessLifecycleOwner.get().lifecycle.addObserver(AppLifecycleObserver())
    }

    class AppLifecycleObserver : DefaultLifecycleObserver {
        override fun onResume(owner: LifecycleOwner) {
            Log.d(LOG_TAG, "onResume")
            CastReceiverContext.getInstance().start()
        }

        override fun onPause(owner: LifecycleOwner) {
            Log.d(LOG_TAG, "onPause")
            CastReceiverContext.getInstance().stop()
        }
    }
}

MediaManager에 MediaSession 연결

MediaManagerCastReceiverContext 싱글톤의 속성으로, 미디어 상태를 관리하고 로드 인텐트를 처리하며 발신기의 미디어 네임스페이스 메시지를 미디어 명령어로 변환하고 미디어 상태를 다시 발신기로 전송합니다.

MediaSession을 만들 때 현재 MediaSession 토큰도 MediaManager에 제공하여 명령어를 전송할 위치와 미디어 재생 상태를 검색할 위치를 알 수 있도록 해야 합니다. PlaybackVideoFragment.kt 파일에서 토큰을 MediaManager로 설정하기 전에 MediaSession가 초기화되었는지 확인합니다.

import com.google.android.gms.cast.tv.CastReceiverContext
import com.google.android.gms.cast.tv.media.MediaManager
...

class PlaybackVideoFragment : VideoSupportFragment() {
    private var castReceiverContext: CastReceiverContext? = null
    ...

    private fun initializePlayer() {
        if (mPlayer == null) {
            ...
            mMediaSession = MediaSessionCompat(getContext(), LOG_TAG)
            ...
            castReceiverContext = CastReceiverContext.getInstance()
            if (castReceiverContext != null) {
                val mediaManager: MediaManager = castReceiverContext!!.getMediaManager()
                mediaManager.setSessionCompatToken(mMediaSession!!.getSessionToken())
            }

        }
    }
}

비활성 재생으로 인해 MediaSession을 해제할 때 MediaManager에서 null 토큰을 설정해야 합니다.

private fun releasePlayer() {
    mMediaSession?.release()
    castReceiverContext?.mediaManager?.setSessionCompatToken(null)
    ...
}

샘플 앱 실행

Android 스튜디오의 Run 버튼(오른쪽을 가리키는 녹색 삼각형)Run 버튼을 클릭하여 ATV 기기에 앱을 배포하고 앱을 닫고 ATV 홈 화면으로 돌아갑니다. 발신자에서 전송 버튼 전송 버튼 아이콘을 클릭하고 ATV 기기를 선택합니다. ATV 앱이 ATV 기기에서 실행되고 Cast 버튼 상태가 연결된 것을 확인할 수 있습니다.

6. 미디어 로드 중

로드 명령어는 개발자 콘솔에서 정의한 패키지 이름이 있는 인텐트를 통해 전송됩니다. Android TV 앱에 다음과 같은 사전 정의된 인텐트 필터를 추가하여 이 인텐트를 수신할 타겟 활동을 지정해야 합니다. AndroidManifest.xml 파일에서 로드 인텐트 필터를 PlayerActivity에 추가합니다.

<activity android:name="com.google.sample.cast.castconnect.PlaybackActivity"
          android:launchMode="singleTask"
          android:exported="true">
  <intent-filter>
     <action android:name="com.google.android.gms.cast.tv.action.LOAD"/>
     <category android:name="android.intent.category.DEFAULT" />
  </intent-filter>
</activity>

Android TV에서 로드 요청 처리

이제 활동이 로드 요청이 포함된 이 인텐트를 수신하도록 구성되었으므로 이를 처리해야 합니다.

앱에서는 활동이 시작되면 processIntent라는 비공개 메서드를 호출합니다. 이 메서드에는 수신 인텐트를 처리하는 로직이 포함되어 있습니다. 로드 요청을 처리하기 위해 이 메서드를 수정하고 MediaManager 인스턴스의 onNewIntent 메서드를 호출하여 추가로 처리되도록 인텐트를 전송합니다. MediaManager는 인텐트가 로드 요청이라고 감지하면 인텐트에서 MediaLoadRequestData 객체를 추출하고 MediaLoadCommandCallback.onLoad()를 호출합니다. 로드 요청이 포함된 인텐트를 처리하도록 PlaybackVideoFragment.kt 파일의 processIntent 메서드를 수정합니다.

fun processIntent(intent: Intent?) {
    val mediaManager: MediaManager = CastReceiverContext.getInstance().getMediaManager()
    // Pass intent to Cast SDK
    if (mediaManager.onNewIntent(intent)) {
        return
    }

    // Clears all overrides in the modifier.
    mediaManager.getMediaStatusModifier().clear()

    // If the SDK doesn't recognize the intent, handle the intent with your own logic.
    ...
}

다음으로 MediaManager에서 호출한 onLoad() 메서드를 재정의하는 추상 클래스 MediaLoadCommandCallback을 확장합니다. 이 메서드는 로드 요청의 데이터를 수신하여 Movie 객체로 변환합니다. 변환되면 영화가 로컬 플레이어에서 재생됩니다. 그런 다음 MediaManagerMediaLoadRequest로 업데이트되고 연결된 발신기에 MediaStatus를 브로드캐스트합니다. PlaybackVideoFragment.kt 파일에 MyMediaLoadCommandCallback이라는 중첩된 비공개 클래스를 만듭니다.

import com.google.android.gms.cast.MediaLoadRequestData
import com.google.android.gms.cast.MediaInfo
import com.google.android.gms.cast.MediaMetadata
import com.google.android.gms.cast.MediaError
import com.google.android.gms.cast.tv.media.MediaException
import com.google.android.gms.cast.tv.media.MediaCommandCallback
import com.google.android.gms.cast.tv.media.QueueUpdateRequestData
import com.google.android.gms.cast.tv.media.MediaLoadCommandCallback
import com.google.android.gms.tasks.Task
import com.google.android.gms.tasks.Tasks
import android.widget.Toast
...

private inner class MyMediaLoadCommandCallback :  MediaLoadCommandCallback() {
    override fun onLoad(
        senderId: String?, mediaLoadRequestData: MediaLoadRequestData): Task<MediaLoadRequestData> {
        Toast.makeText(activity, "onLoad()", Toast.LENGTH_SHORT).show()
        return if (mediaLoadRequestData == null) {
            // Throw MediaException to indicate load failure.
            Tasks.forException(MediaException(
                MediaError.Builder()
                    .setDetailedErrorCode(MediaError.DetailedErrorCode.LOAD_FAILED)
                    .setReason(MediaError.ERROR_REASON_INVALID_REQUEST)
                    .build()))
        } else Tasks.call {
            play(convertLoadRequestToMovie(mediaLoadRequestData)!!)
            // Update media metadata and state
            val mediaManager = castReceiverContext!!.mediaManager
            mediaManager.setDataFromLoad(mediaLoadRequestData)
            mediaLoadRequestData
        }
    }
}

private fun convertLoadRequestToMovie(mediaLoadRequestData: MediaLoadRequestData?): Movie? {
    if (mediaLoadRequestData == null) {
        return null
    }
    val mediaInfo: MediaInfo = mediaLoadRequestData.getMediaInfo() ?: return null
    var videoUrl: String = mediaInfo.getContentId()
    if (mediaInfo.getContentUrl() != null) {
        videoUrl = mediaInfo.getContentUrl()
    }
    val metadata: MediaMetadata = mediaInfo.getMetadata()
    val movie = Movie()
    movie.videoUrl = videoUrl
    movie.title = metadata?.getString(MediaMetadata.KEY_TITLE)
    movie.description = metadata?.getString(MediaMetadata.KEY_SUBTITLE)
    if(metadata?.hasImages() == true) {
        movie.cardImageUrl = metadata.images[0].url.toString()
    }
    return movie
}

이제 콜백이 정의되었으므로 MediaManager에 콜백을 등록해야 합니다. 콜백은 MediaManager.onNewIntent()를 호출하기 전에 등록해야 합니다. 플레이어가 초기화될 때 setMediaLoadCommandCallback을 추가합니다.

private fun initializePlayer() {
    if (mPlayer == null) {
        ...
        mMediaSession = MediaSessionCompat(getContext(), LOG_TAG)
        ...
        castReceiverContext = CastReceiverContext.getInstance()
        if (castReceiverContext != null) {
            val mediaManager: MediaManager = castReceiverContext.getMediaManager()
            mediaManager.setSessionCompatToken(mMediaSession.getSessionToken())
            mediaManager.setMediaLoadCommandCallback(MyMediaLoadCommandCallback())
        }
    }
}

샘플 앱 실행

Android 스튜디오의 Run 버튼(오른쪽을 가리키는 녹색 삼각형)Run 버튼을 클릭하여 ATV 기기에 앱을 배포합니다. 발신자에서 전송 버튼 전송 버튼 아이콘을 클릭하고 ATV 기기를 선택합니다. ATV 앱이 ATV 기기에서 실행됩니다. 휴대기기에서 동영상을 선택하면 동영상이 ATV에서 재생됩니다. 재생 컨트롤이 있는 휴대전화에서 알림을 수신하는지 확인합니다. 일시중지와 같은 컨트롤을 사용해 보면 ATV 기기에서 동영상이 일시중지됩니다.

7. Cast 제어 명령어 지원

현재 애플리케이션에서는 이제 미디어 세션과 호환되는 기본 명령어(예: 재생, 일시중지, 탐색)를 지원합니다. 그러나 미디어 세션에서 사용할 수 없는 몇 가지 Cast 제어 명령어가 있습니다. MediaCommandCallback을 등록하여 이러한 Cast 제어 명령어를 지원해야 합니다.

플레이어가 초기화될 때 setMediaCommandCallback을 사용하여 MediaManager 인스턴스에 MyMediaCommandCallback을 추가합니다.

private fun initializePlayer() {
    ...
    castReceiverContext = CastReceiverContext.getInstance()
    if (castReceiverContext != null) {
        val mediaManager = castReceiverContext!!.mediaManager
        ...
        mediaManager.setMediaCommandCallback(MyMediaCommandCallback())
    }
}

메서드(예: onQueueUpdate())를 재정의하는 MyMediaCommandCallback 클래스를 만들어 이러한 Cast 제어 명령어를 지원합니다.

private inner class MyMediaCommandCallback : MediaCommandCallback() {
    override fun onQueueUpdate(
        senderId: String?,
        queueUpdateRequestData: QueueUpdateRequestData
    ): Task<Void> {
        Toast.makeText(getActivity(), "onQueueUpdate()", Toast.LENGTH_SHORT).show()
        // Queue Prev / Next
        if (queueUpdateRequestData.getJump() != null) {
            Toast.makeText(
                getActivity(),
                "onQueueUpdate(): Jump = " + queueUpdateRequestData.getJump(),
                Toast.LENGTH_SHORT
            ).show()
        }
        return super.onQueueUpdate(senderId, queueUpdateRequestData)
    }
}

8. 미디어 상태 작업

미디어 상태 수정

Cast Connect는 미디어 세션에서 기본 미디어 상태를 가져옵니다. 고급 기능을 지원하려면 Android TV 앱에서 MediaStatusModifier를 통해 추가 상태 속성을 지정하고 재정의하면 됩니다. MediaStatusModifier는 항상 CastReceiverContext에서 설정한 MediaSession에서 작동합니다.

예를 들어 onLoad 콜백이 트리거될 때 setMediaCommandSupported를 지정하려면 다음 명령어를 실행합니다.

import com.google.android.gms.cast.MediaStatus
...
private class MyMediaLoadCommandCallback : MediaLoadCommandCallback() {
    fun onLoad(
        senderId: String?,
        mediaLoadRequestData: MediaLoadRequestData
    ): Task<MediaLoadRequestData> {
        Toast.makeText(getActivity(), "onLoad()", Toast.LENGTH_SHORT).show()
        ...
        return Tasks.call({
            play(convertLoadRequestToMovie(mediaLoadRequestData)!!)
            ...
            // Use MediaStatusModifier to provide additional information for Cast senders.
            mediaManager.getMediaStatusModifier()
                .setMediaCommandSupported(MediaStatus.COMMAND_QUEUE_NEXT, true)
                .setIsPlayingAd(false)
            mediaManager.broadcastMediaStatus()
            // Return the resolved MediaLoadRequestData to indicate load success.
            mediaLoadRequestData
        })
    }
}

전송하기 전에 MediaStatus 가로채기

웹 수신기 SDK의 MessageInterceptor와 마찬가지로 MediaManager에서 MediaStatusWriter를 지정하여 연결된 발신자에게 브로드캐스트되기 전에 MediaStatus을 추가로 수정할 수 있습니다.

예를 들어 모바일 발신기에 전송하기 전에 MediaStatus에서 맞춤 데이터를 설정할 수 있습니다.

import com.google.android.gms.cast.tv.media.MediaManager.MediaStatusInterceptor
import com.google.android.gms.cast.tv.media.MediaStatusWriter
import org.json.JSONObject
import org.json.JSONException
...

private fun initializePlayer() {
    if (mPlayer == null) {
        ...
        if (castReceiverContext != null) {
            ...
            val mediaManager: MediaManager = castReceiverContext.getMediaManager()
            ...
            // Use MediaStatusInterceptor to process the MediaStatus before sending out.
            mediaManager.setMediaStatusInterceptor(
                MediaStatusInterceptor { mediaStatusWriter: MediaStatusWriter ->
                    try {
                        mediaStatusWriter.setCustomData(JSONObject("{myData: 'CustomData'}"))
                    } catch (e: JSONException) {
                        Log.e(LOG_TAG,e.message,e);
                    }
            })
        }
    }
}        

9. 완료

지금까지 Cast Connect 라이브러리를 사용하여 Android TV 앱에서 Cast를 지원하도록 하는 방법을 알아봤습니다.

자세한 내용은 개발자 가이드를 참고하세요. /cast/docs/android_tv_receiver.