How to access microphone in guacamole common js?

336 views Asked by At

I'm using Guacamole-common.js to create a remote desktop connection in the browser. I'm trying to activate the microphone in Guacamole. But it's not working. As ScriptProcessorNode is deprecated, I try to use AudioWorklet.

Microphone access is allowed. But in my Windows remote desktop connection, I always get the message "No input device found".

Has anyone tried using audioworkletnode and Guacamole-common.js to enable microphone?

//code snippet of how I try to retrieve audio input from the browser

    const tunnel = new Guacamole.WebSocketTunnel(WEB_SOCKET_TUNNEL);
    const client = new Guacamole.Client(tunnel);  
    
    var audioStream = client.createAudioStream("audio/L16");
    var writer = new Guacamole.ArrayBufferWriter(audioStream);
    
          // Attempt to retrieve an audio input stream from the browser
          navigator.mediaDevices.getUserMedia({ audio: true })
                .then(async function (stream) {
    
                    const context = new AudioContext();
                    const source = context.createMediaStreamSource(stream);
    
                    // Load and execute the module script.
                    await context.audioWorklet.addModule('worklet/processor.js');
                    // Create an AudioWorkletNode. The name of the processor is the
                    // one passed to registerProcessor() in the module script.
    
                    const processor = new AudioWorkletNode(context, "processor");
    
                    source.connect(processor).connect(context.destination);
                 
                    console.log("Microphone access allowed");
    
                    const streamDestination = context.createMediaStreamDestination();
                    processor.connect(streamDestination);
    
                    const inputStream = new Guacamole.InputStream(streamDestination.stream);
    
                    // Connect the audio recorder to the output stream
                    processor.ondataavailable = function (blob) {
                        console.log(blob, 'blob')
                        inputStream.sendBlob(blob);
                    };
    
                    processor.addEventListener('processorerror', (event) => {
                        console.log(`Audio processing error: ${event}`);
                    });
    
                    // Start the audio processing
                    processor.addEventListener('audioprocess', (event) => {
                        var inputBuffer = event.inputBuffer;
                        var inputData = inputBuffer.getChannelData(0);
                        // Write the audio data to the Guacamole audio input stream
                        var bytes = new Int16Array(inputData.length);
                        //console.log(bytes, 'bytes')
                        for (var i = 0; i < inputData.length; i++) {
                            bytes[i] = inputData[i] * 32766;
                        };
                        writer.sendData(bytes.buffer);
                    });
    
                })
                .catch(function (error) {
                    console.log(error, 'error');
                    console.log("Microphone access denied");
                    writer.sendEnd();
                });
1

There are 1 answers

0
AmiS On

I figured it out. To enable audio input, set "enable-audio-input" to true in settings when establishing a connection with the desired remote host.

settings : {
            hostname: " ", // Replace with IP address
            username : " ",
            password : " ",
            port : "  ",
            enable-drive' : true,
            create-drive-path' : true,
            security : 'any',
            ignore-cert' : true,
            enable-wallpaper': false,
            enable-audio-input': true,
        },

To authorize access to the microphone from the browser, I included the following code.

  Const handleAudio = function () {
       var audioStream = client.createAudioStream("audio/L16;rate=44100,channels=2") ;
       var writer = new Guacamole.ArrayBufferWriter(stream) ;
    
    navigator.mediaDevices.getUserMedia({ audio : true }).then((stream) => {
        var context = Guacamole.AudioContextFactory.getAudioContext() ;
        var processor = context.createScriptProcessor(2048, 2, 2) ;
            processor.connect(context.destination) ;
        
            // Send blobs when audio buffers are received
            processor.addEventListener('audioprocess', function processAudio(e) {
                writer.sendData(toSampleArray(e.inputBuffer).buffer) ;
            }) ;
    
            // Connect the processing node to the user's audio input source
            source = context.createMediaStreamSource(stream) ;
            source.connect(processor) ;
    
            // Attempt to explicitly resume AudioContext, as it can be paused
            // by default
            if (context.state === 'suspended')
                context.resume() ;
}

After including the above code, the microphone is activated.

client.onstatechange = function clientStateChanged(state) {

// When client is connected
        if (state === 3) {
            setTimeout(function () {
                // code to be executed after 1 minutes
                handleAudio();
            }, 1 * 60 * 1000);;
        }
    };

handleAudio function is run after a 1-minute timer. Without the timer, the buffer is automatically closed after opening. I can't figure out why the buffer closes.