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

Commit 16739a8e authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "Wait for Notifications before sending audio data"

parents 1fdcae14 9100ae8b
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