สแต็กเครือข่าย

ExoPlayer มักใช้สำหรับการสตรีมสื่อผ่านอินเทอร์เน็ต รองรับ สแต็กเครือข่ายหลายรายการเพื่อสร้างคำขอเครือข่ายที่สำคัญ ตัวเลือกของคุณ ของสแต็กเครือข่ายอาจส่งผลกระทบอย่างมากต่อประสิทธิภาพการสตรีม

หน้านี้จะแสดงวิธีกำหนดค่า ExoPlayer เพื่อใช้กลุ่มเครือข่าย ตัวเลือก แสดงตัวเลือกที่มี ให้คำแนะนำเกี่ยวกับวิธีการเลือก สแต็กเครือข่ายสำหรับแอป และอธิบายวิธีเปิดใช้การแคชสำหรับสตรีม สื่อ

การกำหนดค่า ExoPlayer เพื่อใช้สแต็กเครือข่ายที่เฉพาะเจาะจง

ExoPlayer จะโหลดข้อมูลผ่านคอมโพเนนต์ DataSource ซึ่งได้มาจากคอมโพเนนต์ดังกล่าว DataSource.Factory อินสแตนซ์ที่แทรกจากโค้ดของแอป

หากแอปของคุณต้องการเล่นเฉพาะเนื้อหา http(s) โดยเลือกเครือข่าย สแต็กนั้นง่ายพอๆ กับการอัปเดตอินสแตนซ์ DataSource.Factory ที่ มีการแทรกแอปเป็นอินสแตนซ์ของ HttpDataSource.Factory ที่สอดคล้องกับสแต็กเครือข่ายที่คุณต้องการใช้ หากแอปของคุณ ต้องเล่นเนื้อหาที่ไม่ใช่ http เช่น ไฟล์ในเครื่อง DefaultDataSource.Factory:

Kotlin

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

Java

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

ในตัวอย่างนี้ PreferredHttpDataSource.Factory คือค่าเริ่มต้นที่ตรงกับ สแต็กเครือข่ายที่ต้องการ เลเยอร์ DefaultDataSource.Factory ช่วยเพิ่มการสนับสนุน สำหรับแหล่งข้อมูลที่ไม่ใช่ http เช่น ไฟล์ในเครื่อง

ตัวอย่างต่อไปนี้แสดงวิธีสร้าง ExoPlayer ที่จะใช้ Cronet การกองซ้อนเครือข่าย และรองรับการเล่นเนื้อหาที่ไม่ใช่ 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();

สแต็กเครือข่ายที่รองรับ

ExoPlayer ให้การสนับสนุนโดยตรงสำหรับ HttpEngine, Cronet, OkHttp และ Android สแต็กเครือข่ายเริ่มต้นในตัว นอกจากนี้ยังสามารถขยาย ExoPlayer เพื่อรองรับ สแต็กเครือข่ายอื่นๆ ที่ใช้งานได้ใน Android

HttpEngine

HttpEngine คือสแต็กเครือข่ายเริ่มต้นที่แนะนำใน Android จาก API 34 (หรือ S ส่วนขยาย 7) ในกรณีส่วนใหญ่ โมเดลจะใช้สแต็กเครือข่าย Cronet ภายใน รองรับ HTTP, HTTP/2 และ HTTP/3 ผ่านโปรโตคอล QUIC

ExoPlayer รองรับ HttpEngine ด้วย HttpEngineDataSource.Factory คุณสามารถ ป้อนโรงงานของแหล่งข้อมูลนี้ตามที่อธิบายไว้ในการกำหนดค่า ExoPlayer เพื่อใช้ สแต็กเครือข่ายที่เจาะจง

Cronet

