From: weichinweng Date: Wed, 20 Mar 2019 10:53:11 +0000 (+0800) Subject: Add service change handle for Hearing Aids X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=c410c2e7f1f004bc4f0f70e421c65070d8b86719;p=android-x86%2Fsystem-bt.git Add service change handle for Hearing Aids When receive service changed indication from Hearing Aid (which indicates Hearing Aid service changed), it will refresh the hearing aid attribute handle to ensure the attribute handle is correct. Bug: 122008481 Test: 1.run unit test 2.After Pair old version FW HearingAid, Disconnect/Reconnect new version FW HearingAId, then check whether HearingAid is working fine. 3.After Pair old version FW HearingAid, Bluetooth off/on to reconnect new version FW HearingAId, then check whether HearingAid is working fine. Change-Id: I48eae10a3016429f35f4f904752be93bb419d515 --- diff --git a/bta/gatt/bta_gattc_act.cc b/bta/gatt/bta_gattc_act.cc index f5f9c71a4..5e60049ee 100644 --- a/bta/gatt/bta_gattc_act.cc +++ b/bta/gatt/bta_gattc_act.cc @@ -722,6 +722,12 @@ void bta_gattc_disc_cmpl(tBTA_GATTC_CLCB* p_clcb, */ if (p_q_cmd != p_clcb->p_q_cmd) osi_free_and_reset((void**)&p_q_cmd); } + + if (p_clcb->p_rcb->p_cback) { + tBTA_GATTC bta_gattc; + bta_gattc.remote_bda = p_clcb->p_srcb->server_bda; + (*p_clcb->p_rcb->p_cback)(BTA_GATTC_SRVC_DISC_DONE_EVT, &bta_gattc); + } } /** Read an attribute */ diff --git a/bta/hearing_aid/hearing_aid.cc b/bta/hearing_aid/hearing_aid.cc index 9732e8b47..a83392c22 100644 --- a/bta/hearing_aid/hearing_aid.cc +++ b/bta/hearing_aid/hearing_aid.cc @@ -521,13 +521,16 @@ class HearingAidImpl : public HearingAid { DVLOG(2) << __func__ << " " << address; - if (!hearingDevice->first_connection) { - // Use cached data, jump to connecting socket - ConnectSocket(hearingDevice); - return; + if (hearingDevice->audio_control_point_handle && + hearingDevice->audio_status_handle && + hearingDevice->audio_status_ccc_handle && + hearingDevice->volume_handle && hearingDevice->read_psm_handle) { + // Use cached data, jump to read PSM + ReadPSM(hearingDevice); + } else { + hearingDevice->first_connection = true; + BTA_GATTC_ServiceSearchRequest(hearingDevice->conn_id, &HEARING_AID_UUID); } - - BTA_GATTC_ServiceSearchRequest(hearingDevice->conn_id, &HEARING_AID_UUID); } void OnServiceChangeEvent(const RawAddress& address) { @@ -537,16 +540,23 @@ class HearingAidImpl : public HearingAid { return; } LOG(INFO) << __func__ << ": address=" << address; + hearingDevice->first_connection = true; + hearingDevice->service_changed_rcvd = true; + BtaGattQueue::Clean(hearingDevice->conn_id); + if (hearingDevice->gap_handle) { + GAP_ConnClose(hearingDevice->gap_handle); + hearingDevice->gap_handle = 0; + } + } - /* Re-register the Audio Status Notification since the Service Change will - * clear it */ - tGATT_STATUS register_status; - register_status = BTA_GATTC_RegisterForNotifications( - gatt_if, address, hearingDevice->audio_status_handle); - if (register_status != GATT_SUCCESS) { - LOG(INFO) << __func__ - << ": BTA_GATTC_RegisterForNotifications failed, status=" - << loghex(register_status); + void OnServiceDiscDoneEvent(const RawAddress& address) { + HearingDevice* hearingDevice = hearingDevices.FindByAddress(address); + if (!hearingDevice) { + VLOG(2) << "Skipping unknown device" << address; + return; + } + if (hearingDevice->service_changed_rcvd) { + BTA_GATTC_ServiceSearchRequest(hearingDevice->conn_id, &HEARING_AID_UUID); } } @@ -574,10 +584,15 @@ class HearingAidImpl : public HearingAid { const gatt::Service* service = nullptr; for (const gatt::Service& tmp : *services) { - if (tmp.uuid != HEARING_AID_UUID) continue; - LOG(INFO) << "Found Hearing Aid service, handle=" << loghex(tmp.handle); - service = &tmp; - break; + if (tmp.uuid == Uuid::From16Bit(UUID_SERVCLASS_GATT_SERVER)) { + LOG(INFO) << "Found UUID_SERVCLASS_GATT_SERVER, handle=" + << loghex(tmp.handle); + const gatt::Service* service_changed_service = &tmp; + find_server_changed_ccc_handle(conn_id, service_changed_service); + } else if (tmp.uuid == HEARING_AID_UUID) { + LOG(INFO) << "Found Hearing Aid service, handle=" << loghex(tmp.handle); + service = &tmp; + } } if (!service) { @@ -587,7 +602,6 @@ class HearingAidImpl : public HearingAid { return; } - uint16_t psm_handle = 0x0000; for (const gatt::Characteristic& charac : service->characteristics) { if (charac.uuid == READ_ONLY_PROPERTIES_UUID) { DVLOG(2) << "Reading read only properties " @@ -614,16 +628,26 @@ class HearingAidImpl : public HearingAid { } else if (charac.uuid == VOLUME_UUID) { hearingDevice->volume_handle = charac.value_handle; } else if (charac.uuid == LE_PSM_UUID) { - psm_handle = charac.value_handle; + hearingDevice->read_psm_handle = charac.value_handle; } else { LOG(WARNING) << "Unknown characteristic found:" << charac.uuid; } } - if (psm_handle) { - DVLOG(2) << "Reading PSM " << loghex(psm_handle); + if (hearingDevice->service_changed_rcvd) { + hearingDevice->service_changed_rcvd = false; + } + + ReadPSM(hearingDevice); + } + + void ReadPSM(HearingDevice* hearingDevice) { + if (hearingDevice->read_psm_handle) { + LOG(INFO) << "Reading PSM " << loghex(hearingDevice->read_psm_handle) + << ", device=" << hearingDevice->address; BtaGattQueue::ReadCharacteristic( - conn_id, psm_handle, HearingAidImpl::OnPsmReadStatic, nullptr); + hearingDevice->conn_id, hearingDevice->read_psm_handle, + HearingAidImpl::OnPsmReadStatic, nullptr); } } @@ -790,24 +814,25 @@ class HearingAidImpl : public HearingAid { return; } - uint16_t psm_val = *((uint16_t*)value); - hearingDevice->psm = psm_val; - VLOG(2) << "read psm:" << loghex(hearingDevice->psm); + uint16_t psm = *((uint16_t*)value); + VLOG(2) << "read psm:" << loghex(psm); - ConnectSocket(hearingDevice); + ConnectSocket(hearingDevice, psm); } - void ConnectSocket(HearingDevice* hearingDevice) { + void ConnectSocket(HearingDevice* hearingDevice, uint16_t psm) { tL2CAP_CFG_INFO cfg_info = tL2CAP_CFG_INFO{.mtu = 512}; + SendEnableServiceChangedInd(hearingDevice); + uint8_t service_id = hearingDevice->isLeft() ? BTM_SEC_SERVICE_HEARING_AID_LEFT : BTM_SEC_SERVICE_HEARING_AID_RIGHT; uint16_t gap_handle = GAP_ConnOpen( - "", service_id, false, &hearingDevice->address, hearingDevice->psm, - 514 /* MPS */, &cfg_info, nullptr, - BTM_SEC_NONE /* TODO: request security ? */, L2CAP_FCR_LE_COC_MODE, - HearingAidImpl::GapCallbackStatic, BT_TRANSPORT_LE); + "", service_id, false, &hearingDevice->address, psm, 514 /* MPS */, + &cfg_info, nullptr, BTM_SEC_NONE /* TODO: request security ? */, + L2CAP_FCR_LE_COC_MODE, HearingAidImpl::GapCallbackStatic, + BT_TRANSPORT_LE); if (gap_handle == GAP_INVALID_HANDLE) { LOG(ERROR) << "UNABLE TO GET gap_handle"; return; @@ -993,6 +1018,17 @@ class HearingAidImpl : public HearingAid { return (OTHER_SIDE_NOT_STREAMING); } + void SendEnableServiceChangedInd(HearingDevice* device) { + VLOG(2) << __func__ << " Enable " << device->address + << "service changed ind."; + std::vector value(2); + uint8_t* ptr = value.data(); + UINT16_TO_STREAM(ptr, GATT_CHAR_CLIENT_CONFIG_INDICTION); + BtaGattQueue::WriteDescriptor( + device->conn_id, device->service_changed_ccc_handle, std::move(value), + GATT_WRITE, nullptr, nullptr); + } + void SendStart(HearingDevice* device) { std::vector start({CONTROL_POINT_OP_START, codec_in_use, AUDIOTYPE_UNKNOWN, (uint8_t)current_volume, @@ -1464,6 +1500,29 @@ class HearingAidImpl : public HearingAid { HearingDevices hearingDevices; + void find_server_changed_ccc_handle(uint16_t conn_id, + const gatt::Service* service) { + HearingDevice* hearingDevice = hearingDevices.FindByConnId(conn_id); + if (!hearingDevice) { + DVLOG(2) << "Skipping unknown device, conn_id=" << loghex(conn_id); + return; + } + for (const gatt::Characteristic& charac : service->characteristics) { + if (charac.uuid == Uuid::From16Bit(GATT_UUID_GATT_SRV_CHGD)) { + hearingDevice->service_changed_ccc_handle = + find_ccc_handle(conn_id, charac.value_handle); + if (!hearingDevice->service_changed_ccc_handle) { + LOG(ERROR) << __func__ + << ": cannot find service changed CCC descriptor"; + continue; + } + LOG(INFO) << __func__ << " service_changed_ccc=" + << loghex(hearingDevice->service_changed_ccc_handle); + break; + } + } + } + // Find the handle for the client characteristics configuration of a given // characteristics uint16_t find_ccc_handle(uint16_t conn_id, uint16_t char_handle) { @@ -1485,6 +1544,12 @@ class HearingAidImpl : public HearingAid { void send_state_change(HearingDevice* device, std::vector payload) { if (device->conn_id != 0) { + if (device->service_changed_rcvd) { + LOG(INFO) + << __func__ + << ": service discover is in progress, skip send State Change cmd."; + return; + } // Send the data packet LOG(INFO) << __func__ << ": Send State Change. device=" << device->address << ", status=" << loghex(payload[1]); @@ -1585,6 +1650,11 @@ void hearingaid_gattc_callback(tBTA_GATTC_EVT event, tBTA_GATTC* p_data) { instance->OnServiceChangeEvent(p_data->remote_bda); break; + case BTA_GATTC_SRVC_DISC_DONE_EVT: + if (!instance) return; + instance->OnServiceDiscDoneEvent(p_data->remote_bda); + break; + default: break; } diff --git a/bta/include/bta_gatt_api.h b/bta/include/bta_gatt_api.h index 618cb04ca..917650154 100644 --- a/bta/include/bta_gatt_api.h +++ b/bta/include/bta_gatt_api.h @@ -54,6 +54,7 @@ typedef struct { #define BTA_GATTC_CLOSE_EVT 5 /* GATTC close request status event */ #define BTA_GATTC_SEARCH_CMPL_EVT 6 /* GATT discovery complete event */ #define BTA_GATTC_SEARCH_RES_EVT 7 /* GATT discovery result event */ +#define BTA_GATTC_SRVC_DISC_DONE_EVT 8 /* GATT service discovery done event */ #define BTA_GATTC_NOTIF_EVT 10 /* GATT attribute notification event */ #define BTA_GATTC_EXEC_EVT 12 /* execute write complete event */ #define BTA_GATTC_ACL_EVT 13 /* ACL up event */ diff --git a/bta/include/bta_hearing_aid_api.h b/bta/include/bta_hearing_aid_api.h index efecdc751..aa8c7c7c2 100644 --- a/bta/include/bta_hearing_aid_api.h +++ b/bta/include/bta_hearing_aid_api.h @@ -24,6 +24,8 @@ #include #include +constexpr uint16_t HEARINGAID_MAX_NUM_UUIDS = 1; + constexpr uint16_t HA_INTERVAL_10_MS = 10; constexpr uint16_t HA_INTERVAL_20_MS = 20; @@ -82,6 +84,7 @@ struct HearingDevice { /* This is true only during first connection to profile, until we store the * device */ bool first_connection; + bool service_changed_rcvd; /* we are making active attempt to connect to this device, 'direct connect'. * This is true only during initial phase of first connection. */ @@ -107,8 +110,9 @@ struct HearingDevice { uint16_t audio_control_point_handle; uint16_t audio_status_handle; uint16_t audio_status_ccc_handle; + uint16_t service_changed_ccc_handle; uint16_t volume_handle; - uint16_t psm; + uint16_t read_psm_handle; uint8_t capabilities; uint64_t hi_sync_id; @@ -131,11 +135,15 @@ struct HearingDevice { int read_rssi_count; int num_intervals_since_last_rssi_read; - HearingDevice(const RawAddress& address, uint16_t psm, uint8_t capabilities, uint16_t codecs, - uint16_t audio_control_point_handle, uint16_t audio_status_handle, uint16_t audio_status_ccc_handle, - uint16_t volume_handle, uint64_t hiSyncId, uint16_t render_delay, uint16_t preparation_delay) + HearingDevice(const RawAddress& address, uint8_t capabilities, + uint16_t codecs, uint16_t audio_control_point_handle, + uint16_t audio_status_handle, uint16_t audio_status_ccc_handle, + uint16_t service_changed_ccc_handle, uint16_t volume_handle, + uint16_t read_psm_handle, uint64_t hiSyncId, + uint16_t render_delay, uint16_t preparation_delay) : address(address), first_connection(false), + service_changed_rcvd(false), connecting_actively(false), connection_update_status(NONE), accepting_audio(false), @@ -144,8 +152,9 @@ struct HearingDevice { audio_control_point_handle(audio_control_point_handle), audio_status_handle(audio_status_handle), audio_status_ccc_handle(audio_status_ccc_handle), + service_changed_ccc_handle(service_changed_ccc_handle), volume_handle(volume_handle), - psm(psm), + read_psm_handle(read_psm_handle), capabilities(capabilities), hi_sync_id(hiSyncId), render_delay(render_delay), @@ -158,6 +167,7 @@ struct HearingDevice { HearingDevice(const RawAddress& address, bool first_connection) : address(address), first_connection(first_connection), + service_changed_rcvd(false), connecting_actively(first_connection), connection_update_status(NONE), accepting_audio(false), @@ -165,7 +175,8 @@ struct HearingDevice { gap_handle(0), audio_status_handle(0), audio_status_ccc_handle(0), - psm(0), + service_changed_ccc_handle(0), + read_psm_handle(0), playback_started(false), command_acked(false), read_rssi_count(0) {} diff --git a/btif/src/btif_storage.cc b/btif/src/btif_storage.cc index d4cee12bd..a7462ff3e 100644 --- a/btif/src/btif_storage.cc +++ b/btif/src/btif_storage.cc @@ -1423,7 +1423,7 @@ bt_status_t btif_storage_remove_hid_info(RawAddress* remote_bd_addr) { return BT_STATUS_SUCCESS; } -constexpr char HEARING_AID_PSM[] = "HearingAidPsm"; +constexpr char HEARING_AID_READ_PSM_HANDLE[] = "HearingAidReadPsmHandle"; constexpr char HEARING_AID_CAPABILITIES[] = "HearingAidCapabilities"; constexpr char HEARING_AID_CODECS[] = "HearingAidCodecs"; constexpr char HEARING_AID_AUDIO_CONTROL_POINT[] = @@ -1433,6 +1433,8 @@ constexpr char HEARING_AID_AUDIO_STATUS_HANDLE[] = "HearingAidAudioStatusHandle"; constexpr char HEARING_AID_AUDIO_STATUS_CCC_HANDLE[] = "HearingAidAudioStatusCccHandle"; +constexpr char HEARING_AID_SERVICE_CHANGED_CCC_HANDLE[] = + "HearingAidServiceChangedCccHandle"; constexpr char HEARING_AID_SYNC_ID[] = "HearingAidSyncId"; constexpr char HEARING_AID_RENDER_DELAY[] = "HearingAidRenderDelay"; constexpr char HEARING_AID_PREPARATION_DELAY[] = "HearingAidPreparationDelay"; @@ -1445,7 +1447,10 @@ void btif_storage_add_hearing_aid(const HearingDevice& dev_info) { [](const HearingDevice& dev_info) { std::string bdstr = dev_info.address.ToString(); VLOG(2) << "saving hearing aid device: " << bdstr; - btif_config_set_int(bdstr, HEARING_AID_PSM, dev_info.psm); + btif_config_set_int(bdstr, HEARING_AID_SERVICE_CHANGED_CCC_HANDLE, + dev_info.service_changed_ccc_handle); + btif_config_set_int(bdstr, HEARING_AID_READ_PSM_HANDLE, + dev_info.read_psm_handle); btif_config_set_int(bdstr, HEARING_AID_CAPABILITIES, dev_info.capabilities); btif_config_set_int(bdstr, HEARING_AID_CODECS, dev_info.codecs); @@ -1477,11 +1482,26 @@ void btif_storage_load_bonded_hearing_aids() { const std::string& name = section.name; if (!RawAddress::IsValidAddress(name)) continue; - BTIF_TRACE_DEBUG("Remote device:%s", name.c_str()); + int size = STORAGE_UUID_STRING_SIZE * HEARINGAID_MAX_NUM_UUIDS; + char uuid_str[size]; + bool isHearingaidDevice = false; + if (btif_config_get_str(name, BTIF_STORAGE_PATH_REMOTE_SERVICE, uuid_str, + &size)) { + Uuid p_uuid[HEARINGAID_MAX_NUM_UUIDS]; + size_t num_uuids = + btif_split_uuids_string(uuid_str, p_uuid, HEARINGAID_MAX_NUM_UUIDS); + for (size_t i = 0; i < num_uuids; i++) { + if (p_uuid[i] == Uuid::FromString("FDF0")) { + isHearingaidDevice = true; + break; + } + } + } + if (!isHearingaidDevice) { + continue; + } - int value; - if (!btif_config_get_int(name, HEARING_AID_PSM, &value)) continue; - uint16_t psm = value; + BTIF_TRACE_DEBUG("Remote device:%s", name.c_str()); if (btif_in_fetch_bonded_device(name) != BT_STATUS_SUCCESS) { RawAddress bd_addr; @@ -1490,6 +1510,7 @@ void btif_storage_load_bonded_hearing_aids() { continue; } + int value; uint8_t capabilities = 0; if (btif_config_get_int(name, HEARING_AID_CAPABILITIES, &value)) capabilities = value; @@ -1509,10 +1530,19 @@ void btif_storage_load_bonded_hearing_aids() { if (btif_config_get_int(name, HEARING_AID_AUDIO_STATUS_CCC_HANDLE, &value)) audio_status_ccc_handle = value; + uint16_t service_changed_ccc_handle = 0; + if (btif_config_get_int(name, HEARING_AID_SERVICE_CHANGED_CCC_HANDLE, + &value)) + service_changed_ccc_handle = value; + uint16_t volume_handle = 0; if (btif_config_get_int(name, HEARING_AID_VOLUME_HANDLE, &value)) volume_handle = value; + uint16_t read_psm_handle = 0; + if (btif_config_get_int(name, HEARING_AID_READ_PSM_HANDLE, &value)) + read_psm_handle = value; + uint64_t lvalue; uint64_t hi_sync_id = 0; if (btif_config_get_uint64(name, HEARING_AID_SYNC_ID, &lvalue)) @@ -1537,9 +1567,10 @@ void btif_storage_load_bonded_hearing_aids() { do_in_main_thread( FROM_HERE, Bind(&HearingAid::AddFromStorage, - HearingDevice(bd_addr, psm, capabilities, codecs, + HearingDevice(bd_addr, capabilities, codecs, audio_control_point_handle, audio_status_handle, - audio_status_ccc_handle, volume_handle, hi_sync_id, + audio_status_ccc_handle, service_changed_ccc_handle, + volume_handle, read_psm_handle, hi_sync_id, render_delay, preparation_delay), is_white_listed)); } @@ -1548,13 +1579,17 @@ void btif_storage_load_bonded_hearing_aids() { /** Deletes the bonded hearing aid device info from NVRAM */ void btif_storage_remove_hearing_aid(const RawAddress& address) { std::string addrstr = address.ToString(); - - btif_config_remove(addrstr, HEARING_AID_PSM); + btif_config_remove(addrstr, HEARING_AID_READ_PSM_HANDLE); btif_config_remove(addrstr, HEARING_AID_CAPABILITIES); btif_config_remove(addrstr, HEARING_AID_CODECS); btif_config_remove(addrstr, HEARING_AID_AUDIO_CONTROL_POINT); btif_config_remove(addrstr, HEARING_AID_VOLUME_HANDLE); + btif_config_remove(addrstr, HEARING_AID_AUDIO_STATUS_HANDLE); + btif_config_remove(addrstr, HEARING_AID_AUDIO_STATUS_CCC_HANDLE); + btif_config_remove(addrstr, HEARING_AID_SERVICE_CHANGED_CCC_HANDLE); btif_config_remove(addrstr, HEARING_AID_SYNC_ID); + btif_config_remove(addrstr, HEARING_AID_RENDER_DELAY); + btif_config_remove(addrstr, HEARING_AID_PREPARATION_DELAY); btif_config_remove(addrstr, HEARING_AID_IS_WHITE_LISTED); btif_config_save(); }