OpenSL ES untuk Android

Halaman ini menyajikan detail tentang bagaimana implementasi NDK untuk OpenSL ES™ berbeda dengan spesifikasi referensi untuk OpenSL ES 1.0.1. Saat menggunakan kode contoh dari spesifikasi ini, Anda mungkin perlu memodifikasinya agar berfungsi di Android.

Kecuali jika dinyatakan berbeda, semua fitur tersedia di Android 2.3 (API level 9) dan lebih baru. Sebagian fitur hanya tersedia untuk Android 4.0 (API level 14); hal ini telah diketahui.

Catatan: Compatibility Definition Document (CDD) Android menyebutkan persyaratan hardware dan software dari perangkat Android yang kompatibel. Lihat Kompatibilitas Android untuk informasi selengkapnya mengenai program kompatibilitas keseluruhan, dan CDD untuk dokumen CDD sebenarnya.

OpenSL ES memberikan antarmuka bahasa C yang juga dapat diakses menggunakan C++. OpenSL ES menampakkan fitur yang mirip dengan bagian audio dalam API Java Android berikut:

Seperti pada semua Android Native Development Kit (NDK), kegunaan utama OpenSL ES untuk Android adalah untuk mempermudah implementasi library bersama yang akan dipanggil menggunakan Java Native Interface (JNI). NDK tidak dimaksudkan untuk menulis aplikasi C/C++ murni. Akan tetapi, OpenSL ES adalah API berfitur lengkap, dan kami berharap Anda dapat memenuhi sebagian besar kebutuhan audio Anda menggunakan API ini saja, tanpa perlu melakukan up-call ke kode yang berjalan di runtime Android.

Catatan: Meskipun didasarkan pada OpenSL ES, API audio native Android (audio performa tinggi) bukanlah implementasi yang mengikuti profil OpenSL ES 1.0.1 (game, musik, atau ponsel). Hal ini karena Android tidak mengimplementasikan semua fitur yang diperlukan oleh salah satu profil tersebut. Semua kasus yang diketahui, di mana Android menampakkan perilaku yang berbeda dengan spesifikasinya, dijelaskan di halaman Ekstensi Android.

Fitur yang diwariskan dari spesifikasi referensi

Implementasi Android NDK untuk OpenSL ES mewarisi banyak set fitur dari spesifikasi referensi, dengan pembatasan tertentu.

Titik masuk global

OpenSL ES untuk Android mendukung semua titik masuk global dalam spesifikasi Android. Titik masuk ini mencakup:

  • slCreateEngine
  • slQueryNumSupportedEngineInterfaces
  • slQuerySupportedEngineInterfaces

Objek dan antarmuka

Tabel berikut menampilkan objek dan antarmuka yang didukung oleh implementasi Android NDK untuk OpenSL ES. Jika Ya muncul dalam sel, berarti fitur tersebut tersedia dalam implementasi ini.

Dukungan Android NDK untuk objek dan antarmuka.

Fitur Pemutar audio Perekam audio Engine Campuran output
Peningkatan bass Ya Tidak Tidak Ya
Antrean buffer Ya Tidak Tidak Tidak
Pencari lokasi data antrean buffer Ya: Sumber Tidak Tidak Tidak
Manajemen antarmuka dinamis Ya Ya Ya Ya
Pengiriman efek Ya Tidak Tidak Tidak
Engine Tidak Tidak Ya Tidak
Gema lingkungan Tidak Tidak Tidak Ya
Equalizer Ya Tidak Tidak Ya
Pencari lokasi data perangkat I/O Tidak Ya: Sumber Tidak Tidak
Ekstraksi metadata Ya: Decode ke PCM Tidak Tidak Tidak
Bisukan audio solo Ya Tidak Tidak Tidak
Objek Ya Ya Ya Ya
Pencari lokasi campuran output Ya: Sink Tidak Tidak Tidak
Putar Ya Tidak Tidak Tidak
Laju pemutaran Ya Tidak Tidak Tidak
Status pra-pengambilan Ya Tidak Tidak Tidak
Gema preset Tidak Tidak Tidak Ya
Rekam Tidak Ya Tidak Tidak
Cari Ya Tidak Tidak Tidak
Pencari lokasi data URI Ya: Sumber Tidak Tidak Tidak
Virtualizer Ya Tidak Tidak Ya
Volume Ya Tidak Tidak Tidak

