2013-06-15 3 views
4

На днях я наткнулся на этот пример записи аудио Javascript:Спросите микрофона на OnClick событие

http://webaudiodemos.appspot.com/AudioRecorder/index.html

который я в конечном итоге, используя для реализации моих собственных. Проблема у меня в том, что в этом файле:

var audioContext = new webkitAudioContext(); 
var audioInput = null, 
    realAudioInput = null, 
    inputPoint = null, 
    audioRecorder = null; 
var rafID = null; 
var analyserContext = null; 
var canvasWidth, canvasHeight; 
var recIndex = 0; 

/* TODO: 

- offer mono option 
- "Monitor input" switch 
*/ 

function saveAudio() { 
    audioRecorder.exportWAV(doneEncoding); 
} 

function drawWave(buffers) { 
    var canvas = document.getElementById("wavedisplay"); 

    drawBuffer(canvas.width, canvas.height, canvas.getContext('2d'), buffers[0]); 
} 

function doneEncoding(blob) { 
    Recorder.forceDownload(blob, "myRecording" + ((recIndex<10)?"0":"") + recIndex + ".wav"); 
    recIndex++; 
} 

function toggleRecording(e) { 
    if (e.classList.contains("recording")) { 
     // stop recording 
     audioRecorder.stop(); 
     e.classList.remove("recording"); 
     audioRecorder.getBuffers(drawWave); 
    } else { 
     // start recording 
     if (!audioRecorder) 
      return; 
     e.classList.add("recording"); 
     audioRecorder.clear(); 
     audioRecorder.record(); 
    } 
} 

// this is a helper function to force mono for some interfaces that return a stereo channel for a mono source. 
// it's not currently used, but probably will be in the future. 
function convertToMono(input) { 
    var splitter = audioContext.createChannelSplitter(2); 
    var merger = audioContext.createChannelMerger(2); 

    input.connect(splitter); 
    splitter.connect(merger, 0, 0); 
    splitter.connect(merger, 0, 1); 
    return merger; 
} 
function toggleMono() { 
    if (audioInput != realAudioInput) { 
     audioInput.disconnect(); 
     realAudioInput.disconnect(); 
     audioInput = realAudioInput; 
    } else { 
     realAudioInput.disconnect(); 
     audioInput = convertToMono(realAudioInput); 
    } 

    audioInput.connect(inputPoint); 
} 


function cancelAnalyserUpdates() { 
    window.webkitCancelAnimationFrame(rafID); 
    rafID = null; 
} 

function updateAnalysers(time) { 
    if (!analyserContext) { 
     var canvas = document.getElementById("analyser"); 
     canvasWidth = canvas.width; 
     canvasHeight = canvas.height; 
     analyserContext = canvas.getContext('2d'); 
    } 

    // analyzer draw code here 
    { 
     var SPACING = 3; 
     var BAR_WIDTH = 1; 
     var numBars = Math.round(canvasWidth/SPACING); 
     var freqByteData = new Uint8Array(analyserNode.frequencyBinCount); 

     analyserNode.getByteFrequencyData(freqByteData); 

     analyserContext.clearRect(0, 0, canvasWidth, canvasHeight); 
     analyserContext.fillStyle = '#F6D565'; 
     analyserContext.lineCap = 'round'; 
     var multiplier = analyserNode.frequencyBinCount/numBars; 

     // Draw rectangle for each frequency bin. 
     for (var i = 0; i < numBars; ++i) { 
      var magnitude = 0; 
      var offset = Math.floor(i * multiplier); 
      // gotta sum/average the block, or we miss narrow-bandwidth spikes 
      for (var j = 0; j< multiplier; j++) 
       magnitude += freqByteData[offset + j]; 
      magnitude = magnitude/multiplier; 
      var magnitude2 = freqByteData[i * multiplier]; 
      analyserContext.fillStyle = "hsl(" + Math.round((i*360)/numBars) + ", 100%, 50%)"; 
      analyserContext.fillRect(i * SPACING, canvasHeight, BAR_WIDTH, -magnitude); 
     } 
    } 

    rafID = window.webkitRequestAnimationFrame(updateAnalysers); 
} 

function gotStream(stream) { 
    // "inputPoint" is the node to connect your output recording to. 
    inputPoint = audioContext.createGainNode(); 

    // Create an AudioNode from the stream. 
    realAudioInput = audioContext.createMediaStreamSource(stream); 
    audioInput = realAudioInput; 
    audioInput.connect(inputPoint); 

// audioInput = convertToMono(input); 

    analyserNode = audioContext.createAnalyser(); 
    analyserNode.fftSize = 2048; 
    inputPoint.connect(analyserNode); 

    audioRecorder = new Recorder(inputPoint); 

    zeroGain = audioContext.createGainNode(); 
    zeroGain.gain.value = 0.0; 
    inputPoint.connect(zeroGain); 
    zeroGain.connect(audioContext.destination); 
    updateAnalysers(); 
} 

function initAudio() { 
    if (!navigator.webkitGetUserMedia) 
     return(alert("Error: getUserMedia not supported!")); 

    navigator.webkitGetUserMedia({audio:true}, gotStream, function(e) { 
      alert('Error getting audio'); 
      console.log(e); 
     }); 
} 

window.addEventListener('load', initAudio); 

Как вы могли бы видеть, initAudio() функция (тот которым запрашивает у пользователя разрешение на использование его/ее микрофон) называется inmediately, когда страница загружается (прочитать последнюю строку) с помощью этого метода:

