我正在尝试从蓝牙耳机录制音频并对其进行分析,为此我使用了对象:android.media.AudioRecord,我的问题是,对于一些与安卓版本相结合的设备,我从手机麦克风而不是蓝牙耳机获得录音。
在某些情况下,我可以解决这个问题——如果当我创建这个对象时,我将不同的音频源类型传递给它的构造函数。
例如,我看到,为了在Nexus 6和Android 5.0中使用蓝牙耳机进行录制,我需要构建这样的AudioRecord:
audioRecord = new AudioRecord(MediaRecorder.AudioSource.DEFAULT, 44100, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, 4410);
但如果我试着对一款名为"THL T6S"的手机使用相同的代码,它也有Android 5.0,录音来自手机麦克风。如果我想从这款手机的耳机中获得它,我需要写下:
audioRecord = new AudioRecord(MediaRecorder.AudioSource.VOICE_COMMUNICATION, 44100, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, 4410);
但当然,我无法在代码中涵盖手机类型和操作系统版本的所有可能组合。
我该如何解决?
附上所有相关代码。
谢谢。
这是我的蓝牙Sco级
public class BluetoothSco {
private static BluetoothSco instance = null;
// Context
private Context mContext;
private Service service;
// Logcat TAG
private final String TAG = BluetoothSco.class.getSimpleName();
// AudioMode
public static final int MODE_IN_CALL = 1;
public static final int MODE_IN_COMMUNICATION = 2;
public static final int MODE_NORMAL = 3;
// BluetoothAdapter
private final BluetoothAdapter btAdapter = BluetoothAdapter.getDefaultAdapter();
protected BluetoothSco() { }
public static BluetoothSco getInstance(Context context) {
if(instance == null) {
instance = new BluetoothSco();
instance.mContext = context;
instance.service = (Service) context;
}
return instance;
}
// Start Sco
public synchronized void startSco(final int audioMode) {
Runnable runnable = new Runnable() {
@Override
public void run() {
if (btAdapter == null) {
Log.i(TAG, "This device does not support Bluetooth");
return;
}
else if (!btAdapter.isEnabled()) {
Log.i(TAG, "Bluetooth headset is disconnected. Would you like to monitor manually?");
return;
}
AudioManager audioManager = (AudioManager) service.getSystemService(Context.AUDIO_SERVICE);
if (!audioManager.isBluetoothScoAvailableOffCall()) {
Log.i(TAG, "Off-call Bluetooth audio not supported on this device.");
return;
}
if (audioMode == BluetoothSco.MODE_IN_CALL) {
audioManager.setMode(AudioManager.MODE_IN_CALL);
}
else if (audioMode == BluetoothSco.MODE_IN_COMMUNICATION) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
audioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
}
else {
audioManager.setMode(AudioManager.MODE_NORMAL);
}
}
else if (audioMode == BluetoothSco.MODE_NORMAL) {
audioManager.setMode(AudioManager.MODE_NORMAL);
}
//Roni - temp code/////////
//audioManager.setMode(AudioManager.MODE_IN_CALL);
////////////////////
audioManager.setBluetoothScoOn(true);
try{
audioManager.startBluetoothSco();
Log.v(TAG, "Bluetooth SCO Started");
}
catch(NullPointerException ex){
Log.i(TAG, "Bluetooth headset is disconnected. Would you like to monitor manually?");
}
}
};
runnable.run();
}
public synchronized void stopSco() {
Runnable runnable = new Runnable() {
@Override
public void run() {
AudioManager audioManager = (AudioManager) service.getSystemService(Context.AUDIO_SERVICE);
try {
audioManager.setBluetoothScoOn(false);
audioManager.stopBluetoothSco();
audioManager.setMode(AudioManager.MODE_NORMAL);
Log.v(TAG, "Bluetooth SCO Stopped");
}
catch (Exception e) {
Log.e(TAG, e.getMessage());
}
}
};
runnable.run();
}
}
以下是我如何初始化AudioRecord和蓝牙Sco
audioRecord = new AudioRecord(Options.audioSource, Options.sampleRate, Options.channelConfig,
Options.audioEncoding, Options.numBuffers * Math.max(minBufSize, bufferSizeBytes));
mBluetoothSco.startSco(BluetoothSco.MODE_NORMAL);
audioRecord.startRecording();
我也遇到了同样的问题。对我来说,添加以下内容修复了这个问题:
audioManager.setMode(AudioManager.VOICE_COMMUNICATION);
代码需要注意的细节(摘要):
- 设置AudioManager模式并启动SCO
mAudioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
mAudioManager.setBluetoothScoOn(true);
mAudioManager.startBluetoothSco();
- AudioRecord使用VOICE_COMMUNICATION进行初始化,在此处输入链接描述
new AudioRecord(VOICE_COMMUNICATION, sampleRateInHz, channelConfig, audioFormat, recordingBufferSize)
通过这些,我可以使用蓝牙在React Native中进行录制。