1. 개요
이 Codelab에서는 Google Cast 지원 기기에서 콘텐츠를 전송하도록 기존 웹 동영상 앱을 수정하는 방법을 설명합니다.
Google Cast란 무엇인가요?
사용자는 Google Cast를 사용하여 휴대기기의 콘텐츠를 TV로 전송할 수 있습니다. 그런 다음, 휴대기기를 리모컨으로 사용해 TV에서 재생 중인 미디어를 제어할 수 있습니다.
Google Cast SDK를 사용하면 앱을 확장하여 TV 또는 사운드 시스템을 제어할 수 있습니다. 다시 말해, Google Cast 디자인 체크리스트에 따라 필요한 UI 구성요소를 추가하는 것이 가능합니다.
Google Cast 디자인 체크리스트는 지원되는 모든 플랫폼에서 Cast 사용자 환경을 간단하고 예측 가능하게 만들기 위해 제공됩니다.
무엇을 빌드하게 되나요?
이 Codelab을 완료하면 Google Cast 기기에 동영상을 전송할 수 있는 Chrome 웹 동영상 앱을 빌드하게 됩니다.
학습할 내용
- 샘플 동영상 앱에 Google Cast SDK를 추가하는 방법
- Google Cast 기기를 선택할 수 있는 전송 버튼을 추가하는 방법
- Cast 기기에 연결하고 미디어 수신기를 실행하는 방법
- 동영상을 전송하는 방법
- Cast Connect 통합 방법
필요한 항목
- 최신 Chrome 브라우저
- Firebase 호스팅 또는 ngrok과 같은 HTTPS 호스팅 서비스
- Chromecast 또는 Android TV 등 인터넷 연결이 가능한 Google Cast 기기
- HDMI 입력 단자가 있는 TV 또는 모니터
- Cast Connect 통합을 테스트하려면 Chromecast with Google TV가 필요하지만 나머지 Codelab에서는 선택사항입니다. 없는 경우 이 튜토리얼의 끝부분에 있는 Cast Connect 지원 추가 단계를 건너뛰어도 됩니다.
경험
- 웹 개발에 관한 사전지식이 있어야 합니다.
- 또한 TV 시청에 관한 사전 지식도 필요합니다. :)
본 가이드를 어떻게 사용하실 계획인가요?
웹 앱 빌드 경험을 평가해 주세요.
TV 시청 관련 경험을 평가해 주세요.
2. 샘플 코드 가져오기
모든 샘플 코드를 컴퓨터에 다운로드할 수 있습니다.
그런 다음 다운로드한 ZIP 파일의 압축을 풉니다.
3. 샘플 앱 실행
먼저 완성된 샘플 앱이 어떤 모습인지 살펴보겠습니다. 기본 동영상 플레이어로 사용되는 앱입니다. 사용자가 목록에서 동영상을 선택한 다음 기기에서 로컬로 재생하거나 Google Cast 기기로 전송할 수 있습니다.
완성된 파일을 사용하려면 호스팅되어야 합니다.
사용할 수 있는 서버가 없다면 Firebase 호스팅 또는 ngrok을 사용할 수 있습니다.
서버 실행
원하는 서비스를 설정한 후 app-done
로 이동하여 서버를 시작합니다.
브라우저에서 호스팅한 샘플의 https URL을 방문합니다.
- 동영상 앱이 표시됩니다.
- 전송 버튼을 클릭하고 Google Cast 기기를 선택합니다.
- 동영상을 선택하고 재생 버튼을 클릭합니다.
- Google Cast 기기에서 동영상이 재생되기 시작합니다.
동영상 요소에서 일시중지 버튼을 클릭하면 수신기에서 동영상이 일시중지됩니다. 동영상을 다시 계속 재생하려면 동영상 요소에서 재생 버튼을 클릭합니다.
Google Cast 기기로의 전송을 중지하려면 전송 버튼을 클릭합니다.
계속하기 전에 서버를 중지합니다.
4. 시작 프로젝트 준비
다운로드한 시작 앱에 Google Cast 지원 기능을 추가해야 합니다. 다음은 이 Codelab에서 사용할 Google Cast 용어입니다.
- 발신기 앱은 휴대기기 또는 노트북에서 실행됩니다.
- 수신기 앱은 Google Cast 기기에서 실행됩니다.
이제 선호하는 텍스트 편집기를 사용하여 시작 프로젝트 상단에 빌드할 준비가 되었습니다.
- 샘플 코드 다운로드에서
app-start
디렉터리를 선택합니다. - 서버를 사용하여 앱을 실행하고 UI를 살펴봅니다.
이 Codelab을 진행하는 동안 서비스에 따라 서버에서 샘플을 다시 호스팅해야 합니다.
앱 디자인
앱이 원격 웹 서버에서 동영상 목록을 가져오고 사용자가 둘러볼 수 있도록 목록을 제공합니다. 사용자는 동영상을 선택하여 세부정보를 보거나 휴대기기에서 로컬로 동영상을 재생할 수 있습니다.
앱은 index.html
에 정의된 기본 뷰와 기본 컨트롤러(CastVideos.js.
)로 구성됩니다.
index.html
이 html 파일에서는 웹 앱의 거의 모든 UI를 선언합니다.
뷰의 일부 섹션에는 동영상 요소가 포함된 div#main_video
가 있습니다. 동영상 div와 관련하여 동영상 요소의 모든 컨트롤을 정의하는 div#media_control
가 있습니다. 그 아래에는 뷰에 동영상의 세부정보를 표시하는 media_info
가 있습니다. 마지막으로 carousel
div는 div의 동영상 목록을 표시합니다.
index.html
파일은 또한 Cast SDK를 부트스트랩하고 CastVideos
함수에 로드하도록 지시합니다.
이러한 요소를 채우는 대부분의 콘텐츠는 CastVideos.js
에서 정의, 삽입 및 관리됩니다. 이제 이 내용을 살펴보겠습니다.
CastVideos.js
이 스크립트는 Cast 동영상 웹 앱의 모든 로직을 관리합니다. CastVideos.js
에 정의된 동영상 및 관련 메타데이터의 목록은 mediaJSON
라는 객체에 포함되어 있습니다.
로컬과 원격으로 모두 동영상을 관리하고 재생하는 몇 개의 주요 섹션이 있습니다. 이 웹 애플리케이션은 전반적으로 간단합니다.
CastPlayer
는 전체 앱을 관리하는 기본 클래스로, 플레이어를 설정하고 미디어를 선택하며 이벤트를 PlayerHandler
에 바인딩하여 미디어를 재생합니다. CastPlayer.prototype.initializeCastPlayer
는 모든 Cast 기능을 설정하는 메서드입니다. CastPlayer.prototype.switchPlayer
는 로컬 플레이어와 원격 플레이어 간에 상태를 전환합니다. CastPlayer.prototype.setupLocalPlayer
및 CastPlayer.prototype.setupRemotePlayer
는 로컬 플레이어와 원격 플레이어를 초기화합니다.
PlayerHandler
는 미디어 재생을 관리하는 클래스입니다. 기타 미디어 및 재생을 세부적으로 관리하는 메서드가 많이 있습니다.
자주 묻는 질문(FAQ)
5. 전송 버튼 추가
Cast 지원 애플리케이션은 동영상 요소에 전송 버튼을 표시합니다. 전송 버튼을 클릭하면 사용자가 선택할 수 있는 Cast 기기 목록이 표시됩니다. 사용자가 발신기 기기에서 로컬로 콘텐츠를 재생 중인 경우 Cast 기기를 선택하면 Cast 기기에서 재생이 시작되거나 재개됩니다. 사용자는 Cast 세션 중 언제든지 전송 버튼을 클릭하여 애플리케이션의 Cast 기기 전송을 중지할 수 있습니다. 사용자는 Google Cast 디자인 체크리스트에 설명된 대로 애플리케이션의 모든 화면에서 Cast 기기에 연결 또는 연결 해제할 수 있어야 합니다.
구성
시작 프로젝트에서는 완료된 샘플 앱에 진행한 동일한 종속 항목과 설정이 필요하지만 이번에는 app-start
의 콘텐츠를 호스팅합니다.
브라우저에서 호스팅한 샘플의 https
URL을 방문합니다.
변경할 때 서비스에 따라 서버에서 샘플을 다시 호스팅해야 합니다.
초기화
Cast 프레임워크에는 프레임워크의 모든 활동을 조정하는 전역 싱글톤 객체 CastContext
가 있습니다. 이 객체는 일반적으로 Cast SDK가 로드된 후 호출되고 사용할 수 있는 window['__onGCastApiAvailable']
에 할당된 콜백에서 호출되는 애플리케이션의 수명 주기 초기에 초기화되어야 합니다. 이 경우 CastContext
는 앞서 언급한 콜백에서 호출되는 CastPlayer.prototype.initializeCastPlayer
에서 호출됩니다.
CastContext
를 초기화할 때 options
JSON 객체를 제공해야 합니다. 이 클래스에는 프레임워크 동작에 영향을 미치는 옵션이 포함되어 있습니다. 그중 가장 중요한 옵션은 수신기 애플리케이션 ID입니다. 지정된 앱을 실행할 수 있는 기기만 표시하도록 사용 가능한 Cast 기기 목록을 필터링하고 Cast 세션이 시작될 때 수신기 애플리케이션을 실행하는 데 사용되는 옵션입니다.
자체 Cast 지원 앱을 개발하는 경우 Cast 개발자로 등록한 다음 앱의 애플리케이션 ID를 받아야 합니다. 이 Codelab에서는 샘플 앱 ID를 사용합니다.
body
섹션 끝의 index.html
에 다음 코드를 추가합니다.
<script type="text/javascript" src="https://www.gstatic.com/cv/js/sender/v1/cast_sender.js?loadCastFramework=1"></script>
index.html
에 다음 코드를 추가하여 CastVideos
앱을 초기화하고 CastContext
도 초기화합니다.
<script src="CastVideos.js"></script>
<script type="text/javascript">
var castPlayer = new CastPlayer();
window['__onGCastApiAvailable'] = function(isAvailable) {
if (isAvailable) {
castPlayer.initializeCastPlayer();
}
};
</script>
이제 CastVideos.js
에 방금 index.html
에서 호출한 메서드에 해당하는 새 메서드를 추가해야 합니다. CastContext에서 옵션을 설정하고 새 RemotePlayer
및 RemotePlayerControllers
를 초기화하는 initializeCastPlayer
라는 새 메서드를 추가하겠습니다.
/**
* This method sets up the CastContext, and a few other members
* that are necessary to play and control videos on a Cast
* device.
*/
CastPlayer.prototype.initializeCastPlayer = function() {
var options = {};
// Set the receiver application ID to your own (created in
// the Google Cast Developer Console), or optionally
// use the chrome.cast.media.DEFAULT_MEDIA_RECEIVER_APP_ID
options.receiverApplicationId = 'C0868879';
// Auto join policy can be one of the following three:
// ORIGIN_SCOPED - Auto connect from same appId and page origin
// TAB_AND_ORIGIN_SCOPED - Auto connect from same appId, page origin, and tab
// PAGE_SCOPED - No auto connect
options.autoJoinPolicy = chrome.cast.AutoJoinPolicy.ORIGIN_SCOPED;
cast.framework.CastContext.getInstance().setOptions(options);
this.remotePlayer = new cast.framework.RemotePlayer();
this.remotePlayerController = new cast.framework.RemotePlayerController(this.remotePlayer);
this.remotePlayerController.addEventListener(
cast.framework.RemotePlayerEventType.IS_CONNECTED_CHANGED,
this.switchPlayer.bind(this)
);
};
마지막으로 RemotePlayer
및 RemotePlayerController
를 위한 변수를 만들어야 합니다.
var CastPlayer = function() {
//...
/* Cast player variables */
/** @type {cast.framework.RemotePlayer} */
this.remotePlayer = null;
/** @type {cast.framework.RemotePlayerController} */
this.remotePlayerController = null;
//...
};
전송 버튼
이제 CastContext
가 초기화되었으므로 전송 버튼을 추가하여 사용자가 Cast 기기를 선택할 수 있도록 해야 합니다. Cast SDK는 ID가 "castbutton"
인 google-cast-launcher
라는 전송 버튼 구성요소를 제공합니다. media_control
섹션에 button
를 추가하기만 하면 애플리케이션의 동영상 요소에 추가할 수 있습니다.
버튼 요소는 다음과 같이 표시됩니다.
<google-cast-launcher id="castbutton"></google-cast-launcher>
media_control
섹션의 index.html
에 다음 코드를 추가합니다.
<div id="media_control">
<div id="play"></div>
<div id="pause"></div>
<div id="progress_bg"></div>
<div id="progress"></div>
<div id="progress_indicator"></div>
<div id="fullscreen_expand"></div>
<div id="fullscreen_collapse"></div>
<google-cast-launcher id="castbutton"></google-cast-launcher>
<div id="audio_bg"></div>
<div id="audio_bg_track"></div>
<div id="audio_indicator"></div>
<div id="audio_bg_level"></div>
<div id="audio_on"></div>
<div id="audio_off"></div>
<div id="duration">00:00:00</div>
</div>
이제 Chrome 브라우저에서 페이지를 새로고침합니다. 동영상 요소에 전송 버튼이 표시되고 버튼을 클릭하면 로컬 네트워크에 Cast 기기가 표시됩니다. 기기 검색은 Chrome 브라우저에서 자동으로 관리됩니다. Cast 기기를 선택하면 샘플 수신기 앱이 Cast 기기에 로드됩니다.
미디어 재생과 관련된 지원이 연결되지 않았으므로 아직 Cast 기기에서 동영상을 재생할 수 없습니다. 전송을 중지하려면 전송 버튼을 클릭합니다.
6. 동영상 콘텐츠 전송
Cast 기기에서 원격으로 동영상을 재생할 수 있도록 샘플 앱을 확장하겠습니다. 이를 처리하려면 Cast 프레임워크에서 생성된 다양한 이벤트를 수신 대기해야 합니다.
미디어 전송
Cast 기기에서 미디어를 재생하려면 대략적으로 다음 단계를 따라야 합니다.
- Cast SDK에서 미디어 항목을 모델링하는
MediaInfo
JSON
객체를 만듭니다. - 사용자가 Cast 기기에 연결하여 수신기 애플리케이션을 실행합니다.
MediaInfo
객체를 수신기에 로드하고 콘텐츠를 재생합니다.- 미디어 상태를 추적합니다.
- 사용자 상호작용에 따라 재생 명령어를 수신기로 전송합니다.
1단계는 한 객체를 다른 객체에 매핑하는 것입니다. MediaInfo
는 Cast SDK가 이해할 수 있는 내용이고 mediaJSON
은 미디어 항목에 관한 앱의 캡슐화입니다. 따라서 mediaJSON
을 MediaInfo
에 쉽게 매핑할 수 있습니다. 이전 섹션에서 이미 2단계를 완료했습니다. 3단계는 Cast SDK를 사용하여 쉽게 할 수 있습니다.
CastPlayer
샘플 앱은 이미 switchPlayer
메서드에서 로컬 재생과 원격 재생을 구분합니다.
if (cast && cast.framework) {
if (this.remotePlayer.isConnected) {
//...
이 Codelab에서 모든 샘플 플레이어 로직의 작동 방식을 정확히 이해하는 것은 중요하지 않습니다. 그러나 로컬 재생과 원격 재생을 모두 인식하도록 앱의 미디어 플레이어를 수정해야 한다는 점을 이해하는 것이 중요합니다.
현재 로컬 플레이어는 전송 상태에 관한 정보를 모르므로 항상 로컬 재생 상태입니다. Cast 프레임워크에서 발생하는 상태 전환에 따라 UI를 업데이트해야 합니다. 예를 들어 전송을 시작하면 로컬 재생을 중지하고 일부 컨트롤을 사용 중지해야 합니다. 마찬가지로 이 뷰 컨트롤러에 있을 때 전송을 중지하면 로컬 재생으로 전환해야 합니다. 이를 처리하려면 Cast 프레임워크에서 생성된 다양한 이벤트를 수신 대기해야 합니다.
전송 세션 관리
Cast 프레임워크의 경우 전송 세션에 기기 연결, 실행 (또는 기존 세션 연결), 수신기 애플리케이션 연결, 필요한 경우 미디어 제어 채널 초기화 단계가 결합되어 있습니다. 미디어 제어 채널은 Cast 프레임워크가 수신기에서 미디어 재생 관련 메시지를 주고받는 방법입니다.
사용자가 전송 버튼에서 기기를 선택하면 전송 세션이 자동으로 시작되고 사용자가 연결을 해제하면 자동으로 중지됩니다. 네트워킹 문제로 인해 수신기 세션에 다시 연결하는 것도 Cast 프레임워크에서 자동으로 처리됩니다.
전송 세션은 cast.framework.CastContext.getInstance().getCurrentSession()
를 통해 액세스할 수 있는 CastSession
에 의해 관리됩니다. EventListener
콜백은 생성, 정지, 재개, 종료와 같은 세션 이벤트를 모니터링하는 데 사용할 수 있습니다.
현재 애플리케이션에서는 setupRemotePlayer
메서드에서 모든 세션 및 상태 관리가 처리됩니다. CastVideos.js
에 다음 코드를 추가하여 앱에서 구성해 보겠습니다.
/**
* Set the PlayerHandler target to use the remote player
*/
CastPlayer.prototype.setupRemotePlayer = function () {
var castSession = cast.framework.CastContext.getInstance().getCurrentSession();
this.playerHandler.setTarget(playerTarget);
// Setup remote player volume right on setup
// The remote player may have had a volume set from previous playback
if (this.remotePlayer.isMuted) {
this.playerHandler.mute();
}
var currentVolume = this.remotePlayer.volumeLevel * FULL_VOLUME_HEIGHT;
var p = document.getElementById('audio_bg_level');
p.style.height = currentVolume + 'px';
p.style.marginTop = -currentVolume + 'px';
this.hideFullscreenButton();
this.playerHandler.play();
};
여전히 콜백의 모든 이벤트를 바인딩하고 수신되는 모든 이벤트를 처리해야 합니다. 이 작업은 매우 간단하므로, 이제 처리해 보겠습니다.
/**
* Set the PlayerHandler target to use the remote player
*/
CastPlayer.prototype.setupRemotePlayer = function () {
var castSession = cast.framework.CastContext.getInstance().getCurrentSession();
// Add event listeners for player changes which may occur outside sender app
this.remotePlayerController.addEventListener(
cast.framework.RemotePlayerEventType.IS_PAUSED_CHANGED,
function() {
if (this.remotePlayer.isPaused) {
this.playerHandler.pause();
} else {
this.playerHandler.play();
}
}.bind(this)
);
this.remotePlayerController.addEventListener(
cast.framework.RemotePlayerEventType.IS_MUTED_CHANGED,
function() {
if (this.remotePlayer.isMuted) {
this.playerHandler.mute();
} else {
this.playerHandler.unMute();
}
}.bind(this)
);
this.remotePlayerController.addEventListener(
cast.framework.RemotePlayerEventType.VOLUME_LEVEL_CHANGED,
function() {
var newVolume = this.remotePlayer.volumeLevel * FULL_VOLUME_HEIGHT;
var p = document.getElementById('audio_bg_level');
p.style.height = newVolume + 'px';
p.style.marginTop = -newVolume + 'px';
}.bind(this)
);
// This object will implement PlayerHandler callbacks with
// remotePlayerController, and makes necessary UI updates specific
// to remote playback
var playerTarget = {};
playerTarget.play = function () {
if (this.remotePlayer.isPaused) {
this.remotePlayerController.playOrPause();
}
var vi = document.getElementById('video_image');
vi.style.display = 'block';
var localPlayer = document.getElementById('video_element');
localPlayer.style.display = 'none';
}.bind(this);
playerTarget.pause = function () {
if (!this.remotePlayer.isPaused) {
this.remotePlayerController.playOrPause();
}
}.bind(this);
playerTarget.stop = function () {
this.remotePlayerController.stop();
}.bind(this);
playerTarget.getCurrentMediaTime = function() {
return this.remotePlayer.currentTime;
}.bind(this);
playerTarget.getMediaDuration = function() {
return this.remotePlayer.duration;
}.bind(this);
playerTarget.updateDisplayMessage = function () {
document.getElementById('playerstate').style.display = 'block';
document.getElementById('playerstatebg').style.display = 'block';
document.getElementById('video_image_overlay').style.display = 'block';
document.getElementById('playerstate').innerHTML =
this.mediaContents[ this.currentMediaIndex]['title'] + ' ' +
this.playerState + ' on ' + castSession.getCastDevice().friendlyName;
}.bind(this);
playerTarget.setVolume = function (volumeSliderPosition) {
// Add resistance to avoid loud volume
var currentVolume = this.remotePlayer.volumeLevel;
var p = document.getElementById('audio_bg_level');
if (volumeSliderPosition < FULL_VOLUME_HEIGHT) {
var vScale = this.currentVolume * FULL_VOLUME_HEIGHT;
if (volumeSliderPosition > vScale) {
volumeSliderPosition = vScale + (pos - vScale) / 2;
}
p.style.height = volumeSliderPosition + 'px';
p.style.marginTop = -volumeSliderPosition + 'px';
currentVolume = volumeSliderPosition / FULL_VOLUME_HEIGHT;
} else {
currentVolume = 1;
}
this.remotePlayer.volumeLevel = currentVolume;
this.remotePlayerController.setVolumeLevel();
}.bind(this);
playerTarget.mute = function () {
if (!this.remotePlayer.isMuted) {
this.remotePlayerController.muteOrUnmute();
}
}.bind(this);
playerTarget.unMute = function () {
if (this.remotePlayer.isMuted) {
this.remotePlayerController.muteOrUnmute();
}
}.bind(this);
playerTarget.isMuted = function() {
return this.remotePlayer.isMuted;
}.bind(this);
playerTarget.seekTo = function (time) {
this.remotePlayer.currentTime = time;
this.remotePlayerController.seek();
}.bind(this);
this.playerHandler.setTarget(playerTarget);
// Setup remote player volume right on setup
// The remote player may have had a volume set from previous playback
if (this.remotePlayer.isMuted) {
this.playerHandler.mute();
}
var currentVolume = this.remotePlayer.volumeLevel * FULL_VOLUME_HEIGHT;
var p = document.getElementById('audio_bg_level');
p.style.height = currentVolume + 'px';
p.style.marginTop = -currentVolume + 'px';
this.hideFullscreenButton();
this.playerHandler.play();
};
미디어 로드
Cast SDK에서 RemotePlayer
및 RemotePlayerController
는 수신기에서 원격 미디어 재생을 편리하게 관리할 수 있는 API 집합을 제공합니다. 미디어 재생을 지원하는 CastSession
의 경우 RemotePlayer
및 RemotePlayerController
인스턴스가 SDK에 의해 자동으로 생성됩니다. 앞서 Codelab에서 설명한 대로 cast.framework.RemotePlayer
및 cast.framework.RemotePlayerController
의 인스턴스를 만들어 액세스할 수 있습니다.
다음으로 SDK가 요청을 처리하고 전달할 MediaInfo 객체를 빌드하여 수신기에 현재 선택된 동영상을 로드해야 합니다. 이렇게 하려면 setupRemotePlayer
에 다음 코드를 추가합니다.
/**
* Set the PlayerHandler target to use the remote player
*/
CastPlayer.prototype.setupRemotePlayer = function () {
//...
playerTarget.load = function (mediaIndex) {
console.log('Loading...' + this.mediaContents[mediaIndex]['title']);
var mediaInfo = new chrome.cast.media.MediaInfo(
this.mediaContents[mediaIndex]['sources'][0], 'video/mp4');
mediaInfo.metadata = new chrome.cast.media.GenericMediaMetadata();
mediaInfo.metadata.metadataType = chrome.cast.media.MetadataType.GENERIC;
mediaInfo.metadata.title = this.mediaContents[mediaIndex]['title'];
mediaInfo.metadata.images = [
{'url': MEDIA_SOURCE_ROOT + this.mediaContents[mediaIndex]['thumb']}];
var request = new chrome.cast.media.LoadRequest(mediaInfo);
castSession.loadMedia(request).then(
this.playerHandler.loaded.bind(this.playerHandler),
function (errorCode) {
this.playerState = PLAYER_STATE.ERROR;
console.log('Remote media load error: ' +
CastPlayer.getErrorMessage(errorCode));
}.bind(this));
}.bind(this);
//...
};
이제 로컬 재생과 원격 재생 간에 전환할 메서드를 추가합니다.
/**
* This is a method for switching between the local and remote
* players. If the local player is selected, setupLocalPlayer()
* is run. If there is a cast device connected we run
* setupRemotePlayer().
*/
CastPlayer.prototype.switchPlayer = function() {
this.stopProgressTimer();
this.resetVolumeSlider();
this.playerHandler.stop();
this.playerState = PLAYER_STATE.IDLE;
if (cast && cast.framework) {
if (this.remotePlayer.isConnected) {
this.setupRemotePlayer();
return;
}
}
this.setupLocalPlayer();
};
마지막으로 Cast 오류 메시지를 처리할 메서드를 추가합니다.
/**
* Makes human-readable message from chrome.cast.Error
* @param {chrome.cast.Error} error
* @return {string} error message
*/
CastPlayer.getErrorMessage = function(error) {
switch (error.code) {
case chrome.cast.ErrorCode.API_NOT_INITIALIZED:
return 'The API is not initialized.' +
(error.description ? ' :' + error.description : '');
case chrome.cast.ErrorCode.CANCEL:
return 'The operation was canceled by the user' +
(error.description ? ' :' + error.description : '');
case chrome.cast.ErrorCode.CHANNEL_ERROR:
return 'A channel to the receiver is not available.' +
(error.description ? ' :' + error.description : '');
case chrome.cast.ErrorCode.EXTENSION_MISSING:
return 'The Cast extension is not available.' +
(error.description ? ' :' + error.description : '');
case chrome.cast.ErrorCode.INVALID_PARAMETER:
return 'The parameters to the operation were not valid.' +
(error.description ? ' :' + error.description : '');
case chrome.cast.ErrorCode.RECEIVER_UNAVAILABLE:
return 'No receiver was compatible with the session request.' +
(error.description ? ' :' + error.description : '');
case chrome.cast.ErrorCode.SESSION_ERROR:
return 'A session could not be created, or a session was invalid.' +
(error.description ? ' :' + error.description : '');
case chrome.cast.ErrorCode.TIMEOUT:
return 'The operation timed out.' +
(error.description ? ' :' + error.description : '');
}
};
이제 앱을 실행합니다. Cast 기기에 연결하여 동영상 재생을 시작합니다. 수신기에서 재생되는 동영상을 볼 수 있습니다.
7. Cast Connect 지원 추가
Cast Connect 라이브러리를 사용하면 기존 발신기 애플리케이션이 Cast 프로토콜을 통해 Android TV 애플리케이션과 통신할 수 있습니다. Cast Connect는 Cast 인프라 위에 빌드되며, Android TV 앱은 수신기 역할을 합니다.
종속 항목
- Chrome 브라우저 버전 M87 이상
Android 수신기 호환 설정
Android TV 애플리케이션(Android 수신기라고도 함)을 실행하려면 CastOptions
객체에서 androidReceiverCompatible
플래그를 true로 설정해야 합니다.
initializeCastPlayer
함수의 CastVideos.js
에 다음 코드를 추가합니다.
var options = {};
...
options.androidReceiverCompatible = true;
cast.framework.CastContext.getInstance().setOptions(options);
실행 사용자 인증 정보 설정
발신자 측에서는 CredentialsData
를 지정하여 세션에 참여하는 사용자를 나타낼 수 있습니다. credentials
는 ATV 앱이 이해할 수 있는 한 사용자가 정의할 수 있는 문자열입니다. CredentialsData
는 실행 또는 참여 시간 중에만 Android TV 앱으로 전달됩니다. 연결된 상태에서 다시 설정하면 Android TV 앱에 전달되지 않습니다.
실행 사용자 인증 정보를 설정하려면 실행 옵션이 설정된 후 언제든지 CredentialsData
를 정의해야 합니다.
initializeCastPlayer
함수 아래의 CastVideos.js
클래스에 다음 코드를 추가합니다.
cast.framework.CastContext.getInstance().setOptions(options);
...
let credentialsData = new chrome.cast.CredentialsData("{\"userId\": \"abc\"}");
cast.framework.CastContext.getInstance().setLaunchCredentialsData(credentialsData);
...
로드 요청 시 사용자 인증 정보 설정
웹 수신기 앱과 Android TV 앱이 credentials
를 다르게 처리하는 경우 각각에 대해 별도의 사용자 인증 정보를 정의해야 할 수 있습니다. 이를 처리하려면 setupRemotePlayer
함수의 playerTarget.load
아래에 있는 CastVideos.js
에 다음 코드를 추가합니다.
...
var request = new chrome.cast.media.LoadRequest(mediaInfo);
request.credentials = 'user-credentials';
request.atvCredentials = 'atv-user-credentials';
...
이제 발신자가 전송하는 수신기 앱에 따라 SDK가 현재 세션에 사용할 사용자 인증 정보를 자동으로 처리합니다.
Cast Connect 테스트
Chromecast with Google TV에 Android TV APK를 설치하는 단계는 다음과 같습니다.
- Android TV 기기의 IP 주소를 찾습니다. 일반적으로 설정 > 네트워크 및 인터넷 > (기기가 연결된 네트워크 이름)에서 확인할 수 있습니다. 오른쪽에는 세부정보와 네트워크에 있는 기기의 IP가 표시됩니다.
- 기기의 IP 주소를 사용하여 터미널을 통해 ADB를 통해 기기에 연결합니다.
$ adb connect <device_ip_address>:5555
- 터미널 창에서 이 Codelab 시작 시 다운로드한 Codelab 샘플의 최상위 폴더로 이동합니다. 예를 들면 다음과 같습니다.
$ cd Desktop/chrome_codelab_src
- 다음을 실행하여 이 폴더의 .apk 파일을 Android TV에 설치합니다.
$ adb -s <device_ip_address>:5555 install android-tv-app.apk
- 이제 Android TV 기기의 내 앱 메뉴에 Cast 동영상이라는 앱이 표시됩니다.
- 업데이트된 웹 송신기 코드를 실행하고 전송 아이콘을 사용하거나 Chrome 브라우저의 드롭다운 메뉴에서
Cast..
를 선택하여 Android TV 기기와 전송 세션을 설정합니다. 이제 Android 수신기에서 Android TV 앱이 실행되고 Android TV 리모컨을 사용하여 재생을 제어할 수 있습니다.
8. 축하합니다
이제 Chrome 웹 앱에서 Cast SDK 위젯을 사용하여 동영상 앱에 Cast 지원을 사용 설정하는 방법을 알아보았습니다.
자세한 내용은 웹 발신자 개발자 가이드를 참고하세요.