Bagian selanjutnya menjelaskan batasan untuk beberapa fitur ini.

Batasan

Batasan tertentu berlaku untuk fitur dalam Tabel 1. Batasan ini menunjukkan perbedaan dengan spesifikasi referensi. Selebihnya dari bagian ini menyajikan informasi tentang perbedaan tersebut.

Manajemen antarmuka dinamis

OpenSL ES untuk Android tidak mendukung RemoveInterface atau ResumeInterface.

Kombinasi efek: gema lingkungan dan gema preset

Anda tidak dapat memiliki gema lingkungan dan gema preset pada campuran output yang sama.

Platform mungkin mengabaikan permintaan efek jika memperkirakan bahwa beban CPU akan menjadi terlalu tinggi.

Pengiriman efek

SetSendLevel() mendukung tingkat pengiriman tunggal per pemutar audio.

Gema lingkungan

Gema lingkungan tidak mendukung kolom reflectionsDelay, reflectionsLevel, atau reverbDelay dari struct SLEnvironmentalReverbSettings.

Format data MIME

Anda dapat menggunakan format data MIME hanya dengan pencari lokasi data URI, dan hanya untuk pemutar audio. Anda tidak dapat menggunakan format data ini untuk perekam audio.

Implementasi Android untuk OpenSL ES mengharuskan Anda menginisialisasi mimeType ke NULL atau string UTF-8 yang valid. Anda juga harus menginisialisasi containerType ke nilai yang valid. Jika tidak ada pertimbangan lain, misalnya portabilitas ke implementasi lainnya atau format konten yang tidak dapat diidentifikasi oleh aplikasi berdasarkan header, kami merekomendasikan Anda menetapkan mimeType ke NULL dan containerType ke SL_CONTAINERTYPE_UNSPECIFIED.

OpenSL ES untuk Android mendukung format audio berikut, selama platform Android juga mendukungnya:

  • WAV PCM.
  • WAV alaw.
  • WAV ulaw.
  • MP3 Ogg Vorbis.
  • AAC LC.
  • HE-AACv1 (AAC+).
  • HE-AACv2 (enhanced AAC+).
  • AMR.
  • FLAC.

Catatan: Untuk daftar format audio yang didukung oleh Android, lihat Format media yang didukung.

Batasan berikut berlaku pada penanganan format berikut dan format lain dalam implementasi OpenSL ES:

  • Format AAC harus berada dalam container MP4 atau ADTS.
  • OpenSL ES untuk Android tidak mendukung MIDI.
  • WMA bukanlah bagian dari AOSP, dan kami belum memverifikasi kompatibilitasnya dengan OpenSL ES untuk Android.
  • Implementasi Android NDK untuk OpenSL ES tidak mendukung pemutaran langsung DRM atau konten yang dienkripsi. Untuk memutar konten audio yang dilindungi, Anda harus mendekripsinya dalam aplikasi sebelum memutarnya, dengan aplikasi Anda yang memberlakukan pembatasan DRM.

OpenSL ES untuk Android tidak mendukung metode berikut untuk memanipulasi objek:

  • Resume()
  • RegisterCallback()
  • AbortAsyncOperation()
  • SetPriority()
  • GetPriority()
  • SetLossOfControlInterfaces()

Format data PCM

PCM adalah satu-satunya format data yang dapat Anda gunakan bersama antrean buffer. Konfigurasi pemutaran PCM yang didukung memiliki karakteristik berikut:

  • 8 bit tidak bertanda tangan atau 16 bit bertanda tangan.
  • Mono atau stereo.
  • Penyusunan byte little-endian.
  • Frekuensi sampel:
    • 8.000 Hz.
    • 11.025 Hz.
    • 12.000 Hz.
    • 16.000 Hz.
    • 22.050 Hz.
    • 24.000 Hz.
    • 32.000 Hz.
    • 44.100 Hz.
    • 48.000 Hz.

Konfigurasi yang didukung OpenSL ES untuk Android untuk perekaman bergantung pada perangkatnya; biasanya 16.000 Hz mono/16 bit bertanda tangan akan tersedia apa pun perangkatnya.

Nilai kolom samplesPerSec adalah dalam satuan miliHz, meskipun namanya mungkin tidak mengindikasikan demikian. Untuk menghindari penggunaan nilai yang salah secara tidak sengaja, kami merekomendasikan Anda menginisialisasi kolom ini menggunakan salah satu konstanta simbolik yang ditentukan untuk keperluan ini, misalnya SL_SAMPLINGRATE_44_1.

Android 5.0 (API level 21) dan yang lebih baru mendukung data floating point.

Laju pemutaran

Laju pemutaran OpenSL ES menunjukkan kecepatan objek dalam menyajikan data, yang dinyatakan dalam seperseribu kecepatan normal, atau permil. Misalnya, laju pemutaran 1.000 permil adalah 1.000/1.000, atau kecepatan normal. Rentang laju adalah interval tertutup yang menyatakan rentang laju pemutaran yang dimungkinkan.

Dukungan untuk rentang laju pemutaran dan kapabilitas lainnya dapat bervariasi bergantung pada versi platform dan implementasi. Aplikasi Anda dapat menentukan kapabilitas ini saat waktu proses menggunakan PlaybackRate::GetRateRange() atau PlaybackRate::GetCapabilitiesOfRate() untuk mengkueri perangkat.

Sebuah perangkat biasanya mendukung rentang laju yang sama untuk sumber data yang berformat PCM, dan rentang laju unitas sebesar 1.000 permil hingga 1.000 permil untuk format lain; dengan kata lain, rentang laju unitas secara efektif adalah nilai tunggal.

Rekam

OpenSL ES untuk Android tidak mendukung peristiwa SL_RECORDEVENT_HEADATLIMIT atau SL_RECORDEVENT_HEADMOVING.

Cari

Metode SetLoop() memungkinkan pengulangan keseluruhan file. Untuk mengaktifkan pengulangan, tetapkan parameter startPos ke 0, dan parameter endPos ke SL_TIME_UNKNOWN.

Pencari lokasi data antrean buffer

Pemutar atau perekam audio dengan pencari lokasi data untuk antrean buffer hanya mendukung format data PCM.

Pencari lokasi data perangkat I/O

OpenSL ES untuk Android hanya mendukung penggunaan pencari lokasi data perangkat I/O jika Anda telah menentukan pencari tersebut sebagai sumber data untuk Engine::CreateAudioRecorder(). Lakukan inisialisasi pencari lokasi data perangkat dengan menggunakan nilai yang dimuat dalam cuplikan kode berikut:

SLDataLocator_IODevice loc_dev =
  {SL_DATALOCATOR_IODEVICE, SL_IODEVICE_AUDIOINPUT,
  SL_DEFAULTDEVICEID_AUDIOINPUT, NULL};

Pencari lokasi data URI

OpenSL ES untuk Android hanya dapat menggunakan pencari lokasi data URI dengan format data MIME, dan hanya untuk pemutar audio. Anda tidak dapat menggunakan pencari lokasi data URI untuk perekam audio. URI ini hanya dapat menggunakan skema http: dan file:. Skema lainnya, seperti https:, ftp:, atau content: tidak diizinkan.

Kami belum memverifikasi dukungan untuk rtsp: dengan audio di platform Android.

Struktur data

Android mendukung struktur data OpenSL ES 1.0.1 ini:

  • SLDataFormat_MIME
  • SLDataFormat_PCM
  • SLDataLocator_BufferQueue
  • SLDataLocator_IODevice
  • SLDataLocator_OutputMix
  • SLDataLocator_URI
  • SLDataSink
  • SLDataSource
  • SLEngineOption
  • SLEnvironmentalReverbSettings
  • SLInterfaceID

Konfigurasi platform

OpenSL ES untuk Android didesain untuk aplikasi multi-thread dan aman untuk thread. OpenSL ES mendukung satu engine per aplikasi dan hingga 32 objek per engine. Memori perangkat dan CPU yang tersedia mungkin membatasi lebih jauh jumlah objek yang dapat digunakan.

