네트워크 스택

ExoPlayer는 인터넷을 통해 미디어를 스트리밍하는 데 일반적으로 사용됩니다. 기본 네트워크 요청을 위해 여러 네트워크 스택을 지원합니다. 네트워크 스택 선택은 스트리밍 성능에 큰 영향을 미칠 수 있습니다.

이 페이지에서는 원하는 네트워크 스택을 사용하도록 ExoPlayer를 구성하는 방법을 설명하고, 사용 가능한 옵션을 나열하며, 앱의 네트워크 스택을 선택하는 방법에 관한 안내를 제공하고, 스트림된 미디어의 캐싱을 사용 설정하는 방법을 설명합니다.

특정 네트워크 스택을 사용하도록 ExoPlayer 구성

ExoPlayer는 앱 코드에서 삽입된 DataSource.Factory 인스턴스에서 가져온 DataSource 구성요소를 통해 데이터를 로드합니다.

앱에서 http(s) 콘텐츠만 재생해야 하는 경우 네트워크 스택을 선택하는 것은 앱에서 삽입하는 DataSource.Factory 인스턴스를 사용하려는 네트워크 스택에 해당하는 HttpDataSource.Factory 인스턴스로 업데이트하는 것만큼 간단합니다. 앱에서 로컬 파일과 같은 http(s)가 아닌 콘텐츠도 재생해야 하는 경우 DefaultDataSource.Factory를 사용하세요.

Kotlin

DefaultDataSource.Factory(
  ...
  /* baseDataSourceFactory= */ PreferredHttpDataSource.Factory(...))

자바

new DefaultDataSource.Factory(
    ...
    /* baseDataSourceFactory= */ new PreferredHttpDataSource.Factory(...));

이 예시에서 PreferredHttpDataSource.Factory는 선호하는 네트워크 스택에 해당하는 팩토리입니다. DefaultDataSource.Factory 레이어는 로컬 파일과 같은 http(s)가 아닌 소스에 대한 지원을 추가합니다.

다음 예에서는 Cronet 네트워크 스택을 사용하고 비 http(s) 콘텐츠 재생도 지원하는 ExoPlayer를 빌드하는 방법을 보여줍니다.

Kotlin

// Given a CronetEngine and Executor, build a CronetDataSource.Factory.
val cronetDataSourceFactory = CronetDataSource.Factory(cronetEngine, executor)

// Wrap the CronetDataSource.Factory in a DefaultDataSource.Factory, which adds
// in support for requesting data from other sources (such as files, resources,
// etc).
val dataSourceFactory =
  DefaultDataSource.Factory(context, /* baseDataSourceFactory= */ cronetDataSourceFactory)

// Inject the DefaultDataSource.Factory when creating the player.
val player =
  ExoPlayer.Builder(context)
    .setMediaSourceFactory(
      DefaultMediaSourceFactory(context).setDataSourceFactory(dataSourceFactory)
    )
    .build()

자바

// Given a CronetEngine and Executor, build a CronetDataSource.Factory.
CronetDataSource.Factory cronetDataSourceFactory =
    new CronetDataSource.Factory(cronetEngine, executor);

// Wrap the CronetDataSource.Factory in a DefaultDataSource.Factory, which adds
// in support for requesting data from other sources (such as files, resources,
// etc).
DefaultDataSource.Factory dataSourceFactory =
    new DefaultDataSource.Factory(
        context, /* baseDataSourceFactory= */ cronetDataSourceFactory);

// Inject the DefaultDataSource.Factory when creating the player.
ExoPlayer player =
    new ExoPlayer.Builder(context)
        .setMediaSourceFactory(
            new DefaultMediaSourceFactory(context).setDataSourceFactory(dataSourceFactory))
        .build();

지원되는 네트워크 스택

ExoPlayer는 HttpEngine, Cronet, OkHttp, Android의 기본 제공 기본 네트워크 스택을 직접 지원합니다. ExoPlayer는 Android에서 작동하는 다른 네트워크 스택을 지원하도록 확장할 수도 있습니다.

HttpEngine

HttpEngine은 API 34 (또는 S 확장 프로그램 7)부터 Android에서 권장되는 기본 네트워크 스택입니다. 대부분의 경우 내부적으로 Cronet 네트워크 스택을 사용하여 QUIC 프로토콜을 통해 HTTP, HTTP/2, HTTP/3을 지원합니다.

ExoPlayer는 HttpEngineDataSource.Factory을 사용하여 HttpEngine를 지원합니다. 특정 네트워크 스택을 사용하도록 ExoPlayer 구성에 설명된 대로 이 데이터 소스 팩토리를 삽입할 수 있습니다.

Cronet

