wake-up-neo.com

Kein Sound bei iOS 6 Web Audio API

Ich war wirklich begeistert, dass iOS 6 die Web-Audio-API unterstützt, da wir HTML5-Spiele erstellen. Ich kann iOS 6 jedoch nicht dazu veranlassen, mit der Web Audio API überhaupt einen Sound abzuspielen. Beispiele hierfür sind in Desktop Chrome gut geeignet.

Hier ist ein HTML5-Spiel mit Touch-Bedienelementen und Audiowiedergabe über die Web-Audio-API (falls vorhanden - falls nicht, wird auf HTML5-Audio zurückgegriffen):

http://www.scirra.com/labs/sbios6b/

Edit: @Srikumar schlug einige Problemumgehungen vor. Ich habe sie in der untenstehenden Version angewendet. Es funktioniert immer noch nicht!

http://www.scirra.com/labs/sbios6f/

Auf Desktop-Chrome läuft alles einwandfrei, aber iOS 6 gibt überhaupt keinen Ton aus. Ich habe Probleme beim Debuggen, da ich nur Windows-Entwicklung durchführe und iOS 6 den Debug-Modus durch Remote-Web-Inspector ersetzt, der anscheinend nicht in Safari für Windows verfügbar ist. Mit ein paar Warnungen habe ich festgestellt, dass die Web-Audio-API richtig erkannt wird, sie verwendet, keine Vorbis-Unterstützung erkennt, also auf AAC-Audio zurückgreift, einen Puffer decodiert und ihn dann abspielt, und es werden keine Fehler ausgegeben, aber ich höre nichts. Und natürlich habe ich versucht, die Lautstärke auf max zu stellen :)

Es sollte kein Codec-Problem geben, da iOS 6 AAC problemlos abspielen kann - Sie können nach einer der .m4as das Spiel spielen und es spielt gut besucht direkt von Safari. 

Schauen Sie sich die Web Audio API-Beispiele hier auf iOS 6 an: http://chromium.googlecode.com/svn/trunk/samples/audio/samples.html - einige funktionieren, andere nicht. Zum Beispiel funktioniert der Chrome Audio Visualizer , aber Javascript Drone nicht.

Es muss eine subtile Inkompatibilität zwischen Web Audio unter iOS 6 und Desktop-Chrome geben. Was vermisse ich?

38
AshleysBrain

Edit (November 2015): Bei iOS 9 ist es nicht mehr möglich, Audio in einem touchstart-Ereignis zu starten, wodurch die unten stehende Lösung zerstört wird. Es funktioniert jedoch in einem touchend-Ereignis. Die ursprüngliche Antwort für iOS 6 wird unten beibehalten. Für die Unterstützung von iOS 9 müssen Sie jedoch touchend verwenden.

Tut mir leid, meine eigene Kopfgeldfrage zu beantworten, aber nach stundenlangem Debugging fand ich endlich die Antwort. Safari unter iOS 6 startet effektiv mit der stummgeschalteten Web-Audio-API. Die Stummschaltung von wird erst wieder aktiviert, wenn Sie versuchen, einen Sound in einem Benutzereingabeereignis abzuspielen (erstellen Sie eine Pufferquelle, verbinden Sie sie mit dem Ziel und rufen Sie noteOn() auf). Danach wird die Stummschaltung aufgehoben, und das Audio wird uneingeschränkt und wie es sein sollte, abgespielt. Dies ist ein nicht dokumentierter Aspekt der Funktionsweise der Web-Audio-API unter iOS 6 ( das Dokument von Apple ist hier , hoffentlich wird es bald aktualisiert!)

Der Benutzer kann den Bildschirm häufig berühren, wenn er mit dem Spiel beschäftigt ist. Es wird aber stumm bleiben. Sie haben, um innerhalb eines Benutzereingabeereignisses wie touchstart [edit: touchend für iOS 9+] zu spielen, einmal, dann wird das gesamte Audio deaktiviert. Danach können Sie jederzeit Audio abspielen (muss sich nicht in einem Benutzereingabeereignis befinden).

Beachten Sie, dass dies von den Einschränkungen für HTML5-Audio abweicht: In der Regel können Sie bei einem Benutzereingabeereignis überhaupt nur Audio starten und jeweils nur einen Sound abspielen. Die Web-Audio-API schaltet die Stummschaltung nach der ersten Play-in-User-Eingabe vollständig auf, so dass Sie jederzeit Sounds abspielen können und diese dann polyphon mischen, coole Effekte verarbeiten usw.

Dies bedeutet, dass viele Spiele, die sich bereits im Web befinden und die Web-Audio-API verwenden, niemals Audio abspielen, da sie bei einem Touch-Event kein NoteOn ausgeben. Sie müssen es anpassen, um auf das erste Benutzereingabeereignis zu warten.

Es gibt einige Möglichkeiten, dies zu umgehen: Spielen Sie Ihre Titelmusik erst, wenn der Benutzer den Bildschirm berührt. Berühren Sie zunächst den Bildschirm, um den Audio-Bildschirm zu aktivieren, und geben Sie einen Ton wieder. Beginnen Sie das Spiel, wenn Sie es berühren. usw. Hoffentlich hilft dies allen anderen, die das gleiche Problem haben, beim Debuggen etwas Zeit zu sparen!

48
AshleysBrain

Ich habe es geschafft, eine einfache Lösung zu finden, die sicher woanders dokumentiert wurde - aber manchmal müssen wir Stunden damit verbringen, diese Dinge für uns selbst herauszufinden ...

Es sieht also so aus, als ob viele Tutorials (wie dieses auf html5rocks ) Sie anweisen, die folgenden Schritte auszuführen:

  • Erstellen Sie eine Instanz von window.AudioContext Und erstellen Sie window.webkitAudioContext, Wenn dies nicht vorhanden ist (was bei iOS nicht der Fall ist).

  • Erstellen Sie ein XMLHttpRequest, um Ihre Sounddatei zu laden

  • Führen Sie beim Ereignis loadcontext.decodeAudioData(....) und dann createBufferSource() aus, füllen Sie es mit den decodierten Daten und schließlich source.start(0), um den Sound abzuspielen.

Wie bereits erwähnt, müssen Sie das AudioContext (das Sie übrigens für die gesamte Lebensdauer der Seite speichern und verwenden müssen) als Ergebnis einer Benutzerinteraktion (Klicken oder Berührungsstart) erstellen.

JEDOCH: Damit iOS seine Audiofunktionen "freischalten" kann, müssen Sie [~ # ~] [~ # ~] Wenn Sie das AudioContext erstellen, stehen Ihnen Audiodaten zur Verfügung. Wenn Sie die Daten asynchron laden, können Sie nichts abspielen. Es reicht nicht aus, nur das AudioContext in einem click -Ereignis zu erstellen.

Hier sind zwei Lösungen für eine zuverlässige iOS-Wiedergabe:

  • 1) Sie müssen mindestens eine Audiodatei laden, bevor Sie den AudioContext überhaupt initialisieren, und dann alle oben genannten Schritte für diese Audiodatei sofort innerhalb einer einzelnen Benutzerinteraktion ausführen (z. B. Klicken).

  • ODER 2) Erstellen Sie einen Sound dynamisch im Speicher und spielen Sie ihn ab.

So habe ich die zweite Option gemacht:

REMEMBER - MUSS innerhalb des Ereignisses click/touch für iOS liegen:

 window.AudioContext = window.AudioContext || window.webkitAudioContext;
 var context = new window.AudioContext();

 // you should null check window.AudioContext for old browsers to not blow up

 // create a dummy sound - and play it immediately in same 'thread'
 var oscillator = context.createOscillator();
 oscillator.frequency.value = 400;
 oscillator.connect(context.destination);
 oscillator.start(0);
 oscillator.stop(.5);    // you can set this to zero, but I left it here for testing.

 // audio context is now 'unlocked' and ready to load and play sounds asynchronously
 // YOU MUST STORE 'context' for future usage. DON'T recreate more AudioContexts

Ich stelle mir vor, dass dies ein häufiger Fehler ist - und ich bin nach 3 Jahren überrascht, dass niemand darauf hingewiesen oder es entdeckt zu haben scheint: - /

5
Simon_Weaver

Sie können versuchen, das Problem mit dem Web Inspector unter Safari 6 auf einem Mac zu debuggen. 

  1. Aktivieren Sie "Webkit Inspector" in den Einstellungen von Mobile Safari/erweitert.
  2. Verbinden Sie das Gerät über ein USB-Kabel mit einem Mac, auf dem Safari 6 ausgeführt wird.
  3. Lade deine Seite/dein Spiel
  4. Gehen Sie zum Menü Entwickeln -> [Gerätename] -> [Seitenurl]

Für mich funktioniert das nicht direkt, aber mit ein paar Versuchen kann das Problem eingegrenzt werden.

Anscheinend gibt es auch die Sache, dass Audio nur durch eine Benutzeraktion ausgelöst werden kann. Ich bin nicht sicher, ob das stimmt. Cos Code, der unter iOS6 auf iPhone4 funktioniert, gibt auf einem iPad (auch iOS6) keinen Ton wieder.

Update : Erfolg mit Web-Audio auf iPhone4 + iOS6. Es wurde festgestellt, dass "currentTime" für eine Weile bei 0 hängen bleibt, sobald Sie einen neuen Audiokontext unter iOS6 erstellen. Um es in Bewegung zu setzen, müssen Sie zuerst einen Dummy-API-Aufruf ausführen (wie createGainNode() und das Ergebnis verwerfen). Sounds werden nur dann abgespielt, wenn currentTime gestartet wird. Die genaue Planung von Sounds zu currentTime scheint jedoch nicht zu funktionieren. Sie müssen ein bisschen in die Zukunft sein (zB 10ms). Mit der folgenden createAudioContext-Funktion können Sie warten, bis der Kontext zum Rauschen bereit ist. Auf dem iPhone scheint keine Benutzeraktion erforderlich zu sein, auf dem iPad ist dies jedoch noch nicht der Fall.

function createAudioContext(callback, errback) {
    var ac = new webkitAudioContext();
    ac.createGainNode(); // .. and discard it. This gets 
                         // the clock running at some point.

    var count = 0;

    function wait() {
        if (ac.currentTime === 0) {
            // Not ready yet.
            ++count;
            if (count > 600) {
                errback('timeout');
            } else {
                setTimeout(wait, 100);
            }
        } else {
            // Ready. Pass on the valid audio context.
            callback(ac); 
        }
    }

    wait();
}

Rufen Sie anschließend beim Spielen einer Note nicht .noteOn(ac.currentTime) auf, sondern führen Sie stattdessen .noteOn(ac.currentTime + 0.01) aus.

Bitte frag mich nicht warum du das alles machen musst. Das ist im Moment einfach so - also verrückt.

5
Srikumar

Ich glaube, ich habe es herausgefunden. 

Es ist ein Problem von Apple, das eine Benutzeraktion erfordert, bevor der Ton abgespielt werden kann. Es stellt sich zumindest für mich heraus, dass Sie den Audiokontext überhaupt nicht erstellen sollten, es sei denn, der Benutzer fordert dazu auf. Es reicht nicht aus, den Kontext beim Laden der Seite zu erstellen und dann createGainNode oder ähnliches für eine Benutzeraktion zu verwenden. 

In Ihrem Fall würde ich den Kontext erstellen, wenn der Benutzer auf die Schaltfläche "Zum Anfang anfassen" klickt.

3
Oskar Eriksson

Ich bin auf die Audiobeschränkungen mit HTML5 Audio unter iOS gestoßen und habe das Problem durchgearbeitet:

1) Erstellen eines Audio-Elements mit einer stillen Audiodatei und Abspielen dieser zunächst mit einem Berührungsereignis (z. B. Schaltfläche "Spiel beginnen") und anschließendes Pausieren sofort.

2) Erstellen einer Sound-Switcher-Funktion, die die Audio-Quelle umschaltet und nach kurzer Zeit das Audio-Element wiedergibt.

3) Aufrufen der Sound-Switcher-Funktion für Ereignisse (muss kein Berührungsereignis sein).

Dies funktioniert, weil das Audio-Element bei der ersten Berührung mit der stillen Audiodatei nicht stummgeschaltet ist und nicht stummgeschaltet bleibt, sodass die Quelle sofort eingeschaltet werden kann.

