Loading system/bta/hearing_aid/hearing_aid.cc +99 −19 Original line number Diff line number Diff line Loading @@ -1151,10 +1151,54 @@ class HearingAidImpl : public HearingAid { hearingDevice->playback_started = true; } /* Compare the two sides LE CoC credit and return true to drop two sides * packet on these situations. * 1) The credit is close * 2) Other side is disconnected * 3) Get one side current credit value failure. * * Otherwise, just flush audio packet one side. */ bool NeedToDropPacket(HearingDevice* target_side, HearingDevice* other_side) { // Just drop packet if the other side does not exist. if (!other_side) { VLOG(2) << __func__ << ": other side not connected to profile"; return true; } uint16_t diff_credit = 0; uint16_t target_current_credit = L2CA_GetPeerLECocCredit( target_side->address, GAP_ConnGetL2CAPCid(target_side->gap_handle)); if (target_current_credit == L2CAP_LE_CREDIT_MAX) { LOG(ERROR) << __func__ << ": Get target side credit value fail."; return true; } uint16_t other_current_credit = L2CA_GetPeerLECocCredit( other_side->address, GAP_ConnGetL2CAPCid(other_side->gap_handle)); if (other_current_credit == L2CAP_LE_CREDIT_MAX) { LOG(ERROR) << __func__ << ": Get other side credit value fail."; return true; } if (target_current_credit > other_current_credit) { diff_credit = target_current_credit - other_current_credit; } else { diff_credit = other_current_credit - target_current_credit; } VLOG(2) << __func__ << ": Target(" << target_side->address << ") Credit: " << target_current_credit << ", Other(" << other_side->address << ") Credit: " << other_current_credit << ", Init Credit: " << init_credit; return diff_credit < (init_credit / 2 - 1); } void OnAudioDataReady(const std::vector<uint8_t>& data) { /* For now we assume data comes in as 16bit per sample 16kHz PCM stereo */ DVLOG(2) << __func__; bool need_drop = false; int num_samples = data.size() / (2 /*bytes_per_sample*/ * 2 /*number of channels*/); Loading Loading @@ -1228,16 +1272,24 @@ class HearingAidImpl : public HearingAid { encoded_data_left.resize(encoded_size); uint16_t cid = GAP_ConnGetL2CAPCid(left->gap_handle); uint16_t packets_to_flush = L2CA_FlushChannel(cid, L2CAP_FLUSH_CHANS_GET); if (packets_to_flush) { VLOG(2) << left->address << " skipping " << packets_to_flush uint16_t packets_in_chans = L2CA_FlushChannel(cid, L2CAP_FLUSH_CHANS_GET); if (packets_in_chans) { // Compare the two sides LE CoC credit value to confirm need to drop or // skip audio packet. if (NeedToDropPacket(left, right)) { LOG(INFO) << left->address << " triggers dropping, " << packets_in_chans << " packets in channel"; need_drop = true; left->audio_stats.trigger_drop_count++; } else { LOG(INFO) << left->address << " skipping " << packets_in_chans << " packets"; left->audio_stats.packet_flush_count += packets_to_flush; left->audio_stats.packet_flush_count += packets_in_chans; left->audio_stats.frame_flush_count++; L2CA_FlushChannel(cid, 0xffff); } hearingDevices.StartRssiLog(); } // flush all packets stuck in queue L2CA_FlushChannel(cid, 0xffff); check_and_do_rssi_read(left); } Loading @@ -1252,16 +1304,24 @@ class HearingAidImpl : public HearingAid { encoded_data_right.resize(encoded_size); uint16_t cid = GAP_ConnGetL2CAPCid(right->gap_handle); uint16_t packets_to_flush = L2CA_FlushChannel(cid, L2CAP_FLUSH_CHANS_GET); if (packets_to_flush) { VLOG(2) << right->address << " skipping " << packets_to_flush uint16_t packets_in_chans = L2CA_FlushChannel(cid, L2CAP_FLUSH_CHANS_GET); if (packets_in_chans) { // Compare the two sides LE CoC credit value to confirm need to drop or // skip audio packet. if (NeedToDropPacket(right, left)) { LOG(INFO) << right->address << " triggers dropping, " << packets_in_chans << " packets in channel"; need_drop = true; right->audio_stats.trigger_drop_count++; } else { LOG(INFO) << right->address << " skipping " << packets_in_chans << " packets"; right->audio_stats.packet_flush_count += packets_to_flush; right->audio_stats.packet_flush_count += packets_in_chans; right->audio_stats.frame_flush_count++; L2CA_FlushChannel(cid, 0xffff); } hearingDevices.StartRssiLog(); } // flush all packets stuck in queue L2CA_FlushChannel(cid, 0xffff); check_and_do_rssi_read(right); } Loading @@ -1271,6 +1331,16 @@ class HearingAidImpl : public HearingAid { uint16_t packet_size = CalcCompressedAudioPacketSize(codec_in_use, default_data_interval_ms); if (need_drop) { if (left) { left->audio_stats.packet_drop_count++; } if (right) { right->audio_stats.packet_drop_count++; } return; } for (size_t i = 0; i < encoded_data_size; i += packet_size) { if (left) { left->audio_stats.packet_send_count++; Loading Loading @@ -1323,7 +1393,11 @@ class HearingAidImpl : public HearingAid { RawAddress address = *GAP_ConnGetRemoteAddr(gap_handle); uint16_t tx_mtu = GAP_ConnGetRemMtuSize(gap_handle); LOG(INFO) << "GAP_EVT_CONN_OPENED " << address << ", tx_mtu=" << tx_mtu; init_credit = L2CA_GetPeerLECocCredit(address, GAP_ConnGetL2CAPCid(gap_handle)); LOG(INFO) << "GAP_EVT_CONN_OPENED " << address << ", tx_mtu=" << tx_mtu << ", init_credit=" << init_credit; OnGapConnection(address); break; } Loading Loading @@ -1445,10 +1519,14 @@ class HearingAidImpl : public HearingAid { << (side ? "right" : "left") << " " << loghex(device.hi_sync_id) << std::endl; stream << " Packet counts (enqueued/flushed) : " << " Trigger dropped counts : " << device.audio_stats.trigger_drop_count << "\n Packet dropped counts : " << device.audio_stats.packet_drop_count << "\n Packet counts (send/flush) : " << device.audio_stats.packet_send_count << " / " << device.audio_stats.packet_flush_count << "\n Frame counts (enqueued/flushed) : " << "\n Frame counts (sent/flush) : " << device.audio_stats.frame_send_count << " / " << device.audio_stats.frame_flush_count << std::endl; Loading Loading @@ -1615,6 +1693,8 @@ class HearingAidImpl : public HearingAid { uint16_t default_data_interval_ms; uint16_t init_credit; HearingDevices hearingDevices; void find_server_changed_ccc_handle(uint16_t conn_id, Loading system/bta/include/bta_hearing_aid_api.h +8 −4 Original line number Diff line number Diff line Loading @@ -74,19 +74,23 @@ struct rssi_log { }; struct AudioStats { size_t packet_flush_count; size_t trigger_drop_count; size_t packet_drop_count; size_t packet_send_count; size_t frame_flush_count; size_t packet_flush_count; size_t frame_send_count; size_t frame_flush_count; std::deque<rssi_log> rssi_history; AudioStats() { Reset(); } void Reset() { packet_flush_count = 0; trigger_drop_count = 0; packet_drop_count = 0; packet_send_count = 0; frame_flush_count = 0; packet_flush_count = 0; frame_send_count = 0; frame_flush_count = 0; } }; Loading system/stack/include/l2c_api.h +12 −0 Original line number Diff line number Diff line Loading @@ -478,6 +478,18 @@ extern uint16_t L2CA_ConnectLECocReq(uint16_t psm, const RawAddress& p_bd_addr, extern bool L2CA_GetPeerLECocConfig(uint16_t lcid, tL2CAP_LE_CFG_INFO* peer_cfg); /******************************************************************************* * * Function L2CA_GetPeerLECocCredit * * Description Get peers current credit for LE Connection Oriented * Channel. * * Return value: Number of the peer current credit * ******************************************************************************/ uint16_t L2CA_GetPeerLECocCredit(const RawAddress& bd_addr, uint16_t lcid); /******************************************************************************* * * Function L2CA_ReconfigCreditBasedConnsReq Loading system/stack/l2cap/l2c_api.cc +28 −0 Original line number Diff line number Diff line Loading @@ -619,6 +619,34 @@ bool L2CA_GetPeerLECocConfig(uint16_t lcid, tL2CAP_LE_CFG_INFO* peer_cfg) { return true; } /******************************************************************************* * * Function L2CA_GetPeerLECocCredit * * Description Get peers current credit for LE Connection Oriented * Channel. * * Return value: Number of the peer current credit * ******************************************************************************/ uint16_t L2CA_GetPeerLECocCredit(const RawAddress& bd_addr, uint16_t lcid) { /* First, find the link control block */ tL2C_LCB* p_lcb = l2cu_find_lcb_by_bd_addr(bd_addr, BT_TRANSPORT_LE); if (p_lcb == NULL) { /* No link. Get an LCB and start link establishment */ L2CAP_TRACE_WARNING("%s no LCB", __func__); return L2CAP_LE_CREDIT_MAX; } tL2C_CCB* p_ccb = l2cu_find_ccb_by_cid(p_lcb, lcid); if (p_ccb == NULL) { L2CAP_TRACE_ERROR("%s No CCB for CID:0x%04x", __func__, lcid); return L2CAP_LE_CREDIT_MAX; } return p_ccb->peer_conn_cfg.credits; } /******************************************************************************* * * Function L2CA_ConnectCreditBasedRsp Loading Loading
system/bta/hearing_aid/hearing_aid.cc +99 −19 Original line number Diff line number Diff line Loading @@ -1151,10 +1151,54 @@ class HearingAidImpl : public HearingAid { hearingDevice->playback_started = true; } /* Compare the two sides LE CoC credit and return true to drop two sides * packet on these situations. * 1) The credit is close * 2) Other side is disconnected * 3) Get one side current credit value failure. * * Otherwise, just flush audio packet one side. */ bool NeedToDropPacket(HearingDevice* target_side, HearingDevice* other_side) { // Just drop packet if the other side does not exist. if (!other_side) { VLOG(2) << __func__ << ": other side not connected to profile"; return true; } uint16_t diff_credit = 0; uint16_t target_current_credit = L2CA_GetPeerLECocCredit( target_side->address, GAP_ConnGetL2CAPCid(target_side->gap_handle)); if (target_current_credit == L2CAP_LE_CREDIT_MAX) { LOG(ERROR) << __func__ << ": Get target side credit value fail."; return true; } uint16_t other_current_credit = L2CA_GetPeerLECocCredit( other_side->address, GAP_ConnGetL2CAPCid(other_side->gap_handle)); if (other_current_credit == L2CAP_LE_CREDIT_MAX) { LOG(ERROR) << __func__ << ": Get other side credit value fail."; return true; } if (target_current_credit > other_current_credit) { diff_credit = target_current_credit - other_current_credit; } else { diff_credit = other_current_credit - target_current_credit; } VLOG(2) << __func__ << ": Target(" << target_side->address << ") Credit: " << target_current_credit << ", Other(" << other_side->address << ") Credit: " << other_current_credit << ", Init Credit: " << init_credit; return diff_credit < (init_credit / 2 - 1); } void OnAudioDataReady(const std::vector<uint8_t>& data) { /* For now we assume data comes in as 16bit per sample 16kHz PCM stereo */ DVLOG(2) << __func__; bool need_drop = false; int num_samples = data.size() / (2 /*bytes_per_sample*/ * 2 /*number of channels*/); Loading Loading @@ -1228,16 +1272,24 @@ class HearingAidImpl : public HearingAid { encoded_data_left.resize(encoded_size); uint16_t cid = GAP_ConnGetL2CAPCid(left->gap_handle); uint16_t packets_to_flush = L2CA_FlushChannel(cid, L2CAP_FLUSH_CHANS_GET); if (packets_to_flush) { VLOG(2) << left->address << " skipping " << packets_to_flush uint16_t packets_in_chans = L2CA_FlushChannel(cid, L2CAP_FLUSH_CHANS_GET); if (packets_in_chans) { // Compare the two sides LE CoC credit value to confirm need to drop or // skip audio packet. if (NeedToDropPacket(left, right)) { LOG(INFO) << left->address << " triggers dropping, " << packets_in_chans << " packets in channel"; need_drop = true; left->audio_stats.trigger_drop_count++; } else { LOG(INFO) << left->address << " skipping " << packets_in_chans << " packets"; left->audio_stats.packet_flush_count += packets_to_flush; left->audio_stats.packet_flush_count += packets_in_chans; left->audio_stats.frame_flush_count++; L2CA_FlushChannel(cid, 0xffff); } hearingDevices.StartRssiLog(); } // flush all packets stuck in queue L2CA_FlushChannel(cid, 0xffff); check_and_do_rssi_read(left); } Loading @@ -1252,16 +1304,24 @@ class HearingAidImpl : public HearingAid { encoded_data_right.resize(encoded_size); uint16_t cid = GAP_ConnGetL2CAPCid(right->gap_handle); uint16_t packets_to_flush = L2CA_FlushChannel(cid, L2CAP_FLUSH_CHANS_GET); if (packets_to_flush) { VLOG(2) << right->address << " skipping " << packets_to_flush uint16_t packets_in_chans = L2CA_FlushChannel(cid, L2CAP_FLUSH_CHANS_GET); if (packets_in_chans) { // Compare the two sides LE CoC credit value to confirm need to drop or // skip audio packet. if (NeedToDropPacket(right, left)) { LOG(INFO) << right->address << " triggers dropping, " << packets_in_chans << " packets in channel"; need_drop = true; right->audio_stats.trigger_drop_count++; } else { LOG(INFO) << right->address << " skipping " << packets_in_chans << " packets"; right->audio_stats.packet_flush_count += packets_to_flush; right->audio_stats.packet_flush_count += packets_in_chans; right->audio_stats.frame_flush_count++; L2CA_FlushChannel(cid, 0xffff); } hearingDevices.StartRssiLog(); } // flush all packets stuck in queue L2CA_FlushChannel(cid, 0xffff); check_and_do_rssi_read(right); } Loading @@ -1271,6 +1331,16 @@ class HearingAidImpl : public HearingAid { uint16_t packet_size = CalcCompressedAudioPacketSize(codec_in_use, default_data_interval_ms); if (need_drop) { if (left) { left->audio_stats.packet_drop_count++; } if (right) { right->audio_stats.packet_drop_count++; } return; } for (size_t i = 0; i < encoded_data_size; i += packet_size) { if (left) { left->audio_stats.packet_send_count++; Loading Loading @@ -1323,7 +1393,11 @@ class HearingAidImpl : public HearingAid { RawAddress address = *GAP_ConnGetRemoteAddr(gap_handle); uint16_t tx_mtu = GAP_ConnGetRemMtuSize(gap_handle); LOG(INFO) << "GAP_EVT_CONN_OPENED " << address << ", tx_mtu=" << tx_mtu; init_credit = L2CA_GetPeerLECocCredit(address, GAP_ConnGetL2CAPCid(gap_handle)); LOG(INFO) << "GAP_EVT_CONN_OPENED " << address << ", tx_mtu=" << tx_mtu << ", init_credit=" << init_credit; OnGapConnection(address); break; } Loading Loading @@ -1445,10 +1519,14 @@ class HearingAidImpl : public HearingAid { << (side ? "right" : "left") << " " << loghex(device.hi_sync_id) << std::endl; stream << " Packet counts (enqueued/flushed) : " << " Trigger dropped counts : " << device.audio_stats.trigger_drop_count << "\n Packet dropped counts : " << device.audio_stats.packet_drop_count << "\n Packet counts (send/flush) : " << device.audio_stats.packet_send_count << " / " << device.audio_stats.packet_flush_count << "\n Frame counts (enqueued/flushed) : " << "\n Frame counts (sent/flush) : " << device.audio_stats.frame_send_count << " / " << device.audio_stats.frame_flush_count << std::endl; Loading Loading @@ -1615,6 +1693,8 @@ class HearingAidImpl : public HearingAid { uint16_t default_data_interval_ms; uint16_t init_credit; HearingDevices hearingDevices; void find_server_changed_ccc_handle(uint16_t conn_id, Loading
system/bta/include/bta_hearing_aid_api.h +8 −4 Original line number Diff line number Diff line Loading @@ -74,19 +74,23 @@ struct rssi_log { }; struct AudioStats { size_t packet_flush_count; size_t trigger_drop_count; size_t packet_drop_count; size_t packet_send_count; size_t frame_flush_count; size_t packet_flush_count; size_t frame_send_count; size_t frame_flush_count; std::deque<rssi_log> rssi_history; AudioStats() { Reset(); } void Reset() { packet_flush_count = 0; trigger_drop_count = 0; packet_drop_count = 0; packet_send_count = 0; frame_flush_count = 0; packet_flush_count = 0; frame_send_count = 0; frame_flush_count = 0; } }; Loading
system/stack/include/l2c_api.h +12 −0 Original line number Diff line number Diff line Loading @@ -478,6 +478,18 @@ extern uint16_t L2CA_ConnectLECocReq(uint16_t psm, const RawAddress& p_bd_addr, extern bool L2CA_GetPeerLECocConfig(uint16_t lcid, tL2CAP_LE_CFG_INFO* peer_cfg); /******************************************************************************* * * Function L2CA_GetPeerLECocCredit * * Description Get peers current credit for LE Connection Oriented * Channel. * * Return value: Number of the peer current credit * ******************************************************************************/ uint16_t L2CA_GetPeerLECocCredit(const RawAddress& bd_addr, uint16_t lcid); /******************************************************************************* * * Function L2CA_ReconfigCreditBasedConnsReq Loading
system/stack/l2cap/l2c_api.cc +28 −0 Original line number Diff line number Diff line Loading @@ -619,6 +619,34 @@ bool L2CA_GetPeerLECocConfig(uint16_t lcid, tL2CAP_LE_CFG_INFO* peer_cfg) { return true; } /******************************************************************************* * * Function L2CA_GetPeerLECocCredit * * Description Get peers current credit for LE Connection Oriented * Channel. * * Return value: Number of the peer current credit * ******************************************************************************/ uint16_t L2CA_GetPeerLECocCredit(const RawAddress& bd_addr, uint16_t lcid) { /* First, find the link control block */ tL2C_LCB* p_lcb = l2cu_find_lcb_by_bd_addr(bd_addr, BT_TRANSPORT_LE); if (p_lcb == NULL) { /* No link. Get an LCB and start link establishment */ L2CAP_TRACE_WARNING("%s no LCB", __func__); return L2CAP_LE_CREDIT_MAX; } tL2C_CCB* p_ccb = l2cu_find_ccb_by_cid(p_lcb, lcid); if (p_ccb == NULL) { L2CAP_TRACE_ERROR("%s No CCB for CID:0x%04x", __func__, lcid); return L2CAP_LE_CREDIT_MAX; } return p_ccb->peer_conn_cfg.credits; } /******************************************************************************* * * Function L2CA_ConnectCreditBasedRsp Loading