Menerapkan radio

Halaman ini menjelaskan cara mengimplementasikan radio pada tingkat perangkat keras dan perangkat lunak.

Komponen sistem

Tumpukan radio siaran mencakup komponen berikut.

Arsitektur Radio Siaran
Gambar 1. Arsitektur Radio Siaran

Aplikasi referensi radio

Untuk detail tentang cara menerapkan kontrol radio, lihat Implementasi kontrol radio .

Contoh aplikasi radio Java ( packages/apps/Car/Radio ) berfungsi sebagai implementasi referensi. Saat layanan aplikasi dimulai, ia meminta Radio Manager untuk membuka Radio Tuner. Kemudian, aplikasi dapat mengirimkan permintaan ke Radio Tuner, seperti menyetel stasiun radio tertentu, frekuensi, atau untuk mencari stasiun radio berikutnya yang tersedia. Aplikasi ini menerima pembaruan dari Manajer Radio dan Penyetel Radio di Radio, seperti informasi program terkini, daftar program radio, konfigurasi, dan parameter yang ditentukan vendor. Aplikasi Radio referensi hanya mendukung radio AM dan FM. OEM dapat memodifikasi atau mengganti aplikasi Radio sesuai keinginan.

Manajer Radio

Ketika aplikasi meminta Radio Manager untuk membuka tuner, Radio Manager ( frameworks/base/core/java/android/hardware/radio/RadioManager.java ) meminta Layanan Radio Siaran untuk membuka sesi Tuner dan kemudian membungkus sesi tersebut dalam sebuah Radio Tuner ( frameworks/base/core/java/android/hardware/radio/RadioTuner.java ), yang dikembalikan ke aplikasi. Radio Tuner mendefinisikan API (seperti menyetel, melangkah, dan membatalkan) yang dapat dipanggil dari aplikasi radio dan mengirim permintaan ke Layanan Radio Siaran. Metode panggilan balik ( RadioTuner.Callback ) yang ditentukan di Radio Tuner mengirimkan pembaruan tentang HAL radio siaran, seperti informasi program terkini, daftar program, dan parameter yang ditentukan vendor, dari Layanan Radio Siaran ke aplikasi.

Layanan Radio Siaran

Layanan Radio Siaran ( frameworks/base/services/core/java/com/android/server/broadcastradio ) adalah layanan klien untuk Radio Siaran HAL. Layanan Radio Siaran mengoordinasikan beberapa Manajer Radio dengan HAL Radio Siaran. Layanan Radio Siaran mendukung bahasa definisi antarmuka HAL (HIDL) dan bahasa definisi antarmuka Android (AIDL) yang menyiarkan HAL radio. Layanan Radio Siaran terhubung ke AIDL HAL ketika ada layanan AIDL HAL; jika tidak, layanan akan terhubung ke HIDL HAL. Layanan Radio Siaran membuat Modul Radio untuk setiap instans HAL yang tersedia (seperti AM, FM, dan DAB).

Setiap Manajer Radio dapat meminta Layanan Radio Siaran untuk membuat sesi tuner pada Modul Radio yang sesuai, berdasarkan jenis radionya. Setiap sesi tuner dapat memanggil metode, seperti menyetel, melangkah, dan membatalkan (didefinisikan dalam antarmuka HAL) untuk melakukan operasi pada instans radio siaran HAL yang sesuai. Ketika satu sesi tuner menerima panggilan balik dari instans HAL pada pembaruan HAL, seperti info program saat ini, daftar program, tanda konfigurasi, dan parameter vendor, panggilan balik tentang pembaruan dikirim ke semua Radio Tuner yang terhubung ke Modul Radio yang sama.

Siaran radio HAL

Untuk mempelajari lebih lanjut tentang antarmuka HIDL dan AIDL pada radio siaran dan perbedaan antara keduanya, lihat Antarmuka HAL radio siaran .

Lapisan abstraksi perangkat keras radio siaran

Bagian berikut menjelaskan cara bekerja dengan lapisan abstraksi perangkat keras (HAL) untuk mengimplementasikan radio siaran.

Antarmuka HAL radio siaran

Radio siaran HAL menyediakan struktur data dan antarmuka di tingkat perangkat keras untuk mengimplementasikan radio siaran, seperti radio AM/FM dan DAB.

Antarmuka HIDL 2.0 dan AIDL

Radio siaran HAL menggunakan antarmuka yang dijelaskan di bagian berikut.

Pendengar pengumuman

IAnnouncementListener adalah antarmuka panggilan balik untuk pendengar pengumuman, yang dapat didaftarkan di radio siaran HAL untuk menerima pengumuman. Antarmuka memiliki metode berikut:

IAnnouncementListener
Deskripsi: Dipanggil setiap kali daftar pengumuman berubah.
MENYEMBUNYIKAN 2.0 oneway onListUpdated(vec<Announcement> announcements)
AIDL oneway void onListUpdated(in Announcement[] announcements)
Tutup pegangannya

ICloseHandle adalah pegangan tutup umum untuk menghapus panggilan balik yang tidak memerlukan antarmuka aktif.

ICcloseHandle
Deskripsi: Tutup pegangannya.
MENYEMBUNYIKAN 2.0 close()
AIDL void close()

Antarmuka panggilan balik

ITunerCallback adalah antarmuka panggilan balik yang dipanggil oleh radio siaran HAL untuk mengirim pembaruan ke layanan klien HAL.

