본문으로 건너뛰기

2. 스트리밍 재생

JWT URL을 사용하여 콘텐츠를 디바이스에 직접 실시간 스트리밍 재생하는 방법을 설명합니다. 로컬에 다운로드된 콘텐츠 재생과 달리, 스트리밍 시에는 매 재생 시점마다 고객사 서버에서 새로 발급받은 일회성(One-time) URL을 사용합니다.

이 문서의 모든 예제 코드는 공식 샘플 앱인 kollus_player_v2_android를 바탕으로 작성되었습니다.


콘텐츠 전달 방식

Kollus 서비스는 채널 설정에 따라 세 가지 전달 방식 중 하나로 콘텐츠를 제공합니다. 애플리케이션 클라이언트 레이어에서는 동일한 JWT URL을 전달받아 setDataSourceByUrl 메서드로 재생하므로 별도의 코드 분기를 구현하지 않아도 됩니다.

다만, 전달 방식에 따라 ABR 작동 방식이나 DRM 검증 및 라이선스 발급 흐름이 달라지므로 인프라 채널 구성을 파악하고 있으면 디버깅과 최적화에 도움이 됩니다.

전달 방식기본값설명채널 설정
MP4 Progressive Download단일 MP4 파일을 실시간으로 내려받으며 동시 재생합니다. 가변 비트레이트(ABR)를 지원하지 않는 단일 품질 방식입니다.별도 설정 없음 (기본 채널)
HLS 스트리밍-매니페스트(.m3u8)와 세그먼트 파일로 구성됩니다. 네트워크 대역폭 변화에 맞춰 실시간으로 비트레이트 품질이 자동 전환(ABR)됩니다.콘솔 채널 설정 내 HLS 출력 활성화
Multi DRM (Widevine/PlayReady)-HLS 또는 DASH 구조에 DRM 보안 라이선스 발급 흐름이 결합된 형태입니다. Widevine L1 / L3 디바이스 보안 레벨을 검증합니다.콘솔 채널 설정 내 DRM 정책 등록

애플리케이션 소스 코드에서는 mMediaPlayer.setDataSourceByUrl(jwtUrl, null) 메서드를 호출하는 것만으로 세 가지 방식을 모두 재생할 수 있습니다. 실제 스트리밍 전달 방식은 Kollus 서버 측에서 채널 설정에 따라 결정되어 클라이언트로 전달됩니다.

전달 방식 상세 비교

비교 영역MP4 Progressive DownloadHLS 스트리밍Multi DRM
ABR 옵션 제어대역폭 설정 영향 없음setInitialBandwidth 등 조절 옵션 정상 적용setInitialBandwidth 등 조절 옵션 정상 적용
탐색(Seek) 동작HTTP Byte-Range 요청 기반 제어세그먼트 단위의 위치 탐색세그먼트 단위의 위치 탐색
디바이스 레벨 검증하드웨어 보안 검증 단계 없음하드웨어 보안 검증 단계 없음디바이스 보안 레벨 검증 (Widevine L1 규격 필수 적용 콘텐츠 운영 가능)
extraDrmParam 지정null 처리 후 전달null 처리 후 전달일반적으로 null 지정 (토큰 내부 DRM 정책 우선, 동적 파라미터가 필요한 특수 환경에서만 전달)
일반적인 채널 운영 패턴

대부분의 고객사는 서비스 초기 단계에서 MP4 Progressive 방식으로 시작하여, 트래픽이 증가하거나 가변 비트레이트(ABR) 환경이 필요한 시점에 HLS 스트리밍으로 전환합니다. 이후 저작권 보호 및 DRM 보안이 필수적인 콘텐츠에 한해 Multi DRM 채널을 추가로 분리하여 운영하는 패턴이 일반적입니다.


기본 스트리밍 재생

KollusPlayer SDK의 MediaPlayer 인스턴스에 연결할 화면(Surface)을 지정하고 발급받은 JWT URL을 설정하여 실시간 스트리밍 재생을 시작합니다.

// VideoView.openVideo() 내부 스트리밍 구현 예시
mMediaPlayer.setScreenOnWhilePlaying(true);

// 1. 화면 컴포넌트 타입에 따른 Surface 바인딩 (TextureView 또는 SurfaceView)
if (mSurfaceView instanceof TextureView) {
TextureView tv = (TextureView) mSurfaceView;
Surface surface = new Surface(tv.getSurfaceTexture());
mMediaPlayer.setSurface(surface);
} else if (mSurfaceView instanceof SurfaceView) {
mMediaPlayer.setDisplay(((SurfaceView) mSurfaceView).getHolder());
}