Cronet คือ การกองซ้อนเครือข่ายของ Chromium พร้อมใช้งานสำหรับแอป Android เป็นไลบรารี Cronet ใช้เวลา จากเทคโนโลยีมากมายที่ลดเวลาในการตอบสนองและเพิ่ม อัตราการส่งข้อมูลของคำขอเครือข่ายที่แอปของคุณต้องใช้ในการทำงาน ซึ่งรวมถึงคำขอ สร้างสรรค์โดย ExoPlayer รองรับ HTTP, HTTP/2 และ HTTP/3 ผ่าน QUIC มาตั้งแต่ต้น โปรโตคอล แอปสตรีมมิง ที่ใหญ่ที่สุดในโลกส่วนหนึ่งใช้ Cronet รวมถึง YouTube

ExoPlayer รองรับ Cronet ผ่าน ไลบรารี Cronet ดูวิธีการใช้งานได้โดยละเอียดที่README.mdของคลังนี้ ได้ โปรดทราบว่าไลบรารี Cronet สามารถใช้ Cronet ได้ 3 รายการ การนำไปใช้งาน:

  1. บริการ Google Play: เราขอแนะนำให้ใช้การติดตั้งใช้งานนี้ใน และกลับไปใช้สแต็กเครือข่ายในตัวของ Android (DefaultHttpDataSource) หากบริการ Google Play ไม่พร้อมใช้งาน
  2. Cronet Embedded: อาจเป็นทางเลือกที่ดีหากผู้ใช้จำนวนมาก อยู่ในตลาดที่บริการ Google Play ไม่พร้อมให้บริการอย่างกว้างขวาง หรือหากคุณ ต้องการควบคุมเวอร์ชันที่แน่นอนของการใช้งาน Cronet ที่กำลังใช้อยู่ ข้อเสียหลักของ Cronet Embedded คือเพิ่มประมาณ 8 MB แอปของคุณ
  3. ทางเลือกสำรองของ Cronet: การใช้งานสำรองของ Cronet API ของ Cronet เป็นพื้นที่โดยรอบของสแต็กเครือข่ายในตัวของ Android ควร จะไม่ใช้กับ ExoPlayer เนื่องจากใช้สแต็กเครือข่ายในตัวของ Android โดยตรง (โดยใช้ DefaultHttpDataSource) จะมีประสิทธิภาพมากกว่า

OkHttp

OkHttp คือสแต็กเครือข่ายสมัยใหม่ที่ ใช้กันอย่างแพร่หลายในแอป Android ยอดนิยมมากมาย รองรับ HTTP และ HTTP/2 แต่ยังไม่รองรับ HTTP/3 ผ่าน QUIC

ExoPlayer รองรับ OkHttp ผ่าน ไลบรารี OkHttp ดูวิธีการใช้งานได้โดยละเอียดที่README.mdของคลังนี้ ได้ เมื่อใช้ไลบรารี OkHttp สแต็กเครือข่ายจะถูกฝังอยู่ภายใน แอป ซึ่งคล้ายกับ Cronet Embedded แต่ OkHttp มีความสำคัญ ที่มีขนาดเล็กลง ทำให้แอปมีขนาดน้อยกว่า 1 MB

สแต็กเครือข่ายในตัวของ Android

ExoPlayer รองรับการใช้สแต็กเครือข่ายในตัวของ Android DefaultHttpDataSource และ DefaultHttpDataSource.Factory ซึ่งเป็นส่วนหนึ่งของ ไลบรารีหลักของ ExoPlayer

การใช้งานสแต็กเครือข่ายที่แน่นอนจะขึ้นอยู่กับซอฟต์แวร์ที่ทำงานบน อุปกรณ์ที่เกี่ยวข้อง อุปกรณ์ส่วนใหญ่รองรับเฉพาะ HTTP เท่านั้น (กล่าวคือ ระบบไม่รองรับ HTTP/2 และ HTTP/3 ผ่าน QUIC)

สแต็กเครือข่ายอื่นๆ

