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

Commit 31281b7c authored by weichinweng's avatar weichinweng Committed by android-build-merger
Browse files

Add service change handle for Hearing Aids

am: aa9465bd

Change-Id: I77c2bec2821d939fe8323d64ab051260bf9d57ee
parents c1d2b10a aa9465bd
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,
@@ -1462,6 +1498,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) {
@@ -1483,6 +1542,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]);
@@ -1583,6 +1648,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();
}