Opsi engine ini telah dikenali, tetapi diabaikan oleh slCreateEngine:

  • SL_ENGINEOPTION_THREADSAFE
  • SL_ENGINEOPTION_LOSSOFCONTROL

OpenMAX AL dan OpenSL ES dapat digunakan bersama-sama dalam aplikasi yang sama. Dalam hal ini, secara internal terdapat satu objek engine bersama, dan batas 32 objek digunakan bersama antara OpenMAX AL dan OpenSL ES. Aplikasi harus membuat kedua engine, menggunakan kedua engine, dan akhirnya memusnahkan kedua engine tersebut. Implementasi ini mempertahankan jumlah referensi atas engine bersama sehingga dapat dimusnahkan dengan benar selama operasi pemusnahan kedua.

Catatan pemrograman

Catatan pemrograman OpenSL ES memberikan informasi tambahan untuk memastikan implementasi OpenSL ES yang tepat.

Catatan: Untuk memudahkan Anda, kami telah menyertakan salinan spesifikasi OpenSL ES 1.0.1 dengan NDK di docs/opensles/OpenSL_ES_Specification_1.0.1.pdf.

Masalah platform

Bagian ini menjelaskan masalah umum dalam rilis platform awal yang mendukung API ini.

Manajemen antarmuka dinamis

DynamicInterfaceManagement::AddInterface tidak berfungsi. Sebagai gantinya, tentukan antarmuka dalam array yang diteruskan ke Create(), seperti ditampilkan dalam kode contoh gema lingkungan.

Perencanaan versi mendatang OpenSL ES

API audio berperforma tinggi Android didasarkan pada OpenSL ES 1.0.1 Khronos Group. Khronos telah merilis versi revisi 1.1 dari standar. Versi revisi ini menyertakan berbagai fitur baru, klarifikasi, koreksi kesalahan ketik, dan beberapa inkompatibilitas. Sebagian besar inkompatibilitas yang diperkirakan relatif tidak berdampak (minor) atau berada dalam area OpenSL ES yang tidak didukung oleh Android.

Aplikasi yang dikembangkan dengan versi ini akan berfungsi pada platform Android versi mendatang, selama Anda mengikuti panduan yang diuraikan di bagian Perencanaan kompatibilitas biner di bawah.

Catatan: Kompatibilitas sumber di waktu mendatang bukanlah suatu sasaran. Dengan kata lain, jika melakukan upgrade ke NDK versi baru, Anda mungkin perlu memodifikasi kode sumber aplikasi agar mematuhi API baru tersebut. Kami memperkirakan bahwa hampir semua perubahan tersebut adalah perubahan kecil; lihat detailnya di bawah.

Perencanaan kompatibilitas biner

Kami menganjurkan aplikasi Anda mengikuti panduan ini untuk meningkatkan kompatibilitas biner pada waktu mendatang:

  • Gunakan hanya subset fitur yang didukung Android dari OpenSL ES 1.0.1, yang telah didokumentasikan.
  • Jangan bergantung pada kode hasil tertentu untuk operasi yang tidak berhasil; bersiaplah menangani berbagai macam kode hasil.
  • Handler callback aplikasi umumnya dijalankan dalam konteks yang dibatasi. Handler tersebut harus ditulis untuk menjalankan tugasnya dengan cepat, lalu menampilkan hasilnya secepat mungkin. Jangan menjalankan operasi yang kompleks dalam handler callback. Misalnya, dalam callback penyelesaian antrean buffer, Anda dapat mengantrekan buffer lain, tetapi jangan membuat pemutar audio.
  • Handler callback harus disiapkan untuk lebih sering atau lebih jarang dipanggil, untuk menerima jenis peristiwa tambahan, dan harus mengabaikan jenis peristiwa yang tidak dikenalnya. Callback yang dikonfigurasi dengan mask peristiwa yang tersusun atas jenis-jenis peristiwa yang diaktifkan harus siap untuk dipanggil dengan berbagai bit jenis peristiwa yang disetel secara serentak. Gunakan "&" untuk menguji setiap bit peristiwa, bukan switch case.
  • Gunakan status pengambilan data dan callback sebagai indikasi progres secara umum, tetapi jangan bergantung pada level isian hard-code atau urutan callback tertentu. Arti dari level isian status pengambilan data, dan perilaku error yang terdeteksi selama pengambilan data, dapat berubah.

