Ngăn xếp mạng

ExoPlayer thường được sử dụng để phát trực tuyến nội dung đa phương tiện qua Internet. Thư viện này hỗ trợ nhiều ngăn xếp mạng để tạo các yêu cầu mạng cơ bản. Lựa chọn ngăn xếp mạng của bạn có thể ảnh hưởng đáng kể đến hiệu suất phát 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 chọn, liệt kê các tuỳ chọn có sẵn, đưa ra 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 tính năng lưu vào bộ nhớ đệm cho nội dung nghe nhìn trực tuyến.

Định cấu hình ExoPlayer để sử dụng 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à ứng dụng lấy 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, hãy chọn một mạng ngăn xếp chỉ đơn giản như việc cập nhật bất kỳ thực thể DataSource.Factory nào mà ứng dụng chèn làm 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(s), chẳng hạn như tệp cục bộ, hãy sử 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à nhà máy tương ứng với ngăn xếp mạng ưu tiên của bạn. Lớp DefaultDataSource.Factory bổ sung chức năng hỗ trợ cho(các) nguồn không phải http, chẳng hạn như tệp cục bộ.

Ví dụ sau đây cho biết 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(s).

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 HttpEngine, Cronet, OkHttp và ngăn xếp mạng mặc định 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.

HttpEngine

HttpEngine là ngăn xếp mạng mặc định được đề xuất trên Android từ API 34 (hoặc tiện ích S 7). Trong hầu hết các trường hợp, nó sử dụng ngăn xếp mạng Cronet nội bộ, hỗ trợ HTTP, HTTP/2 và HTTP/3 qua giao thức QUIC.

ExoPlayer hỗ trợ HttpEngine bằng HttpEngineDataSource.Factory. Bạn có thể chèn nguồn dữ liệu này như mô tả trong Định cấu hình ExoPlayer để sử dụng ngăn xếp mạng cụ thể.

Cronet

Cronet là Ngăn xếp mạng Chromium được cung cấp cho ứng dụng Android dưới dạng thư viện. Cronet sử dụng tận dụng nhiều công nghệ để giảm độ trễ và tăng thời gian thông lượng 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 tạo. Thư viện này hỗ trợ gốc các giao thức HTTP, HTTP/2 và HTTP/3 qua QUIC. Một số ứng dụng truyền trực tuyến lớn nhất trên thế giới sử dụng Cronet. bao gồm cả YouTube.

ExoPlayer hỗ trợ Cronet 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 nó. Xin lưu ý rằng thư viện Cronet có thể sử dụng 3 phương thức triển khai Cronet cơ bản:

  1. Dịch vụ Google Play: Bạn nên sử dụng phương thức 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 nhúng: 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 ở những thị trường mà Dịch vụ Google Play không phổ biến hoặc nếu bạn muốn kiểm soát phiên bản chính xác của cách triển khai Cronet đang được sử dụng. Chiến lược phát hành đĩa đơn Nhược điểm lớn của Cronet Embedded là nó sẽ thêm khoảng 8 MB vào ứng dụng của bạn.
  3. Tính năng dự phòng của Chromium: Hoạt động triển khai dự phòng của Cronet sẽ thực hiện API của Cronet đóng vai trò là một trình bao bọc xung quanh ngăn xếp mạng tích hợp sẵn của Android. Phải không được sử dụng với ExoPlayer, vì việc sử dụng ngăn xếp mạng tích hợp sẵn của Android trực tiếp (bằng cách sử dụng DefaultHttpDataSource) sẽ hiệu quả hơn.

OkHttp

OkHttp là một hệ thống mạng hiện đại khác được nhiều ứng dụng Android phổ biến sử dụng. Giao thức 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 nó. Khi sử dụng thư viện OkHttp, ngăn xếp mạng sẽ được nhúng trong ứng dụng. Điều này tương tự như Cronet Nhúng, tuy nhiên OkHttp nhỏ hơn đáng kể, chỉ thêm dưới 1 MB vào ứng dụng.

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

