Fragen Sie bei einem Klick nach dem Mikrofon

Neulich bin ich auf folgendes Beispiel eines Javascript-Audiorecorders gestoßen:

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

Was ich letztendlich für die Implementierung meiner eigenen verwendet habe. Das Problem, das ich habe, ist das in dieser Akte:

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

Wie Sie vielleicht sehen können, ist dieinitAudio () Die Funktion (die den Benutzer um Erlaubnis zur Verwendung seines Mikrofons bittet) wird sofort aufgerufen, wenn die Seite mit dieser Methode geladen wird (letzte Zeile lesen):

window.addEventListener('load', initAudio );

Jetzt habe ich diesen Code im 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>

Und wie Sie sehen können, rufe ich dietoggleRecording (dies) Funktion (diejenige, die den Aufnahmevorgang startet) erst nach dem Drücken der Taste #rec. Jetzt funktioniert alles mit diesem Code, ABER der Benutzer wird aufgefordert, das Mikrofon zuzulassen, sobald die Seite geladen ist, und ich möchte ihn um Erlaubnis bitten, das Mikrofon nur zu verwenden, nachdem er auf die Schaltfläche #rec geklickt hat. Verstehst du mich? Ich dachte, wenn ich die letzte Zeile der ersten Datei entferne:

window.addEventListener('load', initAudio );

und ändere mein eingebettetes Skript wie folgt:

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

Möglicherweise kann ich das erreichen, was ich wollte, und tatsächlich wird der Benutzer erst dann zur Eingabe seines Mikrofons aufgefordert, wenn er auf die Schaltfläche #rec klickt. Das Problem ist,Der Ton wird nie aufgenommenWenn Sie versuchen, es herunterzuladen, ist das resultierende WAV leer.

Wie kann ich das beheben?

Der Code meines Projekts lautet:https://github.com/Jmlevick/html-recorder

Antworten auf die Frage(2)

Ihre Antwort auf die Frage