TV 입력 서비스 개발

TV 입력 서비스는 미디어 스트림 소스를 나타냅니다. TV 입력 서비스를 사용하면 미디어 콘텐츠를 채널 및 프로그램과 같은 선형 방송 TV 방식으로 내보낼 수 있습니다. 또한 자녀 보호 기능, 프로그램 가이드 정보 및 콘텐츠 등급도 제공할 수 있습니다. TV 입력 서비스를 Android 시스템 TV 앱과 함께 사용할 수 있습니다. 이 앱은 궁극적으로 TV의 채널 콘텐츠를 제어하고 제공합니다. 시스템 TV 앱은 기기 전용으로 개발되며 타사 앱으로 변경할 수 없습니다. TV 입력 프레임워크(TIF) 아키텍처 및 구성요소에 관한 자세한 내용은 TV 입력 프레임워크를 참조하세요.

TIF 컴패니언 라이브러리를 사용하여 TV 입력 서비스 만들기

TIF 컴패니언 라이브러리는 일반 TV 입력 서비스 기능의 확장 가능한 구현을 제공하는 프레임워크입니다. Android TV를 위한 권장사항을 따르는 TV 입력 서비스를 빠르고 쉽게 만들려면 TIF 컴패니언 라이브러리를 사용하세요.

프로젝트 업데이트

TIF 컴패니언 라이브러리 사용을 시작하려면 앱의 build.gradle 파일에 다음을 추가하세요.

    compile 'com.google.android.libraries.tv:companionlibrary:0.2'
    

TIF 컴패니언 라이브러리는 현재 Android 프레임워크의 일부가 아닙니다. TIF 컴패니언 라이브러리는 Android SDK가 아닌 jcenter를 통해 Gradle 종속 항목으로 배포됩니다. TIF 컴패니언 라이브러리의 최신 버전을 찾으려면 jcenter를 확인하세요.

매니페스트에서 TV 입력 서비스 선언

앱은 시스템에서 앱에 액세스하는 데 사용하는 TvInputService 호환 서비스를 제공해야 합니다. TIF 컴패니언 라이브러리는 BaseTvInputService 클래스를 제공하며 이 클래스는 맞춤설정할 수 있는 기본 TvInputService 구현을 제공합니다. BaseTvInputService의 서브클래스를 만들고 매니페스트의 서브클래스를 서비스로 선언합니다.

매니페스트 선언 내에서 BIND_TV_INPUT 권한을 지정하여 서비스에서 TV 입력을 시스템에 연결할 수 있도록 합니다. 시스템 서비스가 결합을 실행하며 시스템 서비스에 BIND_TV_INPUT 권한이 있습니다. 시스템 TV 앱에서 TvInputManager 인터페이스를 통해 TV 입력 서비스에 요청을 보냅니다.

서비스 선언에서는 인텐트를 사용해 실행할 작업으로 TvInputService를 지정하는 인텐트 필터를 포함합니다. 또한 서비스 메타데이터를 별도의 XML 리소스로 선언합니다. 서비스 선언, 인텐트 필터 및 서비스 메타데이터 선언은 다음 예에 나와 있습니다.

    <service android:name=".rich.RichTvInputService"
        android:label="@string/rich_input_label"
        android:permission="android.permission.BIND_TV_INPUT">
        <!-- Required filter used by the system to launch our account service. -->
        <intent-filter>
            <action android:name="android.media.tv.TvInputService" />
        </intent-filter>
        <!-- An XML file which describes this input. This provides pointers to
        the RichTvInputSetupActivity to the system/TV app. -->
        <meta-data
            android:name="android.media.tv.input"
            android:resource="@xml/richtvinputservice" />
    </service>
    

서비스 메타데이터를 별도의 XML 파일에 정의합니다. 서비스 메타데이터 XML 파일에는 TV 입력의 초기 구성 및 채널 스캔을 설명하는 설정 인터페이스가 포함되어야 합니다. 메타데이터 파일에는 사용자가 콘텐츠를 기록할 수 있는지 여부를 나타내는 플래그도 포함되어야 합니다. 앱에서 콘텐츠 녹화를 지원하는 방법에 관한 자세한 내용은 TV 녹화를 참조하세요.

서비스 메타데이터 파일은 앱의 XML 리소스 디렉터리에 있으며 매니페스트에서 선언한 리소스의 이름과 일치해야 합니다. 이전 예의 매니페스트 항목을 사용하여 res/xml/richtvinputservice.xml에 다음 콘텐츠가 포함된 XML 파일을 만듭니다.

    <?xml version="1.0" encoding="utf-8"?>
    <tv-input xmlns:android="http://schemas.android.com/apk/res/android"
      android:canRecord="true"
      android:setupActivity="com.example.android.sampletvinput.rich.RichTvInputSetupActivity" />
    

