Gravação de áudio no Chrome para Android usando a API de áudio da web e navigator.getUserMedia
As versões 30 e 31 beta do Android para Android no Android 4.1 não parecem gravar corretamente o áudio usando áudio da web HTML5 e navigator.webkitGetUserMedia. (O Chrome 30+ no Android deve suportar essas APIs.)
O sintoma é que o código parece funcionar corretamente, incluindo a exibição do prompt para permitir ou não o acesso ao microfone, mas os dados gravados não contêm nada além de zeros.
Eu criei um testcase simplificado (vá parahttp://jsfiddle.net/JCFtK/e clique no botão Gravar e escolha a opção apropriada para permitir que ele acesse seu microfone). A parte chave do código está abaixo (a função 'registro' é o ponto de entrada).
function processAudioBuffer(e) {
var floats = e.inputBuffer.getChannelData(0);
var min = 0, max = 0;
for (var i = 0; i < floats.length; i++) {
var current = floats[i];
min = Math.min(current, min);
max = Math.max(current, max);
}
log('Block min/max: ' + min.toFixed(3) + ', ' + max.toFixed(3));
}
function record() {
if (!window.AudioContext) {
window.AudioContext = window.webkitAudioContext;
}
if (!navigator.getUserMedia) {
navigator.getUserMedia = navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
}
data.context = new AudioContext();
navigator.getUserMedia({audio: true}, function(stream) {
data.mediaStream = stream;
startAudio();
}, function(error) {
log('Stream get error: ' + error);
});
}
function startAudio() {
// Get input media stream.
data.audioStream = data.context.createMediaStreamSource(data.mediaStream);
// Set up JS processor.
data.processor = data.context.createScriptProcessor(2048, 1, 1);
data.processor.onaudioprocess = processAudioBuffer;
// You need to connect the output of processor to the audio output or it
// doesn't work. (In Firefox, connecting it just to a gain node works;
// in Chrome you have to connect to output like this.)
data.processor.connect(data.context.destination);
// Connect input stream to processor, then we're done.
data.audioStream.connect(data.processor);
log('Stream connected OK');
}
O teste mostra o valor mínimo / máximo de áudio de cada bloco gravado. Quando estiver funcionando - como no Chrome de desktop, por exemplo - você verá que os valores mínimo / máximo variam dependendo do ruído de fundo. Quando não está funcionando, esses valores são sempre 0,000.
Este teste funciona no seguinte:
Chrome 30 (Windows)Firefox 25 (Windows)Firefox 25 (Android 4.1) em um Sony Xperia MFirefox 25 (Android 4.1) em um tablet SamsungEste caso de teste não funciona no seguinte:
Chrome 30 (Android 4.1) em um Sony Xperia MChrome beta 31 (Android 4.1) em um Sony Xperia MChrome 30 (Android 4.1) em um tablet SamsungO testcase também não funciona em outros navegadores, como o Safari ou o IE, mas isso é esperado, pois eles não suportam as APIs necessárias. É apenas o Chrome para Android que eu esperava fazer isso funcionar, mas isso não acontece.
Arquivei isso como um problema usando o processo de geração de relatórios de problemas do Chrome (que é particular e possivelmente um buraco negro), mas também gostaria de perguntar aqui: alguém está ciente de soluções alternativas que consertariam esse código para que eu pudesse realmente fazer isso? trabalhar no Chrome para Android?
(Um requisito para meus propósitos é que o áudio gravado deve ir para um manipulador de eventos JavaScript, como o que está aqui, e, por exemplo, não diretamente para o servidor como parte de um upload de formulário, o que possivelmente já pode funcionar.)
Tenho a impressão de que este é um material de ponta e que poucas pessoas estão tentando usá-lo, mas achei que valeria a pena perguntar. :)