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

Commit 6b4cc68d authored by Grzegorz Kołodziejczyk's avatar Grzegorz Kołodziejczyk
Browse files

le_audio: Suspend not allowed updated stream

Resumed stream in which only not allowed contexts will remain should be
suspended and stream stopped. This would help to make faster fallback to
broadcast e.g. while only remaining context after playing media will be
sound effects.

Bug: 360051130
Bug: 376251433
Test: atest bluetooth_le_audio_client_test
Flag: com.android.bluetooth.flags.leaudio_stop_updated_to_not_available_context_stream
Change-Id: I351f659213e7b7170d43f03e4685ce9d40e8e78f
parent fad5b715
Loading
Loading
Loading
Loading
+83 −4
Original line number Diff line number Diff line
@@ -4402,10 +4402,21 @@ public:
      return;
    }

    /* Group should not be resumed if:
     * - configured context type is not allowed
     * - updated metadata contains only not allowed context types
     */
    if (!group->GetAllowedContextMask(bluetooth::le_audio::types::kLeAudioDirectionSink)
                 .test_all(local_metadata_context_types_.source) ||
        !group->GetAllowedContextMask(bluetooth::le_audio::types::kLeAudioDirectionSink)
                 .test(configuration_context_type_)) {
      log::warn("Block source resume request context type: {}",
                ToHexString(configuration_context_type_));
      log::warn(
              "Block source resume request context types: {}, allowed context mask: {}, "
              "configured: {}",
              ToString(local_metadata_context_types_.source),
              ToString(group->GetAllowedContextMask(
                      bluetooth::le_audio::types::kLeAudioDirectionSink)),
              ToString(configuration_context_type_));
      CancelLocalAudioSourceStreamingRequest();
      return;
    }
@@ -4679,10 +4690,21 @@ public:
      return;
    }

    /* Group should not be resumed if:
     * - configured context type is not allowed
     * - updated metadata contains only not allowed context types
     */
    if (!group->GetAllowedContextMask(bluetooth::le_audio::types::kLeAudioDirectionSource)
                 .test_all(local_metadata_context_types_.sink) ||
        !group->GetAllowedContextMask(bluetooth::le_audio::types::kLeAudioDirectionSource)
                 .test(configuration_context_type_)) {
      log::warn("Block sink resume request context type: {}",
                ToHexString(configuration_context_type_));
      log::warn(
              "Block sink resume request context types: {} vs allowed context mask: {}, "
              "configured: {}",
              ToString(local_metadata_context_types_.sink),
              ToString(group->GetAllowedContextMask(
                      bluetooth::le_audio::types::kLeAudioDirectionSource)),
              ToString(configuration_context_type_));
      CancelLocalAudioSourceStreamingRequest();
      return;
    }
@@ -4911,6 +4933,30 @@ public:
    return true;
  }

  bool StopStreamIfUpdatedContextIsNoLongerSupporteded(uint8_t direction, LeAudioDeviceGroup* group,
                                                       AudioContexts local_contexts) {
    AudioContexts allowed_contexts = group->GetAllowedContextMask(direction);

    /* Stream should be suspended if:
     * - updated metadata is only not allowed
     * - there is no metadata (cleared) but configuration is for not allowed context
     */
    if (group->IsStreaming() && !allowed_contexts.test_any(local_contexts) &&
        !(allowed_contexts.test(configuration_context_type_) && local_contexts.none())) {
      /* SuspendForReconfiguration and ReconfigurationComplete is a workaround method to let Audio
       * Framework know that session is suspended. Strem resume would be handled from
       * suspended session context with stopped group.
       */
      SuspendedForReconfiguration();
      ReconfigurationComplete(direction);
      GroupStop(active_group_id_);

      return true;
    }

    return false;
  }

  void OnLocalAudioSourceMetadataUpdate(
          const std::vector<struct playback_track_metadata_v7>& source_metadata, DsaMode dsa_mode) {
    if (active_group_id_ == bluetooth::groups::kGroupUnknown) {
@@ -4946,6 +4992,23 @@ public:
    /* Set the remote sink metadata context from the playback tracks metadata */
    local_metadata_context_types_.source = GetAudioContextsFromSourceMetadata(source_metadata);

    /* Check if stream should be suspended due to reamaining only not allowed contexts in metadata
     * or configured context.
     */
    if (com::android::bluetooth::flags::leaudio_stop_updated_to_not_available_context_stream() &&
        StopStreamIfUpdatedContextIsNoLongerSupporteded(
                bluetooth::le_audio::types::kLeAudioDirectionSink, group,
                local_metadata_context_types_.source)) {
      log::info(
              "Updated source metadata contexts are not allowed context types: {} | configured: {} "
              "vs allowed context mask: {}",
              ToString(local_metadata_context_types_.source), ToString(configuration_context_type_),
              ToString(group->GetAllowedContextMask(
                      bluetooth::le_audio::types::kLeAudioDirectionSink)));

      return;
    }

    local_metadata_context_types_.source =
            ChooseMetadataContextType(local_metadata_context_types_.source);

@@ -5096,6 +5159,22 @@ public:
    /* Set remote source metadata context from the recording tracks metadata */
    local_metadata_context_types_.sink = GetAudioContextsFromSinkMetadata(sink_metadata);

    /* Check if stream should be suspended due to only reamaining not allowed contexts in metadata
     * or configured context.
     */
    if (com::android::bluetooth::flags::leaudio_stop_updated_to_not_available_context_stream() &&
        StopStreamIfUpdatedContextIsNoLongerSupporteded(
                bluetooth::le_audio::types::kLeAudioDirectionSource, group,
                local_metadata_context_types_.sink)) {
      log::info(
              "Updated sink metadata contexts are not allowed context types: {} | configured: {} "
              "vs allowed context mask: {}",
              ToString(local_metadata_context_types_.sink), ToString(configuration_context_type_),
              ToString(group->GetAllowedContextMask(
                      bluetooth::le_audio::types::kLeAudioDirectionSource)));
      return;
    }

    local_metadata_context_types_.sink =
            ChooseMetadataContextType(local_metadata_context_types_.sink);

+61 −0
Original line number Diff line number Diff line
@@ -13009,4 +13009,65 @@ TEST_F(UnicastTest, CodecFrameBlocks2) {
  ASSERT_EQ(codec_manager_stream_params.sink.codec_frames_blocks_per_sdu, max_codec_frames_per_sdu);
}
TEST_F(UnicastTestHandoverMode, UpdateMetadataToNotAllowedContexts) {
  com::android::bluetooth::flags::provider_->leaudio_stop_updated_to_not_available_context_stream(
          true);
  const RawAddress test_address0 = GetTestAddress(0);
  int group_id = bluetooth::groups::kGroupUnknown;
  available_snk_context_types_ =
          (types::LeAudioContextType::RINGTONE | types::LeAudioContextType::CONVERSATIONAL |
           types::LeAudioContextType::UNSPECIFIED | types::LeAudioContextType::MEDIA |
           types::LeAudioContextType::SOUNDEFFECTS)
                  .value();
  available_src_context_types_ = available_snk_context_types_;
  supported_snk_context_types_ = types::kLeAudioContextAllTypes.value();
  supported_src_context_types_ =
          (types::kLeAudioContextAllRemoteSource | types::LeAudioContextType::UNSPECIFIED).value();
  /* Don't allow SOUNDEFFECTS context type to be streamed */
  int allowed_context_types =
          (types::LeAudioContextType::RINGTONE | types::LeAudioContextType::CONVERSATIONAL |
           types::LeAudioContextType::UNSPECIFIED | types::LeAudioContextType::MEDIA)
                  .value();
  SetSampleDatabaseEarbudsValid(1, test_address0, codec_spec_conf::kLeAudioLocationStereo,
                                codec_spec_conf::kLeAudioLocationStereo, default_channel_cnt,
                                default_channel_cnt, 0x0004, false /*add_csis*/, true /*add_cas*/,
                                true /*add_pacs*/, default_ase_cnt /*add_ascs_cnt*/, 1 /*set_size*/,
                                0 /*rank*/);
  EXPECT_CALL(mock_audio_hal_client_callbacks_,
              OnConnectionState(ConnectionState::CONNECTED, test_address0))
          .Times(1);
  EXPECT_CALL(mock_audio_hal_client_callbacks_,
              OnGroupNodeStatus(test_address0, _, GroupNodeStatus::ADDED))
          .WillOnce(DoAll(SaveArg<1>(&group_id)));
  ConnectLeAudio(test_address0);
  ASSERT_NE(group_id, bluetooth::groups::kGroupUnknown);
  EXPECT_CALL(*mock_le_audio_source_hal_client_, Start(_, _, _)).Times(1);
  types::BidirectionalPair<types::AudioContexts> metadata = {.sink = types::AudioContexts(),
                                                             .source = types::AudioContexts()};
  EXPECT_CALL(mock_state_machine_, StartStream(_, types::LeAudioContextType::MEDIA, _, _)).Times(1);
  LeAudioClient::Get()->GroupSetActive(group_id);
  SyncOnMainLoop();
  /* Set the same allowed context mask for sink and source */
  LeAudioClient::Get()->SetGroupAllowedContextMask(group_id, allowed_context_types,
                                                   allowed_context_types);
  StartStreaming(AUDIO_USAGE_MEDIA, AUDIO_CONTENT_TYPE_UNKNOWN, group_id, AUDIO_SOURCE_INVALID,
                 false, false);
  SyncOnMainLoop();
  Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_);
  Mock::VerifyAndClearExpectations(mock_le_audio_source_hal_client_);
  /* Expect stream to be stopped when not allowed context would be updated in metadata */
  EXPECT_CALL(mock_state_machine_, StopStream(_));
  UpdateLocalSourceMetadata(AUDIO_USAGE_ASSISTANCE_SONIFICATION, AUDIO_CONTENT_TYPE_UNKNOWN, true);
}
}  // namespace bluetooth::le_audio