*/
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 */
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) {
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);
}
}
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) {
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 "
} 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);
}
}
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;
return (OTHER_SIDE_NOT_STREAMING);
}
+ void SendEnableServiceChangedInd(HearingDevice* device) {
+ VLOG(2) << __func__ << " Enable " << device->address
+ << "service changed ind.";
+ std::vector<uint8_t> 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<uint8_t> start({CONTROL_POINT_OP_START, codec_in_use,
AUDIOTYPE_UNKNOWN, (uint8_t)current_volume,
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) {
void send_state_change(HearingDevice* device, std::vector<uint8_t> 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]);
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;
}
#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 */
#include <future>
#include <vector>
+constexpr uint16_t HEARINGAID_MAX_NUM_UUIDS = 1;
+
constexpr uint16_t HA_INTERVAL_10_MS = 10;
constexpr uint16_t HA_INTERVAL_20_MS = 20;
/* 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. */
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;
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),
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),
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),
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) {}
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[] =
"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";
[](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);
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;
continue;
}
+ int value;
uint8_t capabilities = 0;
if (btif_config_get_int(name, HEARING_AID_CAPABILITIES, &value))
capabilities = value;
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))
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));
}
/** 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();
}