2012-09-20 25 views
37

Estaba realmente emocionado de ver que iOS 6 admite Web Audio API, ya que hacemos juegos HTML5. Sin embargo, no puedo hacer que iOS 6 reproduzca ningún sonido con la API de Web Audio con ejemplos que funcionan bien en Chrome para computadoras de escritorio.No hay sonido en iOS 6 Web Audio API

Aquí es un juego de HTML5 con controles táctiles y reproducción de audio a través de la API de audio web (si está presente - si no se va a caer de nuevo a HTML5 de audio):

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

Editar: @Srikumar sugirió algunas soluciones. Los apliqué en la versión de abajo. ¡Todavía no funciona!

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

Todo juega muy bien en el escritorio de Chrome, pero iOS 6 emite ningún sonido. Tengo problemas para depurarlo porque solo desarrollo Windows, y iOS 6 reemplazó el modo de depuración con el inspector web remoto, que aparentemente no está disponible en Safari para Windows. Usando algunas alertas encontré que identifica correctamente la API de Web Audio, la usa, no detecta compatibilidad con Vorbis, por lo que regresa al audio de AAC, decodifica un búfer y luego lo reproduce, y no se producen errores, pero no escucho nada. Y, por supuesto, intenté subir el volumen al máximo :)

No debería haber un problema de códec, porque iOS 6 puede reproducir AAC correctamente - puede navegar a one of the .m4a's the game plays y reproduce bien visitado directamente desde Safari.

Mirando los ejemplos de la API de Web Audio aquí en iOS 6: http://chromium.googlecode.com/svn/trunk/samples/audio/samples.html - algunos funcionan y otros no. Por ejemplo, el Chrome Audio Visualizer funciona, pero Javascript Drone no.

Debe haber alguna incompatibilidad sutil entre Web Audio en iOS 6 y Chrome de escritorio. ¿Qué me estoy perdiendo?

+0

Podría estar relacionado con los formatos de archivo. He tenido problemas con algunos mp3 en Safari. –

+0

Posiblemente, pero como la publicación dice que podría reproducir uno de los sonidos .m4a directamente desde Safari. – AshleysBrain

+0

¿Con cuáles específicamente tienes problemas? –

Respuesta

46

Editar (noviembre de 2015): iOS 9 ya no permite que el audio se inicie en un evento touchstart, que rompe la solución a continuación. Sin embargo, funciona en un evento touchend. La respuesta original para iOS 6 se deja intacta a continuación, pero para iOS 9, asegúrese de usar touchend.

Bueno, disculpe la respuesta a mi propia pregunta de recompensa, pero después de horas de depurar finalmente encontré la respuesta. Safari en iOS 6 comienza de manera efectiva con la API de Web Audio silenciada. No se silenciará el hasta que intente reproducir un sonido en un evento de entrada de usuario (cree una fuente de búfer, conéctela al destino y llame al noteOn()). Después de esto, se activa y el audio se reproduce sin restricciones y como debería. Este es un aspecto no documentado de cómo Web API API funciona en iOS 6 (Apple's doc is here, ¡espero que lo actualicen con una mención de esto pronto!)

El usuario puede estar tocando la pantalla mucho, participando en el juego. Pero permanecerá silenciado. Usted tiene para jugar dentro de un evento de entrada de usuario como touchstart [Editar: touchend para iOS 9+], una vez, luego se activa el audio. Después de eso, puede reproducir audio en cualquier momento (no tiene que estar en un evento de entrada de usuario).

Tenga en cuenta que esto es diferente a las restricciones de audio HTML5: por lo general, solo puede iniciar el audio en un evento de entrada de usuario y solo reproducir un sonido a la vez; Web Audio API se activa completamente después de la primera entrada de play-in-user, para que pueda reproducir sonidos en cualquier momento, y luego puede mezclarlos polifónicamente, procesar efectos geniales, etc.

Esto significa muchos juegos ya en la web con la API de Web Audio nunca se reproducirá audio, ya que no emiten una nota en un evento táctil. Tienes que ajustarlo para esperar el primer evento de entrada del usuario.

Hay algunas formas de evitar esto: no reproduzca su música de título hasta que el usuario toque la pantalla; tener una pantalla inicial de "toque para habilitar el audio" y reproducir un sonido, luego comenzar el juego cuando toquen; etc. ¡Espero que esto ayude a cualquier otra persona que tenga el mismo problema, ahorre algo de tiempo intentando depurarlo!

+0

¿Las dos respuestas anteriores no indicaron que se requiere una acción del usuario para obtener audio? –

+0

Los leo como implicando que solo se puede crear el contexto allí (no del todo correcto) o que el audio no activado en una acción del usuario nunca se reproducirá (tampoco es correcto) – AshleysBrain

+0

_No se activará hasta que intente reproducir un sonido en un evento de entrada de usuario_. Tengo un ejemplo de contador para esto - http://srikumarks.github.com/demos/tala. (Es una especie de "metrónomo" para las talas del sur de la India.) Si carga eso en Safari/iOS6/iPhone y simplemente espera un momento, el metrónomo comenzará a correr, aunque los gráficos no funcionan de la manera que lo hace en Chrome. No se necesita la entrada del usuario (excepto la introducción de la URL?). – Srikumar

5

Puede intentar depurarlo utilizando Web Inspector en Safari 6 en un mac.

  1. Habilite "Webkit Inspector" en la configuración de Mobile Safari/advanced.
  2. Conecta el dispositivo a una Mac que ejecuta Safari 6 con un cable USB.
  3. cargar la página/juego
  4. Ir al menú Desarrollo -> [devicename] -> [PAGEURL]

No funciona fuera de la caja para mí, pero con un par de intentos que puede ayuda a reducir el problema

Aparentemente, también existe la posibilidad de que el audio solo pueda ser activado por una acción del usuario. No estoy seguro de que esto sea cierto porque algunos códigos que funcionan en iOS6 en iPhone4 no reproducen ningún sonido en un iPad (también iOS6).

Actualización: Algún éxito con el audio web en iPhone4 + iOS6. Descubrió que el "tiempo actual" permanece bloqueado en 0 por un tiempo tan pronto como crea un nuevo contexto de audio en iOS6. Para que se mueva, primero debe realizar una llamada ficticia a la API (como createGainNode() y descartar el resultado). Los sonidos se reproducen solo cuando CurrentTime comienza a ejecutarse, pero la programación suena exactamente en el momento actual. Parece que no funciona. Necesitan estar un poco en el futuro (ej .: 10ms). Puede usar la siguiente función createAudioContext para esperar hasta que el contexto esté listo para hacer ruido. La acción del usuario no parece ser necesaria en el iPhone, pero aún no ha tenido tanto éxito en el 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(); 
} 

