You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Cordova Android端实时麦克风音频捕获异常问题求助

Hey Juan, let's fix your Cordova audio capture issue!

First, let's break down why your web code works in Firefox but not on Android via Cordova:

  • Cordova's Android WebView has stricter permission rules (media access requires user interaction, not auto-execution)
  • Deprecated APIs like createScriptProcessor behave inconsistently across WebViews
  • AudioContext initialization might be blocked without a user gesture

Solution 1: Fix your existing Web Audio API code for Cordova

Step 1: Update Cordova permissions

Add these lines to your config.xml to ensure audio capture permissions are granted:

<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />

Step 2: Replace auto-execution with user-triggered start

Modern WebViews (including Cordova's) block media access unless initiated by a user gesture (like a button click). Modify your code to run on button press instead of immediately:

<button id="startCaptureBtn">Start Audio Monitoring</button>
<div id="barra-progreso" style="width:0%; height:20px; background:blue;"></div>
<div id="barra-progreso2" style="width:0%; height:20px; background:red; margin-top:10px;"></div>

<script>
var ventanas = []; 
var MAX_VENTANAS = 7; 
var audioContext = null;
var gain_node = null, script_processor_node = null, microphone_stream = null;
const BUFF_SIZE = 16384;

// Trigger audio setup on button click
document.getElementById('startCaptureBtn').addEventListener('click', initAudioProcessing);

function initAudioProcessing() {
    try {
        // Cross-browser AudioContext fallback
        window.AudioContext = window.AudioContext || window.webkitAudioContext;
        audioContext = new AudioContext();
        alert("Audio system initialized");

        // Use modern mediaDevices API with fallback to old getUserMedia
        if (navigator.mediaDevices?.getUserMedia) {
            navigator.mediaDevices.getUserMedia({ audio: true })
                .then(startMicrophone)
                .catch(handleAudioError);
        } else if (navigator.getUserMedia) {
            navigator.getUserMedia({ audio: true }, startMicrophone, handleAudioError);
        } else {
            alert("Audio capture not supported on this device");
        }
    } catch (e) {
        alert(`Failed to initialize audio: ${e.message}`);
    }
}

function handleAudioError(error) {
    alert(`Audio capture error: ${error.message}`);
}

function processMicrophoneBuffer(event) {
    const microphoneBuffer = event.inputBuffer.getChannelData(0);
    let sum = 0;
    
    // Calculate average amplitude
    for (let i = 0; i < BUFF_SIZE; i++) {
        sum += Math.abs(microphoneBuffer[i]);
    }
    sum /= BUFF_SIZE;

    // Update progress bars (check if elements exist to avoid errors)
    const bar1 = document.getElementById("barra-progreso");
    if (bar1) bar1.style.width = `${Math.floor(sum * 100)}%`;

    // Update sliding window average
    if (ventanas.length >= MAX_VENTANAS) ventanas.shift();
    ventanas.push(sum);

    let windowSum = 0;
    ventanas.forEach(val => windowSum += val);
    windowSum = (windowSum / (MAX_VENTANAS * BUFF_SIZE)) * 1000000;
    
    const bar2 = document.getElementById("barra-progreso2");
    if (bar2) bar2.style.width = `${Math.floor(windowSum)}%`;
    console.log(`Window average: ${windowSum}`);
}

function startMicrophone(stream) {
    gain_node = audioContext.createGain();
    microphone_stream = audioContext.createMediaStreamSource(stream);
    microphone_stream.connect(gain_node);

    // Fix: Connect script processor to destination (required for some WebViews)
    script_processor_node = audioContext.createScriptProcessor(BUFF_SIZE, 1, 1);
    script_processor_node.onaudioprocess = processMicrophoneBuffer;
    microphone_stream.connect(script_processor_node);
    script_processor_node.connect(audioContext.destination);
    
    alert("Microphone connected successfully!");
}
</script>

createScriptProcessor is deprecated—use AudioWorklet for better performance and compatibility. Here's a quick snippet to replace it:

// In initAudioProcessing, after creating audioContext:
await audioContext.audioWorklet.addModule('audio-processor.js');
const workletNode = new AudioWorkletNode(audioContext, 'microphone-processor');
microphone_stream.connect(workletNode);
workletNode.connect(audioContext.destination);

// Create audio-processor.js file:
class MicrophoneProcessor extends AudioWorkletProcessor {
    process(inputs) {
        const buffer = inputs[0][0];
        // Your buffer processing logic here (same as processMicrophoneBuffer)
        // To send data to main thread: this.port.postMessage(buffer);
        return true;
    }
}
registerProcessor('microphone-processor', MicrophoneProcessor);

Solution 2: Use Cordova AudioInput Plugin

If Web Audio API still gives you trouble, the cordova-plugin-audioinput is designed specifically for this use case.

Step 1: Install the plugin

cordova plugin add cordova-plugin-audioinput

Step 2: Sample implementation

<button id="startBtn">Start Monitoring</button>
<button id="stopBtn">Stop Monitoring</button>

<script>
var ventanas = [];
var MAX_VENTANAS = 7;
const BUFF_SIZE = 16384;

document.getElementById('startBtn').addEventListener('click', startAudioCapture);
document.getElementById('stopBtn').addEventListener('click', stopAudioCapture);

function startAudioCapture() {
    const config = {
        sampleRate: 44100,
        bufferSize: BUFF_SIZE,
        channels: 1,
        format: 'float32' // Matches Web Audio's buffer format
    };

    audioInput.start(config, processBuffer, handleError);
}

function processBuffer(buffer) {
    // Same processing logic as before—buffer is a Float32Array
    let sum = 0;
    for (let i = 0; i < buffer.length; i++) {
        sum += Math.abs(buffer[i]);
    }
    sum /= buffer.length;

    // Update UI elements...
    // (copy your existing progress bar update code here)
}

function handleError(error) {
    alert(`Audio input error: ${error}`);
}

function stopAudioCapture() {
    audioInput.stop();
}
</script>
  • Cordova Core Docs: Focus on the Android platform guide and permission configuration to understand WebView behavior.
  • Web Audio API Guide: Learn modern practices like AudioWorklet to avoid deprecated APIs and improve compatibility.
  • Cordova Plugin Development: If you want to customize audio handling, learn how plugins bridge native code and web apps.
  • Android WebView Permissions: Deep dive into Android's rules for media access in WebViews to avoid permission-related bugs.

内容的提问来源于stack exchange,提问作者Juan Bulla

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 08:43:54