채널 정의 및 설정 활동 만들기

TV 입력 서비스는 사용자가 시스템 TV 앱을 통해 액세스하는 채널을 하나 이상 정의해야 합니다. 시스템 데이터베이스에 채널을 등록하고 시스템에서 앱의 채널을 찾을 수 없을 때 호출하는 설정 활동을 제공해야 합니다.

먼저 시스템 전자 프로그래밍 가이드(EPG)에서 읽고 쓸 수 있도록 앱을 사용 설정하세요. 시스템 전자 프로그래밍 가이드의 데이터에는 사용자가 사용할 수 있는 채널 및 프로그램이 포함됩니다. 이 작업을 수행하도록 앱을 사용 설정하고 기기를 다시 시작한 후 EPG와 동기화하려면 앱 manifest에 다음 요소를 추가하세요.

    <uses-permission android:name="com.android.providers.tv.permission.WRITE_EPG_DATA" />
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED "/>
    

다음 요소를 추가하여 Google Play 스토어에 앱이 Android TV의 콘텐츠 채널을 제공하는 앱으로 표시되도록 하세요.

    <uses-feature
        android:name="android.software.live_tv"
        android:required="true" />
    

다음으로 EpgSyncJobService 클래스를 확장하는 클래스를 만드세요. 이 추상 클래스를 사용하면 시스템 데이터베이스에서 채널을 만들고 업데이트하는 작업 서비스를 쉽게 생성할 수 있습니다.

서브클래스에서 getChannels()에 전체 채널 목록을 만들고 반환합니다. XMLTV 파일에서 채널을 가져왔다면 XmlTvParser 클래스를 사용합니다. 그러지 않으면 Channel.Builder 클래스를 사용하여 프로그래매틱 방식으로 채널을 생성합니다.

각 채널과 관련하여 시스템은 지정된 시간 내에 채널에서 볼 수 있는 프로그램의 목록이 필요할 때 getProgramsForChannel()을 호출합니다. 채널의 Program 객체 목록을 반환합니다. XmlTvParser 클래스를 사용하여 XMLTV 파일에서 프로그램을 가져오거나 Program.Builder 클래스를 사용하여 프로그래매틱 방식으로 프로그램을 생성합니다.

Program 객체와 관련해서는 InternalProviderData 객체를 사용하여 프로그램의 동영상 유형과 같은 프로그램 정보를 설정합니다. 채널에서 제한된 수의 프로그램만 루프로 반복해야 한다면 프로그램 관련 정보를 설정할 때 InternalProviderData.setRepeatable() 메서드를 true 값과 함께 사용합니다.

작업 서비스를 구현한 후 다음과 같이 앱 매니페스트에 추가하세요.

    <service
        android:name=".sync.SampleJobService"
        android:permission="android.permission.BIND_JOB_SERVICE"
        android:exported="true" />
    

마지막으로 설정 활동을 만드세요. 설정 활동에서 채널과 프로그램 데이터를 동기화하는 방법을 제공해야 합니다. 채널과 프로그램 데이터를 동기화하는 한 가지 방법은 사용자가 활동의 UI를 통해 동기화하는 것입니다. 활동이 시작될 때 앱에서 자동으로 동기화하도록 할 수도 있습니다. 설정 활동에서 채널과 프로그램 정보를 동기화해야 하는 경우 앱에서 작업 서비스를 시작해야 합니다.

Kotlin

    val inputId = getActivity().intent.getStringExtra(TvInputInfo.EXTRA_INPUT_ID)
    EpgSyncJobService.cancelAllSyncRequests(getActivity())
    EpgSyncJobService.requestImmediateSync(
            getActivity(),
            inputId,
            ComponentName(getActivity(), SampleJobService::class.java)
    )
    

자바

    String inputId = getActivity().getIntent().getStringExtra(TvInputInfo.EXTRA_INPUT_ID);
    EpgSyncJobService.cancelAllSyncRequests(getActivity());
    EpgSyncJobService.requestImmediateSync(getActivity(), inputId,
            new ComponentName(getActivity(), SampleJobService.class));
    

requestImmediateSync() 메서드를 사용하여 작업 서비스를 동기화합니다. 사용자가 동기화가 완료될 때까지 기다려야 하므로 요청 기간을 비교적 짧게 유지해야 합니다.

setUpPeriodicSync() 메서드를 사용하여 작업 서비스가 백그라운드에서 채널 및 프로그램 데이터를 주기적으로 동기화하도록 합니다.