window.addEventListener('load', initAudio); 

Теперь у меня есть этот код в HTML:

<script type="text/javascript" > 
$(function() { 
    $("#recbutton").on("click", function() { 
    $("#entrance").hide(); 
    $("#live").fadeIn("slow"); 
    toggleRecording(this); 
    $(this).toggle(); 
    return $("#stopbutton").toggle(); 
    }); 
    return $("#stopbutton").on("click", function() { 
    audioRecorder.stop(); 
    $(this).toggle(); 
    $("#recbutton").toggle(); 
    $("#live").hide(); 
    return $("#entrance").fadeIn("slow"); 
    }); 
}); 
</script> 

И как вы можете видеть, я вызываю функцию toggleRecording (this) (тот, который начинает процесс записи) только после нажатия кнопки #recbutton. Теперь все работает отлично с этим кодом. НО, пользователь получает запрос на разрешение микрофона, как только загружается страница, и я хочу попросить у них разрешения использовать микрофон ТОЛЬКО ПОСЛЕ того, как они нажали кнопку #recbutton. Вы меня поняли? Я учил, что если удалить последнюю строку первого файла:

window.addEventListener('load', initAudio); 

и изменить свой встроенный скрипт так:

<script type="text/javascript" > 
$(function() { 
    $("#recbutton").on("click", function() { 
    $("#entrance").hide(); 
    $("#live").fadeIn("slow"); 
    initAudio(); 
    toggleRecording(this); 
    $(this).toggle(); 
    return $("#stopbutton").toggle(); 
    }); 
    return $("#stopbutton").on("click", function() { 
    audioRecorder.stop(); 
    $(this).toggle(); 
    $("#recbutton").toggle(); 
    $("#live").hide(); 
    return $("#entrance").fadeIn("slow"); 
    }); 
}); 
</script> 

я мог бы добиться того, чего я хотел, и на самом деле я , пользователь не получает запрос на его/ее микрофон, пока не нажмет кнопку #recbutton. Проблема заключается в том, что звук никогда не записывается, когда вы пытаетесь его загрузить, в результате WAV он пуст.

Как это исправить?

код моего проекта по адресу: https://github.com/Jmlevick/html-recorder

+0

какой браузер вы используете? – basilikum

+0

Chrome, пример работает только в последних версиях Chrome. – Jmlevick

+0

Попробуйте пойти на chrome: // flags/и посмотреть, есть ли параметр, который вы можете изменить. И даже если нет. Попробуйте снова запустить свой пример после посещения этого сайта. Это звучит глупо, но у меня была такая же проблема с записью звука и по какой-то странной причине, просто посетив этот сайт, заработали записи. Было бы интересно узнать, если вы испытаете то же самое. – basilikum

ответ

0

Я нашел элегантное & простое решение для этого (или, по крайней мере, я вижу, что путь):

То, что я был бросить «main.js» и «recorder.js» Внутри getScript, который выполняется только тогда, когда пользователь нажимает определенную кнопку (# button1) ... Эти сценарии не загружаются самой веб-страницей, пока кнопка не будет нажата, но нам нужны еще несколько полезных трюков, чтобы заставить ее работать который я описал и хотел выше:

в основной.JS, я изменил:

window.addEventListener('load', initAudio); 

для:

window.addEventListener('click', initAudio); 

Так что, когда скрипты загружаются на страницу с getScript "main.js" файл в настоящее время прослушивает событие в клик на веб-странице, чтобы спросить пользователя о микрофоне. Затем мне нужно было создать скрытую кнопку (# button2) на странице, которую случайно щелкнул jQuery сразу после загрузки скриптов на странице, поэтому он запускает событие «спросить о микрофонном разрешении», а затем, чуть ниже этого строка кода Wich генерирует фальшивый клик я добавил:

window.removeEventListener("click", initAudio, false); 

так что «рабочий» на этот трюк заканчивается следующим образом:

  1. Пользователь нажимает кнопку которым загружает necesary JS файлы в страницы с getScript, стоит упомянуть, что теперь файл «main.js» прослушивает нажмите событие на ветру w вместо груз один.

  2. У нас есть скрытая кнопка, которую «fakely clicked» от jQuery как раз в тот момент, когда вы нажимаете первую, поэтому она вызывает событие permisson для пользователя.

  3. После того, как это событие было вызвано, прослушиватель событий щелчка удаляется из окна, поэтому он никогда не запускает событие «попросить разрешение» еще раз, когда пользователь щелкает в любом месте страницы.

И в основном это все люди! :) Теперь, когда пользователь переходит на страницу, он/она никогда не запрашивается для разрешения микрофона, пока не нажмете кнопку «Rec» на странице, как я этого хотел. Одним щелчком пользователя мы делаем 3 вещи в jQuery, но для пользователя кажется, что ничего не случилось, что сообщение «micphone permisson» появляется на экране сразу же после нажатия кнопки «Rec».

0

Нет, ваша проблема в том, что GetUserMedia() имеет асинхронный обратный вызов (gotMedia()); вам нужно иметь остальную часть вашей логики кода в вызове startbutton (в частности, бит бит toggleRecording) внутри этого обратного вызова, потому что прямо сейчас он выполняется, прежде чем getUserMedia вернется (и настроит аудиоустройства).

Смежные вопросы