แอปยังสามารถผสานรวมสแต็กเครือข่ายอื่นๆ กับ ExoPlayer ได้ด้วย โดยใช้ HttpDataSource ที่รวมกลุ่มเครือข่าย พร้อมด้วย HttpDataSource.Factory ที่เกี่ยวข้อง Cronet ของ ExoPlayer และ ไลบรารี OkHttp เป็นตัวอย่างที่ดีของการดำเนินการนี้

เมื่อผสานรวมกับสแต็กเครือข่าย Java ล้วน ขอแนะนำว่า DataSourceContractTestเพื่อตรวจสอบว่าการใช้งาน HttpDataSource ของคุณ ทำงานได้อย่างถูกต้อง OkHttpDataSourceContractTest ในไลบรารี OkHttp คือ ตัวอย่างที่ดีของวิธีการนี้

การเลือกสแต็กเครือข่าย

ตารางต่อไปนี้สรุปข้อดีและข้อเสียของสแต็กเครือข่ายที่ ExoPlayer

สแต็กเครือข่าย โปรโตคอล ผลกระทบของขนาด APK หมายเหตุ
HttpEngine HTTP
HTTP/2
HTTP/3 ผ่าน QUIC
ไม่มี ใช้ได้กับ API 34 หรือ S Extensions 7 เท่านั้น
Cronet (บริการ Google Play) HTTP
HTTP/2
HTTP/3 ผ่าน QUIC
เล็ก
(<100 KB)
ต้องใช้บริการ Google Play อัปเดตเวอร์ชัน Cronet โดยอัตโนมัติแล้ว
Cronet (ฝัง) HTTP
HTTP/2
HTTP/3 ผ่าน QUIC
ใหญ่
(~8 MB)
เวอร์ชัน Cronet ที่ควบคุมโดยนักพัฒนาแอป
Cronet (สำรอง) HTTP
(แตกต่างกันไปตามอุปกรณ์)
เล็ก
(<100 KB)
ไม่แนะนำสำหรับ ExoPlayer
OkHttp HTTP
HTTP/2
เล็ก
(<1MB)
สแต็กเครือข่ายในตัว HTTP
(แตกต่างกันไปตามอุปกรณ์)
ไม่มี การใช้งานจะแตกต่างกันไปตามอุปกรณ์

โปรโตคอล HTTP/2 และ HTTP/3 ผ่านโปรโตคอล QUIC ช่วยปรับปรุงสื่อได้อย่างมาก ประสิทธิภาพของสตรีมมิง โดยเฉพาะอย่างยิ่ง เมื่อสตรีมสื่อแบบปรับอัตโนมัติที่ เผยแพร่โดยใช้เครือข่ายการกระจายเนื้อหา (CDN) แต่ก็มีกรณีต่างๆ การใช้โปรโตคอลเหล่านี้สามารถช่วยให้ CDN ทำงานได้อย่างมีประสิทธิภาพมากขึ้น ด้วยเหตุนี้ การรองรับทั้ง HTTP/2 และ HTTP/3 ของ HttpEngine และ Cronet มากกว่า QUIC (และ OkHttp ที่สนับสนุน HTTP/2) เป็นข้อดีที่สำคัญเมื่อเทียบกับ โดยใช้สแต็กเครือข่ายในตัวของ Android ในกรณีที่เซิร์ฟเวอร์มี เนื้อหาที่มีการโฮสต์ก็สนับสนุนโปรโตคอลเหล่านี้เช่นกัน

เมื่อพิจารณาการสตรีมสื่อแยกต่างหาก เราขอแนะนำให้ใช้ HttpEngine หรือ Cronet ให้บริการโดยบริการ Google Play กลับไปเป็น DefaultHttpDataSource หากบริการ Google Play ไม่พร้อมใช้งาน คำแนะนำนี้ให้ผลลัพธ์ที่ดี ความสมดุลระหว่างการเปิดใช้ HTTP/2 และ HTTP/3 ผ่าน QUIC ในอุปกรณ์ส่วนใหญ่ และ ทำให้ขนาด 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();