Kotlin

    EpgSyncJobService.setUpPeriodicSync(
            context,
            inputId,
            ComponentName(context, SampleJobService::class.java)
    )
    

자바

    EpgSyncJobService.setUpPeriodicSync(context, inputId,
            new ComponentName(context, SampleJobService.class));
    

TIF 컴패니언 라이브러리는 채널 데이터의 동기화 기간을 밀리초로 지정할 수 있는 requestImmediateSync()의 오버로드된 메서드를 추가로 제공합니다. 기본 메서드는 1시간 분량의 채널 데이터를 동기화합니다.

또한 TIF 컴패니언 라이브러리는 채널 데이터의 동기화 기간 및 주기적 동기화 발생 빈도를 지정할 수 있는 setUpPeriodicSync()의 오버로드된 메서드를 추가로 제공합니다. 기본 메서드는 12시간마다 48시간 분량의 채널 데이터를 동기화합니다.

채널 데이터 및 EPG에 관한 자세한 내용은 채널 데이터 작업을 참조하세요.

미세 조정 요청 및 미디어 재생 처리

사용자가 특정 채널을 선택하면 시스템 TV 앱은 앱에서 생성한 Session을 사용하여 요청된 채널을 미세 조정하고 콘텐츠를 재생합니다. TIF 컴패니언 라이브러리는 시스템의 채널 및 세션 호출을 처리하기 위해 확장할 수 있는 여러 클래스를 제공합니다.

BaseTvInputService 서브클래스는 미세 조정 요청을 처리하는 세션을 생성합니다. onCreateSession() 메서드를 재정의하고 BaseTvInputService.Session 클래스에서 확장된 세션을 생성하고 새로운 세션으로 super.sessionCreated()를 호출합니다. 다음 예에서 onCreateSession()BaseTvInputService.Session을 확장하는 RichTvInputSessionImpl 객체를 반환합니다.

Kotlin

    override fun onCreateSession(inputId: String): Session =
            RichTvInputSessionImpl(this, inputId).apply {
                setOverlayViewEnabled(true)
            }
    

자바

    @Override
    public final Session onCreateSession(String inputId) {
        RichTvInputSessionImpl session = new RichTvInputSessionImpl(this, inputId);
        session.setOverlayViewEnabled(true);
        return session;
    }
    

사용자가 시스템 TV 앱을 사용하여 채널 중 하나를 보기 시작하면 시스템에서 세션의 onPlayChannel() 메서드를 호출합니다. 프로그램이 재생되기 전에 특수 채널 초기화를 실행해야 한다면 이 메서드를 재정의하세요.

그러면 시스템에서 현재 예약된 프로그램을 가져오고 세션의 onPlayProgram() 메서드를 호출한 후 프로그램 정보를 지정하고 시작 시간을 밀리초로 지정합니다. 프로그램 재생을 시작하려면 TvPlayer 인터페이스를 사용합니다.

미디어 플레이어 코드는 특정 재생 이벤트를 처리하기 위해 TvPlayer를 구현해야 합니다. TvPlayer 클래스는 BaseTvInputService 구현을 더 복잡하게 만들지 않고 타임 시프팅 제어와 같은 기능을 처리합니다.

세션의 getTvPlayer() 메서드에서 TvPlayer를 구현하는 미디어 플레이어를 반환하세요. TV 입력 서비스 샘플 앱은 ExoPlayer를 사용하는 미디어 플레이어를 구현합니다.

TV 입력 프레임워크를 사용하여 TV 입력 서비스 만들기

TV 입력 서비스에서 TIF 컴패니언 라이브러리를 사용할 수 없다면 다음 구성요소를 구현해야 합니다.

  • TvInputService - TV 입력에 장기 실행 및 백그라운드 가용성을 제공합니다.
  • TvInputService.Session - TV 입력 상태를 유지하고 호스팅 앱과 통신합니다.
  • TvContract - TV 입력에 사용할 수 있는 채널 및 프로그램을 설명합니다.
  • TvContract.Channels - TV 채널에 관한 정보를 나타냅니다.
  • TvContract.Programs - 프로그램 제목 및 시작 시간과 같은 데이터를 사용하여 TV 프로그램을 설명합니다.
  • TvTrackInfo - 오디오, 동영상 또는 자막 트랙을 나타냅니다.
  • TvContentRating - 콘텐츠 등급을 설명하며 맞춤 콘텐츠 등급 체계를 사용할 수 있도록 허용합니다.
  • TvInputManager - 시스템 TV 앱에 API를 제공하고 TV 입력 및 앱과의 상호작용을 관리합니다.

