本文主要是Android做为Audio Source端,A2DP的基本操作:包括连接、断开连接、设置优先级、获取优先级、获取A2DP连接状态、获取A2DP连接的设备列表等功能。

1.简介

Audio Source(音频源) 音频的输入端对音频数据进行编码,发送到Sink端。 A2DP全名是Advanced Audio Distribution Profile,高质量音频数据传输的协议,其定义里了传送单声道或立体声等高质量音频(区别于蓝牙SCO链路上传输的普通语音)信息的协议和过程。A2DP的典型应用是将音乐播放器的音频数据发送到耳机或音箱。 
A2DP定义了两种角色:

Audio Source(音频源) 音频的输入端对音频数据进行编码,发送到Sink端。 
Audio Sink(音频接收器) 接收到音频数据后,进行解码操作还原出音频。

2.A2DP profile

要想操作A2DP相关,首先要获取A2DP代理对象,获取代理对象的方法比较简单,如下:

  1. mBtAdapter = BluetoothAdapter.getDefaultAdapter();
  2. if(!mBtAdapter.isEnabled()){
  3. //弹出对话框提示用户是后打开
  4. Intent enabler = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
  5. startActivityForResult(enabler, 1);
  6. }
  7. //获取A2DP代理对象
  8. mBtAdapter.getProfileProxy(mContext, mListener, BluetoothProfile.A2DP);

getProfileProxy并不会直接返回A2DP代理对象,而是通过mListener中回调获取。

  1. private ServiceListener mListener = new ServiceListener() {
  2. @Override
  3. public void onServiceDisconnected(int profile) {
  4. if(profile == BluetoothProfile.A2DP){
  5. mA2dp = null;
  6. }
  7. }
  8. @Override
  9. public void onServiceConnected(int profile, BluetoothProfile proxy) {
  10. if(profile == BluetoothProfile.A2DP){
  11. mA2dp = (BluetoothA2dp) proxy; //转换
  12. }
  13. }
  14. };

成功会回调mListener中的onServiceConnected函数,判断proflie是否为BluetoothProfile.A2DP,转换为BluetoothA2dp对象。通过代理对象即可进行A2DP的相关操作了

3.A2DP操作

A2DP连接首先需要与蓝牙耳机进行配对,如何配对这里就不细说了。 
我这里是连接到之前配对过的一个设备。设备名称为:

private final String BT_NAME = "QCY-QY7";

获取该设备,首先获取配对的蓝牙设备,然后遍历这些蓝牙设备,找出蓝牙名称符合条件的设备,就是要操作的设备,

  1. //获取配对的蓝牙设备
  2. Set<BluetoothDevice> bondDevice = mBtAdapter.getBondedDevices();
  3. for(BluetoothDevice device:bondDevice){
  4. //获取指定名称的设备
  5. if(BT_NAME.equals(device.getName())){
  6. mConnectDevice = device;
  7. }
  8. }

mConnectDevice为要操作的设备。

3.1 A2DP连接

  1. private void connectA2dp(BluetoothDevice device){
  2. setPriority(mConnectDevice, 100); //设置priority
  3. try {
  4. //通过反射获取BluetoothA2dp中connect方法(hide的),进行连接。
  5. Method connectMethod =BluetoothA2dp.class.getMethod("connect",
  6. BluetoothDevice.class);
  7. connectMethod.invoke(mA2dp, device);
  8. } catch (Exception e) {
  9. e.printStackTrace();
  10. }
  11. }

BluetoothA2dp中的connect方法是hide的,不能直接访问,需要通过反射的机制获取该方法进行连接。连接成功后手机可以播放音乐,声音就会从蓝牙耳机出来。

3.2 断开连接

  1. private void disConnectA2dp(BluetoothDevice device){
  2. setPriority(mConnectDevice, 0);
  3. try {
  4. //通过反射获取BluetoothA2dp中connect方法(hide的),断开连接。
  5. Method connectMethod =BluetoothA2dp.class.getMethod("disconnect",
  6. BluetoothDevice.class);
  7. connectMethod.invoke(mA2dp, device);
  8. } catch (Exception e) {
  9. e.printStackTrace();
  10. }
  11. }

