Ngăn xếp mạng

ExoPlayer thường được dùng để phát trực tuyến nội dung nghe nhìn qua Internet. Tính năng này hỗ trợ nhiều ngăn xếp mạng để đưa ra các yêu cầu mạng cơ bản. Lựa chọn ngăn xếp mạng có thể có tác động đáng kể đến hiệu suất truyền trực tuyến.

Trang này trình bày cách định cấu hình ExoPlayer để sử dụng ngăn xếp mạng mà bạn lựa chọn, liệt kê các tuỳ chọn có sẵn, cung cấp một số hướng dẫn về cách chọn ngăn xếp mạng cho ứng dụng và giải thích cách bật chức năng lưu vào bộ nhớ đệm cho nội dung nghe nhìn phát trực tuyến.

Định cấu hình ExoPlayer để sử dụng một ngăn xếp mạng cụ thể

ExoPlayer tải dữ liệu thông qua các thành phần DataSource mà nó nhận được từ các thực thể DataSource.Factory được chèn từ mã ứng dụng.

Nếu ứng dụng của bạn chỉ cần phát nội dung http, thì việc chọn ngăn xếp mạng cũng đơn giản như việc cập nhật bất kỳ thực thể DataSource.Factory nào mà ứng dụng của bạn chèn vào thành thực thể của HttpDataSource.Factory tương ứng với ngăn xếp mạng mà bạn muốn sử dụng. Nếu ứng dụng của bạn cũng cần phát nội dung không phải http, chẳng hạn như tệp cục bộ, hãy dùng DefaultDataSource.Factory:

Kotlin

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

Java

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

Trong ví dụ này, PreferredHttpDataSource.Factory là trạng thái ban đầu tương ứng với ngăn xếp mạng ưu tiên của bạn. Lớp DefaultDataSource.Factory hỗ trợ thêm các nguồn không phải http, chẳng hạn như các tệp cục bộ.

Ví dụ sau đây cho thấy cách tạo một ExoPlayer sẽ sử dụng ngăn xếp mạng Cronet và cũng hỗ trợ phát nội dung không phải http.

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()

Java

// 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();

Ngăn xếp mạng được hỗ trợ

ExoPlayer hỗ trợ trực tiếp cho Cronet, OkHttp và ngăn xếp mạng tích hợp của Android. Bạn cũng có thể mở rộng ExoPlayer để hỗ trợ mọi ngăn xếp mạng khác hoạt động trên Android.

Cronet

Cronet là ngăn xếp mạng Chromium được cung cấp cho các ứng dụng Android dưới dạng một thư viện. Cronet tận dụng nhiều công nghệ giúp giảm độ trễ và tăng công suất của các yêu cầu mạng mà ứng dụng của bạn cần để hoạt động, bao gồm cả những yêu cầu do ExoPlayer đưa ra. Nền tảng này hỗ trợ sẵn giao thức HTTP, HTTP/2 và HTTP/3 qua giao thức QUIC. Cronet được một số ứng dụng phát trực tuyến lớn nhất thế giới, bao gồm cả YouTube, sử dụng.

ExoPlayer hỗ trợ Cronet thông qua thư việnCronet. Hãy xem README.md của thư viện để biết hướng dẫn chi tiết về cách sử dụng thư viện đó. Lưu ý rằng thư viện Cronet có thể sử dụng ba cách triển khai Cronet cơ bản:

  1. Dịch vụ Google Play: Bạn nên sử dụng cách triển khai này trong hầu hết các trường hợp và quay lại ngăn xếp mạng tích hợp của Android (DefaultHttpDataSource) nếu không có Dịch vụ Google Play.
  2. Cronet Embedded: Có thể là một lựa chọn phù hợp nếu phần lớn người dùng của bạn ở các thị trường nơi Dịch vụ Google Play không được cung cấp rộng rãi hoặc nếu bạn muốn kiểm soát chính xác phiên bản triển khai Cronet đang được sử dụng. Nhược điểm chính của Cronet Embedded là thêm khoảng 8 MB vào ứng dụng của bạn.
  3. Dự phòng Cronet: Việc triển khai dự phòng của Cronet sẽ triển khai API của Cronet dưới dạng một trình bao bọc xung quanh ngăn xếp mạng tích hợp của Android. Bạn không nên dùng phương thức này với ExoPlayer, vì việc sử dụng trực tiếp ngăn xếp mạng tích hợp của Android (bằng cách sử dụng DefaultHttpDataSource) sẽ hiệu quả hơn.

OkHttp

OkHttp là một ngăn xếp mạng hiện đại khác được nhiều ứng dụng Android phổ biến sử dụng rộng rãi. API này hỗ trợ HTTP và HTTP/2, nhưng chưa hỗ trợ HTTP/3 qua QUIC.

ExoPlayer hỗ trợ OkHttp thông qua thư viện OkHttp. Hãy xem README.md của thư viện để biết hướng dẫn chi tiết về cách sử dụng thư viện đó. Khi sử dụng thư viện OkHttp, ngăn xếp mạng sẽ được nhúng trong ứng dụng. Tương tự như Cronet Embedded, tuy nhiên OkHttp nhỏ hơn đáng kể, thêm dưới 1 MB vào ứng dụng.

Ngăn xếp mạng tích hợp của Android

ExoPlayer hỗ trợ sử dụng ngăn xếp mạng tích hợp của Android với DefaultHttpDataSourceDefaultHttpDataSource.Factory, thuộc thư viện ExoPlayer chính.

