在 chrome 浏览器中使用 recordJs 库期间将定义的变量转换为未定义的

converting defined variable as undefined during using recordJs library in chrome browser

我正在使用 recordJs 库来录制客户端的语音并将其发送到服务器。在firefox等浏览器中运行良好,无任何错误。当我在 chrome 中尝试 运行 它时,它开始录制语音,但是当它调用 stopRecording 函数时,它面临以下错误:


Uncaught TypeError: Cannot read property 'stop' of undefined
    at stopRecording (توانایی-پرسش-سن-از-افراد:1209)
    at startTimer (توانایی-پرسش-سن-از-افراد:1364)

这是我的 JS 代码:


<script type="text/javascript">
    'use strict';

    //webkitURL is deprecated but nevertheless
    URL = window.URL || window.webkitURL;

    let gumStream;                      //stream from getUserMedia()
    let rec;                            //Recorder.js object
    let input;                          //MediaStreamAudioSourceNode we'll be recording

    // shim for AudioContext when it's not avb.
    let AudioContext = window.AudioContext || window.webkitAudioContext;
    let audioContext //audio context to help us record


    function startRecording() {
        console.log("recordButton clicked");

        /*
            Simple constraints object, for more advanced audio features see
            https://addpipe.com/blog/audio-constraints-getusermedia/
        */

        var constraints = { audio: true, video:false }

        /*
           Disable the record button until we get a success or fail from getUserMedia()
       */



        /*
            We're using the standard promise based getUserMedia()
            https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia
        */

        navigator.mediaDevices.getUserMedia(constraints).then(function(stream) {
            console.log("getUserMedia() success, stream created, initializing Recorder.js ...");

            /*
                create an audio context after getUserMedia is called
                sampleRate might change after getUserMedia is called, like it does on macOS when recording through AirPods
                the sampleRate defaults to the one set in your OS for your playback device

            */
            audioContext = new AudioContext();

            //update the format
            // document.getElementById("formats").innerHTML="Format: 1 channel pcm @ "+audioContext.sampleRate/1000+"kHz"

            /*  assign to gumStream for later use  */
            gumStream = stream;

            /* use the stream */
            input = audioContext.createMediaStreamSource(stream);

            /*
                Create the Recorder object and configure to record mono sound (1 channel)
                Recording 2 channels  will double the file size
            */
            rec = new Recorder(input,{numChannels:1});


            //start the recording process
            rec.record();

            console.log("Recording started");

        }).catch(function(err) {

        });
    }

    function pauseRecording(){
        console.log("pauseButton clicked rec.recording=",rec.recording );
        if (rec.recording){
            //pause
            rec.stop();
        }else{
            rec.record();
        }
    }

    function stopRecording() {

        //tell the recorder to stop the recording
        rec.stop();

        //stop microphone access
        gumStream.getAudioTracks()[0].stop();

        //create the wav blob and pass it on to createDownloadLink
        rec.exportWAV(setUserVoice);
    }

    function setUserVoice(blob)
    {
        let formData = new FormData
        formData.append('userVoice', blob)

        $.ajax({
            type: 'POST',
            headers: {'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')},
            url: '{{ route('user.mockTest.participation.saveUserVoice') }}',
            data: formData,
            processData: false,
            contentType: false,
            success: function (data) {

                if (data['result'] == 'success')
                {
                    $('#recordUserVoice').prop('disabled', true);
                }
                else
                {

                    Swal.fire(
                        '{{__('Error')}}',
                        '{{__('An error occurred')}}',
                        'error'
                    );

                }

            },
            error: function (err) {
                console.log(err);
            }
        });

    }

    function createDownloadLink(blob) {

        var url = URL.createObjectURL(blob);
        var au = document.createElement('audio');
        var li = document.createElement('li');
        var link = document.createElement('a');

        //name of .wav file to use during upload and download (without extendion)
        var filename = new Date().toISOString();

        //add controls to the <audio> element
        au.controls = true;
        au.src = url;

        //save to disk link
        link.href = url;
        link.download = filename+".wav"; //download forces the browser to donwload the file using the  filename
        link.innerHTML = "Save to disk";

        //add the new audio element to li
        li.appendChild(au);

        //add the filename to the li
        li.appendChild(document.createTextNode(filename+".wav "))

        //add the save to disk link to li
        li.appendChild(link);

        //upload link
        var upload = document.createElement('a');
        upload.href="#";
        upload.innerHTML = "Upload";
        upload.addEventListener("click", function(event){
            var xhr=new XMLHttpRequest();
            xhr.onload=function(e) {
                if(this.readyState === 4) {
                    console.log("Server returned: ",e.target.responseText);
                }
            };
            var fd=new FormData();
            fd.append("audio_data",blob, filename);
            xhr.open("POST","upload.php",true);
            xhr.send(fd);
        })
        li.appendChild(document.createTextNode (" "))//add a space in between
        li.appendChild(upload)//add the upload link to li

        //add the li element to the ol
        recordingsList.appendChild(li);
    }

document.getElementById('timer').innerHTML =
            '00' + ":" + '00';

        function startRecord()
        {
            startRecording();
            startTimer();
        }


        function startTimer() {

            $('#recordTextHolder').addClass('d-none');
            $('#timer').removeClass('d-none');

            var presentTime = document.getElementById('timer').innerHTML;
            var timeArray = presentTime.split(/[:]+/);
            var m = timeArray[0];
            console.log(timeArray[1])
            var s = checkSecond((parseInt(timeArray[1]) + 1));
            if(parseInt(s) == 5)
            {
                m = '0'+(parseInt(m)+1)
                s = '00'
            }

            if(m == 2 && s == 1){

                stopRecording()
                shake()
                return
            }

            document.getElementById('timer').innerHTML =
                m + ":" + s;
            console.log(m)
            setTimeout(startTimer, 1000);

        }

        function checkSecond(sec) {
            if (sec < 10 && sec >= 0) {sec = "0" + sec}; // add zero in front of numbers <10
            if (sec < 0) {sec = "59"};
            return sec;

</script>

如果有人指导我处理这个问题,我将不胜感激。

您似乎在此处设置 rec 的值:

rec = new Recorder(input,{numChannels:1});

错误消息大概来自这里:

function stopRecording() {

    //tell the recorder to stop the recording
    rec.stop();

你可以尝试添加一个 console.log 吗?

function stopRecording() {

    console.log("rec:", rec)
    rec.stop();

报告当时 rec 包含的内容。

感谢您报告说“未定义”。

现在问问自己:'rec' 怎么可能在那个时候是未定义的?

我假设您的控制台正在显示“recordButton clicked”?

还有“getUserMedia() 成功...”?

“录制开始”消息怎么样?

我建议删除以下块:

.catch(function(err) {

        });

该块所做的是默默地“吞下”您原本会看到的任何错误消息。一般来说,除非您真的不想知道那里发生的错误,否则不要放入空的 catch 块。