BluetoothA2dp中的disconnect方法也是hide的,与connect类似.

3.3 设置优先级

设置优先级是必要的,否则可能导致连接或断开连接失败等问题。

  1. public void setPriority(BluetoothDevice device, int priority) {
  2. if (mA2dp == null) return;
  3. try {//通过反射获取BluetoothA2dp中setPriority方法(hide的),设置优先级
  4. Method connectMethod =BluetoothA2dp.class.getMethod("setPriority",
  5. BluetoothDevice.class,int.class);
  6. connectMethod.invoke(mA2dp, device, priority);
  7. } catch (Exception e) {
  8. e.printStackTrace();
  9. }
  10. }

3.4 获取优先级

  1. public int getPriority(BluetoothDevice device) {
  2. int priority = 0;
  3. if (mA2dp == null) return priority;
  4. try {//通过反射获取BluetoothA2dp中getPriority方法(hide的),获取优先级
  5. Method connectMethod =BluetoothA2dp.class.getMethod("getPriority",
  6. BluetoothDevice.class);
  7. priority = (Integer) connectMethod.invoke(mA2dp, device);
  8. } catch (Exception e) {
  9. e.printStackTrace();
  10. }
  11. return priority;
  12. }

3.5  获取与某设备A2DP连接状态

mA2dp.getConnectionState(device);

3.6 获取连接设备列表

  1. //返回值类型List<BluetoothDevice>
  2. mA2dp.getConnectedDevices();

3.7 A2DP是否正在发送音频流

  1. //返回值类型boolean,表示设备是否在通过A2DP发送音频流。
  2. mA2dp.isA2dpPlaying(device);

4.状态监听

通过广播接收者监听A2DP连接状态的改变,A2DP播放状态的改变。

  1. private void initReceiver(){
  2. //注册广播接收者监听状态改变
  3. IntentFilter filter = new IntentFilter(BluetoothA2dp.
  4. ACTION_CONNECTION_STATE_CHANGED);
  5. filter.addAction(BluetoothA2dp.ACTION_PLAYING_STATE_CHANGED);
  6. registerReceiver(mReceiver, filter);
  7. }

广播接收者,通过intent获取状态值。

  1. private BroadcastReceiver mReceiver = new BroadcastReceiver() {
  2. @Override
  3. public void onReceive(Context context, Intent intent) {
  4. String action = intent.getAction();
  5. Log.i(TAG,"onReceive action="+action);
  6. //A2DP连接状态改变
  7. if(action.equals(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED)){
  8. int state = intent.getIntExtra(BluetoothA2dp.EXTRA_STATE, BluetoothA2dp.STATE_DISCONNECTED);
  9. Log.i(TAG,"connect state="+state);
  10. }else if(action.equals(BluetoothA2dp.ACTION_PLAYING_STATE_CHANGED)){
  11. //A2DP播放状态改变
  12. int state = intent.getIntExtra(BluetoothA2dp.EXTRA_STATE, BluetoothA2dp.STATE_NOT_PLAYING);
  13. Log.i(TAG,"play state="+state);
  14. }
  15. }
  16. };

连接小demo:http://download.csdn.net/detail/vnanyesheshou/9841491

转载出处:http://blog.csdn.net/vnanyesheshou/article/details/71713786

Android 蓝牙开发之A2DP基本功能的更多相关文章

  1. Android混合开发之WebViewJavascriptBridge实现JS与java安全交互

    前言: 为了加快开发效率,目前公司一些功能使用H5开发,这里难免会用到Js与Java函数互相调用的问题,这个Android是提供了原生支持的,不过存在安全隐患,今天我们来学习一种安全方式来满足Js与j ...

  2. Android混合开发之WebView与Javascript交互

    前言: 最近公司的App为了加快开发效率选择了一部分功能采用H5开发,从目前市面的大部分App来讲,大致分成Native App.Web App.Hybrid App三种方式,个人觉得目前以Hybri ...

  3. Android安全开发之WebView中的地雷

    Android安全开发之WebView中的地雷 0X01 About WebView 在Android开发中,经常会使用WebView来实现WEB页面的展示,在Activiry中启动自己的浏览器,或者 ...

  4. Android混合开发之WebView使用总结

    前言: 今天修改项目中一个有关WebView使用的bug,激起了我总结WebView的动机,今天抽空做个总结. 混合开发相关博客: Android混合开发之WebView使用总结 Android混合开 ...

  5. Android安全开发之ZIP文件目录遍历

    1.ZIP文件目录遍历简介 因为ZIP压缩包文件中允许存在“../”的字符串,攻击者可以利用多个“../”在解压时改变ZIP包中某个文件的存放位置,覆盖掉应用原有的文件.如果被覆盖掉的文件是动态链接s ...

  6. Android驱动开发之Hello实例

    Android驱动开发之Hello实例:   驱动部分 modified:   kernel/arch/arm/configs/msm8909-1gb_w100_hd720p-perf_defconf ...

  7. android软件开发之webView.addJavascriptInterface循环渐进【二】

    本篇文章由:http://www.sollyu.com/android-software-development-webview-addjavascriptinterface-cycle-of-gra ...

  8. android软件开发之webView.addJavascriptInterface循环渐进【一】

    本篇文章由:http://www.sollyu.com/android-software-development-webview-addjavascriptinterface-cycle-of-gra ...

  9. Android NDK开发之C调用Java及原生代码断点调试(二)

    上一篇中,我们主要学习了Java调用本地方法,并列举了两大特殊实例来例证我们的论据,还没学习的伙伴必须先去阅读下,本次的学习是直接在上一篇的基础上进行了.点击:Android NDK开发之从Java与 ...

随机推荐

  1. HDU 1108.最小公倍数-辗转相除法

    最小公倍数 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submi ...

  2. python 自定义过滤器

    文件目录结构: 新建文件并且命名为“templatetags” , 然后复制 __init__.py文件,拷贝到templatetags文件夹里, __pycache__文件夹可以忽略哈,那是程序运行 ...

  3. (5) go 控制台输入输出、进制转换、原反补码、位运算

    一.控制台接受输入 二.原反补码 三.位运算 四.移位运算

  4. FZU 2297 Number theory【线段树/单点更新/思维】

    Given a integers x = 1, you have to apply Q (Q ≤ 100000) operations: Multiply, Divide. Input First l ...

  5. NetCore2.0 RozarPage自动生成增删改查

    原文链接:https://docs.microsoft.com/zh-cn/aspnet/core/tutorials/web-api-help-pages-using-swagger 上面的只是原文 ...

  6. codevs 1014 装箱问题 2001年NOIP全国联赛普及组

    题目描述 Description 有一个箱子容量为V(正整数,0<=V<=20000),同时有n个物品(0<n<=30),每个物品有一个体积(正整数). 要求n个物品中,任取若 ...

  7. POJ1067 取石子游戏 威佐夫博弈 博弈论

    http://poj.org/problem?id=1067 有两堆石子,数量任意,可以不同.游戏开始由两个人轮流取石子.游戏规定,每次有两种不同的取法,一是可以在任意的一堆中取走任意多的石子:二是可 ...

  8. wannafly挑战赛14

    第一次打wannafly..觉得自己好菜啊... 题目描述 在三维空间中,平面 x = 0, y = 0, z = 0,以及平面 x + y + z = K 围成了一个三棱锥. 整天与整数打交道的小明 ...

  9. 【Splay】bzoj3224 Tyvj 1728 普通平衡树

    #include<cstdio> #include<iostream> #include<cstring> #include<algorithm> us ...

  10. 8VC Venture Cup 2016 - Elimination Round D. Jerry's Protest 暴力

    D. Jerry's Protest 题目连接: http://www.codeforces.com/contest/626/problem/D Description Andrew and Jerr ...