Việc triển khai ngăn xếp mạng chính xác phụ thuộc vào phần mềm đang chạy trên thiết bị cơ sở. Trên hầu hết các thiết bị (kể từ năm 2021), chỉ hỗ trợ HTTP (nghĩa là không hỗ trợ HTTP/2 và HTTP/3 qua QUIC).

Các ngăn xếp mạng khác

Các ứng dụng cũng có thể tích hợp các nhóm mạng khác với ExoPlayer. Để thực hiện việc này, hãy triển khai một HttpDataSource gói ngăn xếp mạng cùng với HttpDataSource.Factory tương ứng. Các thư viện Cronet và OkHttp của ExoPlayer là những ví dụ điển hình về cách thực hiện việc này.

Khi tích hợp với ngăn xếp mạng Java thuần tuý, bạn nên triển khai DataSourceContractTest để kiểm tra xem quá trình triển khai HttpDataSource của bạn có hoạt động chính xác hay không. OkHttpDataSourceContractTest trong thư viện OkHttp là một ví dụ hay về cách thực hiện việc này.

Chọn ngăn xếp mạng

Bảng sau đây trình bày ưu và nhược điểm của các ngăn xếp mạng mà ExoPlayer hỗ trợ.

Bộ phần cứng và phần mềm mạng Giao thức Ảnh hưởng của kích thước APK Ghi chú
Cronet (Dịch vụ Google Play) HTTP
HTTP/2
HTTP/3 qua QUIC
Nhỏ
(<100KB)
Cần có Dịch vụ Google Play. Phiên bản Cronet đã tự động cập nhật
Cronet (Được nhúng) HTTP
HTTP/2
HTTP/3 qua QUIC
Lớn
(~8 MB)
Phiên bản Cronet do nhà phát triển ứng dụng kiểm soát
Cronet (Dự phòng) HTTP
(khác nhau tuỳ thiết bị)
Nhỏ
(<100KB)
Không đề xuất cho ExoPlayer
OkHttp HTTP
HTTP/2
Nhỏ
(<1MB)
Cần có thời gian chạy Kotlin
Ngăn xếp mạng tích hợp HTTP
(khác nhau tuỳ thiết bị)
Không có Cách triển khai khác nhau tuỳ theo thiết bị

HTTP/2 và HTTP/3 qua giao thức QUIC có thể cải thiện đáng kể hiệu suất phát trực tuyến nội dung nghe nhìn. Cụ thể, khi phát trực tuyến nội dung nghe nhìn thích ứng được phân phối bằng mạng phân phối nội dung (CDN), có một số trường hợp sử dụng các giao thức này có thể cho phép CDN hoạt động hiệu quả hơn nhiều. Vì lý do này, sự hỗ trợ củaCronet cho cả HTTP/2 và HTTP/3 qua QUIC (và sự hỗ trợ của OkHttp cho HTTP/2), là một lợi ích lớn so với việc sử dụng ngăn xếp mạng tích hợp của Android, với điều kiện các máy chủ lưu trữ nội dung cũng hỗ trợ các giao thức này.

Khi xem xét riêng hoạt động phát nội dung nghe nhìn, bạn nên sử dụng Cronet do Dịch vụ Google Play cung cấp, quay lại sử dụng DefaultHttpDataSource nếu không có Dịch vụ Google Play. Đề xuất này tạo ra sự cân bằng hợp lý giữa việc cho phép sử dụng HTTP/2 và HTTP/3 qua QUIC trên hầu hết các thiết bị và tránh việc tăng đáng kể kích thước tệp APK. Có các trường hợp ngoại lệ đối với đề xuất này. Trong những trường hợp mà Dịch vụ Google Play có thể không hoạt động trên một phần đáng kể các thiết bị sẽ chạy ứng dụng của bạn, thì việc sử dụng Cronet Embedded hoặc OkHttp có thể phù hợp hơn. Bạn có thể chấp nhận việc sử dụng ngăn xếp mạng tích hợp sẵn nếu kích thước APK là một vấn đề quan trọng hoặc nếu truyền trực tuyến nội dung nghe nhìn chỉ là một phần nhỏ trong chức năng của ứng dụng.

Ngoài nội dung nghe nhìn, bạn nên chọn một ngăn xếp mạng duy nhất cho tất cả hoạt động nối mạng mà ứng dụng của mình thực hiện. Điều này cho phép các tài nguyên (chẳng hạn như ổ cắm) được gộp và chia sẻ một cách hiệu quả giữa ExoPlayer và các thành phần khác của ứng dụng.

Vì ứng dụng của bạn rất có thể sẽ cần thực hiện kết nối mạng không liên quan đến việc phát nội dung đa phương tiện, do đó, lựa chọn ngăn xếp mạng của bạn cuối cùng phải tính đến các đề xuất ở trên về việc phát nội dung đa phương tiện một cách riêng biệt, yêu cầu của mọi thành phần khác thực hiện việc nối mạng và tầm quan trọng tương đối của chúng đối với ứng dụng của bạn.

Lưu nội dung nghe nhìn vào bộ nhớ đệm

ExoPlayer hỗ trợ lưu các byte được tải vào bộ nhớ đệm vào ổ đĩa để ngăn việc tải liên tục cùng một byte từ mạng. Tính năng này rất hữu ích khi tìm kiếm lại trong nội dung nghe nhìn hiện tại hoặc lặp lại cùng một mục.

Việc lưu vào bộ nhớ đệm yêu cầu một thực thể SimpleCache trỏ đến một thư mục bộ nhớ đệm chuyên dụng và một 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();