Panggilan Balik ITuner
Deskripsi: Dipanggil oleh HAL ketika operasi penyetelan (tune, seek (dalam AIDL) atau scan (dalam HIDL) dan langkah berhasil) gagal secara asinkron.
MENYEMBUNYIKAN 2.0 oneway onCurrentProgramInfoChanged(ProgramInfo info)
AIDL void onCurrentProgramInfoChanged(in ProgramInfo info)
Deskripsi: Dipanggil ketika pencarian, pencarian (dalam AIDL) atau pemindaian (dalam HIDL), atau langkah berhasil.
MENYEMBUNYIKAN 2.0 oneway onTuneFailed(Result result, ProgramSelector selector)
AIDL void onTuneFailed(in Result result, in ProgramSelector selector)
Deskripsi: Dipanggil ketika pencarian, pencarian (dalam AIDL) atau pemindaian (dalam HIDL), atau langkah berhasil.
MENYEMBUNYIKAN 2.0 oneway onCurrentProgramInfoChanged(ProgramInfo info)
AIDL void onCurrentProgramInfoChanged(in ProgramInfo info)
Deskripsi: Dipanggil ketika daftar program diperbarui; ukuran setiap potongan harus dibatasi hingga 500kiB.
MENYEMBUNYIKAN 2.0 oneway onProgramListUpdated(ProgramListChunk chunk)
AIDL oneway onProgramListUpdated(ProgramListChunk chunk)
Deskripsi: Dipanggil ketika antena terhubung atau terputus.
MENYEMBUNYIKAN 2.0 oneway onAntennaStateChange(bool connected)
AIDL void onCurrentProgramInfoChanged(in ProgramInfo info)
Deskripsi: Dipanggil ketika nilai parameter khusus vendor diperbarui secara internal di HAL (tidak boleh dipanggil setelah memanggil setParameters oleh klien HAL).
MENYEMBUNYIKAN 2.0 oneway onParametersUpdated(vec<VendorKeyValue> parameters)
AIDL void onParametersUpdated(in VendorKeyValue[] parameters)
Deskripsi: Baru di AIDL. Dipanggil ketika flag konfigurasi diperbarui secara internal di HAL (tidak boleh dipanggil setelah memanggil setConfigFlag oleh klien HAL).
MENYEMBUNYIKAN 2.0 Tak dapat diterapkan.
AIDL void onConfigFlagUpdated(in ConfigFlag flag, in boolean value)

Antarmuka HAL radio siaran utama

IBroadcastRadio adalah antarmuka utama untuk siaran radio HAL. Di HIDL 2.0 HAL, gunakan antarmuka ITunerSession ke tuner untuk memanggil operasi. Namun, paling banyak satu tuner aktif pada satu waktu (asalkan setiap instans radio siaran HAL hanya memiliki satu chip tuner). ITunerSession telah dihapus dari antarmuka AIDL dan antarmukanya dipindahkan ke IBroadcastRadio .

IBroadcastRadio
Deskripsi: Dapatkan deskripsi modul dan kemampuannya.
MENYEMBUNYIKAN 2.0 getProperties() generates (Properties properties)
AIDL Properties getProperties()
Deskripsi: Mengambil konfigurasi wilayah AM/FM saat ini atau yang mungkin.
MENYEMBUNYIKAN 2.0 getAmFmRegionConfig(bool full) generates (Result result, AmFmRegionConfig config)
AIDL AmFmRegionConfig getAmFmRegionConfig(bool full)
Deskripsi: Mengambil konfigurasi wilayah DAB saat ini.
MENYEMBUNYIKAN 2.0 getDabRegionConfig() generates (Result result, vec<DabTableEntry> config)
AIDL DabTableEntry[] getDabRegionConfig()
Deskripsi: Mendapatkan gambar dari cache modul radio. Di AIDL, ukuran gambar harus kurang dari 1MB karena adanya batasan ketat pada buffer transaksi pengikat.
MENYEMBUNYIKAN 2.0 getImage(uint32_t id) generates (vec<uint8_t> image)
AIDL byte[] getImage(in int id)
Deskripsi: Mendaftarkan pendengar pengumuman.
MENYEMBUNYIKAN 2.0 registerAnnouncementListener(vec<AnnouncementType> enabled,IAnnouncementListener listener) generates (Result result, ICloseHandle closeHandle)
AIDL ICloseHandle registerAnnouncementListener(in IAnnouncementListener listener, in AnnouncementType[] enabled)
Keterangan:
  • HIDL HAL: Ketika sesi tuner baru dibuka, sesi lama harus dihentikan.
  • AIDL HAL: Karena tidak ada sesi tuner yang tersedia, hanya callback tuner yang perlu disetel. Jika ada, panggilan balik yang lama seharusnya tidak disetel.
MENYEMBUNYIKAN 2.0 openSession(ITunerCallback callback) menghasilkan (Result result, ITunerSession session)
AIDL void setTunerCallback(in ITunerCallback callback)
Keterangan:
  • HIDL HAL: Menutup sesi tuner tidak boleh gagal dan hanya boleh dikeluarkan satu kali.
  • AIDL HAL: Tidak ada tuner dan hanya panggilan balik tuner yang perlu tidak disetel.
MENYEMBUNYIKAN 2.0 close()
AIDL unsetTunerCallback()
Deskripsi: Menyesuaikan program tertentu.
MENYEMBUNYIKAN 2.0 tune(ProgramSelector program) generates (Result result)
AIDL void tune(in ProgramSelector program)
Deskripsi: Mencari program valid berikutnya yang mengudara . Untuk menghindari kebingungan di AIDL, scan diganti namanya menjadi seek .
MENYEMBUNYIKAN 2.0 scan(bool directionUp, bool skipSubChannel) generates (Result result)
AIDL void seek(in boolean directionUp, in boolean skipSubChannel)
Deskripsi: Langkah menuju saluran yang berdekatan, yang mungkin tidak ditempati oleh program apa pun.
MENYEMBUNYIKAN 2.0 step(bool directionUp) generates (Result result)
AIDL void step(in boolean directionUp)
Deskripsi: Membatalkan operasi penelusuran, pemindaian (dalam HIDL) atau pencarian (dalam AIDL), atau langkah yang tertunda.
MENYEMBUNYIKAN 2.0 cancel()
AIDL void cancel()
Deskripsi: Menerapkan filter ke daftar program dan mulai mengirimkan pembaruan daftar program melalui panggilan balik onProgramListUpdated .
MENYEMBUNYIKAN 2.0 startProgramListUpdates(ProgramFilter filter) generates (Result result)
AIDL void startProgramListUpdates(in ProgramFilter filter)
Deskripsi: Berhenti mengirim pembaruan daftar program.
MENYEMBUNYIKAN 2.0 stopProgramListUpdates()
AIDL void stopProgramListUpdates()
Deskripsi: Mengambil pengaturan saat ini dari tanda konfigurasi tertentu.
MENYEMBUNYIKAN 2.0 isConfigFlagSet(ConfigFlag flag) generates (Result result, bool value)
AIDL boolean isConfigFlagSet(in ConfigFlag flag)
Deskripsi: Menyetel tanda konfigurasi yang diberikan.
MENYEMBUNYIKAN 2.0 setConfigFlag(ConfigFlag flag, bool value) generates (Result result)
AIDL void setConfigFlag(in ConfigFlag flag, boolean value)
Deskripsi: Menetapkan nilai parameter khusus vendor.
MENYEMBUNYIKAN 2.0 setParameters(vec<VendorKeyValue> parameters)

