Android在蓝牙开发过程中,经常需要蓝牙成功连接后,控制像音箱,蓝牙灯之类的硬件。这时候,打开手机的蓝牙设置,常会看到电话音频和媒体音频,这两个是什么鬼?

从开发Android到现在,我感觉都是懵懵懂懂的,每天和硬件工程师在一起。只能说算是能开发Android app,至于这些协议总是啃了忘,忘了啃。下面说一下,我的理解。如果有不对的地方,烦请留言或者私信告诉我。

蓝牙连接时.jpg

如上图中,一般电话音频是否支持要和嵌入式工程师确认。蓝牙芯片如果不支持电话音频,这里就不会显示出来了。
这里说一下电话音频的协议:HSP和HFP。
先看定义:

HSP(手机规格)– 提供手机(移动电话)与耳机之间通信所需的基本功能。
HFP(免提规格)– 在 HSP 的基础上增加了某些扩展功能,原来只用于从固定车载免提装置来控制移动电话。

这个网上的解释我觉得是最好理解的了。这里要重点说一下连接HSP的核心代码处理了。

public class Hfp {public static final String TAG = "Hfp";private BluetoothAdapter mBluetoothAdapter;private BluetoothProfile hfpProfile;private static Hfp INSTANCE;private boolean enableHfp = false;private Hfp() {    mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();    enableHfp = mBluetoothAdapter.getProfileProxy(XApplication.getInstance(), new ProfileListener(), BluetoothProfile.HEADSET);}public boolean isEnableHfp(){    return enableHfp;}public synchronized static Hfp getInstance() {    if (INSTANCE == null) {        INSTANCE = new Hfp();    }    return INSTANCE;}public class ProfileListener implements BluetoothProfile.ServiceListener {    @Override    public void onServiceConnected(int profile, BluetoothProfile proxy) {        if (profile == BluetoothProfile.HEADSET) {            hfpProfile = proxy;        }    }    @Override    public void onServiceDisconnected(int profile) {        Log.i(TAG, "onServiceDisconnected="+profile);    }}public int getHfpState(){    if(mBluetoothAdapter != null){        return mBluetoothAdapter.getProfileConnectionState(BluetoothProfile.HEADSET);    }else{        return -1;    }}public BluetoothDevice getSysHfpConnected(){    List devices = DeviceManager.getSysPairedDevices();    for(BluetoothDevice device : devices){        if(getHfpState(device)){            return device;        }    }    return null;}public boolean getHfpState(BluetoothDevice device){    Logg.e(TAG, "hfpProfile_-->" + hfpProfile);    if(hfpProfile != null && hfpProfile.getConnectionState(device) == BluetoothProfile.STATE_CONNECTED){        return true;    }    return false;}

}

————————————————————————————————————
估计没有写注释很多人还是云里雾里的。说一下具体思路:
构造函数:Hfp()
获取蓝牙适配器:(蓝牙开发中常用代码)

 mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();//判断Hsp的状态enableHfp = mBluetoothAdapter.getProfileProxy(XApplication.getInstance(), new   ProfileListener(), BluetoothProfile.HEADSET);注意:XApplication.getInstance()XApplication就是你的项目的application,记得绑定在一起。

getHfpState(),getSysHfpConnected(),getHfpState三个方法根据实际情况使用。
至于:public class ProfileListener implements BluetoothProfile.ServiceListener
记得看Google的api,上面都有。官方推荐的获取hsp的代理。

再说一下:
A2DP,AVRCP。
找一个能看懂的解释:
A2DP(高级音频传送规格)– 允许传输立体声音频信号。 (相比用于 HSP 和 HFP 的单声道加密,质量要好得多)。
AVRCP(音频/视频遥控规格)–用于从控制器(如立体声耳机)向目标设备(如装有 Media Player 的电脑)发送命令(如前跳、暂停和播放)。

