原以为手机连上蓝牙耳机就能录入语音信号,too young to simple.
经过一番搜寻与折腾,找到两种方式:
第一种方式是通过sco,这种方式有个缺点:连接上和释放时会有嘟的一声
第二种方式则没这个缺点
设置蓝牙权限AndroidManifest.xml
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.BROADCAST_STICKY" />
<uses-permission android:name="android.permission.BLUETOOTH" />
private AudioManager mAudioManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
mAudioManager = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
//启动蓝牙输入
btStart();
}
//启动蓝牙输入
private void btStart() {
if (mAudioManager != null) {
mAudioManager.setBluetoothScoOn(true);
mAudioManager.startBluetoothSco();
}
}
//停止蓝牙输入--如果不停止,播放语音的时候没声音
private void btStop() {
if (mAudioManager != null) {
mAudioManager.setBluetoothScoOn(false);
mAudioManager.stopBluetoothSco();
}
}
语音播报用的是百度TTS SDK,如果不调用btStop
停止蓝牙sco,会听不到任何声音。
为了能听到声音,在百度TTS 的回调接口SpeechSynthesizerListener
的合成开始阶段onSynthesizeStart
调用btStop
停止sco
,当语音播放完成onSpeechFinish
之后调用btStart
重新获取语音输入通道。(因为我的app是带语音唤醒功能的,所以要一直让蓝牙耳机采集到输入信号)
package com.twx.poc.voiceprint.baidu.tts;
import android.media.AudioManager;
import android.util.Log;
import com.baidu.tts.client.SpeechError;
import com.baidu.tts.client.SpeechSynthesizerListener;
import com.twx.poc.voiceprint.util.bluetooth.MyBluetooth;
public class SpeechListener implements SpeechSynthesizerListener {
private static final String TAG = "SpeechListener";
private AudioManager mAudioManager;
public SpeechListener(AudioManager mAudioManager) {
this.mAudioManager = mAudioManager;
}
@Override
public void onSynthesizeStart(String s) {
Log.i(TAG, "onSynthesizeStart: 开始合成语音...");
btStop();
}
@Override
public void onSynthesizeDataArrived(String s, byte[] bytes, int i, int i1) {
}
@Override
public void onSynthesizeFinish(String s) {
Log.i(TAG, "onSynthesizeStart: 合成语音完成...");
}
@Override
public void onSpeechStart(String s) {
}
@Override
public void onSpeechProgressChanged(String s, int i) {
}
@Override
public void onSpeechFinish(String s) {
Log.i(TAG, "onSpeechFinish: 完成播放");
btStart();
}
@Override
public void onError(String s, SpeechError speechError) {
Log.e(TAG, "onError: 语音播放出错了"+speechError.description );
}
private void btStart() {
if (mAudioManager != null) {
mAudioManager.setBluetoothScoOn(true);
mAudioManager.startBluetoothSco();
}
}
private void btStop() {
if (mAudioManager != null) {
mAudioManager.setBluetoothScoOn(false);
mAudioManager.stopBluetoothSco();
}
}
}
这个方案的好处是连接与释放的时候没有嘟声
参考博文:
权限:在soc方案的基础上加一个
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
创建一个MyBluetooth
类,该类负责获取已连接的蓝牙设备、启动、停止蓝牙语音输入。
package com.twx.poc.voiceprint.util.bluetooth;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
public class MyBluetooth {
private BluetoothHeadset bluetoothHeadset;
private BluetoothDevice btDevice;
BluetoothProfile.ServiceListener blueHeadsetListener = new BluetoothProfile.ServiceListener() {
@Override
public void onServiceConnected(int profile, BluetoothProfile proxy) {
if(profile==BluetoothProfile.HEADSET){
bluetoothHeadset=(BluetoothHeadset) proxy;
}
if (bluetoothHeadset != null) {
List<BluetoothDevice> devices = bluetoothHeadset.getConnectedDevices();
System.out.println("蓝牙已连接...数量"+devices.size());
for (int i = 0; i < devices.size(); i++) {
System.out.println("名称: "+devices.get(i).getName());
btDevice = devices.get(i);
}
//这里启动蓝牙语音输入
start();
}
}
@Override
public void onServiceDisconnected(int profile) {
if(profile==BluetoothProfile.HEADSET){
bluetoothHeadset=null;
}
}
};
public void initBlueToothHeadset(Context context,Activity activity){
BluetoothAdapter adapter;
//android4.3之前直接用BluetoothAdapter.getDefaultAdapter()就能得到BluetoothAdapter
if(android.os.Build.VERSION.SDK_INT<android.os.Build.VERSION_CODES.JELLY_BEAN_MR2){
adapter=BluetoothAdapter.getDefaultAdapter();
}else {
BluetoothManager bm=(BluetoothManager) activity.getSystemService(Context.BLUETOOTH_SERVICE);
adapter=bm.getAdapter();
}
adapter.getProfileProxy(context, blueHeadsetListener, BluetoothProfile.HEADSET);
}
/**
* 蓝牙开始录入语音...
*/
public void start() {
if (btDevice != null) {
System.out.println(btDevice.getName()+" 蓝牙开始录入语音...");
bluetoothHeadset.startVoiceRecognition(btDevice);
}
}
/**
* 蓝牙停止录入语音...
*/
public void stop() {
if (btDevice != null) {
System.out.println(btDevice.getName()+" 蓝牙停止录入语音...");
bluetoothHeadset.stopVoiceRecognition(btDevice);
}
}
}
在activity
中使用MyBluetooth
:
@Override
protected void onCreate(Bundle savedInstanceState) {
MyBluetooth bluetooth = new MyBluetooth();
//获取已连接的BluetoothDevice并启动蓝牙输入
bluetooth.initBlueToothHeadset(this,this);
//百度语音播报回调接口
SpeechListener speechListener = new SpeechListener(bluetooth);
}
在SpeechListener
中控制蓝牙耳机的语音输入和释放(为了语音播报能正常进行,必须释放)
public class SpeechListener implements SpeechSynthesizerListener {
private static final String TAG = "SpeechListener";
private MyBluetooth bluetooth;
public SpeechListener(MyBluetooth bluetooth) {
this.bluetooth = bluetooth;
}
@Override
public void onSynthesizeStart(String s) {
Log.i(TAG, "onSynthesizeStart: 开始合成语音...");
btStop();
}
@Override
public void onSynthesizeDataArrived(String s, byte[] bytes, int i, int i1) {
}
@Override
public void onSynthesizeFinish(String s) {
Log.i(TAG, "onSynthesizeStart: 合成语音完成...");
}
@Override
public void onSpeechStart(String s) {
}
@Override
public void onSpeechProgressChanged(String s, int i) {
}
@Override
public void onSpeechFinish(String s) {
Log.i(TAG, "onSpeechFinish: 完成播放");
btStart();
}
@Override
public void onError(String s, SpeechError speechError) {
Log.e(TAG, "onError: 语音播放出错了"+speechError.description );
}
private void btStart() {
if (bluetooth != null) {
bluetooth.start();
}
}
private void btStop() {
if (bluetooth != null) {
bluetooth.stop();
}
}
}