蓝牙基础浅析

蓝牙

由于项目中负责了蓝牙音乐模块,所以也对蓝牙做了一点点基础研究

申请权限

    <uses-permission android:name="android.permission.BLUETOOTH" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />

确认蓝牙功能

BluetoothManager mBluetoothManager = (BluetoothManager) requireContext()
            .getSystemService(Context.BLUETOOTH_SERVICE);
BluetoothAdapter mBluetoothAdapter = mBluetoothManager.getAdapter();
//在API17及以下版本
//BluetoothAdapter mDefaultAdapter = BluetoothAdapter.getDefaultAdapter();
if (mBluetoothAdapter != null) {
    //说明支持蓝牙功能
}

开启蓝牙

//确认蓝牙是否开启,未开启进行蓝牙打开控制
if (!mBluetoothAdapter.isEnabled()) {
   Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
   startActivityForResult(enableBtIntent, 200);
}
//接收蓝牙开关请求结果
@Override
public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        Log.d(TAG, "onActivityResult: requestCode = " + requestCode);
        if (requestCode == 200) {
            if (resultCode == RESULT_OK) {
                // 用户已开启蓝牙
                Log.d(TAG, "onActivityResult: 用户已开启蓝牙");
            } else {
                // 用户未开启蓝牙
                Log.d(TAG, "onActivityResult: 用户未开启蓝牙");
            }
        }
}

获取配对过的蓝牙

BluetoothManager mBluetoothManager = (BluetoothManager) requireContext()
            .getSystemService(Context.BLUETOOTH_SERVICE);
BluetoothAdapter mBluetoothAdapter = mBluetoothManager.getAdapter();
Set<BluetoothDevice> bondedDevices = mBluetoothAdapter.getBondedDevices();
for (BluetoothDevice bondedDevice : bondedDevices) {
    Log.d(TAG, "onViewCreated: bondedDevice = " + bondedDevice);
}

扫描蓝牙并配对

权限

扫描蓝牙需要以下运行时权限,进行控制

    <!-- google在android6.0之后,为了更好的保护用户的数据安全,所有需要访问硬件唯一标识符的地方都需要申请位置权限 -->
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

实现

IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
requireContext().registerReceiver(mScanDevicesReceiver, filter);
mBinding.discoveryBluetooth.setOnClickListener(new View.OnClickListener() {
         @Override
         public void onClick(View v) {
            Log.d(TAG, "onClick: discoveryBluetooth");
            mBluetoothAdapter.startDiscovery();
         }
});  
public BroadcastReceiver mScanDevicesReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (intent.getAction().equals(BluetoothDevice.ACTION_FOUND)) {
                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                Log.d(TAG, "onReceive: device = " + device.getAddress()
                    + " device name = " + device.getName());
                // 如果已经找到想要的设备,可以停止扫描
                mBluetoothAdapter.cancelDiscovery();
                // 与发现的蓝牙设备配对
                device.createBond();
            }
        }
    };

蓝牙连接

蓝牙设备间是通过socket通信,C/S架构,一个为服务端,一个为client段;由于蓝牙连接是耗时操作,因此我们需要在子线程中进行调用实现

服务端
public class AcceptThread extends Thread {
    private static final String TAG = AcceptThread.class.getSimpleName();
    private final BluetoothServerSocket mmServerSocket;
    private BluetoothAdapter mBluetoothAdapter;
    public static final String NAME = "CUSTOM_NAME";
    public static final UUID MY_UUID = UUID.fromString("1231233213");

    public AcceptThread(BluetoothAdapter adapter) {
        mBluetoothAdapter = adapter;
        BluetoothServerSocket tmp = null;
        try {
            tmp = mBluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
        } catch (IOException e) {
            Log.e(TAG, "Socket's listen() method failed", e);
        }
        mmServerSocket = tmp;
    }

    public void run() {
        BluetoothSocket socket = null;
        try {
            socket = mmServerSocket.accept();
            if (socket != null) {
                //TODO 用来处理数据
                mmServerSocket.close();
            }
        } catch (IOException e) {
            Log.e(TAG, "Socket's accept() method failed", e);
        }
    }

    public void cancel() {
        try {
            mmServerSocket.close();
        } catch (IOException e) {
            Log.e(TAG, "Could not close the connect socket", e);
        }
    }
}
客户端
public class ConnectThread extends Thread {
    private static final String TAG = ConnectThread.class.getSimpleName();
    private final BluetoothSocket mSocket;
    private final BluetoothDevice mDevice;
    public static final UUID MY_UUID = UUID.fromString("1231233213");

    public ConnectThread(BluetoothDevice device) {
        BluetoothSocket tmp = null;
        mDevice = device;

        try {
            tmp = mDevice.createRfcommSocketToServiceRecord(MY_UUID);
        } catch (IOException e) {
            Log.e(TAG, "Socket's create() method failed", e);
        }
        mSocket = tmp;
    }

    public void run() {
        try {
            mSocket.connect();
            //TODO 处理数据
        } catch (IOException connectException) {
            try {
                mSocket.close();
            } catch (IOException closeException) {
                Log.e(TAG, "Could not close the client socket", closeException);
            }
        }
    }

    public void cancel() {
        try {
            mSocket.close();
        } catch (IOException e) {
            Log.e(TAG, "Could not close the client socket", e);
        }
    }
}

注意客户端和服务端的UUID应保持一致

A2DPSinkStateMachine

A2DPSinkStateMachineA2DP Sink State Machine)是Android中用于管理A2DPAdvanced Audio Distribution Profile)音频音频接收端的状态机。A2DP是一种蓝牙配置文件,用于在蓝牙设备之间传输高质量的音频流。

A2DPSinkStateMachine负责处理A2DP Sink设备的连接、断开连接和音频流的控制。它管理连接状态、音频焦点和音频路由等相关操作。

以下是A2DPSinkStateMachine的几个关键状态:

  1. Idle(空闲状态):表示A2DP Sink设备处于未连接状态。
  2. Connecting(连接中状态):表示A2DP Sink设备正在连接到A2DP源设备。
  3. Connected(已连接状态):表示A2DP Sink设备已成功连接到A2DP源设备,并可以接收音频流。
  4. Disconnecting(断开连接中状态):表示A2DP Sink设备正在与A2DP源设备断开连接。

A2DPSinkStateMachine还提供了一些方法和回调事件,用于控制和监控A2DP Sink设备的连接和音频流操作。开发人员可以使用这些方法和回调来管理A2DP Sink设备的状态、处理连接和断开连接的操作,并执行相关的音频控制,例如音频焦点管理和音频路由控制。

需要注意的是,A2DPSinkStateMachineAndroid框架中的一个内部组件,一般情况下,开发人员无需直接与其交互。相反,可以使用Android提供的A2DP API和相关类来实现对A2DP Sink设备的操作和控制。

AvrcpControllerStateMachine

AvrcpControllerStateMachineAVRCP Controller State Machine)是Android中用于管理AVRCPAudio/Video Remote Control Profile)控制器设备的状态机。AVRCP是一种蓝牙配置文件,用于在蓝牙设备之间进行音频和视频的远程控制。

AvrcpControllerStateMachine负责处理AVRCP控制器设备与远程设备(如蓝牙音箱或蓝牙耳机)之间的连接、断开连接和媒体控制。它管理连接状态、媒体播放控制、元数据信息和事件通知等相关操作。

以下是AvrcpControllerStateMachine的几个关键状态:

  1. Idle(空闲状态):表示AVRCP控制器设备处于未连接状态。
  2. Connecting(连接中状态):表示AVRCP控制器设备正在连接到远程设备。
  3. Connected(已连接状态):表示AVRCP控制器设备已成功连接到远程设备,并可以进行媒体控制。
  4. Disconnecting(断开连接中状态):表示AVRCP控制器设备正在与远程设备断开连接。

AvrcpControllerStateMachine还提供了一些方法和回调事件,用于控制和监控AVRCP控制器设备与远程设备之间的连接和媒体控制操作。开发人员可以使用这些方法和回调来管理AVRCP控制器设备的状态、处理连接和断开连接的操作,并执行相关的媒体控制,例如播放、暂停、跳转等操作。

需要注意的是,AvrcpControllerStateMachineAndroid框架中的一个内部组件,一般情况下,开发人员无需直接与其交互。相反,可以使用Android提供的AVRCP API和相关类来实现对AVRCP控制器设备的操作和控制。

BluetoothMediaBrowserService

BluetoothMediaBrowserService是一个类似于MediaBrowserService的Android服务类,用于与蓝牙媒体设备进行通信和交互。它提供了管理与蓝牙媒体设备连接、浏览媒体内容和控制播放等功能。

在项目中主要通过该类判断,蓝牙底层传递的音乐信息,如歌曲进度,歌曲切换等

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

立花泷える宫水三叶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值