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

Commit 504ee538 authored by William Escande's avatar William Escande
Browse files

Aics: shift ids to start at 0

Bug: 372328699
Flag: com.android.bluetooth.flags.aics_api
Test: atest vc_test
Change-Id: I97e343899b33d3b20c5bd275bb4b537cc70d690d
parent 4038e37a
Loading
Loading
Loading
Loading
+2 −3
Original line number Diff line number Diff line
@@ -947,9 +947,8 @@ public class VolumeControlService extends ProfileService {
            inputs.clear();
        }

        /* Stack delivers us number of audio inputs.
         * Offset ids a countinous from 1 to numberOfExternalInputs*/
        for (int i = 1; i <= numberOfExternalInputs; i++) {
        // Stack delivers us number of audio inputs. ids are countinous from [0;n[
        for (int i = 0; i < numberOfExternalInputs; i++) {
            inputs.add(i);
        }
    }
+42 −34
Original line number Diff line number Diff line
@@ -123,53 +123,61 @@ bool VolumeControlDevice::set_volume_control_service_handles(const gatt::Service
}

void VolumeControlDevice::set_audio_input_control_service_handles(const gatt::Service& service) {
  VolumeAudioInput input = VolumeAudioInput(service.handle);
  uint16_t state_handle{0};
  uint16_t state_ccc_handle{0};
  uint16_t gain_setting_handle{0};
  uint16_t type_handle{0};
  uint16_t status_handle{0};
  uint16_t status_ccc_handle{0};
  uint16_t control_point_handle{0};
  uint16_t description_handle{0};
  uint16_t description_ccc_handle{0};
  uint16_t description_writable{0};

  for (const gatt::Characteristic& chrc : service.characteristics) {
    if (chrc.uuid == kVolumeAudioInputStateUuid) {
      input.state_handle = chrc.value_handle;
      input.state_ccc_handle = find_ccc_handle(chrc.value_handle);
      log::debug("{}, input_state handle={:#x}, ccc {:#x}", address, input.state_handle,
                 input.state_ccc_handle);

    } else if (chrc.uuid == kVolumeAudioInputGainSettingUuid) {
      input.gain_setting_handle = chrc.value_handle;

      state_handle = chrc.value_handle;
      state_ccc_handle = find_ccc_handle(chrc.value_handle);
      log::debug("{} state_handle={:#x} ccc={:#x}", address, state_handle, state_ccc_handle);
    } else if (chrc.uuid == kVolumeAudioInputGainSettingPropertiesUuid) {
      gain_setting_handle = chrc.value_handle;
    } else if (chrc.uuid == kVolumeAudioInputTypeUuid) {
      input.type_handle = chrc.value_handle;

      type_handle = chrc.value_handle;
    } else if (chrc.uuid == kVolumeAudioInputStatusUuid) {
      input.status_handle = chrc.value_handle;
      input.status_ccc_handle = find_ccc_handle(chrc.value_handle);
      log::debug("{}, input_status handle={:#x}, ccc {:#x}", address, input.status_handle,
                 input.status_ccc_handle);

      status_handle = chrc.value_handle;
      status_ccc_handle = find_ccc_handle(chrc.value_handle);
      log::debug("{} status_handle={:#x} ccc={:#x}", address, status_handle, status_ccc_handle);
    } else if (chrc.uuid == kVolumeAudioInputControlPointUuid) {
      input.control_point_handle = chrc.value_handle;

      control_point_handle = chrc.value_handle;
    } else if (chrc.uuid == kVolumeAudioInputDescriptionUuid) {
      input.description_handle = chrc.value_handle;
      input.description_ccc_handle = find_ccc_handle(chrc.value_handle);
      input.description_writable = chrc.properties & GATT_CHAR_PROP_BIT_WRITE_NR;
      log::debug("{}, input_desc handle={:#x}, ccc {:#x}", address, input.description_handle,
                 input.description_ccc_handle);

      description_handle = chrc.value_handle;
      description_ccc_handle = find_ccc_handle(chrc.value_handle);
      description_writable = chrc.properties & GATT_CHAR_PROP_BIT_WRITE_NR;
      log::debug("{} description_handle={:#x} ccc={:#x}", address, description_handle,
                 description_ccc_handle);
    } else {
      log::warn("unknown characteristic={}", chrc.uuid);
      log::info("found unexpected characteristic={}", chrc.uuid);
    }
  }

  // Check if all mandatory attributes are present
  if (GATT_HANDLE_IS_VALID(input.state_handle) && GATT_HANDLE_IS_VALID(input.state_ccc_handle) &&
      GATT_HANDLE_IS_VALID(input.gain_setting_handle) && GATT_HANDLE_IS_VALID(input.type_handle) &&
      GATT_HANDLE_IS_VALID(input.status_handle) && GATT_HANDLE_IS_VALID(input.status_ccc_handle) &&
      GATT_HANDLE_IS_VALID(input.control_point_handle) &&
      GATT_HANDLE_IS_VALID(input.description_handle)
  if (!GATT_HANDLE_IS_VALID(state_handle) || !GATT_HANDLE_IS_VALID(state_ccc_handle) ||
      !GATT_HANDLE_IS_VALID(gain_setting_handle) || !GATT_HANDLE_IS_VALID(type_handle) ||
      !GATT_HANDLE_IS_VALID(status_handle) || !GATT_HANDLE_IS_VALID(status_ccc_handle) ||
      !GATT_HANDLE_IS_VALID(control_point_handle) || !GATT_HANDLE_IS_VALID(description_handle)
      /* description_ccc_handle is optional */) {
    log::error(
            "The remote device {} does not comply with AICS 1-0, some handles are invalid. "
            "The aics service with handle {:#x} will be ignored",
            address, service.handle);
    return;
  }
  VolumeAudioInput input = VolumeAudioInput(
          audio_inputs.Size(), service.handle, state_handle, state_ccc_handle, gain_setting_handle,
          type_handle, status_handle, status_ccc_handle, control_point_handle, description_handle,
          description_ccc_handle, description_writable);
  audio_inputs.Add(input);
  log::info("{}, input added id={:#x}", address, input.id);
  } else {
    log::warn("{}, ignoring input handle={:#x}", address, service.handle);
  }
}

void VolumeControlDevice::set_volume_offset_control_service_handles(const gatt::Service& service) {
+1 −1
Original line number Diff line number Diff line
@@ -156,7 +156,7 @@ private:
  /*
   * This is used to track the pending GATT operation handles. Once the list is
   * empty the device is assumed ready and connected. We are doing it because we
   * want to make sure all the required characteristics and descritors are
   * want to make sure all the required characteristics and descriptors are
   * available on server side.
   */
  std::unordered_set<uint16_t> handles_pending;
+18 −18
Original line number Diff line number Diff line
@@ -289,7 +289,7 @@ protected:
    builder.AddService(0x0020, 0x002e, kVolumeAudioInputUuid, false);
    builder.AddCharacteristic(0x0021, 0x0022, kVolumeAudioInputStateUuid, GATT_CHAR_PROP_BIT_READ);
    builder.AddDescriptor(0x0023, Uuid::From16Bit(GATT_UUID_CHAR_CLIENT_CONFIG));
    builder.AddCharacteristic(0x0024, 0x0025, kVolumeAudioInputGainSettingUuid,
    builder.AddCharacteristic(0x0024, 0x0025, kVolumeAudioInputGainSettingPropertiesUuid,
                              GATT_CHAR_PROP_BIT_READ);
    builder.AddCharacteristic(0x0026, 0x0027, kVolumeAudioInputTypeUuid, GATT_CHAR_PROP_BIT_READ);
    builder.AddCharacteristic(0x0028, 0x0029, kVolumeAudioInputStatusUuid,
@@ -305,7 +305,7 @@ protected:
    builder.AddCharacteristic(0x0041, 0x0042, kVolumeAudioInputStateUuid,
                              GATT_CHAR_PROP_BIT_READ | GATT_CHAR_PROP_BIT_NOTIFY);
    builder.AddDescriptor(0x0043, Uuid::From16Bit(GATT_UUID_CHAR_CLIENT_CONFIG));
    builder.AddCharacteristic(0x0044, 0x0045, kVolumeAudioInputGainSettingUuid,
    builder.AddCharacteristic(0x0044, 0x0045, kVolumeAudioInputGainSettingPropertiesUuid,
                              GATT_CHAR_PROP_BIT_READ);
    builder.AddCharacteristic(0x0046, 0x0047, kVolumeAudioInputTypeUuid, GATT_CHAR_PROP_BIT_READ);
    builder.AddCharacteristic(0x0048, 0x0049, kVolumeAudioInputStatusUuid,
@@ -388,7 +388,7 @@ TEST_F(VolumeControlDeviceTest, test_service_aics_incomplete) {
  builder.AddCharacteristic(0x000c, 0x000d, kVolumeAudioInputStateUuid,
                            GATT_CHAR_PROP_BIT_READ | GATT_CHAR_PROP_BIT_NOTIFY);
  builder.AddDescriptor(0x000e, Uuid::From16Bit(GATT_UUID_CHAR_CLIENT_CONFIG));
  builder.AddCharacteristic(0x000f, 0x0010, kVolumeAudioInputGainSettingUuid,
  builder.AddCharacteristic(0x000f, 0x0010, kVolumeAudioInputGainSettingPropertiesUuid,
                            GATT_CHAR_PROP_BIT_READ);
  builder.AddCharacteristic(0x0011, 0x0012, kVolumeAudioInputTypeUuid, GATT_CHAR_PROP_BIT_READ);
  builder.AddCharacteristic(0x0013, 0x0014, kVolumeAudioInputStatusUuid,
@@ -424,7 +424,7 @@ TEST_F(VolumeControlDeviceTest, test_service_aics_found) {
  builder.AddCharacteristic(0x000c, 0x000d, kVolumeAudioInputStateUuid,
                            GATT_CHAR_PROP_BIT_READ | GATT_CHAR_PROP_BIT_NOTIFY);
  builder.AddDescriptor(0x000e, Uuid::From16Bit(GATT_UUID_CHAR_CLIENT_CONFIG));
  builder.AddCharacteristic(0x000f, 0x0010, kVolumeAudioInputGainSettingUuid,
  builder.AddCharacteristic(0x000f, 0x0010, kVolumeAudioInputGainSettingPropertiesUuid,
                            GATT_CHAR_PROP_BIT_READ);
  builder.AddCharacteristic(0x0011, 0x0012, kVolumeAudioInputTypeUuid, GATT_CHAR_PROP_BIT_READ);
  builder.AddCharacteristic(0x0013, 0x0014, kVolumeAudioInputStatusUuid,
@@ -543,8 +543,8 @@ TEST_F(VolumeControlDeviceTest, test_multiple_services_found) {
  SetSampleDatabase1();
  ASSERT_EQ((size_t)2, device->audio_offsets.Size());
  ASSERT_EQ((size_t)2, device->audio_inputs.Size());
  VolumeAudioInput* input_1 = device->audio_inputs.FindById(1);
  VolumeAudioInput* input_2 = device->audio_inputs.FindById(2);
  VolumeAudioInput* input_1 = device->audio_inputs.FindById(0);
  VolumeAudioInput* input_2 = device->audio_inputs.FindById(1);
  ASSERT_NE(nullptr, input_1);
  ASSERT_NE(nullptr, input_2);
  ASSERT_NE(input_1->service_handle, input_2->service_handle);
@@ -579,7 +579,7 @@ TEST_F(VolumeControlDeviceTest, test_enqueue_initial_requests) {
  tGATT_IF gatt_if = 0x0001;
  std::vector<uint8_t> register_for_notification_data({0x01, 0x00});

  std::map<uint16_t, uint16_t> expected_subscribtions{
  std::map<uint16_t, uint16_t> expected_subscriptions{
          {0x0011, 0x0012} /* volume control state */,
          {0x0016, 0x0017} /* volume control flags */,
          {0x0022, 0x0023} /* audio input state 1 */,
@@ -596,7 +596,7 @@ TEST_F(VolumeControlDeviceTest, test_enqueue_initial_requests) {
  EXPECT_CALL(gatt_queue, ReadCharacteristic(_, 0x0011, _, _));
  EXPECT_CALL(gatt_queue, ReadCharacteristic(_, 0x0016, _, _));

  for (auto const& handle_pair : expected_subscribtions) {
  for (auto const& handle_pair : expected_subscriptions) {
    EXPECT_CALL(gatt_queue, WriteDescriptor(_, handle_pair.second, register_for_notification_data,
                                            GATT_WRITE, _, _));
    EXPECT_CALL(gatt_interface, RegisterForNotifications(gatt_if, _, handle_pair.first));
@@ -857,7 +857,7 @@ TEST_F(VolumeControlDeviceTest, test_get_ext_audio_in_state) {
                               uint16_t /*len*/, uint8_t* /*value*/, void* /*data*/) {};
  SetSampleDatabase1();
  EXPECT_CALL(gatt_queue, ReadCharacteristic(_, 0x0022, read_cb, nullptr));
  device->GetExtAudioInState(1, read_cb, nullptr);
  device->GetExtAudioInState(0, read_cb, nullptr);
}

TEST_F(VolumeControlDeviceTest, test_get_ext_audio_in_status) {
@@ -865,7 +865,7 @@ TEST_F(VolumeControlDeviceTest, test_get_ext_audio_in_status) {
                               uint16_t /*len*/, uint8_t* /*value*/, void* /*data*/) {};
  SetSampleDatabase1();
  EXPECT_CALL(gatt_queue, ReadCharacteristic(_, 0x0049, read_cb, nullptr));
  device->GetExtAudioInStatus(2, read_cb, nullptr);
  device->GetExtAudioInStatus(1, read_cb, nullptr);
}

TEST_F(VolumeControlDeviceTest, test_get_ext_audio_in_gain_props) {
@@ -873,7 +873,7 @@ TEST_F(VolumeControlDeviceTest, test_get_ext_audio_in_gain_props) {
                               uint16_t /*len*/, uint8_t* /*value*/, void* /*data*/) {};
  SetSampleDatabase1();
  EXPECT_CALL(gatt_queue, ReadCharacteristic(_, 0x0025, read_cb, nullptr));
  device->GetExtAudioInGainProps(1, read_cb, nullptr);
  device->GetExtAudioInGainProps(0, read_cb, nullptr);
}

TEST_F(VolumeControlDeviceTest, test_get_ext_audio_in_description) {
@@ -881,7 +881,7 @@ TEST_F(VolumeControlDeviceTest, test_get_ext_audio_in_description) {
                               uint16_t /*len*/, uint8_t* /*value*/, void* /*data*/) {};
  SetSampleDatabase1();
  EXPECT_CALL(gatt_queue, ReadCharacteristic(_, 0x002e, read_cb, nullptr));
  device->GetExtAudioInDescription(1, read_cb, nullptr);
  device->GetExtAudioInDescription(0, read_cb, nullptr);
}

TEST_F(VolumeControlDeviceTest, test_set_ext_audio_in_description) {
@@ -890,7 +890,7 @@ TEST_F(VolumeControlDeviceTest, test_set_ext_audio_in_description) {
  std::vector<uint8_t> expected_data(descr.begin(), descr.end());
  EXPECT_CALL(gatt_queue,
              WriteCharacteristic(_, 0x004e, expected_data, GATT_WRITE_NO_RSP, nullptr, nullptr));
  device->SetExtAudioInDescription(2, descr);
  device->SetExtAudioInDescription(1, descr);
}

TEST_F(VolumeControlDeviceTest, test_set_ext_audio_in_description_non_writable) {
@@ -898,34 +898,34 @@ TEST_F(VolumeControlDeviceTest, test_set_ext_audio_in_description_non_writable)
  std::string descr = "AUX";
  std::vector<uint8_t> expected_data(descr.begin(), descr.end());
  EXPECT_CALL(gatt_queue, WriteCharacteristic(_, _, _, _, _, _)).Times(0);
  device->SetExtAudioInDescription(1, descr);
  device->SetExtAudioInDescription(0, descr);
}

TEST_F(VolumeControlDeviceTest, test_ext_audio_in_control_point_operation) {
  GATT_WRITE_OP_CB write_cb = [](uint16_t /*conn_id*/, tGATT_STATUS /*status*/, uint16_t /*handle*/,
                                 uint16_t /*len*/, const uint8_t* /*value*/, void* /*data*/) {};
  SetSampleDatabase1();
  VolumeAudioInput* input = device->audio_inputs.FindById(2);
  VolumeAudioInput* input = device->audio_inputs.FindById(1);
  ASSERT_NE(nullptr, input);
  input->change_counter = 0x11;
  std::vector<uint8_t> expected_data({0x0c, 0x11});
  EXPECT_CALL(gatt_queue,
              WriteCharacteristic(_, 0x004c, expected_data, GATT_WRITE, write_cb, nullptr));
  device->ExtAudioInControlPointOperation(2, 0x0c, nullptr, write_cb, nullptr);
  device->ExtAudioInControlPointOperation(1, 0x0c, nullptr, write_cb, nullptr);
}

TEST_F(VolumeControlDeviceTest, test_ext_audio_in_control_point_operation_arg) {
  GATT_WRITE_OP_CB write_cb = [](uint16_t /*conn_id*/, tGATT_STATUS /*status*/, uint16_t /*handle*/,
                                 uint16_t /*len*/, const uint8_t* /*value*/, void* /*data*/) {};
  SetSampleDatabase1();
  VolumeAudioInput* input = device->audio_inputs.FindById(2);
  VolumeAudioInput* input = device->audio_inputs.FindById(1);
  ASSERT_NE(nullptr, input);
  input->change_counter = 0x12;
  std::vector<uint8_t> expected_data({0x0d, 0x12, 0x01, 0x02, 0x03, 0x04});
  std::vector<uint8_t> arg({0x01, 0x02, 0x03, 0x04});
  EXPECT_CALL(gatt_queue,
              WriteCharacteristic(_, 0x004c, expected_data, GATT_WRITE, write_cb, nullptr));
  device->ExtAudioInControlPointOperation(2, 0x0d, &arg, write_cb, nullptr);
  device->ExtAudioInControlPointOperation(1, 0x0d, &arg, write_cb, nullptr);
}

}  // namespace internal
+61 −67
Original line number Diff line number Diff line
@@ -66,7 +66,7 @@ static const Uuid kVolumeOffsetOutputDescriptionUuid = Uuid::From16Bit(0x2B83);

static const Uuid kVolumeAudioInputUuid                      = Uuid::From16Bit(0x1843);
static const Uuid kVolumeAudioInputStateUuid                 = Uuid::From16Bit(0x2B77);
static const Uuid kVolumeAudioInputGainSettingUuid    = Uuid::From16Bit(0x2B78);
static const Uuid kVolumeAudioInputGainSettingPropertiesUuid = Uuid::From16Bit(0x2B78);
static const Uuid kVolumeAudioInputTypeUuid                  = Uuid::From16Bit(0x2B79);
static const Uuid kVolumeAudioInputStatusUuid                = Uuid::From16Bit(0x2B7A);
static const Uuid kVolumeAudioInputControlPointUuid          = Uuid::From16Bit(0x2B7B);
@@ -127,64 +127,58 @@ struct VolumeOperation {
};

struct GainSettings {
  uint8_t unit;
  int8_t min;
  int8_t max;
  uint8_t unit = 0;
  int8_t min = 0;
  int8_t max = 0;

  GainSettings() : unit(0), min(0), max(0) {}
  GainSettings() {}
};

struct VolumeAudioInput {
  uint8_t id;
  bool mute;
  int8_t gain_value;
  VolumeInputStatus status;
  VolumeInputType type;
  uint8_t change_counter;
  uint8_t mode;
  std::string description;
  uint16_t service_handle;
  uint16_t state_handle;
  uint16_t state_ccc_handle;
  uint16_t gain_setting_handle;
  uint16_t type_handle;
  uint16_t status_handle;
  uint16_t status_ccc_handle;
  uint16_t control_point_handle;
  uint16_t description_handle;
  uint16_t description_ccc_handle;
  bool description_writable;
  struct GainSettings gain_settings;

  explicit VolumeAudioInput(uint16_t service_handle)
      : id(0),
        mute(false),
        gain_value(0),
        status(VolumeInputStatus::Inactive),
        type(VolumeInputType::Unspecified),
        change_counter(0),
        mode(0),
        description(""),
  /* const */ uint8_t id;
  bool mute = false;
  int8_t gain_value = 0;
  VolumeInputStatus status = VolumeInputStatus::Inactive;
  VolumeInputType type = VolumeInputType::Unspecified;
  uint8_t change_counter = 0;
  uint8_t mode = 0;
  std::string description = "";
  /* const */ uint16_t service_handle;
  /* const */ uint16_t state_handle;
  /* const */ uint16_t state_ccc_handle;
  /* const */ uint16_t gain_setting_handle;
  /* const */ uint16_t type_handle;
  /* const */ uint16_t status_handle;
  /* const */ uint16_t status_ccc_handle;
  /* const */ uint16_t control_point_handle;
  /* const */ uint16_t description_handle;
  /* const */ uint16_t description_ccc_handle;
  /* const */ bool description_writable;
  struct GainSettings gain_settings = GainSettings();

  explicit VolumeAudioInput(uint8_t id, uint16_t service_handle, uint16_t state_handle,
                            uint16_t state_ccc_handle, uint16_t gain_setting_handle,
                            uint16_t type_handle, uint16_t status_handle,
                            uint16_t status_ccc_handle, uint16_t control_point_handle,
                            uint16_t description_handle, uint16_t description_ccc_handle,
                            bool description_writable)
      : id(id),
        service_handle(service_handle),
        state_handle(0),
        state_ccc_handle(0),
        gain_setting_handle(0),
        type_handle(0),
        status_handle(0),
        status_ccc_handle(0),
        control_point_handle(0),
        description_handle(0),
        description_ccc_handle(0),
        description_writable(false),
        gain_settings(GainSettings()) {}
        state_handle(state_handle),
        state_ccc_handle(state_ccc_handle),
        gain_setting_handle(gain_setting_handle),
        type_handle(type_handle),
        status_handle(status_handle),
        status_ccc_handle(status_ccc_handle),
        control_point_handle(control_point_handle),
        description_handle(description_handle),
        description_ccc_handle(description_ccc_handle),
        description_writable(description_writable) {}
};

class VolumeAudioInputs {
public:
  void Add(VolumeAudioInput input) {
    input.id = (uint8_t)Size() + 1;
    volume_audio_inputs.push_back(input);
  }
  void Add(VolumeAudioInput input) { volume_audio_inputs.push_back(input); }

  VolumeAudioInput* FindByType(VolumeInputType type) {
    auto iter = std::find_if(volume_audio_inputs.begin(), volume_audio_inputs.end(),
Loading