switchSound: (id) ->
        @soundSwitch.pause()
        @soundSwitch.src = @sounds[id]._src

        clearTimeout @switchSoundDelay
        @switchSoundDelay = setTimeout =>
            # @soundSwitch.volume = 1
            @soundSwitch.play()
        ,50 
1
Jack Wild

Update: iOS erfordert noch eine Benutzereingabe zur Wiedergabe von Sound ( Kein Sound unter iOS 6 Web Audio API )

Ich war vorher mit Web-Audio bei iOS-Web beschäftigt. Und um es noch schlimmer zu machen, muss es auf Android und anderen Desktop-Plattformen funktionieren. Dieser Beitrag ist einer der Beiträge, die ich gelesen und keine unmittelbaren Antworten gefunden habe.

Bis ich howler.js gefunden habe. 

Dies ist die Lösung für eine plattformübergreifende Web-Audiolösung: 

<script src="https://cdnjs.cloudflare.com/ajax/libs/howler/2.0.3/howler.min.js"></script>

<script>

  var sound = new Howl({
    src: ['yay3.mp3']
  });
  sound.play();


</script>
1
ytbryan

Auf die Frage " original " beantworte ich einige Probleme mit Dateiformaten auf iPhone 4S/iOS 6 und MacOSX. Wenn eine MP3-Datei für Safari "nicht gut" ist, wird die Dekodierung schlecht und der Aufruf von AudioContext.createBuffer (array, bool) führt zu einem Fehler.

Das seltsame ist über den Fehler: "SYNTAX_ERR, DOM Exception 12", wie von anderen aufgezeigt. Das lässt mich denken, dass es ein Fehler ist ....

Gleiches Verhalten auch unter MacOS mit Safari 6.0 (7536.25).

1
Enrico MRK

aktualisiert für 2015 Lösung: Hey, wenn Sie hier an einem Web-Audio-Problem mit ios6 + arbeiten, habe ich diese Links als Hilfe gefunden.

-dies ist ein guter Artikel mit Codelösung: http://matt-harrison.com/perfect-web-audio-on-ios-devices-mit-the-web-audio-api/

- Es gibt ein Update für die API, nachdem der oben beschriebene Lösungsartikel geschrieben wurde https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API/Porting_webkitAudioContext_code_to_standards_based_AudioContext

-bevorzugen ist meine aktualisierte Lösung für den ersten Artikel, wobei die Änderungen aus dem zweiten Artikel verwendet werden. Das Problem, das ich hatte, war die iOS 7-Safari, die einen seltsamen, nicht genug Argumenten auslöste. das reparierte es:

define(function() {

  try {
    window.AudioContext = window.AudioContext || window.webkitAudioContext;
    window.audioContext = new window.AudioContext();
  } catch (e) {
    console.log("No Web Audio API support");
  }
/*
 * WebAudioAPISoundManager Constructor
 */
 var WebAudioAPISoundManager = function (context) {
  this.context = context;
  this.bufferList = {};
  this.playingSounds = {};
};

/*
 * WebAudioAPISoundManager Prototype
 */
 WebAudioAPISoundManager.prototype = {
   addSound: function (url) {
      // Load buffer asynchronously
      var request = new XMLHttpRequest();
      request.open("GET", url, true);
      request.responseType = "arraybuffer";

      var self = this;

      request.onload = function () {
        // Asynchronously decode the audio file data in request.response
        self.context.decodeAudioData(
          request.response,

          function (buffer) {
            if (!buffer) {
              alert('error decoding file data: ' + url);
              return;
            }
            self.bufferList[url] = buffer;
          });
      };

      request.onerror = function () {
        alert('BufferLoader: XHR error');
      };

      request.send();
    },
    stopSoundWithUrl: function(url) {
      if(this.playingSounds.hasOwnProperty(url)){
        for(var i in this.playingSounds[url]){
          if(this.playingSounds[url].hasOwnProperty(i)) {
            this.playingSounds[url][i].stop(0);
          }
        }
      }
    }
  };

/*
 * WebAudioAPISound Constructor
 */
 var WebAudioAPISound = function (url, options) {
  this.settings = {
    loop: false
  };

  for(var i in options){
    if(options.hasOwnProperty(i)) {
      this.settings[i] = options[i];
    }
  }

  this.url = '/src/www/assets/audio/' + url + '.mp3';
  this.volume = 1;
  window.webAudioAPISoundManager = window.webAudioAPISoundManager || new WebAudioAPISoundManager(window.audioContext);
  this.manager = window.webAudioAPISoundManager;
  this.manager.addSound(this.url);
    // this.buffer = this.manager.bufferList[this.url];
  };

/*
 * WebAudioAPISound Prototype
 */
 WebAudioAPISound.prototype = {
  play: function () {
    var buffer = this.manager.bufferList[this.url];
    //Only play if it's loaded yet
    if (typeof buffer !== "undefined") {
      var source = this.makeSource(buffer);
      source.loop = this.settings.loop;
        source.start(0);

        if(!this.manager.playingSounds.hasOwnProperty(this.url)) {
          this.manager.playingSounds[this.url] = [];
        }
        this.manager.playingSounds[this.url].Push(source);
      }
    },
    stop: function () {
      this.manager.stopSoundWithUrl(this.url);
    },
    getVolume: function () {
      return this.translateVolume(this.volume, true);
    },
    //Expect to receive in range 0-100
    setVolume: function (volume) {
      this.volume = this.translateVolume(volume);
    },
    translateVolume: function(volume, inverse){
      return inverse ? volume * 100 : volume / 100;
    },
    makeSource: function (buffer) {
      var source = this.manager.context.createBufferSource();
      var gainNode = this.manager.context.createGain();
      source.connect(gainNode);
      gainNode.gain.value = this.volume;
      source.buffer = buffer;
      // source.connect(gainNode);
      gainNode.connect(this.manager.context.destination);
      return source;
    }
  };

  return WebAudioAPISound;
});
1
mat