而实际开发中,Android工程师要控制的就是A2DP的连接了。逻辑和获取HSP的大致差不多。
构造函数:

     mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();    mBluetoothAdapter.getProfileProxy(XApplication.getInstance(), new   profileListener(), BluetoothProfile.A2DP);获取A2DP的代理:   public class profileListener implements BluetoothProfile.ServiceListener {    @Override    public void onServiceConnected(int profile, BluetoothProfile proxy) {        Log.i(TAG, "connect to a2dp server");        a2dpProfile = proxy;    }    @Override    public void onServiceDisconnected(int profile) {        Log.i(TAG, "disconnect to a2dp server");        a2dpProfile = null;    }}判断A2DP的连接状态:  public boolean getA2dpState(BluetoothDevice device){    if(a2dpProfile != null && a2dpProfile.getConnectionState(device) ==     BluetoothProfile.STATE_CONNECTED){        return true;    }    return false;}

A2DP与设备相连:

public void a2dpConnect(BluetoothDevice device){    if(a2dpProfile != null){        BluetoothA2dp a2dp = (BluetoothA2dp) a2dpProfile;        Class<? extends BluetoothA2dp> clazz = a2dp.getClass();        Method m2;        try {            Log.i(TAG,"use reflect to connect a2dp");            m2 = clazz.getMethod("connect",BluetoothDevice.class);            m2.invoke(a2dp, device);        } catch (Exception e) {            Log.e(TAG,"error:" + e.toString());        }    }}

注意了:这里运用到了Java反射的原理。


在实际开发中:关于A2DP,手机支持A2DP的(安卓机都是标配了),只需要通过广播就可以获取状态了。我实际在开发中,建议借鉴网络连接的逻辑,一旦A2DP中断,蓝牙音响设备自然就没有声音了。所以,必须是全局的。

关于AVRCP,这部分嵌入式工程师的逻辑多,硬件上的按键可以控制手机app的,比如按键加减时,可以与app交互。

关于HSP,HFP。尽管可以实现手机来电时,硬件设备也会响,自然接听时,会被别人听到,所以接听时,需要嵌入式工程师做额外处理。Android工程师看情况要不要配合一下。

还是那句老话,强烈建议学习Google 官方在github的demo:https://github.com/googlesamples/
然后再根据自己的实际情况代码的扩展。


这里回答一下评论里面feer921的一个问题:如何判断 其他蓝牙设备实现了哪些Profile呢?即是如何判断某设备是媒体音频、电话音频的呢?

根据你获取的蓝牙设备。假设你拿到了为:device。

获取它的设备对象:

  final int deviceClass = device.getBluetoothClass().getDeviceClass();

然后:

 final int deviceClassMasked = deviceClass & 0x1F00;    if(deviceClass == BluetoothClass.Device.AUDIO_VIDEO_HEADPHONES)    {       //耳机    }    else if(deviceClass == BluetoothClass.Device.AUDIO_VIDEO_MICROPHONE)    {         //麦克风    }    else if(deviceClassMasked == BluetoothClass.Device.Major.COMPUTER)    {        //电脑    }    else if(deviceClassMasked == BluetoothClass.Device.Major.PHONE)    {        //手机    }    else if(deviceClassMasked == BluetoothClass.Device.Major.HEALTH)    {        //健康类设备    }    else    {        //蓝牙:比如蓝牙音响。    }

更多相关文章

  1. Android之使用SoundPool播放一小段音频,实现猜歌的功能
  2. Android游戏编程之音频编程
  3. 将你的老旧Android平板或手机改造成服务器
  4. Android中的网络应用之网页设置,检测、配置用户设备属性。
  5. Android视频编辑器(五)音频编解码、从视频中分离音频、音频混音、
  6. 【Android】蓝牙开发——经典蓝牙:配对与解除配对 & 实现配对或连
  7. 跟Google学习Android开发-起始篇-支持不同的设备(3)
  8. android集成Umeng推送获取不到device_token也收不到消息,但是在Um
  9. android实现MP3音频录制(lame,支持暂停)

随机推荐

  1. 【Android】ExpandableListView二级列表
  2. Android之网络通信
  3. Android 之 Android目录
  4. 第3.3.1节 处理手势操作
  5. Android常见报错之 - Only the original
  6. Android脚本语言环境 SL4A
  7. 平安科技移动开发二队技术周报(第十三期)
  8. 2017年11月1日Android职位数据分析
  9. 史上最全的android studio 插件大全整理
  10. Android之ActionBar学习