Kisah ini dimulai sekitar 1,5 tahun yang lalu. Ini terkait dengan memainkan musik di berbagai browser dan platform tempat mereka menjalankannya. Sebuah jalan yang penuh dengan
“rasa sakit dan penderitaan” dari kesadaran bahwa tugas yang mudah pada pandangan pertama mungkin tidak begitu mudah, dan rincian “tidak penting” yang Anda tidak menganggap penting pada awalnya, dapat mempengaruhi segalanya.
Detail kecil untuk yang paling penasaran :)1. Mengunduh data tentang setiap trek berikutnya dari jaringan.
2. Untuk setiap elemen audio: Audio baru () atau <audio> Anda memerlukan izin dari pengguna - tindakan pengguna di halaman tersebut.
Latar belakang
Mungkin setiap orang yang pernah menulis pemutar audio untuk browser setidaknya sekali dalam hidup mereka telah mengalami masalah kompatibilitas lintas browser dan lintas platform.
Jadi saat mengerjakan MVP baru, saya menemukan berbagai fitur mengenai pemutaran audio di browser.
Dan itu semua dimulai dengan fakta bahwa itu perlu untuk membuat crossfade mulus dari dua lagu selama pemutaran - ini adalah fitur pertama. Tim kami ingin membuat perubahan trek seperti di radio. Dan fitur kedua - setiap trek berikutnya diminta dari jaringan.

Penelitian
Kemudian, hampir semua proyek kami menggunakan perpustakaan Sound Manager 2.
Hampir dengan segera, Anda menyadari bahwa memutar dua file audio secara bersamaan di perangkat seluler tidak berfungsi sama di mana saja!
Di Chrome (~ versi 62) untuk PC, trek diputar sebagaimana mestinya. Pada perangkat seluler (juga di Chrome), pemutaran lagu berfungsi, tetapi hanya dengan layar aktif. Ketika layar terkunci, trek berikutnya setelah pemain saat ini tidak dimainkan. Sedangkan untuk iOS / macOS, pemutaran bekerja dengan cara yang sama. Informasi lebih lanjut dapat diperoleh di
sini - bagian “Single Audio Stream”.
Maka mulailah
berjalan di atas tiga laut mencari informasi sedikit demi sedikit tentang fitur browser dengan audio.
Oke, saya mencoba solusi dengan Audio Web tanpa menggunakan perpustakaan apa pun. Ya, teknologi ini ditujukan untuk tujuan lain: sintesis, pemrosesan suara, untuk game, dll., Bukan sekadar memainkan trek. Tetapi demi percobaan, itu perlu untuk dicoba, karena memungkinkan Anda untuk menyusun suara dari sumber yang berbeda menjadi satu
output audio - speaker / headphone / speaker telepon / dll. Ada orang yang dengan sengaja
meneliti kemungkinan memainkan suara pada perangkat seluler menggunakan Web Audio API.
Setelah implementasi, nuansa tertentu menjadi jelas.
Pertama, Anda harus menunggu sampai seluruh trek terisi penuh. Dengan koneksi Internet yang lambat, jeda akan terlihat karena trek kedua mungkin tidak punya waktu untuk memuat pada saat trek pertama berakhir. Unduhan penuh dapat dihindari jika Anda menggunakan sekelompok tag Audio HTML5 yang akan bertindak sebagai sumber suara untuk Audio Web, tetapi dalam hal ini lagi menjadi mustahil untuk memutar dua suara secara bersamaan.
Kedua, jika Anda mengunduh trek melalui jaringan dalam fragmen dan mendekodekannya secara terprogram, ini menambah beban pada CPU. Itu dapat diterima untuk PC, tetapi penting untuk perangkat seluler.
Ketiga, ada masalah dengan decoding. Jika fragmen file mp3 / ogg / wav datang ke klien, maka potongan-potongan ini diam-diam
diterjemahkan dan dimainkan. Tetapi jika potongan file mp4, yang bertindak sebagai wadah untuk HE-AAC, datang ke browser, maka mereka tidak dapat diterjemahkan. Ini juga berlaku sampai batas tertentu ke browser Opera, di mana pemutaran file MP3 tidak stabil dari versi ke versi - kadang-kadang mereproduksi, dan memberikan kesalahan bahwa format ini tidak didukung.
Keempat, nama trek tidak ditampilkan / tidak berubah pada layar yang terkunci di piring dengan pemutar audio asli (di iPad), termasuk. saat beralih di antara trek. Mungkin karena fakta bahwa tes menggunakan iPad dengan versi 9 iOS - tidak ada yang lain pada saat itu.
Akibatnya, pada tahap ini, Audio Web harus ditinggalkan. Meski demikian, crossfade bukan untuk browser, komposisi musik standar dalam kualitas yang baik memiliki bobot yang cukup banyak.
Karena kami menolak dari crossfade, kami menerapkan fade in dan fade out, masing-masing di awal dan di akhir trek musik.
Kode pada tahun sebelumnya sedikit dimodifikasi dan diuji. Sebagai hasil dari tes, berbagai nuansa muncul (ditunjukkan pada tabel). Semua ini menggunakan perpustakaan Sound Manager 2.

Kami menambahkan pencatatan semua peristiwa untuk menentukan saat transisi antar trek dan untuk memahami pada titik mana mereka berhenti bermain.

Aktivasi tabDi Safari 9+, suara tidak selalu muncul ketika tab diaktifkan.
Dari sini dapat diasumsikan bahwa eksekusi JS di latar belakang melambat atau bahwa utas eksekusi berhenti sepenuhnya (peristiwa dan
timer ). Namun, akan menjadi jelas nanti bahwa ini sebagian kesimpulan yang benar. Di bawah ini kami akan mempertimbangkan nuansa 1 lainnya yang terkait dengan pemutaran trek dan memahami mengapa suara tidak muncul.
KomentarUntuk bekerja dengan progres (progressbar), misalnya, merendernya untuk trek, ada baiknya menggunakan requestAnimationFrame alih-alih setInterval / setTimeout. Anda dapat menghindari efek kumulatif saat menonaktifkan (tab latar belakang) dan kemudian mengaktifkan tab dan membekukannya sementara, terkait dengan semua perhitungan dan menggambar ulang keadaan kemajuan.
Pada saat yang sama, muncul pertanyaan: bagaimana dengan pemutaran otomatis trek pada PC dan perangkat seluler?
Putar otomatis mengacu pada permulaan otomatis memutar trek tanpa tindakan pengguna saat memuat halaman.
Adapun Safari terkait dengan
pemutaran otomatis ketika halaman dimuat, ini tidak mungkin, Anda perlu
interaksi pengguna dengan halaman, seperti pada
perangkat seluler . Ini berlaku untuk
konten video dan
konten audio .
Maka, pada saat itu ada yang berikut:
- tidak mungkin (tidak diinginkan) untuk mereproduksi dua suara atau lebih pada saat yang sama;
- untuk "permainan otomatis" pseudo trek, diperlukan izin pengguna - interaksi pertama, kemudian disebut "Jual jari ke perangkat";
- di latar belakang (tab latar belakang / layar kunci) JS (semuanya tergantung pada browser):
entah membeku sepenuhnya;
baik pelambatan;
keduanya berfungsi sama dengan tab aktif;
- Anda dapat secara otomatis memulai pemutaran tanpa suara, tetapi tidak jelas mengapa (untuk konten audio)?
- di suatu tempat yang jauh pikiran itu mulai menjulang, tetapi bagaimana membuat JS terus mengeksekusi di latar belakang?
Perpustakaan lain yang menerapkan fungsi pemain melanjutkan dengan asumsi bahwa mungkin ada solusi untuk masalah ini. Terlepas dari kenyataan bahwa banyak masalah ditonton di GitHub dengan deskripsi masalah ketika memainkan trek di berbagai browser, masih ada harapan bahwa Anda akan sampai ke bawah: mengapa itu tidak berhasil dan bagaimana membuatnya bekerja. Ternyata, tidak ...
Beberapa contoh kode dengan demonstrasi video dari karya perpustakaan:
- Sound Manager 2 - halaman github , repositori github , video: macOS Safari 12 ; iOS Safari 10 dengan layar tidak terkunci
- Howler
Howler v2.0.9 - halaman github , repositori github , video: macOS Safari 12 , iOS Safari 10
Howler v2.0.15 - halaman github , repositori github , video: macOS Safari 12
Howler v2.1.1 - halaman github , repositori github , video: macOS Safari 12 , iOS Safari 10
Untuk macOS, rekaman video dibuat tanpa suara, jadi Anda perlu melihat indikator volume - gambar speaker di tab.
Lebih banyak contoh video tersedia di repositori.
Dalam contoh interaktif untuk Howler v2.1.1 - terkadang Anda dapat mendengar beberapa suara pada saat yang sama, ini disebabkan oleh penambahan kumpulan elemen audio yang tidak dikunci oleh pengguna (ini harus diperbaiki di versi perpustakaan yang akan datang).
Apa alasan ketidakberdayaan perpustakaan ini?
Saya menulis di atas:
"Di latar belakang (tab latar belakang), JS membeku sepenuhnya atau mengalami pelambatan .
" Jadi di sini titik lain muncul: pustaka dalam kode menggunakan penciptaan objek audio baru melalui Audio baru (). Jika mereka dibuat secara dinamis, mis. jika objek audio yang ada tidak digunakan, dan pengguna tidak berinteraksi dengan situs dengan cara apa pun, tab tidak aktif atau layar terkunci, beberapa browser dapat mempertimbangkan bahwa suara dari elemen audio ini tidak boleh diputar sampai tab aktif lagi atau pengguna tidak tindakan apa pun.
Contoh pengujian pada
halaman github dan di
repositori pada github menggunakan Audio baru (). Video:
macOS Safari 12 ;
iOS Safari 10 dengan layar tidak terkunci.
Tampaknya beberapa jenis alat universal tidak ada dan perlu untuk mencari beberapa solusi kompromi lainnya.Kemudian kami duduk bersama orang-orang dari tim untuk berdiskusi, dan apa yang benar-benar penting dalam pekerjaan pemutar audio? Untuk itu mungkin untuk melanjutkan eksperimen ad infinitum, tetapi kita perlu bergerak maju.
Pertama, poin-poin penting diidentifikasi yang mencegah pencapaian hasil yang diinginkan:
- Safari di macOS tidak memutar trek saat tab tidak aktif;
- tidak ada kemungkinan untuk mendengarkan musik di latar belakang (ketika layar terkunci) pada smartphone yang menjalankan iOS dan Android, saya ingin menghindari pengalihan agresif pengguna ke aplikasi seluler (di masa depan), karena pengalaman sebelumnya menunjukkan bahwa sebagian besar pengguna tidak ingin menginstal aplikasi seluler ;
- pemain tidak bekerja dengan benar dengan daftar putar dinamis, mis. ketika tidak diketahui sebelumnya apa lagu berikutnya.
Selanjutnya, itu memungkinkan untuk merumuskan tujuan yang diperlukan untuk mencapai:
- menyediakan pemain di latar belakang - di berbagai browser dan di berbagai platform;
- memungkinkan pengguna untuk memilih apa yang akan digunakan: mendengarkan musik di situs atau di aplikasi seluler;
- memberikan kemampuan untuk menggunakan pemain (atau pendekatan) dalam berbagai proyek masa depan.
Tahap baru dalam mencari solusi untuk masalah telah dimulai. Pada tahap ini, berbagai perpustakaan tidak lagi digunakan, semua studi dilakukan menggunakan Audio HTML5. Hasilnya adalah opsi ditemukan menggunakan
pekerja berdedikasi . iOS tidak mengizinkan keputusan ini untuk menang lagi - pemutaran di latar belakang tidak berfungsi, tetapi ternyata berfungsi di Android (Chrome, Opera, Safari).
HTML5 Audio + Contoh pengujian Pekerja
Terdedikasi pada halaman github dan di
repositori github .
Ketika Pekerja diinisialisasi, data tentang trek saat ini diminta. Pekerja juga mengirim sinyal untuk mendapatkan status kemajuan - berapa lama trek diputar - dari aliran utama dan memutuskan kapan akan meminta data tentang trek berikutnya dari jaringan berdasarkan data ini.

Juga pada waktu itu, contoh berikut diuji (
halaman github ,
repositori github ), ketika tag audio HTML5 tertanam dalam DOM (video:
macOS Safari 12 ,
iOS Safari 10 ) dan itu hanya menggantikan SRC ketika beralih di antara trek. Sampai saat ini, pada macOS di 12 Safari, contoh ini berfungsi. Sayangnya, saat ini tidak ada cara untuk menguji fungsionalitas contoh ini pada macOS di Safari 10 dan 11, tetapi pada saat itu contoh ini tidak berfungsi selama pengujian (
kebijakan putar otomatis ,
batasan putar otomatis ).
Untuk meringkas, untuk iOS dan macOS, browser Safari tidak menganggap instance baru elemen audio yang akan diaktifkan oleh pengguna jika itu dibuat di latar belakang di dalam suatu acara, misalnya, ajax, setTimeout, onended.
Selanjutnya, mengenai pemutaran trek di iOS Safari dan iOS Chrome, ditemukan kemungkinan untuk memutar trek di latar belakang (saat layar dikunci) hanya menggunakan
HLS . Untuk platform iOS dan macOS, format ini standar dan penyiaran didukung oleh sistem operasi. Untuk Android Chrome dan Edge, implementasi asli juga tersedia. Dan untuk PC di Chrome, Anda dapat menggunakan penangan perangkat lunak, misalnya,
hls.js ,
Bitmovin Player , dll.
Tautan ke repositori github memberikan contoh kode yang mencakup kasus penggunaan paling sederhana - cukup memainkan streaming yang dihasilkan di server tanpa kemampuan untuk mundur, beralih ke trek berikutnya, dll. Contoh disajikan dengan menggunakan: tag audio, tag video, perpustakaan hls.js, dan pemutar dari Bitmovin. Konten ini membutuhkan Node.js.
Kesimpulan
Poin pertama, sayangnya, karena variasi browser, tidak ada solusi universal yang memungkinkan mendengarkan musik di browser sama baiknya di mana-mana. Di mana-mana ada batasan dan seperti yang ditunjukkan oleh latihan, Anda dapat, cukup, hidup nyaman dengan itu.
Poin kedua, terkadang perlu memeriksa kasus batas secepat mungkin, misalnya, implementasi asli. Temukan beberapa jenis persyaratan yang dapat diterima secara minimal dan periksa kinerjanya dengan cepat daripada mengambil pustaka apa pun sebagai dasar. Ini akan memberi lebih banyak pemahaman tentang bagaimana perpustakaan ini diatur secara internal dan mengapa fungsi-fungsi tertentu bekerja atau tidak bekerja. Kalau tidak, Anda dapat menjalankan cukup jauh dalam proyek dan setelah Anda menyadari bahwa ada sesuatu yang salah. Dan mungkin ternyata meninggalkan perpustakaan akan sangat mahal. Sebagian besar kode perlu ditulis ulang.
Poin ketiga, pastikan untuk memperhatikan audiens layanan Anda - dari mana browser dan sistem operasi pengguna Anda berasal. Ini cukup mudah dilacak menggunakan berbagai metrik dan sistem pemantauan kesalahan. Pendekatan semacam itu akan membantu untuk memahami platform dan browser mana yang penting untuk didukung, dan mana yang dapat digunakan tanpa upaya apa pun.
Dan akhirnya
Saya mengumumkan kontes kecil yang terkait dengan bermain musik di iOS menggunakan teknologi HLS.
Deskripsi dapat dilihat pada
tautan di github .