Ich habe Probleme mit allen einfachen Lösungen. Besonders, wenn ich einen Ton mehrmals abspielen möchte.

Also benutze ich diese js-Bibliothek: http://pupunzi.open-lab.com/2013/03/13/making-html5-audio-actually-work-on-mobile

0
Matthias M

Dies ist keine wirkliche Antwort, nur eine Richtung, um zu sehen, ob die Dinge immer noch nicht funktionieren. iOS6 hat Audioprobleme auf einigen -Geräten (insbesondere den 64-Gb-4s, die in einem bestimmten Zeitraum hergestellt wurden, obwohl ich andere gesehen habe, sodass sie möglicherweise nicht auf die Hardware bezogen sind) und hört auf mysteriöse Weise auf, einige Arten von Sounds (nicht Klingeltöne oder andere) zu spielen Stimme, aus irgendeinem Grund, aber viele andere Sounds), und die Lautstärkeregler werden verschwinden. Ich habe es notorisch schwierig gefunden, ein Debugging durchzuführen, da es normalerweise (nicht immer gedacht, manchmal kann man es fangen) nur passieren, wenn es nicht mit einem Netzkabel verbunden ist.

Suchen Sie in der Konsole nach ASSERTION FAILURE-Meldungen vom VirtualAudio_Device und mit verschiedenen Codecs. Dies hat möglicherweise nichts mit Ihrem speziellen Problem zu tun, aber ein Fehler in einem Bereich des Soundgeräts kann sich auf einen anderen beziehen. Zumindest ist es ein Bereich, in dem untersucht wird, ob nichts anderes hilft.

0
Mason Cloud

Die API scheint unter iOS 6.1 defekt zu sein oder zumindest hat sich eine grundlegende Änderung ergeben, dh, dass derzeit keine Websites damit arbeiten.

0
Mark

Okay, ich mag die Antwort von AshleysBrain, sie hat mir geholfen, das Problem zu lösen. Ich fand jedoch eine etwas allgemeinere Lösung.

Bevor Sie den Wiedergabeton von einem Benutzerereignis aus initiieren mussten, zwingen Sie Sie jetzt dazu, dies über ein Benutzereingabeereignis zu tun (klingt merkwürdig).

So

  $('#start-lesson').click(function() {
  return startThisLesson();
});
startThisLesson = function() {
     var value;
     value = $('#key-pad-value')[0].value;
     playSoundFile(yourBuffer);
}

playSoundFile ist das, was Sie zum Erstellen der Pufferquelle verwenden.

0
bobbdelsol