Cronet은 Android 앱에서 라이브러리로 사용하도록 제공되는 Chromium 네트워크 스택입니다. Cronet은 ExoPlayer에서 이루어진 요청을 비롯해 앱이 작동하는 데 필요한 네트워크 요청의 지연 시간을 줄이고 처리량을 늘리는 여러 기술을 활용합니다. HTTP, HTTP/2, HTTP/3 over QUIC 프로토콜을 기본적으로 지원합니다. Cronet은 YouTube를 비롯한 세계 최대 규모의 스트리밍 앱에서 사용됩니다.

ExoPlayer는 Cronet 라이브러리를 통해 Cronet을 지원합니다. 사용 방법에 관한 자세한 내용은 라이브러리의 README.md를 참고하세요. Cronet 라이브러리는 다음과 같은 세 가지 기본 Cronet 구현을 사용할 수 있습니다.

  1. Google Play 서비스: 대부분의 경우 이 구현을 사용하고 Google Play 서비스를 사용할 수 없는 경우 Android의 내장 네트워크 스택(DefaultHttpDataSource)으로 대체하는 것이 좋습니다.
  2. Cronet 삽입: Google Play 서비스를 널리 사용할 수 없는 시장에 있는 사용자의 비율이 높거나 사용되는 Cronet 구현의 정확한 버전을 제어하려는 경우에 적합합니다. Cronet Embedded의 가장 큰 단점은 앱에 약 8MB가 추가된다는 것입니다.
  3. Cronet 대체: Cronet의 대체 구현은 Android의 내장 네트워크 스택을 래퍼로 사용하여 Cronet의 API를 구현합니다. Android의 내장 네트워크 스택을 직접 사용하는 것이 (DefaultHttpDataSource 사용) 더 효율적이므로 ExoPlayer와 함께 사용해서는 안 됩니다.

OkHttp

OkHttp는 많은 인기 Android 앱에서 널리 사용되는 또 다른 최신 네트워크 스택입니다. HTTP 및 HTTP/2를 지원하지만 아직 QUIC을 통한 HTTP/3은 지원하지 않습니다.

ExoPlayer는 OkHttp 라이브러리를 통해 OkHttp를 지원합니다. 사용 방법에 관한 자세한 내용은 라이브러리의 README.md를 참고하세요. OkHttp 라이브러리를 사용하면 네트워크 스택이 앱 내에 삽입됩니다. 이는 Cronet 삽입과 유사하지만 OkHttp는 훨씬 작아 앱에 1MB 미만을 추가합니다.

Android의 내장 네트워크 스택

ExoPlayer는 핵심 ExoPlayer 라이브러리의 일부인 DefaultHttpDataSourceDefaultHttpDataSource.Factory와 함께 Android의 내장 네트워크 스택 사용을 지원합니다.

정확한 네트워크 스택 구현은 기본 기기에서 실행되는 소프트웨어에 따라 다릅니다. 대부분의 기기에서는 HTTP만 지원됩니다 (즉, QUIC를 통한 HTTP/2 및 HTTP/3은 지원되지 않음).

기타 네트워크 스택

앱은 다른 네트워크 스택을 ExoPlayer와 통합할 수도 있습니다. 이렇게 하려면 네트워크 스택을 래핑하는 HttpDataSource를 해당 HttpDataSource.Factory와 함께 구현합니다. ExoPlayer의 Cronet 및 OkHttp 라이브러리는 이를 수행하는 방법을 보여주는 좋은 예입니다.

순수 Java 네트워크 스택과 통합할 때는 HttpDataSource 구현이 올바르게 작동하는지 확인하기 위해 DataSourceContractTest를 구현하는 것이 좋습니다. OkHttp 라이브러리의 OkHttpDataSourceContractTest는 이를 수행하는 방법을 보여주는 좋은 예입니다.

네트워크 스택 선택

다음 표에는 ExoPlayer에서 지원하는 네트워크 스택의 장단점이 나와 있습니다.

네트워크 스택 프로토콜 APK 크기 영향 참고
HttpEngine HTTP
HTTP/2
HTTP/3 over QUIC
없음 API 34 또는 S 확장 프로그램 7에서만 사용 가능
Cronet (Google Play 서비스) HTTP
HTTP/2
HTTP/3 over QUIC
소형
(<100KB)
Google Play 서비스가 필요합니다. Cronet 버전이 자동으로 업데이트됨
Cronet (삽입됨) HTTP
HTTP/2
HTTP/3 over QUIC
대형
(~8MB)
앱 개발자가 제어하는 Cronet 버전
Cronet (대체) HTTP
(기기에 따라 다름)
소형
(<100KB)
ExoPlayer에는 권장되지 않음
OkHttp HTTP
HTTP/2
소형
(<1MB)
내장 네트워크 스택 HTTP
(기기에 따라 다름)
없음 구현은 기기에 따라 다름