또한 다음을 실행해야 합니다.

  1. 매니페스트에서 TV 입력 서비스 선언에 설명된 대로 매니페스트에서 TV 입력 서비스를 선언합니다.
  2. 서비스 메타데이터 파일을 만듭니다.
  3. 채널과 프로그램 정보를 만들고 등록합니다.
  4. 설정 활동을 만듭니다.

TV 입력 서비스 정의

서비스의 TvInputService 클래스를 확장합니다. TvInputService 구현은 바인드된 서비스이며, 여기서 시스템 서비스는 결합된 클라이언트입니다. 구현해야 하는 서비스 수명 주기 메서드는 그림 1에 나와 있습니다.

onCreate() 메서드는 시스템 기반 작업을 처리하기 위해 UI 스레드와 별도로 프로세스 스레드를 제공하는 HandlerThread를 초기화하고 시작합니다. 다음 예에서 onCreate() 메서드는 CaptioningManager를 초기화하고 ACTION_BLOCKED_RATINGS_CHANGEDACTION_PARENTAL_CONTROLS_ENABLED_CHANGED 작업을 처리할 준비를 합니다. 이러한 작업은 사용자가 자녀 보호 기능 설정을 변경하고 차단된 등급 목록이 변경되었을 때 실행된 시스템 인텐트를 설명합니다.

Kotlin

    override fun onCreate() {
        super.onCreate()
        handlerThread = HandlerThread(javaClass.simpleName).apply {
            start()
        }
        dbHandler = Handler(handlerThread.looper)
        handler = Handler()
        captioningManager = getSystemService(Context.CAPTIONING_SERVICE) as CaptioningManager

        setTheme(android.R.style.Theme_Holo_Light_NoActionBar)

        sessions = mutableListOf<BaseTvInputSessionImpl>()
        val intentFilter = IntentFilter().apply {
            addAction(TvInputManager.ACTION_BLOCKED_RATINGS_CHANGED)
            addAction(TvInputManager.ACTION_PARENTAL_CONTROLS_ENABLED_CHANGED)
        }
        registerReceiver(broadcastReceiver, intentFilter)
    }
    

자바

    @Override
    public void onCreate() {
        super.onCreate();
        handlerThread = new HandlerThread(getClass()
          .getSimpleName());
        handlerThread.start();
        dbHandler = new Handler(handlerThread.getLooper());
        handler = new Handler();
        captioningManager = (CaptioningManager)
          getSystemService(Context.CAPTIONING_SERVICE);

        setTheme(android.R.style.Theme_Holo_Light_NoActionBar);

        sessions = new ArrayList<BaseTvInputSessionImpl>();
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(TvInputManager
          .ACTION_BLOCKED_RATINGS_CHANGED);
        intentFilter.addAction(TvInputManager
          .ACTION_PARENTAL_CONTROLS_ENABLED_CHANGED);
        registerReceiver(broadcastReceiver, intentFilter);
    }
    

그림 1.TvInputService 수명 주기

차단된 콘텐츠 작업 및 자녀 보호 기능 제공에 관한 자세한 내용은 콘텐츠 제어를 참조하세요. TV 입력 서비스에서 처리할 수 있는 다양한 시스템 기반 작업에 관해서는 TvInputManager를 참조하세요.

TvInputServiceHandler.Callback을 구현하여 플레이어 상태 변경사항을 처리하는 TvInputService.Session을 생성합니다. onSetSurface()를 사용하면 TvInputService.Session은 동영상 콘텐츠로 Surface를 설정합니다. Surface를 사용하여 동영상을 렌더링하는 방법에 관한 자세한 내용은 플레이어를 표면과 통합을 참조하세요.

TvInputService.Session은 사용자가 채널을 선택할 때 onTune() 이벤트를 처리하며 콘텐츠 및 콘텐츠 메타데이터의 변경사항을 시스템 TV 앱에 알립니다. 이러한 notify() 메서드는 이 학습 과정의 콘텐츠 제어트랙 선택 처리 섹션에 자세히 설명되어 있습니다.

설정 활동 정의

시스템 TV 앱에서는 TV 입력에 정의된 설정 활동을 사용합니다. 설정 활동은 필수사항이며 시스템 데이터베이스에 채널 레코드를 하나 이상 제공해야 합니다. 시스템 TV 앱은 TV 입력을 위한 채널을 찾을 수 없을 때 설정 활동을 호출합니다.

설정 활동은 다음 과정인 채널 데이터 만들기 및 업데이트에 설명된 대로 TV 입력을 통해 제공된 채널을 시스템 TV 앱에 설명합니다.

추가 자료