menghasilkan ,

(vec<VendorKeyValue> results)
AIDL VendorKeyValue[] setParameters(in VendorKeyValue[] parameters)
Deskripsi: Mengambil nilai parameter spesifik vendor.
MENYEMBUNYIKAN 2.0 getParameters(vec<string> keys) generates (vec<VendorKeyValue> parameters)
AIDL VendorKeyValue[] getParameters(in String[] keys)

Klarifikasi antarmuka

Perilaku asinkron

Karena setiap operasi penyetelan (misalnya, penyetelan, pemindaian (dalam HIDL) atau pencarian (dalam AIDL), dan langkah) mungkin memakan waktu dan thread tidak boleh diblokir untuk waktu yang lama, operasi tersebut harus menjadwalkan operasi yang memakan waktu terjadi kemudian dan dengan cepat mengembalikan status atau hasil. Secara rinci, setiap operasi harus:

  • Batalkan semua operasi penyetelan yang tertunda.
  • Periksa apakah operasi dapat diproses berdasarkan input metode dan status tuner.
  • Jadwalkan tugas penyetelan lalu segera kembalikan Result (dalam HIDL) atau status (dalam AIDL). Jika Result atau status OK , panggilan balik tuner tuneFailed atau currentProgramInfoChanged harus dipanggil ketika tugas penyetelan gagal (misalnya, karena waktu habis) atau selesai.

Demikian pula, startProgramListUpdates juga menjadwalkan tugas yang memakan waktu untuk memperbarui daftar program agar dilakukan nanti dan dengan cepat mengembalikan status atau hasil. Metode ini pertama-tama membatalkan permintaan pembaruan yang tertunda, lalu menjadwalkan tugas pembaruan dan dengan cepat mengembalikan hasilnya.

Kondisi balapan

Karena perilaku operasi penyetelan yang tidak sinkron (misalnya, penyetelan, pemindaian (dalam HIDL) atau pencarian (dalam AIDL), dan langkah), terdapat kondisi perlombaan antara pembatalan operasi dan operasi penyetelan. Jika cancel dipanggil setelah HAL menyelesaikan operasi penyetelan dan sebelum panggilan balik selesai, pembatalan dapat diabaikan dan panggilan balik harus selesai dan diterima oleh klien HAL.

Demikian pula, jika stopProgramListUpdates dipanggil setelah HAL menyelesaikan pembaruan daftar program dan sebelum callback onCurrentProgramInfoChanged selesai, stopProgramListUpdates dapat diabaikan dan callback harus selesai.

Batas ukuran data

Karena ada batasan tegas pada buffer transaksi pengikat, batas data untuk beberapa metode antarmuka yang meneruskan data dengan potensi ukuran besar diklarifikasi dalam AIDL HAL.

  • getImage mengharuskan gambar yang dikembalikan kurang dari 1 MB.
  • onProgramListUpdate mengharuskan setiap chunk berukuran kurang dari 500kiB. Daftar program yang lebih besar harus dipecah oleh implementasi HAL menjadi beberapa bagian dan dikirim melalui beberapa callback.

Perubahan struktur data AIDL HAL

Selain perubahan antarmuka, perubahan ini juga diterapkan pada struktur data yang ditentukan dalam radio siaran AIDL HAL, yang memanfaatkan AIDL.

  • Enum Constant dihapus di AIDL dan didefinisikan sebagai const int di IBroadcastRadio . Sementara itu, ANTENNA_DISCONNECTED_TIMEOUT_MS diubah namanya menjadi ANTENNA_STATE_CHANGE_TIMEOUT_MS . Const int TUNER_TIMEOUT_MS baru ditambahkan. Semua operasi penyetelan, pencarian, dan langkah harus diselesaikan dalam waktu ini.
  • Enum RDS dan Deemphasis dihapus di AIDL dan didefinisikan sebagai const int di AmFmRegionConfig . Sejalan dengan itu, fmDeemphasis dan fmRds di ProgramInfo dideklarasikan sebagai int, yang merupakan hasil komputasi bit dari masing-masing flag. Sementara itu, D50 dan D75 masing-masing diganti namanya menjadi DEEMPHASIS_D50 dan DEEMPHASIS_D75 .
  • Enum ProgramInfoFlags dihapus di AIDL dan didefinisikan sebagai const int di ProgramInfo dengan awalan FLAG_ ditambahkan. Sejalan dengan itu, infoFlags di ProgramInfo dideklarasikan sebagai int, sebuah bit hasil komputasi dari flag. TUNED juga diganti namanya menjadi FLAG_TUNABLE , untuk lebih menjelaskan definisi stasiun yang dapat disetel.
  • Di AmFmBandRange , scanSpacing diganti namanya menjadi seekSpacing , karena scan diganti namanya menjadi seek di AIDL.
  • Sejak konsep penyatuan diperkenalkan di AIDL, MetadataKey dan Metadata yang didefinisikan dalam HIDL HAL tidak lagi digunakan. Metadata gabungan AIDL didefinisikan dalam AIDL HAL. Setiap nilai enum yang sebelumnya di MetadataKey sekarang menjadi bidang di Metadata dengan tipe string atau int, bergantung pada definisinya.

Implementasi kontrol radio

Implementasi kontrol radio didasarkan pada MediaSession dan MediaBrowse , yang memungkinkan aplikasi Media dan asisten suara untuk mengontrol radio. Untuk informasi selengkapnya, lihat Membuat aplikasi media untuk mobil di developer.android.com.

Implementasi pohon penelusuran media disediakan di perpustakaan dukungan siaran mobil di packages/apps/Car/libs . Perpustakaan ini juga berisi ekstensi ProgramSelector untuk mengkonversi ke dan dari URI. Direkomendasikan agar implementasi radio menggunakan perpustakaan ini untuk membangun pohon penelusuran terkait.

Pengalih sumber media

