Android蓝牙开发系列文章

您所在的位置:网站首页 手机中文稿与数据什么意思 Android蓝牙开发系列文章

Android蓝牙开发系列文章

2023-03-26 09:32| 来源: 网络整理| 查看: 265

本文是蓝牙音频相关的第3篇文章,查阅其他内容,请点击《Android蓝牙开发系列文章-策划篇》。

目前a2dp相关的内容有:

《Android蓝牙开发系列文章-AudioTrack播放PCM音频》

《Android蓝牙开发系列文章-蓝牙音箱连接》

我们通常直接手机听歌或者接个蓝牙音箱来听歌,其实你的手机也可以变成一个蓝牙音箱来使用。

怎么来做这个转变呢?让我一起学起来吧~

本文主要内容包括:1.什么是a2dp sink? 2.如何实现a2dp和a2dp sink状态的切换?

目录

1.什么是a2dp sink?

2.如何实现a2dp和a2dp sink状态的切换?

2.1将设备暂停a2dp

2.2启动a2dp sink

1.什么是a2dp sink?

两个蓝牙设备连接之后,一个设备提供音频数据,另外一个设备出声音,我们将提供数据的一端称为a2dp source(源端),发出声音的一端称为a2dp sink(目的端)。

也就是说,a2dp与a2dp sink是两个相对的状态,一个蓝牙设备一个时刻只能处于其中的一种状态。

现在一些智能设备可以实现a2dp与a2dp sink状态之间的切换(但一个时刻只能是其中一个状态)。

与a2dp/a2dp sink协议紧密关联的一个协议之avrcp(Audio/Video Remote Control Profile)协议,该协议实现了从sink端到souce端的反向控制,例如,暂停、停止、启动重放、音量控制及其它类型的远程控制操作。

2.如何实现a2dp和a2dp sink状态的切换?

在实际动手完成两个状态切换前,需要明确你的设备是否支持这两种状态。对于耳机、音箱这类设备而言,即使将它砸了,它也很难切到a2dp source状态,因为它一出生就决定了自己没有这个状态的使用场景,不信你可以砸了试一下,O(∩_∩)O哈哈~

而对于通常作为音乐播放端的某些手机和智能电视是可能切到sink状态的。 

怎么来判断自己的手机或者电视是否支持a2dp sink呢?大体可以按照如下步骤确定,但是不是说这个步骤都满足了,你的设备肯定是支持a2dp sink的,因为我们看不到设备的源码,甚至我们连root权限都没有。

确认设备是否自带sink功能的使用场景(一般来说,如果没有自带使用场景,sink功能应该要默认关闭,不然就是给自己的产品挖了一个坑)串口执行:dumpsys package com.android.bluetooth,看一下是否支持A2dpSinkService去跟蓝牙芯片方案商确认是否支持sink功能参考本文的代码,写一个demo来试一下

下面来讲一下我们的demo实现:

2.1将设备暂停a2dp

在停掉a2dp前,我们需要将处于连接状态的设备进行断开。

为了让我们的设备可以被其他设备扫描到和可被连接,我们需要将设备的蓝牙扫描模式设置成可被发现、可被连接。

如上提到的两点也是很重要的,我的demo里面没有实现它,是通过在设置中进行操作来替代了代码实现。

停掉a2d的动作对于应用层来说就是停掉a2dp service,这个动作会触发一些系列的a2dp状态清理动作,这个动作是从上而下的一整套,不仅仅是设计Host端,也涉及Controller。

public void stopSource() { Intent intent = new Intent(); intent.setAction("com.android.bluetooth/.a2dp.A2dpService"); intent.setPackage("com.android.bluetooth"); intent.putExtra("action", "com.android.bluetooth.btservice.action.STATE_CHANGED"); intent.putExtra(BluetoothAdapter.EXTRA_STATE, 10); startService(intent); }

你也许会问:你怎么知道这样写就可以启动A2dpService的?

如果,你研究过蓝牙开关流程的话,你应该看到过各种profile的启动流程,也就是说以上这段代码就是从源码中摘出来的,

Android源码如下:

@SuppressWarnings("rawtypes") private void setGattProfileServiceState(Class[] services, int state) { if (state != BluetoothAdapter.STATE_ON && state != BluetoothAdapter.STATE_OFF) { Log.w(TAG,"setGattProfileServiceState(): invalid state...Leaving..."); return; } int expectedCurrentState= BluetoothAdapter.STATE_OFF; int pendingState = BluetoothAdapter.STATE_TURNING_ON; if (state == BluetoothAdapter.STATE_OFF) { expectedCurrentState= BluetoothAdapter.STATE_ON; pendingState = BluetoothAdapter.STATE_TURNING_OFF; } for (int i=0; i


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3