ExoPlayer hỗ trợ sử dụng ngăn xếp mạng tích hợp của Android bằng DefaultHttpDataSourceDefaultHttpDataSource.Factory, là một phần của thư viện ExoPlayer cốt lõi.

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

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

Ứng dụng cũng có thể tích hợp các ngăn xếp mạng khác với ExoPlayer. Để làm việc này, hãy triển khai một HttpDataSource gói ngăn xếp mạng cùng với một HttpDataSource.Factory tương ứng. 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 một DataSourceContractTest để kiểm tra nhằm đảm bảo rằng việc triển khai HttpDataSource của bạn hoạt động chính xác. OkHttpDataSourceContractTest trong thư viện OkHttp là một ví dụ điển hình về cách làm việc này.

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

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

Ngăn xếp mạng Giao thức Mức tác động của kích thước APK Ghi chú
HttpEngine HTTP
HTTP/2
HTTP/3 qua QUIC
Không có Chỉ có trên API 34 hoặc Tiện ích S 7
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 được cập nhật tự động
Cronet (Được nhúng) HTTP
HTTP/2
HTTP/3 qua QUIC
Lớn
(~8MB)
Phiên bản Cronet do nhà phát triển ứng dụng kiểm soát
Cronet (Bản dự phòng) HTTP
(khác nhau tuỳ theo thiết bị)
Nhỏ
(<100KB)
Không nên dùng cho ExoPlayer
OkHttp HTTP
HTTP/2
Nhỏ
(<1MB)
Bộ phần cứng và phần mềm mạng tích hợp HTTP
(tuỳ theo thiết bị)
Không có Cách triển khai sẽ khác nhau tuỳ theo thiết bị

Giao thức HTTP/2 và HTTP/3 qua 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 truyền trực tuyến nội dung đa phương tiện thích ứng được phân phối bằng mạng phân phối nội dung (CDN), có những trường hợp việc 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ủa HttpEngine và Cronet cho cả HTTP/2 và HTTP/3 qua QUIC (và hỗ trợ của OkHttp cho HTTP/2), là một lợi ích lớn so với sử dụng ngăn xếp mạng tích hợp sẵn của Android, miễn là các máy chủ mà nội dung được lưu trữ cũng hỗ trợ các giao thức này.

Khi cân nhắc việc phát trực tuyến nội dung nghe nhìn một cách riêng biệt, bạn nên sử dụng HttpEngine hoặc Cronet do Dịch vụ Google Play cung cấp trở lại DefaultHttpDataSource nếu Dịch vụ Google Play không hoạt động. Đề xuất này tạo ra trải nghiệm tốt cân bằng giữa việc bật 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 APK. Tuy nhiên, có một số trường hợp ngoại lệ đối với đề xuất này. Đối với các trường hợp mà Dịch vụ Google Play có khả năng không dùng được trên một phần đáng kể các thiết bị sẽ chạy ứng dụng của bạn, việc sử dụng Cronet Embedded hoặc OkHttp có thể phù hợp hơn. Việc sử dụng tính năng tích hợp sẵn bộ phần cứng và phần mềm mạng có thể được chấp nhận nếu kích thước APK là một vấn đề quan trọng, hoặc nếu nội dung đa phương tiện truyền trực tuyến chỉ là một phần nhỏ trong chức năng của ứng dụng.

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

Vì rất có thể ứng dụng của bạn 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 nghe nhìn, nên 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 truyền phát nội dung nghe nhìn riêng biệt, các yêu cầu của mọi thành phần khác thực hiện kết nối mạng và tầm quan trọng tương đối của các thành phần đó đố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 đã tải vào bộ nhớ đệm trên ổ đĩa để tránh tải lại cùng một byte từ mạng. Điều này rất hữu ích khi tua lại trong dòng thời gian nội dung nghe nhìn 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();