Posteriormente, cuando se reproduce una nota, no llame a .noteOn(ac.currentTime), pero no .noteOn(ac.currentTime + 0.01) lugar.

Por favor, no me preguntes por qué tienes que hacer todo eso. Así es en este momento, es decir, loco.

+0

Gracias por la respuesta, muy interesante. Lamentablemente, no parece aplicarse a mi primer ejemplo. Considere esta demostración hecha desde cero que funciona bien en un iPad 2 con iOS 6: http://www.scirra.com/labs/webaudio-ios6-working/ - solo usa noteOn (0) y no usa su " crear la solución del nodo de ganancia en el inicio. Debe haber algo más en juego aquí ... – AshleysBrain

+0

El truco createGainNode() pareció funcionar para mí; solo asegúrese de que se invoque en una devolución de llamada desde un evento táctil, y la restricción de sonidos que necesitan ser activados por contacto parece desaparecer. – TomW

+0

Esta es la respuesta que estaba buscando, ¡gran solución! – Clafou

3

Creo que lo he descubierto.

Es una cuestión de Apple que requiere una acción del usuario antes de poder reproducir el sonido. Resulta, al menos para mí, que no debes crear el contexto de audio, excepto cuando el usuario lo solicite. No es suficiente crear el contexto cuando la página se carga y luego usar createGainNode o similar en una acción del usuario.

En su caso crearía el contexto cuando el usuario haga clic en el botón "Toque para comenzar".

+0

No creo que sea eso - este ejemplo crea el contexto de audio en el inicio y funciona bien: http://www.scirra.com/labs/webaudio-ios6-working/ También intenté reproducir los sonidos en un temporizador (como en, no en un evento de entrada de usuario) y funcionó. – AshleysBrain

+0

Sí, parece que funciona bien. El juego original, sin embargo, parece que tiene algunos errores en este momento. Lo entiendo al ingresar en el iPad: "sbios6b: 9 - La clave del argumento de la vista" target-densitydpi "no se reconoce ni se ignora." "c2runtime.js: 5534 - SYNTAX_ERR: DOM Exception 12: Se especificó una cadena no válida o ilegal". –

+0

Disculpe el formato @AshleysBrain –

1

Respondiendo a la pregunta original , puedo confirmar con formatos de archivo en el iPhone 4S/iOS 6 y MacOSX con algunas dificultades. Si un archivo MP3 "no es bueno" para Safari, la decodificación falla y la invocación de AudioContext.createBuffer (array, bool) le da un error.

Lo extraño es sobre el error: "SYNTAX_ERR, DOM Excepción 12", como se ha señalado por otros. Esto me hace pensar que es un error ....

mismo comportamiento también en MacOS, con Safari 6.0 (7.536,25).

0

Esta no es una respuesta real, solo una dirección para ver si las cosas aún no funcionan. iOS6 tiene problemas de audio en algunos dispositivos (especialmente los 64gb 4s fabricados durante un período determinado, aunque he visto otros por lo que puede no estar relacionado con el hardware) y misteriosamente dejarán de reproducir algunos tipos de sonidos (no tonos o voz, por alguna razón, pero muchos otros sonidos), y sus controles deslizantes de volumen desaparecerán. He encontrado que es notoriamente difícil de depurar, ya que normalmente (aunque no siempre, a veces puedes verlo) solo ocurre cuando no está conectado con un cable de alimentación.

