Nessun suono su iOS 6 Web Audio API

Ero davvero entusiasta di vedere iOS 6 supporta l’API Web Audio, dato che realizziamo giochi HTML5. Tuttavia, non riesco a far sì che iOS 6 riproduca alcun suono utilizzando l’API Web Audio con esempi che funzionano perfettamente in Chrome desktop.

Ecco un gioco HTML5 con controlli touch e riproduzione audio tramite l’API Web Audio (se presente, se non tornerà all’audio HTML5):

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

Modifica: @Srikumar ha suggerito alcuni soluzioni alternative. Li ho applicati alla versione di seguito. Ancora non funziona!

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

    Tutto suona bene sul desktop Chrome, ma iOS 6 non emette alcun suono. Ho problemi nel debugging perché eseguo solo lo sviluppo di Windows e iOS 6 ha sostituito la modalità di debug con l’ispettore web remoto, che apparentemente non è disponibile su Safari per Windows. Usando alcuni avvisi, ho trovato che identifica correttamente l’API Web Audio, la usa, non rileva il supporto Vorbis, quindi ricade nell’audio AAC, decodifica un buffer e poi lo riproduce, e non vengono lanciati errori, ma non sento nulla. E, naturalmente, ho provato a portare il volume al massimo 🙂

    Non dovrebbe esserci un problema con il codec, perché iOS 6 può giocare bene con AAC: puoi sfogliare uno dei giochi .m4a e gioca bene visitato direttamente da Safari.

    Osservando gli esempi di API Web Audio qui su iOS 6: http://chromium.googlecode.com/svn/trunk/samples/audio/samples.html – alcuni funzionano e altri no. Ad esempio, Chrome Audio Visualizer funziona, ma Javascript Drone no.

    Deve esserci una leggera incompatibilità tra Web Audio su iOS 6 e desktop Chrome. Cosa mi manca?

    Modifica (novembre 2015): iOS 9 non consente più l’avvio dell’audio in un evento touchstart , che interrompe la soluzione riportata di seguito. Tuttavia funziona in un evento touchend . La risposta originale per iOS 6 è rimasta intatta di seguito, ma per il supporto per iOS 9 assicurati di utilizzare touchend .

    Bene, mi dispiace rispondere alla mia domanda di taglie, ma dopo ore di debug ho finalmente trovato la risposta. Safari su iOS 6 inizia effettivamente con l’audio di Web Audio distriggersto. Non riattiverà l’ audio finché non tenterai di riprodurre un suono in un evento di input dell’utente (crea una sorgente di buffer, collegalo alla destinazione e chiama noteOn() ). Dopo questo, si ritriggers e l’audio viene riprodotto senza restrizioni e come dovrebbe. Questo è un aspetto non documentato di come funziona l’API Web Audio su iOS 6 ( il documento Apple è qui , si spera che lo aggiornino con una menzione a breve!)

    L’utente può toccare molto lo schermo, impegnato nel gioco. Ma rimarrà in sordina. Devi giocare all’interno di un evento di input dell’utente come touchstart [edit: touchend per iOS 9+], una volta, quindi ritriggersre l’audio. Successivamente è ansible riprodurre l’audio in qualsiasi momento (non deve essere presente in un evento di input dell’utente).

    Nota che questo è diverso dalle restrizioni sull’audio HTML5: in genere puoi solo avviare l’audio in un evento di input dell’utente, e suonare solo un suono alla volta; l’API Web Audio si ritriggers completamente dopo il primo input di input dell’utente, in modo che tu possa riprodurre i suoni in qualsiasi momento, e quindi puoi mescolarli polifonicamente, elaborare effetti interessanti, ecc.

    Ciò significa che molti giochi già sul Web che utilizzano l’API Web Audio non riproducono mai l’audio, perché non emettono una nota in un evento touch. Devi aggiustarlo per aspettare il primo evento di input dell’utente.

    Ci sono alcuni modi per ovviare a questo problema: non riprodurre la musica del titolo finché l’utente non tocca lo schermo; avere una schermata iniziale “triggers per abilitare l’audio” e riprodurre un suono, quindi iniziare il gioco quando toccano; ecc. Speriamo che questo possa aiutare chiunque abbia lo stesso problema a risparmiare tempo cercando di eseguire il debugging!

    Puoi provare a eseguirne il debug utilizzando Web Inspector su Safari 6 su un Mac.

    1. Abilita “Webkit Inspector” nelle impostazioni di Mobile Safari / Avanzate.
    2. Collega il dispositivo a un Mac con Safari 6 utilizzando un cavo USB.
    3. Carica la tua pagina / gioco
    4. Vai al menu Sviluppi -> [nomevideo] -> [paginaurl]

    Per me non funziona fuori dagli schemi, ma con alcuni tentativi può aiutare a restringere il problema.

    Apparentemente c’è anche la cosa che l’audio può essere triggersto solo da un’azione dell’utente. Non sono sicuro che sia vero perché un codice che funziona su iOS6 su iPhone4 non riproduce alcun suono su un iPad (anche iOS6).

    Aggiornamento : un po ‘di successo con l’audio del web su iPhone4 + iOS6. Scoperto che il “currentTime” rimane bloccato su 0 per un po ‘non appena si crea un nuovo contesto audio su iOS6. Per farlo muovere, devi prima eseguire una chiamata API fittizia (come createGainNode() e scartare il risultato). I suoni vengono riprodotti solo quando currentTime inizia a funzionare, ma la programmazione dei suoni esattamente al momento attuale sembra non funzionare. Devono essere un po ‘nel futuro (es: 10ms). È ansible utilizzare la seguente funzione createAudioContext per attendere finché il contesto non è pronto per fare rumore. L’azione dell’utente non sembra essere richiesta su iPhone, ma non ha ancora un tale successo su iPad.

     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(); } 

    Successivamente, durante la riproduzione di una nota, non chiamare .noteOn(ac.currentTime) , ma fare .noteOn(ac.currentTime + 0.01) .

    Per favore non chiedermi perché devi fare tutto questo. Questo è solo il modo in cui è al momento – cioè pazzo.

    Sono riuscito a capire una soluzione semplice che, sicuramente, deve essere stata documentata altrove, ma a volte dobbiamo passare ore a capire queste cose da soli …

    Quindi sembra che molti tutorial (come questo su html5rocks ) ti insegnino a fare i seguenti passi:

    • Crea un’istanza di window.AudioContext e, se non esiste (cosa che non è su iOS), crea window.webkitAudioContext .

    • Crea un XMLHttpRequest per caricare il tuo file audio

    • Nell’evento load eseguire context.decodeAudioData(....) e quindi createBufferSource() , riempiendolo con i dati decodificati e infine source.start(0) per riprodurre il suono.

    Come altri hanno sottolineato, è necessario creare l’ AudioContext (che, per inciso, è necessario archiviare e utilizzare per la durata della pagina) a seguito di un’interazione dell’utente (clic o touchstart).

    TUTTAVIA: affinché iOS possa “sbloccare” le sue capacità audio, è necessario che siano disponibili dati audio quando si crea AudioContext . Se si caricano i dati in modo asincrono, non c’è niente da giocare. Non è sufficiente creare semplicemente AudioContext all’interno di un evento click .

    Ecco due soluzioni per una riproduzione iOS affidabile:

    • 1) È necessario caricare almeno un file audio prima ancora di inizializzare AudioContext, quindi eseguire tutti i passaggi precedenti per quel file audio immediatamente all’interno di una singola interazione utente (ad esempio, fare clic).

    • OPPURE 2) Creare un suono in modo dinamico nella memoria e riprodurlo.

    Ecco come ho fatto questa seconda opzione:

    RICORDA: DEVE ESSERE entro l’evento click / touch per iOS:

      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 

    Immagino che questo sia un errore comune – e sono sorpreso dopo 3 anni che nessuno sembra averlo sottolineato o scoperto: – /

    Quindi, penso di aver capito.

    È un problema di Apple che richiede un’azione da parte dell’utente prima che il suono possa essere autorizzato a giocare. Si scopre, almeno per me, che non dovresti creare il contesto audio, tranne quando l’utente lo chiama. Non è sufficiente creare il contesto quando la pagina viene caricata e quindi utilizzare createGainNode o simile su un’azione dell’utente.

    Nel tuo caso creerei il contesto quando l’utente fa clic sul pulsante “Tocca per iniziare”.

    Rispondendo alla domanda originale , posso confermare alcuni problemi con i formati di file su iPhone 4S / iOS 6 e MacOSX. Se un file MP3 non è “buono” per Safari, la decodifica va male e chiama AudioContext.createBuffer (array, bool) e ti dà errore.

    La cosa strana riguarda l’errore: “SYNTAX_ERR, DOM Exception 12”, come sottolineato da altri. Questo mi fa pensare che sia un bug ….

    Stesso comportamento anche su MacOS, con Safari 6.0 (7536.25).

    Ho trovato le restrizioni audio con HTML5 Audio su iOS e ho risolto il problema:

    1) Creare un elemento audio con un file audio silenzioso e riprodurlo inizialmente con un evento tattile (ad esempio, il pulsante “avvia il gioco”) e quindi fermarlo immidamente.

    2) Costruire una funzione di commutazione del suono che commuta l’audio src e quindi riproduce l’elemento Audio dopo un breve timeout.

    3) Chiamare la funzione di commutazione del suono su qualsiasi evento (non è necessario essere un evento tattile).

    Funziona perché l’elemento audio non è distriggersto al primo touch, con il file audio silenzioso e rimane non distriggersto, quindi la sorgente può essere triggersta al volo.

     switchSound: (id) -> @soundSwitch.pause() @soundSwitch.src = @sounds[id]._src clearTimeout @switchSoundDelay @switchSoundDelay = setTimeout => # @soundSwitch.volume = 1 @soundSwitch.play() ,50 

    aggiornato per la soluzione 2015: ciao a tutti, se siete qui a lavorare su un problema di audio web con ios6 + ho trovato questi collegamenti come aiuto.

    -questo è un buon articolo con la soluzione di codice: http://matt-harrison.com/perfect-web-audio-on-ios-devices-with-the-web-audio-api/

    -un aggiornamento delle API dopo l’articolo ^ soluzione precedente è stato scritto https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API/Porting_webkitAudioContext_code_to_standards_based_AudioContext

    di seguito è la mia soluzione aggiornata al primo articolo, utilizzando le modifiche del secondo articolo. Il problema che stavo avendo era il safari su iOS 7 che lanciava uno strano errore non sufficiente. questo lo ha risolto:

     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; }); 

    Aggiornamento: iOS richiede ancora un input dell’utente per riprodurre il suono ( Nessun suono su iOS 6 Web Audio API )

    In precedenza ero bloccato con l’audio del web sul web iOS. E per peggiorare le cose, ha bisogno di lavorare su Android e altre piattaforms desktop. Questo post è uno di quei post che ho letto e non ho trovato risposte immediate.

    Fino a quando ho trovato howler.js .

    Questa è la soluzione per la soluzione audio web multipiattaforma:

       

    Questa non è una risposta reale, è solo una direzione da guardare se le cose continuano a non funzionare. iOS6 ha problemi audio su alcuni dispositivi (in particolare i 64GB 4s prodotti in un determinato periodo, anche se ne ho visti altri quindi potrebbero non essere correlati all’hardware) e misteriosamente smetterò di riprodurre alcuni tipi di suoni (non suonerie o voci, per alcuni ragione, ma molti altri suoni), ei suoi cursori del volume svaniranno. Ho notato che è notoriamente difficile eseguire il debug come di solito accade (pensato non sempre, a volte è ansible rilevarlo) solo quando non è collegato a un cavo di alimentazione.

    Cerca nella console i messaggi ASSERTION FAILURE da VirtualAudio_Device e con vari codec. Questo potrebbe non avere nulla a che fare con il tuo particolare problema, ma poi di nuovo, un bug in una zona del dispositivo audio potrebbe essere correlato a un altro. Come minimo, è un’area in cui indagare se nient’altro aiuta.

    L’API sembra essere interrotta su iOS 6.1, o almeno, ha un cambiamento di rottura che significa che nessun sito attualmente funziona con esso.

    Ho dei problemi nell’usare tutte le soluzioni semplici. Soprattutto, quando voglio suonare un suono più volte.

    Quindi sto usando questa libreria js: http://pupunzi.open-lab.com/2013/03/13/making-html5-audio-actually-work-on-mobile

    Okay, mi piace la risposta AshleysBrain, mi ha aiutato a risolvere il problema. Ma ho trovato una soluzione un po ‘più generale.

    Prima di dover avviare il suono di riproduzione da un evento utente, ora ti costringono a farlo tramite un evento di input dell’utente, (sembra strano) Quello che ho fatto è stato solo leggere un campo di input prima di riprodurre il suono.

    Così

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

    playSoundFile è qualsiasi cosa tu usi per creare la sorgente del buffer.