Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit aa9465bd authored by weichinweng's avatar weichinweng Committed by Stanley Tng
Browse files

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
parent d2b1bfa0
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -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 */
+103 −33
Original line number Diff line number Diff line
@@ -521,14 +521,17 @@ 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);
    }
  }

  void OnServiceChangeEvent(const RawAddress& address) {
    HearingDevice* hearingDevice = hearingDevices.FindByAddress(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;
      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;
      break;
      }
    }

    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<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,
@@ -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<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]);
@@ -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;
  }
+1 −0
Original line number Diff line number Diff line
@@ -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 */
+17 −6
Original line number Diff line number Diff line
@@ -24,6 +24,8 @@
#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;

@@ -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) {}
+45 −10
Original line number Diff line number Diff line
@@ -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();
}