• android蓝牙耳机下的语音(输入/识别)及按键监听


    背景:本人负责公司android平台的app开发,最近要开发一个语音助手类的app,类似于灵犀语音助手、虫洞语音助手等。其中有两个蓝牙耳机下的语音识别问题,比较折腾人,问题描述:1.蓝牙耳机连接下捕获蓝牙按键事件,启动语音识别;2.正常启动识别时也必须通过蓝牙耳机录入音频进行语音识别。这两个问题,测试发现灵犀语音助手都解决了,所以本人负责的这个app也必须解决。网上搜了相关的资料,基本上是凤毛麟角,因此本人在此贡献一点小发现供大家参考,如有不对的地方欢迎指正。

           针对第一个问题,蓝牙耳机的按键监听,墙内墙外的资料搜遍,没有发现完美的解决方案(这里看到有人提出的解决办法:http://blog.csdn.net/kangear/article/details/40430673,感觉有点另类,而且也不适合我的app的应用场景,所以没尝试),虽然接听键(该键还有很多功能,不细说,以下都称接听键)的单按、双按没法监听,但是长按却是可以捕获到,默认情况下,已经连接到android手机的蓝牙耳机,长按接听键几秒后会系统会发出一个action=android.intent.action.VOICE_COMMAND的Intent,灵犀语音助手就是使用这个来监听长按的,既然如此,我就仿照灵犀来做吧:

           1.首先,在AndroidManifest.xml中指定的一个activity (用于捕获蓝牙耳机长按事件的activity,以下以A代替之)中添加:

             <intent-filter android:priority="2147483647">
                <action android:name="android.intent.action.VOICE_COMMAND" />
                <category android:name="android.intent.category.DEFAULT" />
               </intent-filter>

    当在连接了蓝牙耳机的情况下,长按接听键几秒,出现提示音后(请戴着蓝牙耳机按,要不听不见,一不小心就成关机了),马上松开,就会弹出一个选择启动某个app的对话框,凡是添加了以上intent-filter的activity的app都会出现对话框中,这需要引导用户选择你的app并选择始终启动你的app(注意A的launchMode,我这里建议设成singleTask),选中确定之后你的app就会被启动,如果A还没有创建,那A自然会被创建啦,如果A已经被创建了,则调用A的onNewIntent(Intent intent)方法,因此你只要在A中检查接收到的intent的action就能监听蓝牙耳机的长按事件了。

           2.关于蓝牙耳机下的识别问题,本app用的语音识别sdk是讯飞的,针对这个问题讯飞有给出解决方法:

    在调用语音识别引擎识别前,打开sco,关键代码:

           AudioManager mAudioManager = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
           mAudioManager.setBluetoothScoOn(true);
           mAudioManager.startBluetoothSco();

    识别启动并识别完成后,关闭sco:

           mAudioManager.setBluetoothScoOn(false);
           mAudioManager.stopBluetoothSco();

    按照这个方法,便可以实现音频录入。

            当然你会问why,这里简单的介绍一下蓝牙耳机的两种链路,A2DP及SCO。android的api表明:A2DP是一种单向的高品质音频数据传输链路,通常用于播放立体声音乐;而SCO则是一种双向的音频数据的传输链路,该链路只支持8K及16K单声道的音频数据,只能用于普通语音的传输,若用于播放音乐那就只能呵呵了。两者的主要区别是:A2DP只能播放,默认是打开的,而SCO既能录音也能播放,默认是关闭的。既然要录音肯定要打开sco啦,因此识别前调用上面的代码就可以通过蓝牙耳机录音了,录完记得要关闭。

            虽然上面的方法能够实现录音,但测试中发现一个问题:startBluetoothSco()和stopBluetoothSco()时,蓝牙耳机都会有一个提示音,如果识别本身就有提示音,那么加上蓝牙的提示音就会让人莫名其妙了,在体验上很不友好。而本人在测试灵犀的蓝牙功能时竟发现没有提示音?为了完整的复制,必须把提示音去掉,然后我又上网搜了一遍,资料真的是凤毛麟角,没什么收获。无奈中翻翻android关于蓝牙部分的api,发现打开及关闭sco还有另外一种办法,那就是android.bluetooth.BluetoothHeadset类的startVoiceRecognition(BluetoothDevice device)及stopVoiceRecognition(BluetoothDevice device),经过测试发现,通过这两个方法打开sco及关闭sco蓝牙耳机是不会有提示音,题外说一句:讯飞真会坑!!!下面列出关键代码:

                    //以下代码用于在已经连接蓝牙耳机的状态下获取BluetoothHeadset,监听蓝牙耳机的连接只需接收action=BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED的广播即可,此处不再赘述。

    private BluetoothHeadset bluetoothHeadset;

    BluetoothProfile.ServiceListener blueHeadsetListener=new BluetoothProfile.ServiceListener() {

    @Override
    public void onServiceDisconnected(int profile) {
    Log.i("blueHeadsetListener", "onServiceDisconnected:"+profile);
    if(profile==BluetoothProfile.HEADSET){
    bluetoothHeadset=null;
    }
    }

    @Override
    public void onServiceConnected(int profile, BluetoothProfile proxy) {
    Log.i("blueHeadsetListener", "onServiceConnected:"+profile);
    if(profile==BluetoothProfile.HEADSET){
    bluetoothHeadset=(BluetoothHeadset) proxy;
    }
    }
    };

    private void initBlueToothHeadset(){
             BluetoothAdapter adapter;
             if(android.os.Build.VERSION.SDK_INT<android.os.Build.VERSION_CODES.JELLY_BEAN_MR2){//android4.3之前直接用BluetoothAdapter.getDefaultAdapter()就能得到BluetoothAdapter
              adapter=BluetoothAdapter.getDefaultAdapter();
             }
             else{
              BluetoothManager bm=(BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
              adapter=bm.getAdapter();
             }
             adapter.getProfileProxy(context, blueHeadsetListener, BluetoothProfile.HEADSET);
     }

            
           如果要通过蓝牙耳机的sco链路输出音频,必须要在sco打开的状态下,把streamType设置为AudioManager.STREAM_VOICE_CALL。
     
           最后有两点要注意的:
         1.测试发现,当sco打开时,第1点中提到的蓝牙耳机接听键长按将不会发送android.intent.action.VOICE_COMMAND,必须在sco关闭时长按才会有这一事件。
         2.sco打开及关闭都是比较消耗时间的,特别是打开,大概是几百毫秒-几秒的时间,请注意要在sco彻底打开时再启动语音识别,sco的状态可以通过接收action=AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED的广播监听,或者使用BluetoothHeadset的isAudioConnected(BluetoothDevice device)判断。测试发现BluetoothHeadset的相关方法打开sco比较快(个人感觉,不明真相,求大神科普)。
  • 相关阅读:
    Thinking in java(八)-正则表达式
    order by与索引
    order by与索引
    004_常量的设置
    008_ajax没有跳转页面的错误
    007_缺少aspactj依赖
    006_为什么我的本机地址是0.0.0.0.0.1
    005_mybatis逆向工程错误
    004_当用数据库账号密码不对时?
    059_SSM——JDK动态代理是怎么回事?它又是怎么运用到了SSM框架中的?
  • 原文地址:https://www.cnblogs.com/dongweiq/p/7941014.html
Copyright © 2020-2023  润新知