Was können Sie lernen, wenn Sie einen Audioplayer für verschiedene Browser entwickeln?

    Diese Geschichte begann vor etwa 1,5 Jahren. Es ist mit der Wiedergabe von Musik in verschiedenen Browsern und den Plattformen verbunden, auf denen sie ausgeführt werden. Der Weg ist voll von „Schmerz und Leid“. Die Erkenntnis, dass die scheinbar einfache Aufgabe nicht so einfach ist, und die „kleinen“ Details, auf die Sie am Anfang keinen Wert legen, können alles beeinflussen.

    Kleinere Details für die Neugierigsten :)
    1. Hochladen von Daten zu jedem nächsten Track aus dem Netzwerk.
    2. Für jedes Audioelement: Neues Audio () oder <Audio> benötigen Sie eine Benutzerberechtigung - eine benutzerdefinierte Aktion auf der Seite.

    Vorgeschichte


    Wahrscheinlich ist jeder, der jemals in seinem Leben einen Audio-Player für Browser geschrieben hat, auf das Problem des Cross-Browser- und Cross-Platform-Problems gestoßen.

    Hier bin ich bei der Arbeit an einem neuen MVP auf verschiedene Funktionen bezüglich der Audiowiedergabe in Browsern gestoßen.

    Begonnen hat alles mit der Tatsache, dass während der Wiedergabe ein sanftes Mischen (Crossfade) von zwei Spuren erforderlich war - dies ist die erste Funktion. Unser Team wollte die Spur im Radio wechseln. Und das zweite Feature - jede nachfolgende Spur wird vom Netzwerk angefordert.



    Forschung


    In fast allen unseren Projekten wurde dann die Sound Manager 2-Bibliothek verwendet, und

    fast sofort merkt man, dass die gleichzeitige Wiedergabe von zwei Audiodateien auf mobilen Geräten nicht überall gleich ist!

    In Chrome (~ 62-Version) für PC werden die Titel wie erwartet abgespielt. Auf mobilen Geräten (auch in Chrome) funktionierte die Wiedergabe der Titel, jedoch nur mit dem aktiven Bildschirm. Wenn der Bildschirm gesperrt war, wurde der nächste Titel für den aktuellen Spieler nicht abgespielt. Wie bei iOS / macOS funktionierte die Wiedergabe genauso. Weitere Informationen finden Sie hier - Abschnitt „Einzelner Audiostrom“.

    So begann die Reise über drei Meere nach Informationen zu den Funktionen der Browser mit Audio zu suchen.

    Nun, ich probiere die Lösung mit Web Audio aus, ohne Bibliotheken zu verwenden. Ja, diese Technologie ist für andere Zwecke gedacht: Synthese, Klangbearbeitung, für Spiele usw., anstatt nur Titel abzuspielen. Um das Experiment zu ermöglichen, war es jedoch notwendig, es zu versuchen, da es möglich ist, Töne aus verschiedenen Quellen auf einer Tonausgabe zusammenzustellen - Lautsprecher / Kopfhörer / Telefonlautsprecher / usw. Es gibt Leute, die sich darauf konzentrieren , die Möglichkeiten der Audiowiedergabe auf mobilen Geräten mithilfe der Web-Audio-API zu erkunden .

    Nach der Implementierung wurden bestimmte Nuancen geklärt.

    Zunächst müssen Sie auf die volle Ladung der gesamten Strecke warten. Bei einer langsamen Verbindung zum Internet kommt es zu spürbaren Pausen, weil der zweite Titel bis zum Ende des ersten Titels keine Zeit zum Laden hat. Ein vollständiger Download kann vermieden werden, wenn Sie eine Reihe von HTML5-Audio-Tags verwenden, die als Audioquellen für Web Audio dienen. In diesem Fall ist es jedoch unmöglich, zwei Sounds gleichzeitig wiederzugeben.

    Zweitens: Wenn Sie einen Track mit Fragmenten über das Netzwerk herunterladen und programmatisch decodieren, erhöht dies die Belastung der CPU. Für den PC war das akzeptabel, für mobile Geräte ist dies jedoch kritisch.

    Drittens gab es Probleme mit der Dekodierung. Wenn Fragmente von mp3 / ogg / wav-Dateien zum Client kamen, wurden diese Stücke leise dekodiertund reproduziert. Wenn jedoch Brocken einer mp4-Datei, die ein Container für HE-AAC war, zum Browser kamen, konnten sie nicht entschlüsselt werden. Zum Teil gilt dies auch für den Opera-Browser, in dem die Wiedergabe von MP3-Dateien von Version zu Version instabil ist. Es wird reproduziert, da es einen Fehler gibt, dass dieses Format nicht unterstützt wird.

    Viertens wurde der Name des Tracks auf dem gesperrten Bildschirm auf einer Platte mit einem nativen Audioplayer (auf dem iPad) nicht angezeigt oder geändert, einschließlich beim Umschalten zwischen den Spuren. Vielleicht, weil das iPad mit der Version 9 von iOS für die Tests verwendet wurde - damals gab es kein anderes.

    Daher musste Web Audio zu diesem Zeitpunkt aufgegeben werden. Trotzdem ist das Crossfade nichts für Browser, Standardmusik in guter Qualität wiegt ziemlich viel.

    Wenn wir das Crossfade ablehnen, implementieren wir am Anfang und am Ende des Musikstücks ein einfaches Ein- und Ausblenden.

    Der Code im vorherigen Schritt wurde ein wenig verfeinert und getestet. Als Ergebnis von Tests tauchten verschiedene Nuancen auf (in der Tabelle gezeigt). All dies mit der Bibliothek Sound Manager. 2.



    Fügen Sie die Protokollierung aller Ereignisse hinzu, um den Moment des Übergangs zwischen den Tracks zu bestimmen und zu verstehen, wann sie die Wiedergabe beenden.



    Tab-Aktivierung
    Im Browser Safari 9+ wird der Sound nicht immer angezeigt, wenn die Registerkarte aktiviert ist.

    Hieraus können wir davon ausgehen, dass die JS-Ausführung im Hintergrund gedrosselt wird oder der Ausführungsablauf vollständig gestoppt wird (Ereignisse und Timer ). Später wird jedoch klar, dass dies zum Teil die richtige Schlussfolgerung war. Im Folgenden wird eine weitere Nuance betrachtet, die mit dem Abspielen von Tracks und dem Verständnis dafür zusammenhängt, warum der Sound nicht erscheint.

    Bemerkung
    Um beispielsweise mit einer Fortschrittsleiste zu arbeiten, indem Sie sie für eine Spur zeichnen, sollten Sie requestAnimationFrame anstelle von setInterval / setTimeout verwenden. Sie können den kumulativen Effekt vermeiden, wenn Sie die Registerkarte (Registerkarte Hintergrund) deaktivieren und dann die Registerkarte aktivieren und vorübergehend aussetzen, um alle Berechnungen durchzuführen und den Status neu zu zeichnen.

    Gleichzeitig stellte sich die Frage: Wie sieht es mit Autoplay-Tracks auf PCs und mobilen Geräten aus?
    Unter Autoplay versteht man den automatischen Start der Wiedergabe eines Titels ohne Benutzeraktion beim Laden der Seite.
    Was Safari in Bezug auf die automatische Wiedergabe beim Laden einer Seite angeht, ist dies nicht möglich. Sie müssen wie auf mobilen Geräten mit dem Benutzer interagieren . Dies gilt sowohl für Videoinhalte als auch für Audioinhalte . Und so war zu dieser Zeit folgendes:



    1. Es ist nicht möglich (nicht wünschenswert), zwei oder mehr Töne gleichzeitig abzuspielen.
    2. Für den Pseudo-Track „Auto-Play“ ist eine Benutzererlaubnis erforderlich - die erste Interaktion wurde später als „Finger an das Gerät verkaufen“ bezeichnet.
    3. im Hintergrund (Hintergrundregisterkarte / Sperrbildschirm) JS (es hängt alles vom Browser ab):
      entweder stoppt es vollständig;
      entweder dem Drosseln ausgesetzt;
      entweder funktioniert das gleiche wie mit der aktiven Registerkarte;
    4. Sie können die Wiedergabe automatisch ohne Ton starten, es ist jedoch nicht klar, warum (für Audioinhalte)?
    5. Irgendwo weit weg beginnt der Gedanke zu schweben, aber wie soll man die JS im Hintergrund weiter ausführen lassen?

    Andere Bibliotheken implementierten die Funktionen des Players mit der Annahme, dass es eine Lösung für dieses Problem geben könnte. Trotz der Tatsache, dass viele Probleme auf GitHub mit einer Beschreibung der Probleme bei der Wiedergabe von Tracks in verschiedenen Browsern besprochen wurden, hoffte man trotzdem, dass Sie zur Sache kommen werden: warum es nicht funktioniert und wie es funktioniert. Wie sich herausgestellt hat, nein ...

    Einige Codebeispiele mit Videodemonstration der Bibliotheksarbeit:

    1. Sound Manager 2 - Github-Seiten , Github-Repository , Video: macOS Safari 12 ; iOS Safari 10 mit nicht gesperrtem Bildschirm
    2. Howler
      Howler v2.0.9 - github-Seiten , github-Repository , Video: macOS Safari 12 , iOS Safari 10
      Howler v2.0.15 - github-Seiten , github-Repository , Video: macOS Safari 12
      Howler v2.1.1 - github-Seiten , github-Repository , Video: macOS Safari 12 , iOS Safari 10

    Bei macOS erfolgt die Videoaufnahme ohne Ton. Daher müssen Sie die Lautstärkeanzeige - das Lautsprecherbild - auf der Registerkarte betrachten.

    Weitere Videobeispiele sind im Repository verfügbar.

    Im interaktiven Beispiel für Howler v2.1.1 - manchmal können Sie mehrere Sounds gleichzeitig hören. Dies ist auf das Hinzufügen eines Pools nicht gesperrter Audioelemente durch den Benutzer zurückzuführen (in zukünftigen Versionen der Bibliothek sollte dies behoben sein).
    Was ist der Grund für die Inoperabilität dieser Bibliotheken?

    Ich schrieb oben: "Im Hintergrund (Hintergrundregisterkarte) friert JS entweder vollständig ein oder wird Throttling ausgesetzt . " Hier kommt also ein anderer Moment: Die Bibliotheken im Code verwenden die Erstellung neuer Audioobjekte durch neues Audio (). Wenn sie dynamisch erstellt werden, d.h. Ein bereits vorhandenes Audioobjekt wird nicht verwendet und der Benutzer interagiert nicht mit der Site, die Registerkarte ist inaktiv oder der Bildschirm ist gesperrt. Einige Browser stellen möglicherweise fest, dass das Audio von diesem Audioelement nicht wiedergegeben werden sollte, bis die Registerkarte wieder aktiv ist oder der Benutzer dies nicht tut oder Aktion.

    Ein Beispiel für einen Test auf Github-Seiten und im Repository auf Github mit neuem Audio (). Video:MacOS Safari 12 ; iOS Safari 10 mit nicht gesperrtem Bildschirm.

    Es scheint, dass es kein universelles Werkzeug gibt, und es ist notwendig, nach einer anderen Kompromisslösung zu suchen.

    Dann setzen Sie sich mit den Jungs des Teams zusammen, um zu besprechen, und was ist im Audioplayer wirklich wichtig? Es wäre zwar möglich, die Experimente unbegrenzt fortzusetzen, aber wir müssen voranschreiten.

    Zunächst wurden wichtige Punkte identifiziert, die das gewünschte Ergebnis verhinderten:

    1. Safari auf macOS gibt keine Titel mit inaktiver Registerkarte wieder.
    2. Es gibt keine Möglichkeit, Musik im Hintergrund (mit gesperrtem Bildschirm) auf Smartphones unter iOS und Android zu hören. Ich möchte das aggressive Umleiten von Benutzern auf die mobile Anwendung (später) vermeiden, da die Erfahrung zeigt, dass ein großer Teil der Benutzer keine mobile Anwendung installieren möchte ;
    3. Der Player funktioniert nicht ordnungsgemäß mit einer dynamischen Wiedergabeliste, d. H. Wenn nicht im Voraus bekannt ist, wie der nächste Titel aussehen wird.

    Weiterhin konnten Ziele formuliert werden, die notwendig sind, um zu erreichen:

    1. den Player im Hintergrund arbeiten lassen - in verschiedenen Browsern und auf verschiedenen Plattformen;
    2. Benutzer können auswählen, was sie verwenden möchten: Hören Sie Musik auf der Website oder in einer mobilen Anwendung.
    3. die Möglichkeit bieten, den Player (oder Ansatz) in verschiedenen zukünftigen Projekten zu verwenden.

    Begann eine neue Phase der Suche nach Lösungen für das Problem. Zu diesem Zeitpunkt wurden verschiedene Bibliotheken nicht mehr verwendet, alle Studien wurden mit HTML5-Audio durchgeführt. Unter dem Strich wurde eine Variante mit engagierten Mitarbeitern gefunden . iOS ließ diese Lösung nicht erneut gewinnen - die Wiedergabe im Hintergrund funktioniert nicht, sie funktioniert jedoch in Android (Chrome, Opera, Safari).

    HTML5 Audio + Dedicated Workers Testbeispiel auf Github-Seiten und in einem Github-Repository .

    Beim Initialisieren des Workers werden die aktuellen Trackdaten abgefragt. Der Worker befasst sich auch mit dem Senden eines Signals zum Empfang eines Fortschrittsstatus - wie lange der Track abgespielt wird - aus dem Hauptstream, und basierend auf diesen Daten entscheidet er, wann Daten über den nächsten Track vom Netzwerk angefordert werden.



    Zu diesem Zeitpunkt wurde auch das folgende Beispiel getestet ( Github-Seiten , Repository auf Github ), wenn ein HTML5- Audiotag in das DOM eingebettet ist (Video: macOS Safari 12 , iOS Safari 10)) und ersetzt nur SRC, wenn Sie zwischen den Spuren wechseln. Heute auf macOS in 12 Safari funktioniert dieses Beispiel. Leider gibt es jetzt keine Möglichkeit, die Leistung dieses Beispiels auf MacOS in Safari 10 und 11 zu testen, aber zu diesem Zeitpunkt funktionierte dieses Beispiel nicht während der Tests ( Autoplay-Richtlinien , Autoplay-Einschränkungen ).

    Zusammenfassend betrachtet, betrachtet Safari unter iOS und macOS eine neue Instanz eines Audioelements nicht als aktivierten Benutzer, wenn sie im Hintergrund eines Ereignisses erstellt wurde, z. B. ajax, setTimeout oder onend.

    Im Hinblick auf das Abspielen von Tracks in iOS Safari und iOS Chrome wurde außerdem die Möglichkeit gefunden, Tracks im Hintergrund (mit gesperrtem Bildschirm) nur mit abzuspielenHLS . Für iOS- und MacOS-Plattformen ist dieses Format Standard und wird vom Betriebssystem unterstützt. Eine native Implementierung ist auch für Android Chrome und Edge verfügbar. Für PCs in Chrome können Sie Softwarehandler verwenden, z. B. hls.js , Bitmovin Player usw.

    Ein Link zum Github-Repository ist verfügbarer Beispielcode, der den einfachsten Anwendungsfall abdeckt - einfache Wiedergabe des auf dem Server erzeugten Wiedergabestroms ohne Rückspulen, Umschalten auf den nächsten Titel usw. Beispiele werden anhand des Audio-Tags, des Video-Tags, der Bibliothek hls.js und des Players von Bitmovin dargestellt. Node.js zum Ausführen erforderlich.

    Schlussfolgerungen


    Im ersten Moment gibt es leider aufgrund der Vielfalt der Browser keine universelle Lösung, mit der sich Musik in Browsern überall gleich gut anhören lässt. Überall gibt es Einschränkungen, und wie die Praxis zeigt, ist es möglich, bequem mit ihnen zu leben.

    Der zweite Punkt, manchmal lohnt es sich, Grenzfälle so schnell wie möglich zu prüfen, beispielsweise eine native Implementierung. Finden Sie einige minimal akzeptable Anforderungen und testen Sie schnell die Leistung, und nehmen Sie keine Bibliothek als Grundlage. Dadurch erhalten Sie einen besseren Einblick in die Funktionsweise dieser Bibliotheken und warum bestimmte Funktionen funktionieren oder nicht funktionieren. Ansonsten können Sie im Projekt weit weglaufen und dann verstehen, dass etwas schief läuft. Möglicherweise ist das Aufgeben der Bibliothek sehr teuer. Sie müssen einen erheblichen Teil des Codes neu schreiben.

    Der dritte Punkt: Achten Sie darauf, das Publikum Ihres Services zu beachten - von welchen Browsern und Betriebssystemen Ihre Benutzer stammen. Verschiedene Metriken und Fehlerüberwachungssysteme lassen sich leicht nachverfolgen. Ein solcher Ansatz ermöglicht es zu verstehen, welche Plattformen und Browser von Bedeutung sind und welche zur Energieeinsparung verwendet werden können.

    Und zum Schluss


    Ich kündige einen kleinen Wettbewerb für das Abspielen von Musik auf iOS mit HLS-Technologie an.

    Die Beschreibung ist auf dem Link zu github zu finden .

    Jetzt auch beliebt: