• 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比较快(个人感觉,不明真相,求大神科普)。
  • 相关阅读:
    Codeforces Round #649 (Div. 2) D. Ehab's Last Corollary
    Educational Codeforces Round 89 (Rated for Div. 2) E. Two Arrays
    Educational Codeforces Round 89 (Rated for Div. 2) D. Two Divisors
    Codeforces Round #647 (Div. 2) E. Johnny and Grandmaster
    Codeforces Round #647 (Div. 2) F. Johnny and Megan's Necklace
    Codeforces Round #648 (Div. 2) G. Secure Password
    Codeforces Round #646 (Div. 2) F. Rotating Substrings
    C++STL常见用法
    各类学习慕课(不定期更新
    高阶等差数列
  • 原文地址:https://www.cnblogs.com/dongweiq/p/7941014.html
Copyright © 2020-2023  润新知