Catatan: Lihat bagian Perilaku antrean buffer di bawah untuk detail selengkapnya.

Perencanaan kompatibilitas sumber

Seperti disebutkan di atas, inkompatibilitas kode sumber telah diperkirakan dalam OpenSL ES versi berikutnya dari Khronos Group. Area yang kemungkinan akan berubah antara lain:

  • Antarmuka antrean buffer diperkirakan mengalami perubahan signifikan, khususnya di area BufferQueue::Enqueue, daftar parameter untuk slBufferQueueCallback, dan nama kolom SLBufferQueueState.playIndex. Sebaiknya aplikasi Anda menggunakan antrean buffer sederhana Android. Dalam kode contoh yang disertakan dengan NDK, kami telah menggunakan antrean buffer sederhana Android untuk pemutaran karena alasan ini. (Kami juga menggunakan antrean buffer sederhana Android untuk perekaman dan dekode ke PCM, tetapi itu karena OpenSL ES 1.0.1 tidak mendukung perekaman atau dekode ke sink data antrean buffer.)
  • Akan ada penambahan const ke parameter input yang diteruskan melalui referensi, dan ke kolom struct SLchar * yang digunakan sebagai nilai input. Penambahan ini tidak memerlukan perubahan apa pun pada kode Anda.
  • Akan ada pengganti dengan jenis yang tidak bertandatangan untuk beberapa parameter yang saat ini bertanda tangan. Anda mungkin perlu mengubah jenis parameter dari SLint32 menjadi SLuint32 atau yang serupa, atau menambahkan cast.
  • Equalizer::GetPresetName menyalin string ke memori aplikasi, bukan menampilkan pointer ke memori implementasi. Ini akan menjadi perubahan signifikan, jadi sebaiknya Anda menghindari memanggil metode ini, atau mengisolasi penggunaannya.
  • Akan ada kolom tambahan dalam jenis struct. Untuk parameter output, kolom baru ini dapat diabaikan, tetapi untuk parameter input, kolom baru ini perlu diinisialisasi. Untungnya, semua kolom ini diperkirakan akan berada di area yang tidak didukung oleh Android.
  • GUID antarmuka akan berubah. Rujuklah antarmuka melalui nama simbolik, bukan GUID, untuk menghindari dependensi.
  • SLchar akan berubah dari unsigned char menjadi char. Perubahan ini terutama memengaruhi pencari lokasi data URI dan format data MIME.
  • SLDataFormat_MIME.mimeType akan diganti namanya menjadi pMimeType, dan SLDataLocator_URI.URI akan diganti namanya menjadi pURI. Kami merekomendasikan Anda menginisialisasi struktur data SLDataFormat_MIME dan SLDataLocator_URI menggunakan daftar nilai yang dipisahkan koma dalam kurung kurawal, bukan berdasarkan nama kolom, untuk mengisolasi kode Anda dari perubahan ini. Teknik ini digunakan dalam kode contoh.
  • SL_DATAFORMAT_PCM tidak mengizinkan aplikasi menentukan representasi data sebagai bilangan bulat bertanda tangan, bilangan bulat tidak bertanda tangan, atau bilangan titik mengambang. Implementasi Android mengasumsikan bahwa data 8 bit adalah bilangan bulat tidak bertanda tangan sedangkan 16 bit adalah bilangan bulat bertanda tangan. Selain itu, kolom samplesPerSec adalah istilah yang salah, karena satuan sebenarnya adalah miliHz. Masalah ini diharapkan akan teratasi dalam OpenSL ES versi berikutnya, yang akan memperkenalkan format data PCM baru yang diperluas, yang mengizinkan aplikasi untuk menentukan representasi secara eksplisit dan mengoreksi nama kolom. Karena ini akan menjadi format data baru, dan format data PCM saat ini tetap akan tersedia (meski tidak digunakan lagi), maka tidak perlu ada perubahan segera pada kode Anda.