マイク音声を拾ってWebSocketで送信するだけ

ResamplerはOfflineAudioContextを使いました。
WebSocket側は16000Hz/16Bitで受ける事を想定しています。

``` html
<!DOCTYPE html>
<html lang='ja'>

<head>
    <title>Recording to WebSocket</title>
    <meta http-equiv='Content-Type' content='text/html; charset=utf-8' />
    <meta http-equiv="Pragma" content="no-cache">
    <meta http-equiv="Cache-Control" content="no-cache">
</head>

<body>
    <button class='start'>start</button>
    <button class='stop' disabled>stop</button>
    <div id='response'></div>

    <script>

        const WEBSOCKET_ENDPOINT = 'wss://echo.websocket.org'
        const WEBSOCKET_SAMPLERATE = 16000

        const bufferSize = 0 //256, 512, 1024, 2048, 4096, 8192, 16384
        const numberOfInputChannels = 1
        const numberOfOutputChannels = 1

        const startButton = document.querySelector(".start")
        const stopButton = document.querySelector(".stop")

        navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia;

        let _WebSocket
        var _MediaStream
        var _ScriptProcessorNode

        // ---------------------------------------------
        // Start Button
        // ---------------------------------------------
        startButton.onclick = () => {
            startButton.disabled = true
            stopButton.disabled = !startButton.disabled

            const _AudioContext = new (window.AudioContext || window.webkitAudioContext)()

            // ##############################################
            // #   WebSocket
            // ##############################################
            _WebSocket = new WebSocket(WEBSOCKET_ENDPOINT)
            _WebSocket.binaryType = 'arraybuffer'
            _WebSocket.onopen = (e) => {
                console.log('WebSocket connect')
                _WebSocket.onmessage = (e) => {
                    // var receive = JSON.parse(e.data)
                    // console.log(receive)
                    console.log(e.data)
                }
                _WebSocket.onclose = (e) => {
                    console.log('WebSocket disconnect')
                    stopButton.onclick()
                }
                _WebSocket.onerror = (e) => {
                    console.error("WebSocket error observed:", e)
                    stopButton.onclick()
                }
            }

            // ##############################################
            // #   Recording
            // ##############################################
            navigator.mediaDevices.getUserMedia({ audio: true, video: false }).then((constraints) => {
                console.log('start recording')

                _MediaStream = constraints

                let _MediaStreamAudioSourceNode = _AudioContext.createMediaStreamSource(_MediaStream)
                _ScriptProcessorNode = _AudioContext.createScriptProcessor(bufferSize, numberOfInputChannels, numberOfOutputChannels)
                _ScriptProcessorNode.onaudioprocess = (_AudioProcessingEvent) => {
                    var RecordingData = _AudioProcessingEvent.inputBuffer// 44100-48000Hz/32Bit
                    resample(RecordingData, (resampled) => {// to 16000Hz
                        var resampledData = resampled.renderedBuffer.getChannelData(0)// 16000Hz/32Bit
                        floatTo16Bit(resampledData, (data) => {// to 16Bit
                            if (_WebSocket.readyState == WebSocket.OPEN)
                                _WebSocket.send(data)// send WebSocket 16000Hz/16Bit
                        })
                    })
                }
                _MediaStreamAudioSourceNode.connect(_ScriptProcessorNode)
                _ScriptProcessorNode.connect(_AudioContext.destination)

            }).catch((err) => {
                console.log(err);
            })

        }

        // ---------------------------------------------
        // Resampler(44100/48000Hz? -> 16000Hz)
        // ---------------------------------------------
        function resample(inputBuffer, callback) {
            var _OfflineAudioContext = new OfflineAudioContext(inputBuffer.numberOfChannels, inputBuffer.duration * inputBuffer.numberOfChannels * WEBSOCKET_SAMPLERATE, WEBSOCKET_SAMPLERATE);
            var _AudioBuffer = _OfflineAudioContext.createBuffer(inputBuffer.numberOfChannels, inputBuffer.length, inputBuffer.sampleRate);
            for (var channel = 0; channel < inputBuffer.numberOfChannels; channel++) {
                _AudioBuffer.copyToChannel(inputBuffer.getChannelData(channel), channel);
            }
            var _AudioBufferSourceNode = _OfflineAudioContext.createBufferSource();
            _AudioBufferSourceNode.buffer = _AudioBuffer;
            _AudioBufferSourceNode.connect(_OfflineAudioContext.destination);
            _AudioBufferSourceNode.start(0);
            _OfflineAudioContext.oncomplete = (_OfflineAudioCompletionEvent) => {
                callback(_OfflineAudioCompletionEvent)
            }
            _OfflineAudioContext.startRendering();
        }

        // ---------------------------------------------
        // Resampler(32bit -> 16bit)
        // ---------------------------------------------
        function floatTo16Bit(buffer, callback) {
            var _Float32Array = new Float32Array(buffer)
            var _Int16Array = new Int16Array(_Float32Array.length);
            for (var i = 0; i < _Float32Array.length; i++) {
                var s = Math.max(-1, Math.min(1, _Float32Array[i]));
                _Int16Array[i] = s < 0 ? s * 0x8000 : s * 0x7FFF;
            }
            callback(_Int16Array);
        }

        // ---------------------------------------------
        // Stop Button
        // ---------------------------------------------
        stopButton.onclick = () => {
            if (!startButton.disabled)
                return
            startButton.disabled = false
            stopButton.disabled = !startButton.disabled
            if (_ScriptProcessorNode != null) {
                _ScriptProcessorNode.disconnect()
                _ScriptProcessorNode.onaudioprocess = null
                _ScriptProcessorNode = null
            }
            _MediaStream.getTracks().forEach((track) => {
                track.stop()
                console.log('stop recording')
            })
            if (_WebSocket.readyState == WebSocket.OPEN)
                _WebSocket.close()
        }

    </script>
</body>

</html>