前面介绍了A2DP的角色和fluoride协议栈对外提供的API,接下来将介绍fluoride的实现。首先梳理一下btif中A2DP 角色和状态各个类之间的关系,如下图:
在btif层用BtifAvPeer表示一个对端设备,分为两个角色:BtifAvSink、BtifAvSoure。BtifAvPeer类的成员变量和方法如下:
class BtifAvPeer {
public:
// flag的取值
enum {
kFlagLocalSuspendPending = 0x1,
kFlagRemoteSuspend = 0x2,
kFlagPendingStart = 0x4,
kFlagPendingStop = 0x8,
};
static constexpr uint64_t kTimeoutAvOpenOnRcMs = 2 * 1000; // 2s
// 构造/析构BtifAvPeer
BtifAvPeer(const RawAddress& peer_address, uint8_t peer_sep, tBTA_AV_HNDL bta_handle, uint8_t peer_id);
~BtifAvPeer();
// 初始化/清理BtifAvPeer
bt_status_t Init();
void Cleanup();
// 检查当前设备是否可以删除
bool CanBeDeleted() const;
// 检查当前设备是否为active设备
bool IsActivePeer() const { return (PeerAddress() == ActivePeerAddress()); }
// 获取active设备的地址
const RawAddress& ActivePeerAddress() const;
// 获取当前设备地址
const RawAddress& PeerAddress() const { return peer_address_; }
// 当前设备是否是Source角色
bool IsSource() const { return (peer_sep_ == AVDT_TSEP_SRC); }
// 当前角色是否是Sink角色
bool IsSink() const { return (peer_sep_ == AVDT_TSEP_SNK); }
// 获取当前设备的角色
uint8_t PeerSep() const { return peer_sep_; }
// 获取当前设备角色的UUID
uint16_t LocalUuidServiceClass();
// 获取/设置BTA handle
tBTA_AV_HNDL BtaHandle() const { return bta_handle_; }
void SetBtaHandle(tBTA_AV_HNDL bta_handle) { bta_handle_ = bta_handle; }
// 获取peer id
uint8_t PeerId() const { return peer_id_; }
// 获取当前设备的状态机
BtifAvStateMachine& StateMachine() { return state_machine_; }
const BtifAvStateMachine& StateMachine() const { return state_machine_; }
//
alarm_t* AvOpenOnRcTimer() { return av_open_on_rc_timer_; }
const alarm_t* AvOpenOnRcTimer() const { return av_open_on_rc_timer_; }
// 是否支持EDR
void SetEdr(tBTA_AV_EDR edr) { edr_ = edr; }
bool IsEdr() const { return (edr_ != 0); }
bool Is3Mbps() const { return ((edr_ & BTA_AV_EDR_3MBPS) != 0); }
// 是否连接、是否正在播放、是否处于静音状态
bool IsConnected() const;
bool IsStreaming() const;
bool IsInSilenceMode() const { return is_silenced_; }
// 设置当前设备为静音
void SetSilence(bool silence) { is_silenced_ = silence; }
// AVDTP协议中的延迟上报的值
void SetDelayReport(uint16_t delay) { delay_report_ = delay; }
uint16_t GetDelayReport() const { return delay_report_; }
// 编码器相关
void SetMandatoryCodecPreferred(bool preferred);
bool IsMandatoryCodecPreferred() const { return mandatory_codec_preferred_; }
// flag 相关
bool CheckFlags(uint8_t bitflags_mask);
void SetFlags(uint8_t bitflags_mask);
void ClearFlags(uint8_t bitflags_mask);
void ClearAllFlags();
std::string FlagsToString() const;
// 是否支持本机发起连接
bool SelfInitiatedConnection() const { return self_initiated_connection_; }
void SetSelfInitiatedConnection(bool v) { self_initiated_connection_ = v; }
private:
const RawAddress peer_address_; //设备地址
const uint8_t peer_sep_; // 角色:AVDT_TSEP_SNK、AVDT_TSEP_SRC
tBTA_AV_HNDL bta_handle_; // bta句柄
const uint8_t peer_id_; // peer id
BtifAvStateMachine state_machine_; // 状态机
alarm_t* av_open_on_rc_timer_;
tBTA_AV_EDR edr_; //是否EDR相关
uint8_t flags_;
bool self_initiated_connection_; // 是否支持本机发起连接
bool is_silenced_; // 是否处于静音状态
uint16_t delay_report_; // 用于AVDTP延迟上报
bool mandatory_codec_preferred_ = false;
};
BtifAVSource类的成员变量和方法如下:
class BtifAvSource {
public:
// peerId用作BTA_AvRegister()的AppId
static constexpr uint8_t kPeerIdMin = 0;
static constexpr uint8_t kPeerIdMax = BTA_AV_NUM_STRS;
BtifAvSource();
~BtifAvSource();
// JNI初始化Souce,注册回调和编码器配置等
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);
void Cleanup();
// 获取回调函数
btav_source_callbacks_t* Callbacks() { return callbacks_; }
// 是否使能
bool Enabled() const { return enabled_; }
bool A2dpOffloadEnabled() const { return a2dp_offload_enabled_; }
// 查找BtifAvPeer
BtifAvPeer* FindPeer(const RawAddress& peer_address);
BtifAvPeer* FindPeerByHandle(tBTA_AV_HNDL bta_handle);
BtifAvPeer* FindPeerByPeerId(uint8_t peer_id);
// 未查找到BtifAvPeer则创建
BtifAvPeer* FindOrCreatePeer(const RawAddress& peer_address, tBTA_AV_HNDL bta_handle);
// 检查是否允许连接到对端设备,会考虑已连接对端设备的最大数量
bool AllowedToConnect(const RawAddress& peer_address) const;
// 删除一个对端设备
bool DeletePeer(const RawAddress& peer_address);
// 删除所有状态为Idle并可以删除的对端设备,刚创建/初始化的设备不能删除
void DeleteIdlePeers();
// 获取为active的对端设备
const RawAddress& ActivePeer() const { return active_peer_; }
// 设置对端设备为active
bool SetActivePeer(const RawAddress& peer_address, std::promise<void> peer_ready_promise);
// 检查对端设备是否是静音状态
bool IsPeerSilenced(const RawAddress& peer_address);
// 设置对端设备的静音状态
bool SetSilencePeer(const RawAddress& peer_address, const bool silence);
// 更新编码器配置
void UpdateCodecConfig(const RawAddress& peer_address, const std::vector<btav_a2dp_codec_config_t>& codec_preferences, std::promise<void> peer_ready_promise);
const std::map<RawAddress, BtifAvPeer*>& Peers() const { return peers_; }
// 注册/注销所有peer id
void RegisterAllBtaHandles();
void DeregisterAllBtaHandles();
void BtaHandleRegistered(uint8_t peer_id, tBTA_AV_HNDL bta_handle);
private:
void CleanupAllPeers();
btav_source_callbacks_t* callbacks_; // JNI注册的回调
bool enabled_; // 是否使能
bool a2dp_offload_enabled_;
int max_connected_peers_; // 最大连接数
std::map<RawAddress, BtifAvPeer*> peers_; //已连接对端设备
std::set<RawAddress> silenced_peers_; // 为静音状态的设备
RawAddress active_peer_; // 为active的设备
std::map<uint8_t, tBTA_AV_HNDL> peer_id2bta_handle_; // peer id对应的bta handle
};
BtifAVSink类的成员变量和方法如下:
class BtifAvSink {
public:
// peerId用作BTA_AvRegister()的AppId
static constexpr uint8_t kPeerIdMin = 0;
static constexpr uint8_t kPeerIdMax = BTA_AV_NUM_STRS;
BtifAvSink();
~BtifAvSink();
// JNI初始化Sink,注册回调函数
bt_status_t Init(btav_sink_callbacks_t* callbacks);
void Cleanup();
// 获取JNI注册的回调函数
btav_sink_callbacks_t* Callbacks() { return callbacks_; }
// 是否使能
bool Enabled() const { return enabled_; }
// 查找对端设备
BtifAvPeer* FindPeer(const RawAddress& peer_address);
BtifAvPeer* FindPeerByHandle(tBTA_AV_HNDL bta_handle);
BtifAvPeer* FindPeerByPeerId(uint8_t peer_id);
// 未查找到则创建
BtifAvPeer* FindOrCreatePeer(const RawAddress& peer_address, tBTA_AV_HNDL bta_handle);
//检查是否允许连接到对端设备,会考虑已连接对端设备的最大数量
bool AllowedToConnect(const RawAddress& peer_address) const;
// 删除一个对端设备
bool DeletePeer(const RawAddress& peer_address);
// 删除所有状态为Idle并可以删除的对端设备,刚创建/初始化的设备不能删除
void DeleteIdlePeers();
// 获取为active的对端设备
const RawAddress& ActivePeer() const { return active_peer_; }
// 设置对端设备为active
bool SetActivePeer(const RawAddress& peer_address, std::promise<void> peer_ready_promise);
// 获取对端设备列表
const std::map<RawAddress, BtifAvPeer*>& Peers() const { return peers_; }
// 注册/注销peer id
void RegisterAllBtaHandles();
void DeregisterAllBtaHandles();
void BtaHandleRegistered(uint8_t peer_id, tBTA_AV_HNDL bta_handle);
private:
void CleanupAllPeers();
btav_sink_callbacks_t* callbacks_; // JNI注册的回调
bool enabled_; // 是否使能
int max_connected_peers_; // 最大连接数
std::map<RawAddress, BtifAvPeer*> peers_; // 已连接的对端设备列表
RawAddress active_peer_; // 为active的设备
std::map<uint8_t, tBTA_AV_HNDL> peer_id2bta_handle_; // peer id对应的bta handle
};
在初始化(BtifAvSource::Init
和BtifAvSink::Init
)时,调用BTA_AvEnable
使能A2DP Profile,同时注册事件回调(bta_av_source_callback
和bta_av_sink_callback
),然后调用BTA_AvRegister
注册peer id获取bta handle。之后A2DP相关事件都会通过注册的回调函数上报的btif,btif集中到btif_av_handle_bta_av_event
处理。在btif_av_handle_bta_av_event
中根据peer_address
或者bta_handle
查找peer,然后进入peer的状态机处理事件。
Sink和Source两个角色是互斥的,即对端设备为Sink,则本机为Source,反之对端为Source,本机为Sink,在BtifAvSource::FindOrCreatePeer
和BtifAvSink::FindOrCreatePeer
函数中可以看出,BtifAvSource
中创建peer时设置的SEP为AVDT_TSEP_SNK
,BtifAvSink
中创建peer时设置的SEP为AVDT_TSEP_SRC
。
流程如下:
注:xxx表示Sink或Source。
有五个状态:StateIdle、StateOpening、StateOpened、StateStarted、StateClosing,它们通过BtifAvStateMachine状态机管理,状态转换关系如下:
其中,Idle状态是初始状态,表示A2DP profile处于未连接状态,Opened状态表示profile已连接但未播放音乐的状态,Started状态表示正在播放音乐的状态,Opening状态表示profile连接过程中的中间状态,Closing表示profile断开连接的中间状态。
进入Idle状态时,先判断当前的对端设备是否是active,如果是则停止音频流,然后判断该设备是否可以删除,如果可以删除则将active设备设置为空,之后删除idle设备。判断是否可以删除的依据:如果该设备是刚刚完成创建或初始化则不删除,如果是经过状态转换到Idle状态则删除,删除Idle状态的设备可以节省资源。流程如下:
对于不可删除的设备,进入Idle状态,收到事件后会进行事件处理,包括以下事件:
BTA_AvClose
断开断开音频通路,如果是Source设备还需要断开AVRCP连接BTA_AvCloseRc
。然后转换到Idle状态。AllowedToConnect()
),如果不允许则发出断开连接的请求BTIF_AV_DISCONNECT_REQ_EVT
,之后执行的动作参考BTIF_AV_DISCONNECT_REQ_EVT
处理,如果收到的事件是BTIF_AV_CONNECT_REQ_EVT
则将连接请求放入队列,稍后主动发起连接。如果允许连接,则调用BTA_AvOpen
连接音频通路,并切换到Opening状态。BTIF_AV_DISCONNECT_REQ_EVT
,进入Idle状态然后删除该设备,如果允许连接则上报BTAV_CONNECTION_STATE_CONNECTED
状态到JNI,切换到Opened状态。如果open状态不是成功,则上报BTAV_CONNECTION_STATE_DISCONNECTED
到JNI,切换到Idle状态。进入Opening状态是向JNI上报BTAV_CONNECTION_STATE_CONNECTING
状态。该状态是从Idle状态到Opened状态的过渡状态,处理的事件如下:
BTAV_CONNECTION_STATE_DISCONNECTED
状态,然后切换到Idle状态,如果允许本机发起连接(在Idle状态下BTIF_AV_CONNECT_REQ_EVT
事件中设置),则将连接请求加入到队列,稍后主动发起连接。BTA_AV_OPEN_EVT
事件处理流程。进入Opened状态时,如果对端设备为Source,则本机的active设备为空,则将对端设备设置为active设备。事件处理如下:
BTA_AvStart
响应请求,设置kFlagPendingStart
flag。BTA_AvClose
端口音频通路,向JNI上报BTAV_CONNECTION_STATE_DISCONNECTING
状态,切换到Closing状态。BTAV_CONNECTION_STATE_DISCONNECTED
,切换到Idle状态。kFlagPendingStart
flag被设置,则调用BTA_AvStart
。进入Started状态后,丢掉接收到的音频帧,然后向JNI上报audio状态BTAV_AUDIO_STATE_STARTED
。事件处理如下:
BTA_AvStop
响应请求。BTA_AvClose
断开音频流传输通路,上报BTAV_CONNECTION_STATE_DISCONNECTING
状态,然后切换到Closing状态。BTAV_AUDIO_STATE_REMOTE_SUSPEND
,如果是本机暂停,则上报BTAV_AUDIO_STATE_STOPPED
,然后切换到Opened状态。BTAV_AUDIO_STATE_STOPPED
,然后切换到Opened状态。BTAV_CONNECTION_STATE_DISCONNECTED
,切换到Idle状态。进入Closing状态时对掉正在发送或接收到音频帧,然后进行事件处理:
BTAV_CONNECTION_STATE_DISCONNECTED
,然后切换到Idle状态。