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

Android SpeechRecognizer无法识别USB麦克风:原因及解决方法

问题:SpeechRecognizer无法识别USB麦克风输入

我开发了一款基于Android SpeechRecognizer API的语音转文字示例应用,使用设备内置麦克风时功能正常,但无法识别USB麦克风(Jabra Speak 510 UC (PHS002W))的音频输入。同一设备上的普通录音应用可正常拾取该USB麦克风的音频。

应用代码

public class MainActivity extends AppCompatActivity {
    public static final Integer RecordAudioRequestCode = 1;
    private SpeechRecognizer speechRecognizer;
    private TextView speechHistory;
    private Button recordVoiceBtn, clearBtn;
    private List<String> voiceInputHistory = new ArrayList<>();
    private boolean isListening = false;
    private Activity thisActivity;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        thisActivity = this;

        PackageManager pm = getPackageManager();
        boolean micPresent = pm.hasSystemFeature(PackageManager.FEATURE_MICROPHONE);

        speechHistory = findViewById(R.id.speechHistory);
        recordVoiceBtn = findViewById(R.id.recordVoiceBtn);
        clearBtn = findViewById(R.id.clearBtn);
        speechRecognizer = SpeechRecognizer.createSpeechRecognizer(this);

        final Intent speechRecognizerIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
        speechRecognizerIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
        speechRecognizerIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, Locale.getDefault());

        speechRecognizer.setRecognitionListener(new RecognitionListener() {
            @Override
            public void onReadyForSpeech(Bundle bundle) {

            }

            @Override
            public void onBeginningOfSpeech() {

            }

            @Override
            public void onRmsChanged(float v) {

            }

            @Override
            public void onBufferReceived(byte[] bytes) {

            }

            @Override
            public void onEndOfSpeech() {

            }

            @Override
            public void onError(int i) {

            }

            @Override
            public void onResults(Bundle bundle) {
                ArrayList<String> data = bundle.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION);
                voiceInputHistory.add(data.get(0));
                StringBuilder fullHistory = new StringBuilder();
                for (String inputText : voiceInputHistory) {
                    fullHistory.append(inputText).append("\n");
                }
                speechHistory.setText(fullHistory.toString());
            }

            @Override
            public void onPartialResults(Bundle bundle) {

            }

            @Override
            public void onEvent(int i, Bundle bundle) {

            }
        });

        if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
            checkPermission();
        }

        recordVoiceBtn.setBackgroundColor(getResources().getColor(R.color.green));
        recordVoiceBtn.setOnClickListener(v -> {
            if (!isListening) {
                isListening = true;
                speechRecognizer.startListening(speechRecognizerIntent);
                recordVoiceBtn.setText("Stop Listening");
                recordVoiceBtn.setBackgroundColor(getResources().getColor(R.color.red));
            } else {
                isListening = false;
                recordVoiceBtn.setText("Start Listening");
                speechRecognizer.stopListening();
                recordVoiceBtn.setBackgroundColor(getResources().getColor(R.color.green));
            }
        });
        clearBtn.setOnClickListener(v -> {
            isListening = false;
            recordVoiceBtn.setText("Start Listening");
            speechRecognizer.stopListening();
            recordVoiceBtn.setBackgroundColor(getResources().getColor(R.color.green));
            voiceInputHistory.clear();
            speechHistory.setText("Your Speech History");
        });

        if (!micPresent) {
            clearBtn.setEnabled(false);
            recordVoiceBtn.setEnabled(false);
            speechHistory.setText("No Mic Detected");
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        speechRecognizer.destroy();
    }

    private void checkPermission() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.RECORD_AUDIO}, RecordAudioRequestCode);
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == RecordAudioRequestCode && grantResults.length > 0) {
            if (grantResults[0] == PackageManager.PERMISSION_GRANTED)
                Toast.makeText(this, "Permission Granted", Toast.LENGTH_SHORT).show();
        }
    }
}

问题原因

  1. 默认音频源限制:系统内置的SpeechRecognizer默认绑定设备内置麦克风,没有自动切换外接USB麦克风的逻辑。
  2. 未指定输入设备:当前代码未在RecognizerIntent中显式指定USB麦克风作为音频输入源,导致API使用系统默认音频通道。
  3. 系统音频路由策略:部分Android设备不会自动将语音识别的音频流路由到USB设备,需要手动配置或代码干预。

解决方法

方法1:显式指定USB麦克风设备(推荐)

从Android 7.0(API 24)开始,RecognizerIntent支持通过EXTRA_AUDIO_DEVICE_ID指定具体的音频输入设备。低版本可 fallback 到EXTRA_AUDIO_SOURCE指定未处理音频源。

步骤1:添加获取USB麦克风ID的工具方法

private int getUsbMicrophoneId() {
    AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
    if (audioManager == null) return -1;

    // 获取所有已连接的音频输入设备ID
    String deviceIdsStr = audioManager.getProperty(AudioManager.PROPERTY_AUDIO_INPUT_DEVICES);
    if (deviceIdsStr == null || deviceIdsStr.isEmpty()) return -1;

    for (String idStr : deviceIdsStr.split(",")) {
        int deviceId = Integer.parseInt(idStr);
        AudioDeviceInfo deviceInfo = audioManager.getAudioDeviceInfo(deviceId);
        // 判断是否为USB类型的音频输入设备
        if (deviceInfo != null && deviceInfo.getType() == AudioDeviceInfo.TYPE_USB_DEVICE) {
            return deviceId;
        }
    }
    return -1;
}

步骤2:修改RecognizerIntent配置

在创建speechRecognizerIntent的代码后添加以下逻辑:

final Intent speechRecognizerIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
speechRecognizerIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
speechRecognizerIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, Locale.getDefault());

// 指定USB麦克风作为输入源
int usbMicId = getUsbMicrophoneId();
if (usbMicId != -1) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        // API 24+支持直接指定设备ID
        speechRecognizerIntent.putExtra(RecognizerIntent.EXTRA_AUDIO_DEVICE_ID, usbMicId);
    } else {
        // 低版本使用未处理音频源,兼容USB设备
        speechRecognizerIntent.putExtra(RecognizerIntent.EXTRA_AUDIO_SOURCE, MediaRecorder.AudioSource.UNPROCESSED);
    }
}

方法2:手动切换系统默认音频输入

引导用户在系统设置中切换默认麦克风:

  1. 进入系统「设置」→「声音与振动」→「音频输入」
  2. 选择Jabra Speak 510 UC作为默认输入设备

方法3:手动捕获USB音频并喂给SpeechRecognizer(复杂但灵活)

如果上述方法无效,可以通过AudioRecord直接从USB麦克风捕获PCM音频数据,再将数据传递给SpeechRecognizer。该方式需要处理音频格式匹配、流传输等细节,适合对音频控制有更高要求的场景。


注意事项

  • 权限检查:确保应用已获取RECORD_AUDIO权限,部分USB设备可能需要额外的USB_PERMISSION权限(需动态申请)。
  • 兼容性:不同厂商的Android设备对USB音频的支持存在差异,需在目标设备上测试验证。
  • API版本:EXTRA_AUDIO_DEVICE_ID仅在API 24及以上可用,低版本需使用EXTRA_AUDIO_SOURCE替代。

内容的提问来源于stack exchange,提问作者Nimila Hiranya

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 17:02:04