Untuk memberikan transisi yang mulus antara radio dan aplikasi lain yang ditampilkan di media, perpustakaan umum media mobil berisi kelas yang harus diintegrasikan ke dalam aplikasi radio. MediaAppSelectorWidget dapat disertakan dalam XML untuk aplikasi radio (ikon dan drop-down yang digunakan di media referensi dan aplikasi radio):

<com.android.car.media.common.MediaAppSelectorWidget
     android:id="@+id/app_switch_container"
     android:layout_width="@dimen/app_switch_widget_width"
     android:layout_height="wrap_content"
     android:background="@drawable/app_item_background"
     android:gravity="center" />

Widget ini meluncurkan AppSelectionFragment , yang menampilkan daftar sumber media yang dapat dialihkan. Jika diinginkan UI selain yang disediakan, Anda dapat membuat widget khusus untuk meluncurkan AppSelectionFragment saat pengalih harus ditampilkan.

AppSelectionFragment newFragment = AppSelectionFragment.create(widget,
            packageName, fullScreen);
    newFragment.show(mActivity.getSupportFragmentManager(), null);

Contoh implementasi disediakan dalam implementasi aplikasi radio referensi, yang terletak di packages/apps/Car/Radio .

Spesifikasi kontrol terperinci

Antarmuka MediaSession (melalui MediaSession.Callback ) menyediakan mekanisme kontrol untuk program radio yang sedang diputar:

  • onPlay , onStop . (Membatalkan) mematikan pemutaran radio.
  • onPause . Jeda waktu-bergeser (jika didukung).
  • onPlayFromMediaId . Memutar konten apa pun dari folder tingkat atas. Misalnya, "Putar FM" atau "Putar Radio".
  • onPlayFromUri . Mainkan frekuensi tertentu. Misalnya, "Putar 88,5 FM".
  • onSkipToNext , onSkipToPrevious . Dengarkan stasiun berikutnya atau sebelumnya.
  • onSetRating . Menambah atau menghapus ke atau dari Favorit.

MediaBrowser menampilkan MediaItem yang dapat disetel pada tiga jenis direktori tingkat atas:

  • ( Opsional ) Program (stasiun). Mode ini biasanya digunakan oleh radio dual-tuner untuk menunjukkan semua stasiun radio yang tersedia dan dapat disetel di lokasi pengguna.
  • Favorit. Program radio ditambahkan ke daftar Favorit, beberapa mungkin tidak tersedia (di luar jangkauan penerimaan).
  • Saluran pita. Semua saluran yang memungkinkan secara fisik di wilayah saat ini (87.9, 88.1, 88.3, ​​88.5, 88.7, 88.9, 89.1, dan seterusnya). Setiap band memiliki direktori tingkat atas yang terpisah.
Struktur pohon MediaBrowserService
Gambar 2. Struktur pohon MediaBrowserService

Setiap elemen di setiap folder ini (AM/FM/Program) adalah MediaItem dengan URI yang dapat digunakan dengan MediaSession untuk melakukan penyesuaian. Setiap folder tingkat atas (AM/FM/Program) adalah MediaItem dengan mediaId yang dapat digunakan dengan MediaSession untuk memicu pemutaran dan bergantung pada kebijaksanaan OEM. Misalnya, "Play FM", "Play AM", dan "Play Radio" adalah kueri radio non-spesifik yang menggunakan mediaId untuk dikirim ke aplikasi radio OEM. Aplikasi radiolah yang menentukan apa yang akan diputar dari permintaan umum dan mediaId.

Sesi Media

Mengingat tidak ada konsep menjeda streaming siaran, tindakan Putar, Jeda, dan Hentikan tidak selalu berlaku untuk radio. Dengan radio, tindakan Stop dikaitkan dengan mematikan streaming sementara Play dikaitkan dengan menghilangkan bisu.

Beberapa penyetel radio (atau aplikasi) menyediakan kemampuan untuk menyimulasikan jeda aliran siaran dengan menyimpan konten dalam cache lalu memutarnya kembali nanti. Dalam kasus seperti itu, gunakan onPause .

Memutar dari tindakan mediaId dan URI dimaksudkan untuk menyetel stasiun yang diambil dari antarmuka MediaBrowser. mediaId adalah string arbitrer yang disediakan oleh aplikasi radio untuk menerapkan nilai unik (sehingga ID tertentu menunjuk ke satu item saja) dan stabil (sehingga item tertentu memiliki ID yang sama di seluruh sesi) yang dapat digunakan untuk mengidentifikasi stasiun tertentu . URI akan memiliki skema yang terdefinisi dengan baik. Singkatnya, bentuk ProgramSelector yang di-URI. Meskipun hal ini mempertahankan atribut keunikannya, namun tidak harus stabil, meskipun dapat berubah ketika stasiun berpindah ke frekuensi yang berbeda.

Secara desain, onPlayFromSearch tidak digunakan. Adalah tanggung jawab klien (aplikasi pendamping) untuk memilih hasil pencarian dari pohon MediaBrowser. Memindahkan tanggung jawab tersebut ke aplikasi radio akan meningkatkan kompleksitas, memerlukan kontrak formal tentang bagaimana kueri string akan muncul, dan mengakibatkan pengalaman pengguna yang tidak merata pada platform perangkat keras yang berbeda.

Catatan: Aplikasi radio tidak berisi informasi tambahan yang berguna untuk mencari nama stasiun yang tidak diekspos ke klien melalui antarmuka MediaBrowser.

Melewati ke stasiun berikutnya atau sebelumnya bergantung pada konteks saat ini:

  • Saat aplikasi disetel ke stasiun dari daftar Favorit, aplikasi tersebut dapat berpindah ke stasiun berikutnya dari daftar Favorit.
  • Mendengarkan stasiun dari daftar Program dapat menyebabkan pencarian stasiun berikutnya yang tersedia, diurutkan berdasarkan nomor saluran.
  • Mendengarkan saluran sembarang dapat mengakibatkan penyetelan ke saluran fisik berikutnya, meskipun tidak ada sinyal siaran.

Aplikasi radio menangani tindakan ini.

Penanganan kesalahan

Tindakan TransportControls (Mainkan, Berhenti, dan Berikutnya) tidak memberikan umpan balik mengenai apakah tindakan tersebut berhasil atau tidak. Satu-satunya cara untuk menunjukkan kesalahan adalah dengan menyetel status MediaSession ke STATE_ERROR dengan pesan kesalahan.

Aplikasi radio harus menangani tindakan tersebut dan menjalankannya atau menetapkan status kesalahan. Jika perintah Putar tidak langsung dijalankan, status pemutaran harus diubah menjadi STATE_CONNECTING (jika penalaan langsung) atau STATE_SKIPPING_TO_PREVIOUS atau NEXT saat perintah dijalankan.

Klien harus memperhatikan PlaybackState dan memverifikasi bahwa sesi tersebut mengubah program saat ini sesuai permintaan atau dimasukkan ke dalam status kesalahan. STATE_CONNECTING tidak boleh lebih dari 30 detik. Namun, penyetelan langsung ke frekuensi AM/FM tertentu akan bekerja lebih cepat.

Tambahkan dan hapus favorit

MediaSession memiliki dukungan rating, yang dapat digunakan untuk mengontrol Favorit. onSetRating dipanggil dengan peringkat tipe RATING_HEART menambah atau menghapus stasiun yang sedang disetel ke atau dari daftar Favorit.

Bertentangan dengan preset lama, model ini mengasumsikan daftar Favorit tidak berurutan dan tidak terbatas, ketika setiap favorit yang disimpan dialokasikan ke slot numerik (biasanya, 1 hingga 6). Akibatnya, sistem berbasis preset tidak kompatibel dengan operasi onSetRating .

Batasan MediaSession API adalah hanya stasiun yang sedang disetel yang dapat ditambahkan atau dihapus. Misalnya, item harus dipilih terlebih dahulu sebelum dapat dihapus. Ini hanya batasan klien MediaBrowser, seperti aplikasi pendamping. Aplikasi radio tidak dibatasi dengan cara yang sama. Bagian ini bersifat opsional ketika aplikasi tidak mendukung Favorit.

Peramban Media

Untuk menyatakan frekuensi atau nama saluran fisik mana (saat menyetel ke saluran sembarang yang sesuai untuk teknologi radio tertentu) yang valid untuk wilayah tertentu, semua saluran (frekuensi) yang valid dicantumkan untuk setiap pita. Di wilayah AS, jumlahnya mencapai 101 saluran FM dalam rentang 87,8 hingga 108,0 MHz (menggunakan spasi 0,2MHz) dan 117 saluran AM dalam rentang 530 hingga 1700 kHz (menggunakan spasi 10kHz). Karena radio HD menggunakan ruang saluran yang sama, maka tidak disajikan secara terpisah.

Daftar program radio yang tersedia saat ini datar karena tidak memungkinkan skema tampilan seperti pengelompokan berdasarkan ansambel siaran audio langsung (DAB).

Entri pada daftar Favorit mungkin tidak dapat disetel. Misalnya jika program tertentu berada di luar jangkauan. Aplikasi radio mungkin mendeteksi atau tidak mendeteksi apakah entri tersebut dapat disetel sebelumnya. Jika demikian, entri tersebut mungkin tidak ditandai sebagai dapat diputar.