QUIC를 통한 HTTP/2 및 HTTP/3 프로토콜은 미디어 스트리밍 성능을 크게 개선할 수 있습니다. 특히 콘텐츠 배포 네트워크 (CDN)를 사용하여 배포되는 적응형 미디어를 스트리밍할 때 이러한 프로토콜을 사용하면 CDN이 훨씬 더 효율적으로 작동할 수 있는 경우가 있습니다. 이러한 이유로 콘텐츠가 호스팅되는 서버가 이러한 프로토콜을 지원하는 경우 Android의 내장 네트워크 스택을 사용하는 것과 비교할 때 HttpEngine과 Cronet의 QUIC 기반 HTTP/2 및 HTTP/3 지원 (그리고 OkHttp의 HTTP/2 지원)은 큰 이점입니다.

미디어 스트리밍만 고려할 때는 Google Play 서비스에서 제공하는 HttpEngine 또는 Cronet을 사용하고 Google Play 서비스를 사용할 수 없는 경우 DefaultHttpDataSource로 대체하는 것이 좋습니다. 이 권장사항은 대부분의 기기에서 QUIC를 통해 HTTP/2 및 HTTP/3을 사용할 수 있도록 지원하는 것과 APK 크기가 크게 증가하지 않도록 하는 것 사이에서 적절한 균형을 유지합니다. 이 권장사항에는 예외가 있습니다. 앱을 실행할 기기의 상당 부분에서 Google Play 서비스를 사용할 수 없는 경우 Cronet Embedded 또는 OkHttp를 사용하는 것이 더 적절할 수 있습니다. APK 크기가 중요한 문제이거나 미디어 스트리밍이 앱 기능의 일부에 불과한 경우 내장 네트워크 스택을 사용해도 됩니다.

미디어뿐만 아니라 앱에서 실행하는 모든 네트워킹에 단일 네트워크 스택을 선택하는 것이 좋습니다. 이렇게 하면 ExoPlayer와 다른 앱 구성요소 간에 소켓과 같은 리소스를 효율적으로 풀링하고 공유할 수 있습니다.

앱이 미디어 재생과 관련이 없는 네트워킹을 실행해야 할 가능성이 높으므로 네트워크 스택 선택 시 미디어 스트리밍에 관한 위의 권장사항, 네트워킹을 실행하는 다른 구성요소의 요구사항, 앱에 대한 상대적 중요성을 고려해야 합니다.

미디어 캐싱

ExoPlayer는 로드된 바이트를 디스크에 캐시하여 네트워크에서 동일한 바이트를 반복적으로 로드하지 않도록 지원합니다. 이 기능은 현재 미디어를 되돌리거나 동일한 항목을 반복할 때 유용합니다.

캐싱에는 전용 캐시 디렉터리를 가리키는 SimpleCache 인스턴스와 CacheDataSource.Factory이 필요합니다.

Kotlin

// Note: This should be a singleton in your app.
val databaseProvider = StandaloneDatabaseProvider(context)

// An on-the-fly cache should evict media when reaching a maximum disk space limit.
val cache =
    SimpleCache(
        downloadDirectory, LeastRecentlyUsedCacheEvictor(maxBytes), databaseProvider)

// Configure the DataSource.Factory with the cache and factory for the desired HTTP stack.
val cacheDataSourceFactory =
    CacheDataSource.Factory()
        .setCache(cache)
        .setUpstreamDataSourceFactory(httpDataSourceFactory)

// Inject the DefaultDataSource.Factory when creating the player.
val player =
    ExoPlayer.Builder(context)
        .setMediaSourceFactory(
            DefaultMediaSourceFactory(context).setDataSourceFactory(cacheDataSourceFactory))
        .build()

Java

// Note: This should be a singleton in your app.
DatabaseProvider databaseProvider = new StandaloneDatabaseProvider(context);

// An on-the-fly cache should evict media when reaching a maximum disk space limit.
Cache cache =
    new SimpleCache(
        downloadDirectory, new LeastRecentlyUsedCacheEvictor(maxBytes), databaseProvider);

// Configure the DataSource.Factory with the cache and factory for the desired HTTP stack.
DataSource.Factory cacheDataSourceFactory =
    new CacheDataSource.Factory()
        .setCache(cache)
        .setUpstreamDataSourceFactory(httpDataSourceFactory);

// Inject the DefaultDataSource.Factory when creating the player.
ExoPlayer player =
    new ExoPlayer.Builder(context)
        .setMediaSourceFactory(
            new DefaultMediaSourceFactory(context).setDataSourceFactory(cacheDataSourceFactory))
        .build();