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

Commit eb6cb85d authored by Stanley Tng's avatar Stanley Tng Committed by android-build-merger
Browse files

Merge "Wait for Notifications before sending audio data" am: 16739a8e

am: b56b98d8

Change-Id: I24474c29c0b4bdc65148357dde18677e404f068c
parents f09c3c15 b56b98d8
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -639,7 +639,7 @@ tGATT_STATUS BTA_GATTC_RegisterForNotifications(tGATT_IF client_if,
  uint8_t i;

  if (!handle) {
    LOG(ERROR) << "deregistration failed, handle is 0";
    LOG(ERROR) << __func__ << ": registration failed, handle is 0";
    return status;
  }

+140 −8
Original line number Diff line number Diff line
@@ -151,6 +151,14 @@ class HearingDevices {
  std::vector<HearingDevice> devices;
};

static void write_rpt_ctl_cfg_cb(uint16_t conn_id, tGATT_STATUS status,
                                 uint16_t handle, void* data) {
  if (status != GATT_SUCCESS) {
    LOG(ERROR) << __func__ << ": handle=" << handle << ", conn_id=" << conn_id
               << ", status=" << loghex(status);
  }
}

g722_encode_state_t* encoder_state_left = nullptr;
g722_encode_state_t* encoder_state_right = nullptr;

@@ -434,6 +442,26 @@ class HearingAidImpl : public HearingAid {
    BTA_GATTC_ServiceSearchRequest(hearingDevice->conn_id, &HEARING_AID_UUID);
  }

  void OnServiceChangeEvent(const RawAddress& address) {
    HearingDevice* hearingDevice = hearingDevices.FindByAddress(address);
    if (!hearingDevice) {
      VLOG(2) << "Skipping unknown device" << address;
      return;
    }
    LOG(INFO) << __func__ << ": address=" << address;

    /* 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 OnServiceSearchComplete(uint16_t conn_id, tGATT_STATUS status) {
    HearingDevice* hearingDevice = hearingDevices.FindByConnId(conn_id);
    if (!hearingDevice) {
@@ -483,10 +511,18 @@ class HearingAidImpl : public HearingAid {
        hearingDevice->audio_control_point_handle = charac.value_handle;
        // store audio control point!
      } else if (charac.uuid == AUDIO_STATUS_UUID) {
        DVLOG(2) << "Reading Audio status " << loghex(charac.value_handle);
        BtaGattQueue::ReadCharacteristic(conn_id, charac.value_handle,
                                         HearingAidImpl::OnAudioStatusStatic,
                                         nullptr);
        hearingDevice->audio_status_handle = charac.value_handle;

        hearingDevice->audio_status_ccc_handle =
            find_ccc_handle(conn_id, charac.value_handle);
        if (!hearingDevice->audio_status_ccc_handle) {
          LOG(ERROR) << __func__ << ": cannot find Audio Status CCC descriptor";
          continue;
        }

        LOG(INFO) << __func__
                  << ": audio_status_handle=" << loghex(charac.value_handle)
                  << ", ccc=" << loghex(hearingDevice->audio_status_ccc_handle);
      } else if (charac.uuid == VOLUME_UUID) {
        hearingDevice->volume_handle = charac.value_handle;
      } else if (charac.uuid == LE_PSM_UUID) {
@@ -503,6 +539,40 @@ class HearingAidImpl : public HearingAid {
    }
  }

  void OnNotificationEvent(uint16_t conn_id, uint16_t handle, uint16_t len,
                           uint8_t* value) {
    HearingDevice* device = hearingDevices.FindByConnId(conn_id);
    if (!device) {
      LOG(INFO) << __func__
                << ": Skipping unknown device, conn_id=" << loghex(conn_id);
      return;
    }

    if (device->audio_status_handle != handle) {
      LOG(INFO) << __func__ << ": Mismatched handle, "
                << loghex(device->audio_status_handle)
                << "!=" << loghex(handle);
      return;
    }

    if (len < 1) {
      LOG(ERROR) << __func__ << ": Data Length too small, len=" << len
                 << ", expecting at least 1";
      return;
    }

    if (value[0] != 0) {
      LOG(INFO) << __func__
                << ": Invalid returned status. data=" << loghex(value[0]);
      return;
    }

    LOG(INFO) << __func__
              << ": audio status success notification. command_acked="
              << device->command_acked;
    device->command_acked = true;
  }

  void OnReadOnlyPropertiesRead(uint16_t conn_id, tGATT_STATUS status,
                                uint16_t handle, uint16_t len, uint8_t* value,
                                void* data) {
@@ -698,6 +768,28 @@ class HearingAidImpl : public HearingAid {
      hearingDevice->first_connection = false;
    }

    LOG(INFO) << __func__ << ": audio_status_handle="
              << loghex(hearingDevice->audio_status_handle)
              << ", audio_status_ccc_handle="
              << loghex(hearingDevice->audio_status_ccc_handle);

    /* Register and enable the Audio Status Notification */
    tGATT_STATUS register_status;
    register_status = BTA_GATTC_RegisterForNotifications(
        gatt_if, address, hearingDevice->audio_status_handle);
    if (register_status != GATT_SUCCESS) {
      LOG(ERROR) << __func__
                 << ": BTA_GATTC_RegisterForNotifications failed, status="
                 << loghex(register_status);
      return;
    }
    std::vector<uint8_t> value(2);
    uint8_t* ptr = value.data();
    UINT16_TO_STREAM(ptr, GATT_CHAR_CLIENT_CONFIG_NOTIFICATION);
    BtaGattQueue::WriteDescriptor(
        hearingDevice->conn_id, hearingDevice->audio_status_ccc_handle,
        std::move(value), GATT_WRITE, write_rpt_ctl_cfg_cb, nullptr);

    ChooseCodec(*hearingDevice);

    SendStart(hearingDevice);
@@ -715,7 +807,7 @@ class HearingAidImpl : public HearingAid {
  }

  void StartSendingAudio(const HearingDevice& hearingDevice) {
    VLOG(0) << __func__ << hearingDevice.address;
    VLOG(0) << __func__ << ": device=" << hearingDevice.address;

    if (encoder_state_left == nullptr) {
      encoder_state_left = g722_encode_init(nullptr, 64000, G722_PACKED);
@@ -764,6 +856,7 @@ class HearingAidImpl : public HearingAid {
      } else {
        LOG(INFO) << __func__ << ": send Stop cmd, device=" << device.address;
        device.playback_started = false;
        device.command_acked = false;
        BtaGattQueue::WriteCharacteristic(device.conn_id,
                                          device.audio_control_point_handle,
                                          stop, GATT_WRITE, nullptr, nullptr);
@@ -822,6 +915,7 @@ class HearingAidImpl : public HearingAid {
                << ", audio type=" << loghex(start[2])
                << ", device=" << device->address;
      device->playback_started = true;
      device->command_acked = false;
      BtaGattQueue::WriteCharacteristic(device->conn_id,
                                        device->audio_control_point_handle,
                                        start, GATT_WRITE, nullptr, nullptr);
@@ -960,9 +1054,11 @@ class HearingAidImpl : public HearingAid {

  void SendAudio(uint8_t* encoded_data, uint16_t packet_size,
                 HearingDevice* hearingAid) {
    if (!hearingAid->playback_started) {
      LOG(INFO) << __func__
                << ": Playback not started, device=" << hearingAid->address;
    if (!hearingAid->playback_started || !hearingAid->command_acked) {
      VLOG(2) << __func__
              << ": Playback stalled, device=" << hearingAid->address
              << ", cmd send=" << hearingAid->playback_started
              << ", cmd acked=" << hearingAid->command_acked;
      return;
    }

@@ -1006,6 +1102,7 @@ class HearingAidImpl : public HearingAid {
        hearingDevice->accepting_audio = false;
        hearingDevice->gap_handle = 0;
        hearingDevice->playback_started = false;
        hearingDevice->command_acked = false;
        break;
      case GAP_EVT_CONN_DATA_AVAIL: {
        DVLOG(2) << "GAP_EVT_CONN_DATA_AVAIL";
@@ -1164,6 +1261,7 @@ class HearingAidImpl : public HearingAid {
    LOG(INFO) << __func__ << ": device=" << hearingDevice->address
              << ", playback_started=" << hearingDevice->playback_started;
    hearingDevice->playback_started = false;
    hearingDevice->command_acked = false;
  }

  void SetVolume(int8_t volume) override {
@@ -1201,6 +1299,25 @@ class HearingAidImpl : public HearingAid {
  uint16_t default_data_interval_ms;

  HearingDevices hearingDevices;

  // 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) {
    const gatt::Characteristic* p_char =
        BTA_GATTC_GetCharacteristic(conn_id, char_handle);

    if (!p_char) {
      LOG(WARNING) << __func__ << ": No such characteristic: " << char_handle;
      return 0;
    }

    for (const gatt::Descriptor& desc : p_char->descriptors) {
      if (desc.uuid == Uuid::From16Bit(GATT_UUID_CHAR_CLIENT_CONFIG))
        return desc.handle;
    }

    return 0;
  }
};

void hearingaid_gattc_callback(tBTA_GATTC_EVT event, tBTA_GATTC* p_data) {
@@ -1234,6 +1351,16 @@ void hearingaid_gattc_callback(tBTA_GATTC_EVT event, tBTA_GATTC* p_data) {
      break;

    case BTA_GATTC_NOTIF_EVT:
      if (!instance) return;
      if (!p_data->notify.is_notify || p_data->notify.len > GATT_MAX_ATTR_LEN) {
        LOG(ERROR) << __func__ << ": rejected BTA_GATTC_NOTIF_EVT. is_notify="
                   << p_data->notify.is_notify
                   << ", len=" << p_data->notify.len;
        break;
      }
      instance->OnNotificationEvent(p_data->notify.conn_id,
                                    p_data->notify.handle, p_data->notify.len,
                                    p_data->notify.value);
      break;

    case BTA_GATTC_ENC_CMPL_CB_EVT:
@@ -1246,6 +1373,11 @@ void hearingaid_gattc_callback(tBTA_GATTC_EVT event, tBTA_GATTC* p_data) {
      instance->OnConnectionUpdateComplete(p_data->conn_update.conn_id, p_data);
      break;

    case BTA_GATTC_SRVC_CHG_EVT:
      if (!instance) return;
      instance->OnServiceChangeEvent(p_data->remote_bda);
      break;

    default:
      break;
  }
+14 −2
Original line number Diff line number Diff line
@@ -91,6 +91,8 @@ struct HearingDevice {
  uint16_t conn_id;
  uint16_t gap_handle;
  uint16_t audio_control_point_handle;
  uint16_t audio_status_handle;
  uint16_t audio_status_ccc_handle;
  uint16_t volume_handle;
  uint16_t psm;

@@ -106,9 +108,13 @@ struct HearingDevice {
     cleared. Please note that the "Start Cmd" is not send during device
     connection in the case when the audio is suspended. */
  bool playback_started;
  /* This tracks whether the last command to Hearing Aids device is
   * ACKnowledged. */
  bool command_acked;

  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)
      : address(address),
@@ -119,6 +125,8 @@ struct HearingDevice {
        conn_id(0),
        gap_handle(0),
        audio_control_point_handle(audio_control_point_handle),
        audio_status_handle(audio_status_handle),
        audio_status_ccc_handle(audio_status_ccc_handle),
        volume_handle(volume_handle),
        psm(psm),
        capabilities(capabilities),
@@ -126,7 +134,8 @@ struct HearingDevice {
        render_delay(render_delay),
        preparation_delay(preparation_delay),
        codecs(codecs),
        playback_started(false) {}
        playback_started(false),
        command_acked(false) {}

  HearingDevice(const RawAddress& address, bool first_connection)
      : address(address),
@@ -136,8 +145,11 @@ struct HearingDevice {
        accepting_audio(false),
        conn_id(0),
        gap_handle(0),
        audio_status_handle(0),
        audio_status_ccc_handle(0),
        psm(0),
        playback_started(false) {}
        playback_started(false),
        command_acked(false) {}

  HearingDevice() : HearingDevice(RawAddress::kEmpty, false) {}

+19 −2
Original line number Diff line number Diff line
@@ -1430,6 +1430,10 @@ constexpr char HEARING_AID_CODECS[] = "HearingAidCodecs";
constexpr char HEARING_AID_AUDIO_CONTROL_POINT[] =
    "HearingAidAudioControlPoint";
constexpr char HEARING_AID_VOLUME_HANDLE[] = "HearingAidVolumeHandle";
constexpr char HEARING_AID_AUDIO_STATUS_HANDLE[] =
    "HearingAidAudioStatusHandle";
constexpr char HEARING_AID_AUDIO_STATUS_CCC_HANDLE[] =
    "HearingAidAudioStatusCccHandle";
constexpr char HEARING_AID_SYNC_ID[] = "HearingAidSyncId";
constexpr char HEARING_AID_RENDER_DELAY[] = "HearingAidRenderDelay";
constexpr char HEARING_AID_PREPARATION_DELAY[] = "HearingAidPreparationDelay";
@@ -1450,6 +1454,10 @@ void btif_storage_add_hearing_aid(const HearingDevice& dev_info) {
                                dev_info.audio_control_point_handle);
            btif_config_set_int(bdstr, HEARING_AID_VOLUME_HANDLE,
                                dev_info.volume_handle);
            btif_config_set_int(bdstr, HEARING_AID_AUDIO_STATUS_HANDLE,
                                dev_info.audio_status_handle);
            btif_config_set_int(bdstr, HEARING_AID_AUDIO_STATUS_CCC_HANDLE,
                                dev_info.audio_status_ccc_handle);
            btif_config_set_uint64(bdstr, HEARING_AID_SYNC_ID,
                                   dev_info.hi_sync_id);
            btif_config_set_int(bdstr, HEARING_AID_RENDER_DELAY,
@@ -1494,6 +1502,14 @@ void btif_storage_load_bonded_hearing_aids() {
    if (btif_config_get_int(name, HEARING_AID_AUDIO_CONTROL_POINT, &value))
      audio_control_point_handle = value;

    uint16_t audio_status_handle = 0;
    if (btif_config_get_int(name, HEARING_AID_AUDIO_STATUS_HANDLE, &value))
      audio_status_handle = value;

    uint16_t audio_status_ccc_handle = 0;
    if (btif_config_get_int(name, HEARING_AID_AUDIO_STATUS_CCC_HANDLE, &value))
      audio_status_ccc_handle = value;

    uint16_t volume_handle = 0;
    if (btif_config_get_int(name, HEARING_AID_VOLUME_HANDLE, &value))
      volume_handle = value;
@@ -1523,8 +1539,9 @@ void btif_storage_load_bonded_hearing_aids() {
        FROM_HERE,
        Bind(&HearingAid::AddFromStorage,
             HearingDevice(bd_addr, psm, capabilities, codecs,
                           audio_control_point_handle, volume_handle,
                           hi_sync_id, render_delay, preparation_delay),
                           audio_control_point_handle, audio_status_handle,
                           audio_status_ccc_handle, volume_handle, hi_sync_id,
                           render_delay, preparation_delay),
             is_white_listed));
  }
}
+6 −2
Original line number Diff line number Diff line
@@ -52,6 +52,10 @@
#define GATT_UUID_EXT_RPT_REF_DESCR 0x2907
#define GATT_UUID_RPT_REF_DESCR 0x2908

/*  Client Characteristic Configuration bits */
#define GATT_CHAR_CLIENT_CONFIG_NOTIFICATION 0x0001
#define GATT_CHAR_CLIENT_CONFIG_INDICTION 0x0002

/* GAP Profile Attributes
 */
#define GATT_UUID_GAP_DEVICE_NAME 0x2A00