Android蓝牙协议栈fluoride(八) - 音乐播放(1)

概述

通常情况下音乐播放与控制这两个profile(即A2DP和AVRCP)都是同时存在的,A2DP分为Sink(SNK)和Source(SRC)两个角色,ACRVP分为Controller(CT)和Target(TG)两个角色。接下来的几篇博客将详细介绍这两个profile。
Sink和Source、CT和TG都是成对出现的。CT和TG可以同时存在在一个设备上,而Sink和Source则不能同时存在在一个设备上(不能同时工作)。角色关系如下:
在这里插入图片描述
在这里插入图片描述

A2DP profile底层依赖AVDTP协议,AVRCP底层依赖AVCTP协议,它们都基于L2CAP协议实现,SDP支持双方的服务发现。AVDTP协议实现了音频流的传输,A2DP进行角色管理以及编解码;AVRCP实现播放控制与信息同步,控制包括:播放、暂停、上一首、下一首、音量调节等,信息包括播放位置、播放状态、专辑信息、音量同步等。SIG的spec对协议栈定义如下:
在这里插入图片描述在这里插入图片描述

接口

flouride协议栈中,A2DP的接口定义如下:

// a2dp source的回调
typedef struct {
  size_t size;
  // 连接状态变化上报
  btav_connection_state_callback connection_state_cb;
  // 音频状态变化上报
  btav_audio_state_callback audio_state_cb;
  // 音频配置变化上报
  btav_audio_source_config_callback audio_config_cb;
  btav_mandatory_codec_preferred_callback mandatory_codec_preferred_cb;
} btav_source_callbacks_t;

// a2dp source的api
typedef struct {
  size_t size;
  // 向协议栈注册回调
  bt_status_t (*init)(btav_source_callbacks_t* callbacks, int max_connected_audio_devices, const std::vector<btav_a2dp_codec_config_t>& codec_priorities, const std::vector<btav_a2dp_codec_config_t>& offloading_preference);
  // 连接指定设备
  bt_status_t (*connect)(const RawAddress& bd_addr);
  // 端口指定设备
  bt_status_t (*disconnect)(const RawAddress& bd_addr);
  // 设置指定的设备是否静音
  bt_status_t (*set_silence_device)(const RawAddress& bd_addr, bool silence);
  // 设置制定的设备为active,有播放时会将音频发送给该设备
  bt_status_t (*set_active_device)(const RawAddress& bd_addr);
  // 编码器配置
  bt_status_t (*config_codec)(const RawAddress& bd_addr, std::vector<btav_a2dp_codec_config_t> codec_preferences);
  void (*cleanup)(void);
} btav_source_interface_t;

// a2dp sink的回调
typedef struct {
  size_t size;
  // 连接状态变化上报
  btav_connection_state_callback connection_state_cb;
  // audio状态变化上报
  btav_audio_state_callback audio_state_cb;
  // audio配置变化上报
  btav_audio_sink_config_callback audio_config_cb;
} btav_sink_callbacks_t;

// a2dp sink的api
typedef struct {
  size_t size;
  // 向协议栈注册回调
  bt_status_t (*init)(btav_sink_callbacks_t* callbacks);
  // 连接指定的设备
  bt_status_t (*connect)(const RawAddress& bd_addr);
  // 断开指定设备
  bt_status_t (*disconnect)(const RawAddress& bd_addr);
  void (*cleanup)(void);
  // 设置音频播放焦点
  void (*set_audio_focus_state)(int focus_state);
  // 设置播放增益
  void (*set_audio_track_gain)(float gain);
  //将制定设备设置为active,即播放收到的该设备的数据
  bt_status_t (*set_active_device)(const RawAddress& bd_addr);
} btav_sink_interface_t;

可以看到,没有音频流相关的API,作为Sink时,解码后的数据直接写入到Audio模块,作为Source时,直接从Audio模块获取数据进行编码,蓝牙应用层不需要关注音频流的具体内容。

AVRCP中大部分接口都可以直接从函数名理解其作用,因此文章中没有详细列出,可参考源码进行理解。

AVRCP Controller的接口如下:

// ACRCP CT的回调
typedef struct {
  ...
} btrc_ctrl_callbacks_t;

//ACRCP TG的API
typedef struct {
  ...
} btrc_ctrl_interface_t;

以前的android版本使用的AVRCP target的接口定义如下:

// AVRCP TG的回调
typedef struct {
  ... 
} btrc_callbacks_t;

// ACRCP TG的API
typedef struct {
  ...
} btrc_interface_t;

旧版本TG的API渐渐的不满足AVRCP版本更新的需求,新版本API采用了面向对象的思想重新实现,接口定义如下:

// 媒体相关的回调
class MediaCallbacks {
 public:
  virtual void SendMediaUpdate(bool track_changed, bool play_state, bool queue) = 0;
  virtual void SendFolderUpdate(bool available_players, bool addressed_players, bool uids_changed) = 0;
  virtual void SendActiveDeviceChanged(const RawAddress& address) = 0;
  virtual ~MediaCallbacks() = default;
};

// JNI给协议栈提供的媒体相关接口
class MediaInterface {
 public:
  // 将CT端的按键事件(AVRCP中的Passthrough命令)发送给应用层,其中包含播放/暂停等
  virtual void SendKeyEvent(uint8_t key, KeyState state) = 0;
  // 从应用层获取歌曲信息
  using SongInfoCallback = base::Callback<void(SongInfo)>;
  virtual void GetSongInfo(SongInfoCallback info_cb) = 0;
  // 从应用层获取播放状态
  using PlayStatusCallback = base::Callback<void(PlayStatus)>;
  virtual void GetPlayStatus(PlayStatusCallback status_cb) = 0;
  // 当前播放列表
  using NowPlayingCallback = base::Callback<void(std::string, std::vector<SongInfo>)>;
  virtual void GetNowPlayingList(NowPlayingCallback now_playing_cb) = 0;
  // 媒体播放器列表
  using MediaListCallback = base::Callback<void(uint16_t curr_player, std::vector<MediaPlayerInfo>)>;
  virtual void GetMediaPlayerList(MediaListCallback list_cb) = 0;
  // 获取目录中的列表
  using FolderItemsCallback = base::Callback<void(std::vector<ListItem>)>;
  virtual void GetFolderItems(uint16_t player_id, std::string media_id, FolderItemsCallback folder_cb) = 0;
  // 浏览播放器
  using SetBrowsedPlayerCallback = base::Callback<void(bool success, std::string root_id, uint32_t num_items)>;
  virtual void SetBrowsedPlayer(uint16_t player_id, SetBrowsedPlayerCallback browse_cb) = 0;
  // 播放指定item
  virtual void PlayItem(uint16_t player_id, bool now_playing, std::string media_id) = 0;
  // 设置active设备
  virtual void SetActiveDevice(const RawAddress& address) = 0;
  // 注册/注销媒体更新的回调
  virtual void RegisterUpdateCallback(MediaCallbacks* callback) = 0;
  virtual void UnregisterUpdateCallback(MediaCallbacks* callback) = 0;
  MediaInterface() = default;
  virtual ~MediaInterface() = default;
};

// JNI给协议栈提供的音量相关接口
class VolumeInterface {
 public:
  using VolumeChangedCb = base::Callback<void(int8_t volume)>;
  // 不支持绝对音量时指示连接状态
  virtual void DeviceConnected(const RawAddress& bdaddr) = 0;
  // 支持绝对音量时指示连接状态,cb是协议栈提供给JNI调节音量的回调,调用cb时向CT发送ACRCP中的SET_ABSOLUTE_VOLUME命令
  virtual void DeviceConnected(const RawAddress& bdaddr, VolumeChangedCb cb) = 0;
  // 指示断开状态
  virtual void DeviceDisconnected(const RawAddress& bdaddr) = 0;
  // 收到CT端的AVRC_EVT_VOLUME_CHANGE事件时调用,通知应用层音量变化
  virtual void SetVolume(int8_t volume) = 0;
  virtual ~VolumeInterface() = default;
};

// 协议栈提供给JNI的接口
class ServiceInterface {
 public:
  // JNI注销接口给协议栈,mediaInterface不能为空,volumeInterface为空时不支持绝对音量
  virtual void Init(MediaInterface* mediaInterface, VolumeInterface* volumeInterface) = 0;
  // 注册/注销BIP服务,用于传输专辑封面信息
  virtual void RegisterBipServer(int psm) = 0;
  virtual void UnregisterBipServer() = 0;
  // 连接/断开指定设备
  virtual bool ConnectDevice(const RawAddress& bdaddr) = 0;
  virtual bool DisconnectDevice(const RawAddress& bdaddr) = 0;
  // 设置BIP客户端的状态
  virtual void SetBipClientStatus(const RawAddress& bdaddr, bool connected) = 0;
  virtual bool Cleanup() = 0;
 protected:
  virtual ~ServiceInterface() = default;
};

在之后的文章中不会专门描述旧接口相关的实现,主要集中在新的接口上,但旧接口和CT的接口是类似的。

  • 9
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Linux 系统中有几种常见的蓝牙协议栈: 1. BlueZ:这是 Linux 系统中默认的蓝牙协议栈,它由 Linux 基金会开发并维护。BlueZ 提供了蓝牙的高级功能,并且可以让用户通过命令行或脚本来控制蓝牙设备。 2. Bluedroid:这是 Android 系统中的蓝牙协议栈,也可以在其他基于 Linux 的系统中使用。Bluedroid 提供了丰富的蓝牙功能,包括蓝牙协议栈、配对、连接、传输数据等。 3. BlueZ for Android:这是一个基于 BlueZ 的蓝牙协议栈,专门为 Android 系统开发。它兼容 BlueZ 命令行工具,可以让用户在 Android 系统中使用 BlueZ 命令行来控制蓝牙设备。 4. hciattach:这是 Linux 中用于驱动蓝牙硬件的工具,它可以将蓝牙硬件附加到蓝牙协议栈中,使蓝牙硬件可以与其他蓝牙设备通信。 总的来说,Linux 系统中的蓝牙协议栈主要有 BlueZ 和 Bluedroid 两种,其中 BlueZ 是 Linux 系统中的默认蓝牙协议栈,Bluedroid 则是 Android 系统中的蓝牙协议栈。 ### 回答2: Linux操作系统中有两种蓝牙协议栈可供选择。 1. BlueZ协议栈:BlueZ是Linux操作系统上最常用的蓝牙协议栈。它提供API和工具,用于在Linux设备上实现蓝牙功能。BlueZ支持几乎所有的蓝牙协议,包括传统的蓝牙核心规范(Bluetooth Core Specification)和最新的蓝牙低功耗(Bluetooth Low Energy)规范。BlueZ协议栈被广泛应用于各种Linux设备,包括智能手机、平板电脑、智能手表等。 2. Affix协议栈:Affix是一个开源的Linux蓝牙协议栈。它提供了蓝牙通信的基本功能,并可以在嵌入式系统上运行。Affix协议栈支持蓝牙核心规范,但对于蓝牙低功耗规范的支持相对有限。它适用于资源受限的嵌入式设备,如物联网设备、传感器等。 总结起来,Linux操作系统上有两种常用的蓝牙协议栈:BlueZ协议栈和Affix协议栈。其中,BlueZ协议栈是最常用和功能最全面的蓝牙协议栈,被广泛应用于各种Linux设备。而Affix协议栈则适用于资源受限的嵌入式设备。 ### 回答3: Linux操作系统支持多种蓝牙协议栈,以下是其中一些常见的蓝牙协议栈: 1. BlueZ:BlueZ是Linux操作系统上最为广泛使用的开源蓝牙协议栈。它提供了一套完整的蓝牙协议栈实现,包括蓝牙核心协议、蓝牙硬件驱动和一系列用户空间的工具和库。BlueZ支持众多的蓝牙协议和功能,如蓝牙文件传输、蓝牙耳机、蓝牙键盘等。 2. Affix:Affix是一种轻量级的蓝牙协议栈,旨在提供更小的内存占用和更低的功耗。它适用于嵌入式设备和资源受限的系统。Affix支持核心蓝牙协议,但不支持所有BlueZ的高级功能。 3. Bluedroid:Bluedroid最初是由Android平台使用的蓝牙协议栈,后来也被移植到了Linux操作系统中。Bluedroid基于BlueZ协议栈,但做了一些定制化的修改和优化,以适应移动设备的需求。 4. FluorideFluoride是谷歌开发的蓝牙协议栈,最初用于Android平台,后来也支持了Linux操作系统。Fluoride提供了一套用于开发蓝牙应用的API和工具,并且与BlueZ相比有一些特有的优化和功能。 这些蓝牙协议栈都有各自的特点和适用场景,开发者可以根据不同的需求选择合适的协议栈来进行蓝牙应用程序的开发和调试。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值