// 2. 가변 비트레이트(ABR) 세부 제어 옵션 설정 (필요 시 지정)
mMediaPlayer.setInitialBandwidth(0); // 0: 초기 대역폭 자동 추정
mMediaPlayer.setMinDurationForQualityIncreaseMs(1000); // ABR 비트레이트 품질 상승을 위한 최소 안정 유지 시간 (ms)

// 3. 데이터 소스 지정 (JWT URL)
String extraDrmParam = null;
mMediaPlayer.setDataSourceByUrl(jwtUrl, extraDrmParam); // jwtUrl 예시: https://v.kr.kollus.com/s?jwt=...

mMediaPlayer.prepareAsync();

prepareAsync() 메서드가 호출되면 플레이어 내부 상태가 STATE_PREPARING으로 진입하며, 스트리밍 초기 버퍼 준비가 완료되는 시점에 OnPreparedListener.onPrepared()가 호출됩니다.


렌더링 Surface 설정

종류특징권장 시나리오
SurfaceView가벼운 출력 경로, 낮은 GPU 합성 비용일반적인 전체 화면 재생
TextureView회전, 투명도, 블렌딩 등 View 변환 가능UI 위 오버레이 재생, PIP 등
// SurfaceView
mMediaPlayer.setDisplay(((SurfaceView) view).getHolder());

// TextureView
Surface surface = new Surface(((TextureView) view).getSurfaceTexture());
mMediaPlayer.setSurface(surface);

DRM 콘텐츠 스트리밍

전달받은 JWT URL 내부에 DRM 제약 정책이 포함되어 있는 경우, SDK가 DRM 라이선스 검증 및 갱신 프로세스를 자동 수행합니다. 개발 레이어에서의 별도 파라미터 매칭 없이 setDataSourceByUrl(jwtUrl, null) 메서드 호출만으로 DRM 스트리밍이 시작됩니다.


가변 비트레이트(ABR) 조절 옵션

제약 사항

ABR 옵션은 HLS 스트리밍 및 Multi DRM 채널에서만 유효하게 작동합니다. 기본값인 MP4 Progressive Download 채널에서는 단일 고정 비트레이트로 미디어가 전달되므로 아래 설정값이 모두 무시됩니다.

API설명
setInitialBandwidth(bps)초기 매니페스트 로드 시점의 대역폭 추정값(bps)을 지정합니다. 0 지정 시 SDK가 자동으로 추정합니다.
setMinDurationForQualityIncreaseMs(ms)상위 품질로 전환하기 위해 현재 대역폭이 안정적으로 유지되어야 하는 시간(ms)입니다. 일반적인 환경에서는 1000ms를 권장합니다.

공식 샘플 앱은 이전 재생 세션의 평균 네트워크 대역폭 데이터를 SharedPreferences에 기록해 두고, 다음 스트리밍 초기화 시점의 setInitialBandwidth 메서드의 파라미터로 전달하여 초기 버퍼링 대기 시간을 최적화하는 패턴을 사용합니다.


플레이어 이벤트 리스너

미디어 상태 변화 이벤트 및 플레이어 제어 신호를 수신하기 위해 MediaPlayer 인스턴스에 리스너 객체들을 연결합니다.

mMediaPlayer.setOnPreparedListener(mPreparedListener);
mMediaPlayer.setOnCompletionListener(mCompletionListener);
mMediaPlayer.setOnErrorListener(mErrorListener);
mMediaPlayer.setOnInfoListener(mInfoListener);
mMediaPlayer.setOnBufferingUpdateListener(mBufferingUpdateListener);
mMediaPlayer.setOnSeekCompleteListener(mSeekCompleteListener);
mMediaPlayer.setOnVideoSizeChangedListener(mSizeChangedListener);
mMediaPlayer.setOnTimedTextDetectListener(mOnTimedTextDetectListener);
mMediaPlayer.setOnTimedTextListener(mOnTimedTextListener);
mMediaPlayer.setOnExternalDisplayDetectListener(mOnExternalDisplayDetectListener);
mMediaPlayer.setKollusPlayerBookmarkListener(mKollusPlayerBookmarkListener);
mMediaPlayer.setCaptureDetectListener(mCaptureDetectListener);
mMediaPlayer.setEmulatorCheckerListener(mEmulatorCheckListener);
리스너역할
OnPreparedListener스트리밍 준비 완료 (안전하게 start() 호출이 가능한 시점)
OnCompletionListener콘텐츠 끝까지 재생 완료
OnErrorListener재생 중 오류 발생 (whatextra 코드로 원인 분석)
OnInfoListener부수적 상태 정보 변화 (버퍼링 시작 및 종료, 미디어 정보 변경 등)
OnBufferingUpdateListener버퍼링 진행률 (0~100)
OnSeekCompleteListener탐색(Seek) 완료
OnVideoSizeChangedListener영상 해상도 변경
OnTimedTextDetectListener / OnTimedTextListener자막 트랙 감지 / 자막 표시
OnExternalDisplayDetectListener외부 디스플레이 연결 상태 변화
KollusPlayerBookmarkListener북마크 위치 정보 감지
CaptureDetectListener화면 캡처 프로그램 실행 감지
EmulatorCheckerListener루팅 기기 또는 가상머신(에뮬레이터) 환경 감지

