繁体   English   中英

在onclick事件上询问麦克风

[英]Ask for microphone on onclick event

有一天,我偶然发现了这个Javascript录音机的例子:

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()函数(要求用户允许使用他/她的麦克风的函数):

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>

正如您所看到的,只有在按下#recbutton之后,才会调用toggleRecording(this)函数(启动录制过程的函数)。 现在,一切正常,使用此代码但是,一旦页面加载,用户就会被提示获得麦克风权限,并且我想要求他们仅在他们点击#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

不,你的问题是getUserMedia()有异步回调(gotMedia()); 你需要在回调中的startbutton调用(特别是toggleRecording位)中使用其余的代码逻辑,因为现在它在getUserMedia返回之前执行(并设置音频节点)。

我找到了一个优雅而简单的解决方案(或者至少我这样看):

我所做的是在getScript调用中抛出“main.js”“recorder.js” ,该调用只有在用户点击某个按钮(#button1)时执行...这些脚本不会加载网页本身直到它被按下按钮,但我们需要一些更好的技巧,使它按照我描述和想要的方式工作:

main.js中 ,我改变了:

window.addEventListener('load', initAudio );

对于:

window.addEventListener('click', initAudio );

因此,当使用getScript将脚本加载到页面中时, “main.js”文件现在会侦听网页中的单击事件 ,以询问用户是否有麦克风。 接下来,我必须在页面上创建一个隐藏按钮(#button2),这个按钮在页面上加载脚本之后被jQuery虚假地点击,因此它会触发“ask for microphone permisson”事件,然后就在那之下代码行产生了我添加的虚假点击:

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

所以这个技巧的“工作流程”最终如下:

  1. 用户按下一个按钮,用于将必要的js文件加载到带有getScript的页面中,值得一提的是,现在“main.js”文件在窗口上侦听单击事件而不是加载一个。

  2. 我们有一个隐藏按钮,只要你点击第一个按钮就被jQuery“虚假点击”,这样它就会触发用户的permisson事件。

  3. 触发此事件后,将从窗口中删除click事件侦听器,因此当用户单击页面上的任何位置时,它永远不会再触发“ask for permisson”事件。

基本上这就是所有人! :)现在,当用户进入页面时,他/她从未被要求提供麦克风许可,直到他们按照我想要的方式单击页面上的“Rec”按钮。 只需单击一下用户,我们就可以在jQuery中执行3项操作,但对于用户来说,似乎没有其他任何事情发生在他们单击“Rec”按钮后立即出现在屏幕上的“麦克风许可消息”。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM