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

Commit c0399e75 authored by Jakub Tyszkowski's avatar Jakub Tyszkowski
Browse files

LeAudio: Fix crash on bad remote audio allocation config

If multiple devices in a group happen to have the same audio
allocation, we will not know which one to choose on the 2nd
device. Since this is abnormal we should print an error but
not crash. Return any left or any right allocation that the
device has. In worst case, the device has no left nor right
location and we will return Disallowed value of 0. In such
case, the remote device can deny the stream enablement.

Bug: 256967923
Test: atest --host bluetooth_le_audio_test bluetooth_le_audio_client_test bluetooth_test_broadcaster bluetooth_test_broadcaster_state_machine --no-bazel-mode
Change-Id: Ib3a3f68a29690e8c50683476a3acbf11e7e33938
parent b8197244
Loading
Loading
Loading
Loading
+34 −37
Original line number Diff line number Diff line
@@ -1333,7 +1333,7 @@ bool LeAudioDeviceGroup::IsConfigurationSupported(
  return true;
}

uint32_t GetFirstLeft(const types::AudioLocations audio_locations) {
static uint32_t GetFirstLeft(const types::AudioLocations& audio_locations) {
  uint32_t audio_location_ulong = audio_locations.to_ulong();

  if (audio_location_ulong & codec_spec_conf::kLeAudioLocationFrontLeft)
@@ -1366,11 +1366,11 @@ uint32_t GetFirstLeft(const types::AudioLocations audio_locations) {
  if (audio_location_ulong & codec_spec_conf::kLeAudioLocationLeftSurround)
    return codec_spec_conf::kLeAudioLocationLeftSurround;

  LOG_ASSERT(0) << __func__ << " shall not happen";
  LOG_WARN("Can't find device able to render left audio channel");
  return 0;
}

uint32_t GetFirstRight(const types::AudioLocations audio_locations) {
static uint32_t GetFirstRight(const types::AudioLocations& audio_locations) {
  uint32_t audio_location_ulong = audio_locations.to_ulong();

  if (audio_location_ulong & codec_spec_conf::kLeAudioLocationFrontRight)
@@ -1404,47 +1404,41 @@ uint32_t GetFirstRight(const types::AudioLocations audio_locations) {
  if (audio_location_ulong & codec_spec_conf::kLeAudioLocationRightSurround)
    return codec_spec_conf::kLeAudioLocationRightSurround;

  LOG_ASSERT(0) << __func__ << " shall not happen";
  LOG_WARN("Can't find device able to render right audio channel");
  return 0;
}

uint32_t PickAudioLocation(types::LeAudioConfigurationStrategy strategy,
                           types::AudioLocations audio_locations,
                           types::AudioLocations* group_audio_locations) {
  DLOG(INFO) << __func__ << " strategy: " << (int)strategy
             << " locations: " << +audio_locations.to_ulong()
             << " group locations: " << +group_audio_locations->to_ulong();
                           types::AudioLocations device_locations,
                           types::AudioLocations* group_locations) {
  LOG_DEBUG("strategy: %d, locations: %lx, group locations: %lx", (int)strategy,
            device_locations.to_ulong(), group_locations->to_ulong());

  auto is_left_not_yet_assigned =
      !(group_locations->to_ulong() & codec_spec_conf::kLeAudioLocationAnyLeft);
  auto is_right_not_yet_assigned = !(group_locations->to_ulong() &
                                     codec_spec_conf::kLeAudioLocationAnyRight);
  uint32_t left_device_loc = GetFirstLeft(device_locations);
  uint32_t right_device_loc = GetFirstRight(device_locations);

  switch (strategy) {
    case types::LeAudioConfigurationStrategy::MONO_ONE_CIS_PER_DEVICE:
    case types::LeAudioConfigurationStrategy::STEREO_TWO_CISES_PER_DEVICE:
      if ((audio_locations.to_ulong() &
           codec_spec_conf::kLeAudioLocationAnyLeft) &&
          !(group_audio_locations->to_ulong() &
            codec_spec_conf::kLeAudioLocationAnyLeft)) {
        uint32_t left_location = GetFirstLeft(audio_locations);
        *group_audio_locations |= left_location;
        return left_location;
      if (left_device_loc && is_left_not_yet_assigned) {
        *group_locations |= left_device_loc;
        return left_device_loc;
      }

      if ((audio_locations.to_ulong() &
           codec_spec_conf::kLeAudioLocationAnyRight) &&
          !(group_audio_locations->to_ulong() &
            codec_spec_conf::kLeAudioLocationAnyRight)) {
        uint32_t right_location = GetFirstRight(audio_locations);
        *group_audio_locations |= right_location;
        return right_location;
      if (right_device_loc && is_right_not_yet_assigned) {
        *group_locations |= right_device_loc;
        return right_device_loc;
      }
      break;

    case types::LeAudioConfigurationStrategy::STEREO_ONE_CIS_PER_DEVICE:
      if ((audio_locations.to_ulong() &
           codec_spec_conf::kLeAudioLocationAnyLeft) &&
          (audio_locations.to_ulong() &
           codec_spec_conf::kLeAudioLocationAnyRight)) {
        uint32_t left_location = GetFirstLeft(audio_locations);
        uint32_t right_location = GetFirstRight(audio_locations);
        *group_audio_locations |= left_location | right_location;
        return left_location | right_location;
      if (left_device_loc && right_device_loc) {
        *group_locations |= left_device_loc | right_device_loc;
        return left_device_loc | right_device_loc;
      }
      break;
    default:
@@ -1452,12 +1446,15 @@ uint32_t PickAudioLocation(types::LeAudioConfigurationStrategy strategy,
      return 0;
  }

  LOG_ALWAYS_FATAL(
      "%s: Shall never exit switch statement, strategy: %hhu, "
      "locations: %lx, group_locations: %lx",
      __func__, strategy, audio_locations.to_ulong(),
      group_audio_locations->to_ulong());
  return 0;
  LOG_ERROR(
      "Can't find device for left/right channel. Strategy: %hhu, "
      "device_locations: %lx, group_locations: %lx.",
      strategy, device_locations.to_ulong(), group_locations->to_ulong());

  /* Return either any left or any right audio location. It might result with
   * multiple devices within the group having the same location.
   */
  return left_device_loc ? left_device_loc : right_device_loc;
}

bool LeAudioDevice::ConfigureAses(