재생 상태 제어

MediaPlayer 인스턴스 메서드를 통해 실시간으로 스트리밍 재생 세션의 라이프사이클을 직접 제어합니다.

mMediaPlayer.start();              // 재생 시작 또는 재개
mMediaPlayer.pause(); // 일시정지
mMediaPlayer.stop(); // 정지
mMediaPlayer.seekTo(positionMs); // 재생 위치 이동 (ms)
mMediaPlayer.release(); // 리소스 해제 (Activity 종료 시 필수)

boolean playing = mMediaPlayer.isPlaying(); // 재생 중 여부
int currentMs = mMediaPlayer.getCurrentPosition(); // 현재 재생 위치 (ms)
int durationMs = mMediaPlayer.getDuration(); // 콘텐츠 전체 길이 (ms)

재생속도 제어 (배속)

디코더 종류에 따라 배속 재생 지원 여부가 달라지므로, 배속 변경 API를 호출하기 전에 supportPlaybackrateControl() 메서드를 호출하여 지원 여부를 확인하세요.

if (mMediaPlayer.supportPlaybackrateControl()) {
// 배속 변경 API 연동
}

백그라운드 재생

장시간 백그라운드 재생을 유지하려면, Android 컴포넌트 라이프사이클을 따르는 Service 구조 내부에서 MediaPlayer 인스턴스를 관리하고 이를 포그라운드 서비스(Foreground Service)로 실행해야 합니다. 공식 샘플 앱은 이를 위해 MoviePlayerService 컴포넌트를 연동하는 구현 패턴을 포함하고 있습니다.

백그라운드 재생을 위한 제어 메시지 설계

시스템 상태 변화에 안정적으로 조율하기 위해 다음 두 가지 설정의 관계를 파악하여 연동 코드를 구현해야 합니다.

  • MoviePlayerService.APP_BACKGROUND: 애플리케이션 화면 레이어가 백그라운드 상태로 전환되었음을 서비스 측에 알리는 메시지입니다. 이 메시지를 전송받는 것 자체만으로는 재생 동작이 멈추지 않습니다.
  • KollusConstants.SUPPORT_BACKGROUND_PLAYBACK: 백그라운드 상태에서의 재생을 허용할지 여부를 판별하는 플래그 변수입니다. 이 속성값은 서비스 컴포넌트 내부로 자동 전달되지 않으므로, 앱 레이어에서 판단 후 정지 메시지를 추가로 전달해야 합니다.
// Activity.onStop() 등 화면 레이어가 백그라운드로 전환되는 시점의 구현 패턴 예시
mMessenger.send(Message.obtain(null, MoviePlayerService.APP_BACKGROUND));

// 백그라운드 재생 비허용 상태인 경우, 명시적으로 일시정지(PAUSE) 메시지 전달
if (!supportBackgroundPlayback) {
mMessenger.send(Message.obtain(null, MoviePlayerService.PAUSE));
}
제어 주체

supportBackgroundPlayback 변수는 KollusConstants.SUPPORT_BACKGROUND_PLAYBACK 설정값을 읽어 초기화한 로컬 변수입니다. 서비스 엔진이 이 값을 직접 참조하지 않으므로, 반드시 위의 코드와 같이 앱 레이어에서 제어해야 합니다.


외부 디스플레이 출력 제한

애플리케이션 실행 중 HDMI 미러링, 크롬캐스트(Chromecast), DLNA 등의 상태 변화가 발생하면 OnExternalDisplayDetectListener 콜백을 통해 이벤트가 즉시 통지됩니다. 보안 정책에 의해 외부 디스플레이 출력을 차단해야 하는 콘텐츠의 경우, 해당 리스너 콜백 트리거 시점에 즉시 플레이어 정지 명령을 실행하는 코드를 적용해야 합니다.


라이브 콘텐츠 스트리밍

실시간 라이브 방송 스트리밍 세션 역시 일반적인 VOD 환경과 동일한 형태의 JWT URL 구조 데이터로 인입됩니다.

  • 라이브 식별 방법: 라이브인지 VOD인지에 대한 판별 처리는 수신된 JWT Payload 내 mc[].live 속성 필드의 존재 여부를 통해 파악할 수 있습니다.
  • SDK 내부 동작: SDK가 라이브 데이터 구조임을 정상 식별하게 되면, 해당 방송 사양에 최적화된 타임시프트(Timeshift) 기능 제어 및 DVR 동작을 자동으로 수행합니다.