Buscar en la consola para los mensajes de error de aserción de la VirtualAudio_Device y con varios códecs. Esto puede no tener nada que ver con su problema en particular, pero una vez más, un error en un área del dispositivo de sonido puede estar relacionado con otro. Como mínimo, es un área para investigar si nada más está ayudando.

0

La API parece no estar funcionando en iOS 6.1, o por lo menos, tiene un cambio importante que significa que no hay sitios funcionan actualmente con él.

1

Me he encontrado con las restricciones de audio con HTML5 Audio en iOS y trabajado alrededor del problema:

1) Creación de un elemento de audio con un archivo de audio silencioso y reproducirlo inicialmente con un evento táctil (por ejemplo, el botón 'comenzar juego') y luego pausarlo inmeditamente.

2) La construcción de una función de sonido-conmutador que conmuta el src de audio y luego toca el elemento de audio después de un corto tiempo de espera.

3) Llamar a la función de conmutación de sonido en cualquier evento (no tiene que ser un evento táctil).

Esto funciona porque el elemento de audio no se silencia en el primer toque, con el archivo de audio silencioso, y permanece sin silenciar, por lo que la fuente se puede cambiar sobre la marcha.

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

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

he conseguido encontrar una solución simple que estoy seguro que debe haber sido documentado en otros lugares - pero a veces tenemos que pasar horas pensando estas cosas por nosotros mismos ...

Por lo tanto, parece que muchos tutoriales (como éste en html5rocks) lo indiquen los siguientes pasos:

  • crear una instancia de window.AudioContext y si eso no existe (que no lo hace en iOS) a continuación, crear window.webkitAudioContext.

  • Crear XMLHttpRequest para cargar el archivo de sonido

  • En la carrera load caso context.decodeAudioData(....) y luego createBufferSource(), llenándolo de los datos decodificados, y finalmente source.start(0) para reproducir el sonido.

Como otros han señalado debe crear el AudioContext (que por cierto debe almacenar y utilizar durante la vida útil de la página) como resultado de una interacción con el usuario (o haga clic en touchstart).

Sin embargo: Para iOS a 'desbloqueo' sus capacidades de audio que DEBE tienen datos de audio disponibles cuando se crea la AudioContext. Si carga los datos de manera asincrónica, no hay nada para que se reproduzca. No es suficiente simplemente crear el AudioContext dentro de un evento click.

Aquí hay dos soluciones para la reproducción iOS fiable:

  • 1) Debe cargar al menos un archivo de sonido, incluso antes de inicializar el AudioContext y ejecute todos los pasos anteriores para ese archivo de sonido inmediatamente dentro de una interacción con un solo usuario (por ejemplo, haga clic en).

  • O 2) Cree un sonido dinámicamente en la memoria y reprodúzcalo.

Ésta es la forma en que lo hice segunda opción:

recuerde - debe estar dentro de click/touch evento para 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 

Me imagino que esto es un error común - y Me sorprende después de 3 años que nadie parece haberlo señalado o descubierto: -/

+0

También funciona cuando se pone en una función que se llama desde un controlador de eventos. ¡Increíble! –

1

actualizado para 2015 solución: Hola a todos, si trabajas aquí en un problema de audio web con iOS6, he encontrado estos enlaces como ayuda.

-Este es un buen artículo con una solución de código: http://matt-harrison.com/perfect-web-audio-on-ios-devices-with-the-web-audio-api/

-aquí es una actualización de la API después del artículo^solución anterior fue escrito https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API/Porting_webkitAudioContext_code_to_standards_based_AudioContext

-por debajo es mi solución actualizada para el primer artículo , usando los cambios del segundo artículo. El problema que estaba teniendo era iOS 7 safari arrojando un error extraño no suficiente. esto esté arreglado que:

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

Actualización: iOS aún requiere una entrada de usuario para reproducir sonido (No sound on iOS 6 Web Audio API)

me he quedado atrapado previamente con audio de la tela en IOS web. Y para empeorar las cosas, necesita funcionar en Android y otras plataformas de escritorio. Esta publicación es una de esas publicaciones que leí y no encontré respuestas inmediatas.

Hasta que encontré howler.js.

Esta es la solución para la solución de audio web multiplataforma:

<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> 
0

bien me gusta la respuesta AshleysBrain, me ayudó a resolver el problema. Pero encontré una solución un poco más general.

Antes de iniciar el sonido de reproducción de un evento de usuario, ahora lo obligan a hacerlo a través de un evento de entrada de usuario (suena extraño) Lo que hice fue leer un campo de entrada antes de reproducir el sonido.

Así

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

playSoundFile es lo que uso para crear la fuente de amortiguamiento.

Cuestiones relacionadas