Untuk mengidentifikasi folder tingkat atas, mekanisme yang sama yang digunakan oleh Bluetooth diterapkan. Artinya, bundel Ekstra dari objek MediaDescription berisi bidang khusus tuner seperti yang dilakukan Bluetooth dengan EXTRA_BT_FOLDER_TYPE . Dalam kasus radio siaran, hal ini mengarah pada penentuan kolom baru berikut di API publik:

  • EXTRA_BCRADIO_FOLDER_TYPE = "android.media.extra.EXTRA_BCRADIO_FOLDER_TYPE" . Salah satu nilai berikut:
    • BCRADIO_FOLDER_TYPE_PROGRAMS = 1 . Program yang tersedia saat ini.
    • BCRADIO_FOLDER_TYPE_FAVORITES = 2 . Favorit.
    • BCRADIO_FOLDER_TYPE_BAND = 3 . Semua saluran fisik untuk band tertentu.

    Tidak perlu menentukan bidang metadata khusus radio apa pun, karena semua data yang relevan cocok dengan skema MediaBrowser.MediaItem yang ada:

    • Nama program (RDS PS, nama layanan DAB). MediaDescription.getTitle .
    • frekuensi FM. URI (lihat ProgramSelector ) atau MediaDescription.getTitle (jika entri ada di folder BROADCASTRADIO_FOLDER_TYPE_BAND ).
    • Pengidentifikasi khusus radio (RDS PI, DAB SId). MediaDescription.getMediaUri diuraikan ke ProgramSelector.

    Biasanya, tidak perlu mengambil frekuensi FM untuk entri pada program saat ini atau daftar Favorit (karena klien harus beroperasi pada ID media). Namun, jika kebutuhan tersebut muncul (misalnya, untuk tujuan tampilan), kebutuhan tersebut ada di URI dan dapat diurai ke ProgramSelector . Meskipun demikian, URI tidak disarankan digunakan untuk memilih item dalam sesi saat ini. Untuk detailnya, lihat ProgramSelector .

    Untuk menghindari masalah kinerja atau terkait pengikat, layanan MediaBrowser harus mendukung penomoran halaman:

    Catatan: Secara default, penomoran halaman diterapkan secara default di varian onLoadChildren() tanpa penanganan opsi.

    Entri terkait dari semua jenis daftar (saluran mentah, program yang ditemukan, dan favorit) mungkin memiliki mediaId yang berbeda (terserah pada aplikasi radio; perpustakaan dukungan akan memilikinya berbeda). URI (dalam bentuk ProgramSelector) berbeda antara saluran mentah dan program yang ditemukan di sebagian besar kasus (kecuali untuk FM tanpa RDS), namun sebagian besar sama antara program yang ditemukan dan favorit (kecuali, misalnya, ketika AF diperbarui).

    Memiliki mediaId yang berbeda untuk entri dari berbagai jenis daftar memungkinkan untuk mengambil tindakan berbeda terhadapnya. Anda dapat melintasi daftar Favorit atau daftar Semua Program di onSkipToNext , bergantung pada folder MediaItem yang baru saja dipilih (lihat MediaSession ).

    Tindakan nada khusus

    Daftar program memungkinkan pengguna untuk mencari stasiun tertentu, namun tidak memungkinkan pengguna untuk membuat permintaan umum seperti "Tune to FM", yang dapat mengakibatkan penyetelan ke stasiun yang baru-baru ini didengarkan pada pita FM.

    Untuk mendukung tindakan tersebut, beberapa direktori tingkat atas memiliki kumpulan tanda FLAG_PLAYABLE (bersama dengan FLAG_BROWSABLE untuk folder).

    Tindakan Lagu ke Bagaimana cara mengeluarkannya
    Putar radio Saluran radio apa pun startService(ACTION_PLAY_BROADCASTRADIO)

    atau

    playFromMediaId(MediaBrowser. getRoot() )
    Putar FM Saluran FM apa pun Putar dari mediaId band FM.

    Penentuan program mana yang akan disesuaikan bergantung pada aplikasi. Biasanya ini adalah saluran yang paling baru disetel dari daftar yang diberikan. Untuk detail tentang ACTION_PLAY_BROADCASTRADIO , lihat Maksud bermain secara umum .

    Penemuan dan koneksi layanan

    PackageManager dapat langsung menemukan pohon radio siaran MediaBrowserService yang menyajikan. Untuk melakukannya, panggil resolveService dengan maksud ACTION_PLAY_BROADCASTRADIO (lihat Maksud permainan umum ) dan tanda MATCH_SYSTEM_ONLY . Untuk menemukan semua layanan yang melayani radio (mungkin ada lebih dari satu; misalnya, AM/FM dan satelit terpisah), gunakan queryIntentServices .

    Layanan yang diselesaikan juga menangani maksud pengikatan android.media.browse.MediaBrowserService . Ini diverifikasi dengan GTS.

    Untuk menyambung ke MediaBrowserService yang dipilih, buat instans MediaBrowser untuk komponen layanan tertentu dan connect . Setelah membuat koneksi, pegangan ke MediaSession dapat diperoleh melalui getSessionToken .

    Aplikasi Radio dapat membatasi paket klien yang diizinkan untuk terhubung dalam implementasi onGetRoot pada layanan mereka. Aplikasi harus mengizinkan aplikasi sistem untuk terhubung tanpa memasukkan ke daftar putih. Untuk mengetahui detail tentang memasukkan ke daftar putih, lihat Menerima paket dan tanda tangan aplikasi Asisten .

    Jika aplikasi khusus sumber (misalnya, aplikasi radio) diinstal pada perangkat tanpa dukungan sumber tersebut, aplikasi tersebut akan tetap mengiklankan dirinya sebagai menangani maksud ACTION_PLAY_BROADCASTRADIO , namun pohon MediaBrowsernya tidak akan berisi tag khusus radio. Oleh karena itu, klien yang ingin memeriksa apakah sumber tertentu tersedia di perangkat, harus:

    1. Temukan layanan radio (panggil resolveService untuk ACTION_PLAY_BROADCASTRADIO ).
    2. Buat MediaBrowser lalu sambungkan ke sana.
    3. Tentukan keberadaan MediaItem dengan tambahan EXTRA_BCRADIO_FOLDER_TYPE .

    Catatan: Dalam kebanyakan kasus, klien harus memindai semua pohon MediaBrowser yang tersedia untuk mendeteksi semua sumber yang tersedia untuk perangkat tertentu.

    Nama band

    Daftar band diwakili oleh sekumpulan direktori tingkat atas dengan tag tipe folder yang disetel ke BCRADIO_FOLDER_TYPE_BAND . Judul MediaItem mereka adalah string lokal yang mewakili nama band. Dalam kebanyakan kasus, terjemahannya akan sama dengan terjemahan bahasa Inggris, namun klien tidak dapat bergantung pada asumsi tersebut.

    Untuk menyediakan mekanisme yang stabil dalam mencari band tertentu, tag tambahan ditambahkan untuk folder band, EXTRA_BCRADIO_BAND_NAME_EN . Ini adalah nama band yang tidak dilokalkan dan hanya dapat mengambil salah satu dari nilai yang telah ditentukan sebelumnya:

    • AM
    • FM
    • DAB

    Jika band tidak ada dalam daftar ini, tag nama band tidak boleh disetel. Namun, jika band tersebut ada dalam daftar, band tersebut harus memiliki tag yang disetel. Radio HD tidak menyebutkan band-band terpisah karena menggunakan media dasar yang sama seperti AM/FM.

    Maksud bermain secara umum

    Setiap aplikasi yang didedikasikan untuk memutar sumber tertentu (seperti radio atau CD) harus menangani maksud pemutaran umum untuk mulai memutar beberapa konten yang mungkin dari keadaan tidak aktif (misalnya, setelah boot). Cara memilih konten yang akan diputar bergantung pada aplikasi, namun biasanya yang diputar adalah program radio atau trek CD yang baru diputar. Ada maksud terpisah yang ditentukan untuk setiap sumber audio:

    • android.car.intent.action.PLAY_BROADCASTRADIO
    • android.car.intent.action.PLAY_AUDIOCD : CD-DA atau CD-Teks
    • android.car.intent.action.PLAY_DATADISC : Disk data optik seperti CD/DVD, tetapi bukan CD-DA (mungkin CD Mode Campuran)
    • android.car.intent.action.PLAY_AUX : Tanpa menentukan port AUX yang mana
    • android.car.intent.action.PLAY_BLUETOOTH
    • android.car.intent.action.PLAY_USB : Tanpa menentukan perangkat USB yang mana
    • android.car.intent.action.PLAY_LOCAL : Penyimpanan media lokal (flash internal)

    Intent dipilih untuk digunakan pada perintah main umum, karena maksud tersebut memecahkan dua masalah sekaligus: perintah main umum itu sendiri dan penemuan layanan. Manfaat tambahan dari memiliki maksud tersebut adalah kemungkinan untuk menjalankan tindakan sederhana tersebut tanpa membuka sesi MediaBrowser.

    Penemuan layanan sebenarnya adalah masalah yang lebih penting yang diselesaikan dengan maksud ini. Prosedur penemuan layanan mudah dan jelas dengan cara ini (lihat Penemuan dan koneksi layanan ).

    Untuk membuat beberapa implementasi klien lebih mudah, ada cara alternatif untuk mengeluarkan perintah Play (yang juga harus diterapkan oleh aplikasi radio): mengeluarkan playFromMediaId dengan rootId dari node root (digunakan sebagai mediaId). Meskipun simpul akar tidak dimaksudkan untuk dapat dimainkan, rootId-nya adalah string arbitrer yang dapat digunakan sebagai mediaId. Namun, klien tidak diharuskan untuk memahami nuansa ini.

    Pemilih Program

    Meskipun mediaId cukup untuk memilih saluran dari MediaBrowserService , saluran tersebut menjadi terikat pada satu sesi dan tidak konsisten antar penyedia. Dalam beberapa kasus, klien mungkin memerlukan penunjuk absolut (seperti frekuensi absolut) untuk mempertahankannya antara sesi dan perangkat.

    Di era siaran radio digital, frekuensi kosong saja tidak cukup untuk menyetel stasiun tertentu. Oleh karena itu, gunakan ProgramSelector untuk mencari saluran analog atau digital. ProgramSelector terdiri dari dua bagian:

    • Pengidentifikasi utama. Pengidentifikasi unik dan stabil untuk stasiun radio tertentu yang tidak berubah tetapi mungkin tidak cukup untuk menyetel stasiun tersebut. Misalnya kode RDS PI, yang dapat diterjemahkan menjadi tanda panggil di AS.
    • Pengidentifikasi sekunder. Pengidentifikasi tambahan yang berguna untuk menyetel stasiun tersebut (misalnya, frekuensi), mungkin termasuk pengidentifikasi dari teknologi radio lainnya. Misalnya, stasiun DAB mungkin memiliki cadangan siaran analog.

    Untuk mengaktifkan ProgramSelector agar sesuai dengan solusi berbasis MediaBrowser - atau MediaSession , tentukan skema URI untuk membuat serialisasinya. Skema ini didefinisikan sebagai berikut:

    broadcastradio://program/<primary ID type>/<primary ID>?
    <secondary ID type>=<secondary ID>&<secondary ID type>=<secondary ID>
    

    Dalam contoh ini, bagian Pengidentifikasi sekunder (setelah tanda tanya ( ? )) bersifat opsional dan dapat dihapus untuk memberikan pengidentifikasi yang stabil untuk digunakan sebagai mediaId . Misalnya:

    • broadcastradio://program/RDS_PI/1234?AMFM_FREQUENCY=88500&AMFM_FREQUENCY=103300
    • broadcastradio://program/AMFM_FREQUENCY/102100
    • broadcastradio://program/DAB_SID_EXT/14895264?RDS_PI=1234

    Bagian yang berwenang (alias tuan rumah) dari program memberikan ruang untuk perluasan skema di masa depan. String tipe pengidentifikasi ditentukan secara tepat sebagai namanya dalam definisi HAL 2.x dari IdentifierType dan format nilainya adalah angka desimal atau heksadesimal (dengan awalan 0x ).

    Semua pengidentifikasi khusus vendor diwakili oleh awalan VENDOR_ . Misalnya, VENDOR_0 untuk VENDOR_START dan VENDOR_1 untuk VENDOR_START ditambah 1. URI tersebut khusus untuk perangkat keras radio tempat URI tersebut dibuat dan tidak dapat ditransfer antar perangkat yang dibuat oleh OEM berbeda.

    URI ini harus ditetapkan ke setiap MediaItem di bawah folder radio tingkat atas. Selain itu, MediaSession harus mendukung playFromMediaId dan playFromUri . Namun, URI terutama ditujukan untuk ekstraksi metadata radio (seperti frekuensi FM) dan penyimpanan persisten. Tidak ada jaminan URI akan tersedia untuk semua item media (misalnya, ketika jenis ID utama belum didukung oleh framework). Di sisi lain, Media ID selalu berfungsi. Klien tidak disarankan menggunakan URI untuk memilih item dari sesi MediaBrowser saat ini. Sebagai gantinya, gunakan playFromMediaId . Meskipun demikian, ini bukan opsional untuk aplikasi penyajian dan URI yang hilang dicadangkan untuk kasus-kasus yang dapat dibenarkan.

    Desain awal menggunakan titik dua tunggal, bukan urutan :// setelah bagian skema. Namun, versi pertama tidak didukung oleh android.net.Uri untuk referensi URI hierarki absolut.

    Jenis sumber lainnya

    Sumber audio lainnya dapat ditangani dengan cara yang sama. Misalnya input tambahan dan pemutar CD Audio.

    Satu aplikasi dapat melayani berbagai jenis sumber. Dalam kasus seperti ini, sebaiknya Anda membuat MediaBrowserService terpisah untuk setiap jenis sumber. Bahkan dalam pengaturan dengan beberapa sumber yang dilayani/Layanan MediaBrowser, sangat disarankan untuk memiliki satu MediaSession dalam satu aplikasi.

    CD Audio

    Mirip dengan Audio CD, aplikasi yang melayani disk tersebut akan mengekspos MediaBrowser dengan satu entri yang dapat dijelajahi (atau lebih, jika sistem memiliki pengubah CD), yang pada gilirannya akan berisi semua trek dari CD tertentu. Jika sistem tidak memiliki pengetahuan tentang track pada setiap CD (misalnya, ketika semua disk dimasukkan ke dalam kartrid sekaligus dan tidak membaca semuanya), maka MediaItem untuk seluruh disk hanya PLAYABLE , bukan BROWSABLE dan PLAYABLE . Jika tidak ada disk pada slot tertentu, item tersebut tidak DAPAT PLAYABLE atau BROWSABLE (tetapi setiap slot harus selalu ada di pohon).

    Struktur pohon CD Audio
    Gambar 3. Struktur pohon CD Audio

    Entri-entri ini akan ditandai dengan cara yang sama seperti folder radio siaran; kolom tersebut akan berisi kolom tambahan tambahan yang ditentukan di MediaDescription API:

    • EXTRA_CD_TRACK : Untuk setiap MediaItem pada CD Audio, 1 nomor track berdasarkan.
    • EXTRA_CD_DISK : nomor disk berdasarkan 1.

    Untuk sistem yang mendukung CD-Teks dan disk yang kompatibel, MediaItem tingkat atas akan memiliki judul disk. Demikian pula, MediaItems untuk trek, akan memiliki judul lagu.

    Masukan tambahan

    Aplikasi yang menyajikan input tambahan menampilkan pohon MediaBrowser dengan satu entri (atau lebih, jika ada beberapa port) yang mewakili port AUX in. MediaSession masing-masing mengambil mediaId-nya dan beralih ke sumber tersebut setelah mendapatkan permintaan playFromMediaId .

    Struktur pohon AUX
    Gambar 4. Struktur pohon AUX

    Setiap entri AUX MediaItem akan memiliki bidang tambahan EXTRA_AUX_PORT_NAME yang disetel ke nama port yang tidak dilokalkan tanpa frasa "AUX". Misalnya, "AUX 1" akan disetel ke "1", "AUX front" ke "front" dan "AUX" ke string kosong. Di lokasi non-Inggris, tag nama akan tetap menggunakan string bahasa Inggris yang sama. Tidak seperti EXTRA_BCRADIO_BAND_NAME_EN , nilainya ditentukan oleh OEM dan tidak dibatasi pada daftar yang telah ditentukan sebelumnya.

    Jika perangkat keras dapat mendeteksi perangkat yang terhubung ke port AUX, perangkat keras harus menandai mediaitem sebagai PLAYABLE , hanya jika input terhubung. Perangkat keras masih harus disebutkan (tetapi tidak PLAYABLE ) jika tidak ada yang terhubung ke port ini. Jika perangkat keras tidak memiliki kemampuan seperti itu, mediaitem harus selalu diatur untuk PLAYABLE .

    Bidang tambahan

    Tentukan bidang berikut:

    • EXTRA_CD_TRACK = "android.media.extra.CD_TRACK"
    • EXTRA_CD_DISK = "android.media.extra.CD_DISK"
    • EXTRA_AUX_PORT_NAME = "android.media.extra.AUX_PORT_NAME"

    Klien perlu meninjau media tingkat atas untuk elemen-elemen yang memiliki EXTRA_CD_DISK atau EXTRA_AUX_PORT_NAME Set bidang tambahan.

    Contoh rinci

    Contoh -contoh berikut membahas struktur pohon mediabrowser untuk jenis sumber yang merupakan bagian dari desain ini.

    Siaran radio mediabrowserService (menangani ACTION_PLAY_BROADCASTRADIO ):

    • Stasiun (browsable) EXTRA_BCRADIO_FOLDER_TYPE=BCRADIO_FOLDER_TYPE_PROGRAMS
      • BBC One (Playable) URI: broadcastradio://program/RDS_PI/1234?AMFM_FREQUENCY=90500
      • ABC 88.1 (dapat dimainkan) URI: broadcastradio://program/RDS_PI/5678?AMFM_FREQUENCY=88100
      • ABC 88.1 HD1 (dapat dimainkan) URI: broadcastradio://program/HD_STATION_ID_EXT/158241DEADBEEF?AMFM_FREQUENCY=88100&RDS_PI=5678
      • ABC 88.1 HD2 (dapat dimainkan) URI: broadcastradio://program/HD_STATION_ID_EXT/158242DEADBEFE
      • 90.5 FM (dapat dimainkan) - FM TANPA RDSURI: broadcastradio://program/AMFM_FREQUENCY/90500
      • 620 AM (dapat dimainkan) URI: broadcastradio://program/AMFM_FREQUENCY/620
      • BBC One (Playable) URI: broadcastradio://program/DAB_SID_EXT/1E24102?RDS_PI=1234
    • Favorit (browsable, dapat dimainkan) EXTRA_BCRADIO_FOLDER_TYPE=BCRADIO_FOLDER_TYPE_FAVORITES
      • BBC One (Playable) URI: broadcastradio://program/RDS_PI/1234?AMFM_FREQUENCY=101300
      • BBC Two (tidak dapat dimainkan) URI: broadcastradio://program/RDS_PI/1300?AMFM_FREQUENCY=102100
    • Am (browsable, playable): EXTRA_BCRADIO_FOLDER_TYPE=BCRADIO_FOLDER_TYPE_BANDEXTRA_BCRADIO_BAND_NAME_EN="AM"
      • 530 AM (dapat dimainkan) URI: broadcastradio://program/AMFM_FREQUENCY/530
      • 540 AM (dapat dimainkan) URI: broadcastradio://program/AMFM_FREQUENCY/540
      • 550 AM (dapat dimainkan) URI: broadcastradio://program/AMFM_FREQUENCY/550
    • Fm (browsable, dapat dimainkan): EXTRA_BCRADIO_FOLDER_TYPE=BCRADIO_FOLDER_TYPE_BANDEXTRA_BCRADIO_BAND_NAME_EN="FM"
      • 87.7 FM (dapat dimainkan) URI: broadcastradio://program/AMFM_FREQUENCY/87700
      • 87.9 FM (dapat dimainkan) URI: broadcastradio://program/AMFM_FREQUENCY/87900
      • 88.1 FM (dapat dimainkan) URI: broadcastradio://program/AMFM_FREQUENCY/88100
    • DAB (dapat dimainkan): EXTRA_BCRADIO_FOLDER_TYPE=BCRADIO_FOLDER_TYPE_BANDEXTRA_BCRADIO_BAND_NAME_EN="DAB"

    Audio CD MediaBrowserService (menangani ACTION_PLAY_AUDIOCD ):

    • Disc 1 (dapat dimainkan) EXTRA_CD_DISK=1
    • Disc 2 (Browsable, dapat dimainkan) EXTRA_CD_DISK=2
      • Lacak 1 (dapat dimainkan) EXTRA_CD_TRACK=1
      • Lacak 2 (dapat dimainkan) EXTRA_CD_TRACK=2
    • CD Musik Saya (Browsable, Dapat Dimainkan) EXTRA_CD_DISK=3
      • All By Myself (dapat dimainkan) EXTRA_CD_TRACK=1
      • Reise, Reise (dapat dimainkan) EXTRA_CD_TRACK=2
    • Slot kosong 4 (tidak dapat dimainkan) EXTRA_CD_DISK=4

    Aux mediabrowserService (menangani ACTION_PLAY_AUX ):

    • Aux front (playable) EXTRA_AUX_PORT_NAME="front"
    • Aux belakang (dapat dimainkan) EXTRA_AUX_PORT_NAME="rear"