Pemecahan masalah


Memperbaiki error "Cleartext HTTP traffic not permitted"

Error ini akan terjadi jika aplikasi Anda meminta traffic HTTP cleartext (yaitu, http://, bukan https://) saat Konfigurasi Keamanan Jaringannya tidak mengizinkannya. Jika aplikasi Anda menargetkan Android 9 (API level 28) atau yang lebih tinggi, traffic HTTP cleartext akan dinonaktifkan oleh konfigurasi default.

Jika aplikasi Anda perlu berfungsi dengan traffic HTTP cleartext, Anda harus menggunakan Konfigurasi Keamanan Jaringan yang mengizinkannya. Lihat dokumentasi keamanan jaringan Android untuk mengetahui detailnya. Untuk mengaktifkan semua traffic HTTP cleartext, Anda cukup menambahkan android:usesCleartextTraffic="true" ke elemen application di AndroidManifest.xml aplikasi Anda.

Aplikasi demo ExoPlayer menggunakan Konfigurasi Keamanan Jaringan default, sehingga tidak mengizinkan traffic HTTP cleartext. Anda dapat mengaktifkannya menggunakan petunjuk di atas.

Memperbaiki error "SSLHandshakeException", "CertPathValidatorException", dan "ERR_CERT_AUTHORITY_INVALID"

SSLHandshakeException, CertPathValidatorException, dan ERR_CERT_AUTHORITY_INVALID menunjukkan masalah dengan sertifikat SSL server. Error ini tidak khusus untuk ExoPlayer. Lihat dokumentasi SSL Android untuk mengetahui detail selengkapnya.

Mengapa beberapa file media tidak dapat dicari?

Secara default, ExoPlayer tidak mendukung pencarian di media yang satu-satunya metode untuk melakukan operasi pencarian akurat adalah dengan memindai dan mengindeks seluruh file. ExoPlayer menganggap file tersebut tidak dapat dicari. Sebagian besar format penampung media modern menyertakan metadata untuk pencarian (seperti indeks sampel), memiliki algoritma pencarian yang ditentukan dengan baik (misalnya, penelusuran biseksi yang diinterpolasi untuk Ogg), atau menunjukkan bahwa kontennya memiliki bitrate konstan. Operasi pencarian yang efisien dimungkinkan dan didukung oleh ExoPlayer dalam kasus ini.

Jika Anda memerlukan pencarian, tetapi memiliki media yang tidak dapat dicari, sebaiknya konversi konten Anda untuk menggunakan format penampung yang lebih sesuai. Untuk file MP3, ADTS, dan AMR, Anda juga dapat mengaktifkan pencarian dengan asumsi bahwa file memiliki bitrate konstan, seperti yang dijelaskan di sini.

Mengapa pencarian tidak akurat di beberapa file MP3?

File MP3 bitrate variabel (VBR) pada dasarnya tidak cocok untuk kasus penggunaan yang memerlukan pencarian yang tepat. Ada dua alasan untuk hal ini:

  1. Untuk pencarian yang tepat, format penampung idealnya akan memberikan pemetaan waktu ke byte yang akurat di header. Pemetaan ini memungkinkan pemutar memetakan waktu pencarian yang diminta ke offset byte yang sesuai, dan mulai meminta, mengurai, dan memutar media dari offset tersebut. Header yang tersedia untuk menentukan pemetaan ini di MP3 (seperti header XING), sayangnya, sering kali tidak akurat.
  2. Untuk format penampung yang tidak memberikan pemetaan waktu ke byte yang akurat (atau pemetaan waktu ke byte sama sekali), pencarian yang tepat masih dapat dilakukan jika penampung menyertakan stempel waktu sampel absolut dalam streaming. Dalam hal ini, pemutar dapat memetakan waktu pencarian ke perkiraan terbaik dari offset byte yang sesuai, mulai meminta media dari offset tersebut, mengurai stempel waktu sampel absolut pertama, dan secara efektif melakukan penelusuran biner terpandu ke media hingga menemukan sampel yang tepat. Sayangnya, MP3 tidak menyertakan stempel waktu sampel absolut dalam streaming, sehingga pendekatan ini tidak memungkinkan.

Karena alasan ini, satu-satunya cara untuk melakukan pencarian yang tepat ke dalam file MP3 VBR adalah dengan memindai seluruh file dan membuat pemetaan waktu ke byte secara manual di pemutar. Strategi ini dapat diaktifkan dengan menggunakan FLAG_ENABLE_INDEX_SEEKING, yang dapat ditetapkan pada DefaultExtractorsFactory menggunakan setMp3ExtractorFlags. Perhatikan bahwa strategi ini tidak dapat diskalakan dengan baik ke file MP3 besar, terutama jika pengguna mencoba mencari ke dekat akhir streaming segera setelah memulai pemutaran, yang mengharuskan pemutar menunggu hingga mendownload dan mengindeks seluruh streaming sebelum melakukan pencarian. Di ExoPlayer, kami memutuskan untuk mengoptimalkan kecepatan daripada akurasi dalam kasus ini, sehingga FLAG_ENABLE_INDEX_SEEKING dinonaktifkan secara default.

Jika Anda mengontrol media yang diputar, sebaiknya gunakan format penampung yang lebih sesuai, seperti MP4. Tidak ada kasus penggunaan yang kami ketahui di mana MP3 adalah pilihan format media terbaik.

Mengapa pencarian di video saya lambat?

Saat pemutar mencari posisi pemutaran baru dalam video, pemutar harus melakukan dua hal:

  1. Memuat data yang sesuai dengan posisi pemutaran baru ke dalam buffer (hal ini mungkin tidak diperlukan jika data ini sudah di-buffer).
  2. Mengosongkan dekoder video dan mulai mendekode dari I-frame (keyframe) sebelum posisi pemutaran baru, karena pengkodean intra-frame yang digunakan oleh sebagian besar format kompresi video. Untuk memastikan pencarian akurat (yaitu, pemutaran dimulai tepat di posisi pencarian), semua frame antara I-frame sebelumnya dan posisi pencarian harus didekode dan segera dihapus (tanpa ditampilkan di layar).

Latensi yang diperkenalkan oleh (1) dapat dikurangi dengan meningkatkan jumlah data yang di-buffer dalam memori oleh pemutar, atau melakukan pra-cache data ke disk.

Latensi yang diperkenalkan oleh (2) dapat dikurangi dengan mengurangi akurasi pencarian menggunakan ExoPlayer.setSeekParameters, atau mengenkode ulang video agar memiliki I-frame yang lebih sering (yang akan menghasilkan file output yang lebih besar).

Mengapa beberapa file MPEG-TS gagal diputar?

Beberapa file MPEG-TS tidak berisi pembatas unit akses (AUD). Secara default, ExoPlayer mengandalkan AUD untuk mendeteksi batas frame dengan murah. Demikian pula, beberapa file MPEG-TS tidak berisi keyframe IDR. Secara default, ini adalah satu-satunya jenis keyframe yang dipertimbangkan oleh ExoPlayer.

ExoPlayer akan tampak stuck dalam status buffering saat diminta untuk memutar file MPEG-TS yang tidak memiliki AUD atau keyframe IDR. Jika perlu memutar file tersebut, Anda dapat melakukannya menggunakan FLAG_DETECT_ACCESS_UNITS dan FLAG_ALLOW_NON_IDR_KEYFRAMES. Flag ini dapat ditetapkan pada DefaultExtractorsFactory menggunakan setTsExtractorFlags atau pada DefaultHlsExtractorFactory menggunakan konstruktor. Penggunaan FLAG_DETECT_ACCESS_UNITS tidak memiliki efek samping selain mahal secara komputasi dibandingkan dengan deteksi batas frame berbasis AUD. Penggunaan FLAG_ALLOW_NON_IDR_KEYFRAMES dapat menyebabkan kerusakan visual sementara pada awal pemutaran dan segera setelah pencarian saat memutar beberapa file MPEG-TS.

Mengapa subtitle tidak ditemukan di beberapa file MPEG-TS?

Beberapa file MPEG-TS menyertakan trek CEA-608, tetapi tidak mendeklarasikannya dalam metadata penampung, sehingga ExoPlayer tidak dapat mendeteksinya. Anda dapat menentukan trek subtitle secara manual dengan memberikan daftar format subtitle yang diharapkan ke DefaultExtractorsFactory, termasuk saluran aksesibilitas yang dapat digunakan untuk mengidentifikasinya dalam streaming MPEG-TS:

Kotlin

val extractorsFactory =
  DefaultExtractorsFactory()
    .setTsSubtitleFormats(
      listOf(
        Format.Builder()
          .setSampleMimeType(MimeTypes.APPLICATION_CEA608)
          .setAccessibilityChannel(accessibilityChannel)
          // Set other subtitle format info, such as language.
          .build()
      )
    )
val player: Player =
  ExoPlayer.Builder(context, DefaultMediaSourceFactory(context, extractorsFactory)).build()

Java

DefaultExtractorsFactory extractorsFactory =
    new DefaultExtractorsFactory()
        .setTsSubtitleFormats(
            ImmutableList.of(
                new Format.Builder()
                    .setSampleMimeType(MimeTypes.APPLICATION_CEA608)
                    .setAccessibilityChannel(accessibilityChannel)
                    // Set other subtitle format info, such as language.
                    .build()));
Player player =
    new ExoPlayer.Builder(context, new DefaultMediaSourceFactory(context, extractorsFactory))
        .build();

Mengapa beberapa file MP4/FMP4 diputar dengan tidak benar?

Beberapa file MP4/FMP4 berisi daftar edit yang menulis ulang linimasa media dengan melewati, memindahkan, atau mengulang daftar sampel. ExoPlayer memiliki dukungan parsial untuk menerapkan daftar edit. Misalnya, ExoPlayer dapat menunda atau mengulang grup sampel yang dimulai pada sampel sinkronisasi, tetapi tidak memangkas sampel audio atau media preroll untuk pengeditan yang tidak dimulai pada sampel sinkronisasi.

Jika Anda melihat bahwa sebagian media tiba-tiba hilang atau diulang, coba tetapkan Mp4Extractor.FLAG_WORKAROUND_IGNORE_EDIT_LISTS atau FragmentedMp4Extractor.FLAG_WORKAROUND_IGNORE_EDIT_LISTS, yang akan menyebabkan ekstraktor mengabaikan daftar edit sepenuhnya. Daftar ini dapat ditetapkan pada DefaultExtractorsFactory menggunakan setMp4ExtractorFlags atau setFragmentedMp4ExtractorFlags.

Mengapa beberapa streaming gagal dengan kode respons HTTP 301 atau 302?

Kode respons HTTP 301 dan 302 menunjukkan pengalihan. Deskripsi singkat dapat ditemukan di Wikipedia. Saat ExoPlayer membuat permintaan dan menerima respons dengan kode status 301 atau 302, ExoPlayer biasanya akan mengikuti pengalihan dan memulai pemutaran seperti biasa. Satu-satunya kasus yang tidak terjadi secara default adalah untuk pengalihan lintas protokol. Pengalihan lintas protokol adalah pengalihan dari HTTPS ke HTTP atau sebaliknya (atau lebih jarang, antara pasangan protokol lainnya). Anda dapat menguji apakah URL menyebabkan pengalihan lintas protokol menggunakan alat command line wget sebagai berikut:

wget "https://yourserver.example.com/test.mp3" 2>&1  | grep Location

Outputnya kurang lebih akan seperti ini:

Location: https://secondserver.example.net/test.mp3 [following]
Location: http://thirdserver.example.org/test.mp3 [following]

Dalam contoh ini, ada dua pengalihan. Pengalihan pertama adalah dari https://yourserver.example.com/test.mp3 ke https://secondserver.example.net/test.mp3. Keduanya adalah HTTPS, sehingga ini bukan pengalihan lintas protokol. Pengalihan kedua adalah dari https://secondserver.example.net/test.mp3 ke http://thirdserver.example.org/test.mp3. Pengalihan ini dari HTTPS ke HTTP, sehingga merupakan pengalihan lintas protokol. ExoPlayer tidak akan mengikuti pengalihan ini dalam konfigurasi defaultnya, yang berarti pemutaran akan gagal.

Jika perlu, Anda dapat mengonfigurasi ExoPlayer untuk mengikuti pengalihan lintas protokol saat membuat instance DefaultHttpDataSource.Factory yang digunakan dalam aplikasi Anda. Pelajari cara memilih dan mengonfigurasi stack jaringan di sini.

Mengapa beberapa streaming gagal dengan UnrecognizedInputFormatException?

Pertanyaan ini terkait dengan kegagalan pemutaran dalam bentuk berikut:

UnrecognizedInputFormatException: None of the available extractors
(MatroskaExtractor, FragmentedMp4Extractor, ...) could read the stream.

Ada dua kemungkinan penyebab kegagalan ini. Penyebab paling umum adalah Anda mencoba memutar konten DASH (mpd), HLS (m3u8), atau SmoothStreaming (ism, isml), tetapi pemutar mencoba memutarnya sebagai streaming progresif. Untuk memutar streaming tersebut, Anda harus bergantung pada modul ExoPlayer masing-masing. Jika URI streaming tidak diakhiri dengan ekstensi file standar, Anda juga dapat meneruskan MimeTypes.APPLICATION_MPD, MimeTypes.APPLICATION_M3U8, atau MimeTypes.APPLICATION_SS ke setMimeType dari MediaItem.Builder untuk menentukan jenis streaming secara eksplisit.

Penyebab kedua, yang kurang umum, adalah ExoPlayer tidak mendukung format penampung media yang Anda coba putar. Dalam hal ini, kegagalan berfungsi seperti yang diharapkan, tetapi Anda dapat mengirimkan permintaan fitur ke issue tracker kami, termasuk detail format penampung dan streaming pengujian. Telusuri permintaan fitur yang ada sebelum mengirimkan permintaan baru.

Mengapa setPlaybackParameters tidak berfungsi dengan benar di beberapa perangkat?

Saat menjalankan build debug aplikasi Anda di Android M dan yang lebih lama, Anda mungkin mengalami performa yang tidak stabil, artefak yang terdengar, dan penggunaan CPU yang tinggi saat menggunakan setPlaybackParameters API. Hal ini karena pengoptimalan yang penting untuk API ini dinonaktifkan untuk build debug yang berjalan di versi Android ini.

Perlu diperhatikan bahwa masalah ini hanya memengaruhi build debug. Masalah ini tidak memengaruhi build rilis, yang pengoptimalannya selalu diaktifkan. Oleh karena itu, rilis yang Anda berikan kepada pengguna akhir tidak akan terpengaruh oleh masalah ini.

Apa arti error "Player is accessed on the wrong thread"?

Lihat Catatan tentang threading di halaman memulai.

Bagaimana cara memperbaiki "Unexpected status line: ICY 200 OK"?

Masalah ini dapat terjadi jika respons server menyertakan baris status ICY, bukan yang sesuai dengan HTTP. Baris status ICY tidak digunakan lagi dan tidak boleh digunakan. Jadi, jika Anda mengontrol server, Anda harus memperbaruinya untuk memberikan respons yang sesuai dengan HTTP. Jika Anda tidak dapat melakukannya, menggunakan library ExoPlayer OkHttp akan menyelesaikan masalah ini, karena library tersebut dapat menangani baris status ICY dengan benar.

Bagaimana cara membuat kueri apakah streaming yang diputar adalah streaming langsung?

Anda dapat membuat kueri metode isCurrentWindowLive pemutar. Selain itu, Anda dapat memeriksa isCurrentWindowDynamic untuk mengetahui apakah jendela bersifat dinamis (yaitu, masih diperbarui dari waktu ke waktu).

Bagaimana cara mempertahankan pemutaran audio saat aplikasi saya berada di latar belakang?

Ikuti langkah-langkah berikut untuk memastikan pemutaran audio terus berlanjut saat aplikasi Anda berada di latar belakang:

  1. Anda harus memiliki layanan latar depan yang berjalan. Hal ini mencegah sistem menghentikan proses Anda untuk mengosongkan resource.
  2. Anda harus memiliki WifiLock dan WakeLock. Hal ini memastikan sistem tetap mengaktifkan radio WiFi dan CPU. Hal ini dapat dilakukan dengan mudah jika menggunakan ExoPlayer dengan memanggil setWakeMode, yang akan otomatis mendapatkan dan melepaskan kunci yang diperlukan pada waktu yang tepat.

Anda harus melepaskan kunci (jika tidak menggunakan setWakeMode) dan menghentikan layanan segera setelah audio tidak lagi diputar.

Mengapa ExoPlayer mendukung konten saya, tetapi library ExoPlayer Cast tidak?

Kemungkinan konten yang Anda coba putar tidak diaktifkan CORS. Framework Cast mengharuskan konten diaktifkan CORS agar dapat diputar.

Mengapa konten gagal diputar, tetapi tidak ada error yang muncul?

Kemungkinan perangkat yang Anda gunakan untuk memutar konten tidak mendukung format sampel media tertentu. Hal ini dapat dikonfirmasi dengan mudah dengan menambahkan an EventLogger sebagai listener ke pemutar Anda, dan mencari baris yang mirip dengan baris ini di Logcat:

[ ] Track:x, id=x, mimeType=mime/type, ... , supported=NO_UNSUPPORTED_TYPE

NO_UNSUPPORTED_TYPE berarti perangkat tidak dapat mendekode format sampel media yang ditentukan oleh mimeType. Lihat dokumentasi format media Android untuk mengetahui informasi tentang format sampel yang didukung. Bagaimana cara memuat library decoding dan menggunakannya untuk pemutaran? mungkin juga berguna.

Bagaimana cara memuat library decoding dan menggunakannya untuk pemutaran?

  • Sebagian besar library dekoder memiliki langkah-langkah manual untuk memeriksa dan mem-build dependensi, jadi pastikan Anda telah mengikuti langkah-langkah dalam README untuk library yang relevan. Misalnya, untuk library ExoPlayer FFmpeg, Anda harus mengikuti petunjuk di libraries/decoder_ffmpeg/README.md, termasuk meneruskan flag konfigurasi untuk mengaktifkan dekoder untuk format apa pun yang ingin Anda putar.
  • Untuk library yang memiliki kode native, pastikan Anda menggunakan versi Android NDK yang benar seperti yang ditentukan dalam README, dan perhatikan error yang muncul selama konfigurasi dan build. Anda akan melihat file .so muncul di subdirektori libs dari jalur library untuk setiap arsitektur yang didukung setelah mengikuti langkah-langkah dalam README.
  • Untuk mencoba pemutaran menggunakan library di aplikasi demo, lihat mengaktifkan dekoder paket. Lihat README untuk library guna mengetahui petunjuk tentang cara menggunakan library dari aplikasi Anda sendiri.
  • Jika menggunakan DefaultRenderersFactory, Anda akan melihat baris log level info seperti "Loaded FfmpegAudioRenderer" di Logcat saat dekoder dimuat. Jika tidak ada, pastikan aplikasi memiliki dependensi pada library decoding.
  • Jika Anda melihat log level peringatan dari LibraryLoader di Logcat, hal ini menunjukkan bahwa pemuatan komponen native library gagal. Jika hal ini terjadi, pastikan Anda telah mengikuti langkah-langkah dalam README library dengan benar dan tidak ada error yang dihasilkan saat mengikuti petunjuk.

Jika Anda masih mengalami masalah saat menggunakan library decoding, periksa Media3 issue tracker untuk mengetahui masalah terbaru yang relevan. Jika Anda perlu mengajukan masalah baru dan masalah tersebut terkait dengan pembuatan bagian native library, sertakan output command line lengkap dari menjalankan petunjuk README, untuk membantu kami mendiagnosis masalah tersebut.

Dapatkah saya memutar video YouTube secara langsung dengan ExoPlayer?

Tidak, ExoPlayer tidak dapat memutar video dari YouTube, seperti URL dalam format https://www.youtube.com/watch?v=.... Sebagai gantinya, Anda harus menggunakan YouTube IFrame Player API, yang merupakan cara resmi untuk memutar video YouTube di Android.

Pemutaran video tersendat-sendat

Perangkat mungkin tidak dapat mendekode konten dengan cukup cepat jika, misalnya, bitrate atau resolusi konten melebihi kemampuan perangkat. Anda mungkin perlu menggunakan konten berkualitas lebih rendah untuk mendapatkan performa yang baik di perangkat tersebut.

Jika Anda mengalami video tersendat-sendat di perangkat yang menjalankan versi Android dari Android 6.0 (API level 23) hingga dan termasuk Android 11 (API level 30), terutama saat memutar konten yang dilindungi DRM atau konten dengan frame rate tinggi, Anda dapat mencoba mengaktifkan antrean buffer asinkron.

Error lint API yang tidak stabil

Media3 menjamin kompatibilitas biner untuk subset platform API. Bagian yang tidak menjamin kompatibilitas biner ditandai dengan @UnstableApi. Untuk memperjelas perbedaan ini, penggunaan simbol API yang tidak stabil akan menghasilkan error lint kecuali jika diberi anotasi dengan @OptIn.

Anotasi @UnstableApi tidak menyiratkan apa pun tentang kualitas atau performa API, hanya fakta bahwa API tersebut tidak "API-frozen".

Anda memiliki dua pilihan untuk menangani error lint API yang tidak stabil:

  • Beralih ke penggunaan API stabil yang mencapai hasil yang sama.
  • Terus gunakan API yang tidak stabil dan beri anotasi penggunaan dengan @OptIn, seperti yang ditunjukkan nanti.
Menambahkan anotasi @OptIn

Android Studio dapat membantu Anda menambahkan anotasi:

Screenshot: Cara menambahkan anotasi Optin
Gambar 2: Menambahkan anotasi @androidx.annotations.OptIn dengan Android Studio.

Anda juga dapat memberi anotasi secara manual pada situs penggunaan tertentu:

Kotlin

import androidx.annotation.OptIn
import androidx.media3.common.util.UnstableApi

@OptIn(UnstableApi::class)
fun functionUsingUnstableApi() { ... }

Java

import androidx.annotation.OptIn;
import androidx.media3.common.util.UnstableApi;

@OptIn(markerClass = UnstableApi.class)
private void methodUsingUnstableApis() { ... }

Seluruh paket dapat diikutsertakan dengan menambahkan file package-info:

Kotlin

// In your package-info.kt
@OptIn(UnstableApi::class)
package name.of.your.package

import androidx.annotation.OptIn
import androidx.media3.common.util.UnstableApi

Java

// In your package-info.java
@OptIn(markerClass = UnstableApi.class)
package name.of.your.package;

import androidx.annotation.OptIn;
import androidx.media3.common.util.UnstableApi;

Seluruh project dapat diikutsertakan dengan menekan error lint tertentu dalam file lint.xml mereka:

 <?xml version="1.0" encoding="utf-8"?>
 <lint>
   <issue id="UnsafeOptInUsageError">
     <option name="opt-in" value="androidx.media3.common.util.UnstableApi" />
   </issue>
 </lint>

Ada juga anotasi kotlin.OptIn yang tidak boleh digunakan. Anda harus menggunakan anotasi androidx.annotation.OptIn.