Loading system/bta/le_audio/audio_hal_client/audio_hal_client_test.cc +79 −0 Original line number Diff line number Diff line Loading @@ -292,6 +292,8 @@ protected: } void TearDown(void) override { com::android::bluetooth::flags::provider_->reset_flags(); /* We have to call Cleanup to tidy up some static variables. * If on the HAL end Source is running it means we are running the Sink * on our end, and vice versa. Loading Loading @@ -450,6 +452,83 @@ TEST_F(LeAudioClientAudioTest, testLeAudioClientAudioSinkResume) { ASSERT_TRUE(source_audio_hal_stream_cb.on_resume_(start_media_task)); } TEST_F(LeAudioClientAudioTest, testAudioHalClientResumeStartSourceTask_workerEnabled) { com::android::bluetooth::flags::provider_->run_ble_audio_ticks_in_worker_thread(true); const LeAudioCodecConfiguration codec_conf{ .num_channels = LeAudioCodecConfiguration::kChannelNumberStereo, .sample_rate = LeAudioCodecConfiguration::kSampleRate16000, .bits_per_sample = LeAudioCodecConfiguration::kBitsPerSample24, .data_interval_us = LeAudioCodecConfiguration::kInterval10000Us, }; ASSERT_TRUE(AcquireLeAudioSourceHalClient()); ASSERT_TRUE(audio_source_instance_->Start(codec_conf, &mock_hal_sink_event_receiver_)); std::promise<void> promise; auto future = promise.get_future(); uint32_t calculated_bytes_per_tick = 0; EXPECT_CALL(mock_hal_interface_audio_sink_, Read(_, _)) .Times(AtLeast(1)) .WillOnce(Invoke([&](uint8_t* p_buf, uint32_t len) -> uint32_t { calculated_bytes_per_tick = len; // fake some data from audio framework for (uint32_t i = 0u; i < len; ++i) { p_buf[i] = i; } // Return exactly as much data as requested promise.set_value(); return len; })) .WillRepeatedly(Invoke([](uint8_t* p_buf, uint32_t len) -> uint32_t { // fake some data from audio framework for (uint32_t i = 0u; i < len; ++i) { p_buf[i] = i; } return len; })); std::promise<void> data_promise; auto data_future = data_promise.get_future(); /* Expect this callback to be called to Client by the HAL glue layer */ std::vector<uint8_t> media_data_to_send; EXPECT_CALL(mock_hal_sink_event_receiver_, OnAudioDataReady(_)) .Times(AtLeast(1)) .WillOnce(Invoke([&](const std::vector<uint8_t>& data) -> void { media_data_to_send = std::move(data); data_promise.set_value(); })) .WillRepeatedly(DoDefault()); /* Expect LeAudio registered event listener to get called when HAL calls the * audio_hal_client's internal resume callback. */ ASSERT_NE(sink_audio_hal_stream_cb.on_resume_, nullptr); EXPECT_CALL(mock_hal_sink_event_receiver_, OnAudioResume()).Times(1); bool start_media_task = true; ASSERT_TRUE(sink_audio_hal_stream_cb.on_resume_(start_media_task)); audio_source_instance_->ConfirmStreamingRequest(); ASSERT_EQ(future.wait_for(std::chrono::seconds(1)), std::future_status::ready); ASSERT_EQ(data_future.wait_for(std::chrono::seconds(1)), std::future_status::ready); // Check against expected payload size // 24 bit audio stream is sent as unpacked, each sample takes 4 bytes. const uint32_t channel_bytes_per_sample = 4; const uint32_t channel_bytes_per_10ms_at_16000Hz = ((10ms).count() * channel_bytes_per_sample * 16000 /*Hz*/) / (1000ms).count(); // Expect 2 channel (stereo) data ASSERT_EQ(calculated_bytes_per_tick, 2 * channel_bytes_per_10ms_at_16000Hz); // Verify if we got just right amount of data in the callback call ASSERT_EQ(media_data_to_send.size(), calculated_bytes_per_tick); } TEST_F(LeAudioClientAudioTest, testAudioHalClientResumeStartSourceTask) { const LeAudioCodecConfiguration codec_conf{ .num_channels = LeAudioCodecConfiguration::kChannelNumberStereo, Loading system/bta/le_audio/audio_hal_client/audio_source_hal_client.cc +6 −4 Original line number Diff line number Diff line Loading @@ -109,6 +109,8 @@ public: LeAudioSourceAudioHalClient::Callbacks* audioSourceCallbacks_ = nullptr; std::mutex audioSourceCallbacksMutex_; std::unique_ptr<bluetooth::audio::asrc::SourceAudioHalAsrc> asrc_; base::WeakPtrFactory<SourceImpl> weak_factory_{this}; }; bool SourceImpl::Acquire() { Loading Loading @@ -258,7 +260,7 @@ void SourceImpl::StartAudioTicks() { } audio_timer_.SchedulePeriodic( worker_thread_->GetWeakPtr(), FROM_HERE, base::BindRepeating(&SourceImpl::SendAudioData, base::Unretained(this)), base::BindRepeating(&SourceImpl::SendAudioData, weak_factory_.GetWeakPtr()), std::chrono::microseconds(source_codec_config_.data_interval_us)); } Loading @@ -273,7 +275,7 @@ bool SourceImpl::OnSuspendReq() { if (CodecManager::GetInstance()->GetCodecLocation() == types::CodecLocation::HOST) { if (com::android::bluetooth::flags::run_ble_audio_ticks_in_worker_thread()) { worker_thread_->DoInThread( FROM_HERE, base::BindOnce(&SourceImpl::StopAudioTicks, base::Unretained(this))); FROM_HERE, base::BindOnce(&SourceImpl::StopAudioTicks, weak_factory_.GetWeakPtr())); } else { StopAudioTicks(); } Loading Loading @@ -372,7 +374,7 @@ void SourceImpl::Stop() { if (CodecManager::GetInstance()->GetCodecLocation() == types::CodecLocation::HOST) { if (com::android::bluetooth::flags::run_ble_audio_ticks_in_worker_thread()) { worker_thread_->DoInThread( FROM_HERE, base::BindOnce(&SourceImpl::StopAudioTicks, base::Unretained(this))); FROM_HERE, base::BindOnce(&SourceImpl::StopAudioTicks, weak_factory_.GetWeakPtr())); } else { StopAudioTicks(); } Loading Loading @@ -400,7 +402,7 @@ void SourceImpl::ConfirmStreamingRequest() { if (com::android::bluetooth::flags::run_ble_audio_ticks_in_worker_thread()) { worker_thread_->DoInThread( FROM_HERE, base::BindOnce(&SourceImpl::StartAudioTicks, base::Unretained(this))); FROM_HERE, base::BindOnce(&SourceImpl::StartAudioTicks, weak_factory_.GetWeakPtr())); } else { StartAudioTicks(); } Loading Loading
system/bta/le_audio/audio_hal_client/audio_hal_client_test.cc +79 −0 Original line number Diff line number Diff line Loading @@ -292,6 +292,8 @@ protected: } void TearDown(void) override { com::android::bluetooth::flags::provider_->reset_flags(); /* We have to call Cleanup to tidy up some static variables. * If on the HAL end Source is running it means we are running the Sink * on our end, and vice versa. Loading Loading @@ -450,6 +452,83 @@ TEST_F(LeAudioClientAudioTest, testLeAudioClientAudioSinkResume) { ASSERT_TRUE(source_audio_hal_stream_cb.on_resume_(start_media_task)); } TEST_F(LeAudioClientAudioTest, testAudioHalClientResumeStartSourceTask_workerEnabled) { com::android::bluetooth::flags::provider_->run_ble_audio_ticks_in_worker_thread(true); const LeAudioCodecConfiguration codec_conf{ .num_channels = LeAudioCodecConfiguration::kChannelNumberStereo, .sample_rate = LeAudioCodecConfiguration::kSampleRate16000, .bits_per_sample = LeAudioCodecConfiguration::kBitsPerSample24, .data_interval_us = LeAudioCodecConfiguration::kInterval10000Us, }; ASSERT_TRUE(AcquireLeAudioSourceHalClient()); ASSERT_TRUE(audio_source_instance_->Start(codec_conf, &mock_hal_sink_event_receiver_)); std::promise<void> promise; auto future = promise.get_future(); uint32_t calculated_bytes_per_tick = 0; EXPECT_CALL(mock_hal_interface_audio_sink_, Read(_, _)) .Times(AtLeast(1)) .WillOnce(Invoke([&](uint8_t* p_buf, uint32_t len) -> uint32_t { calculated_bytes_per_tick = len; // fake some data from audio framework for (uint32_t i = 0u; i < len; ++i) { p_buf[i] = i; } // Return exactly as much data as requested promise.set_value(); return len; })) .WillRepeatedly(Invoke([](uint8_t* p_buf, uint32_t len) -> uint32_t { // fake some data from audio framework for (uint32_t i = 0u; i < len; ++i) { p_buf[i] = i; } return len; })); std::promise<void> data_promise; auto data_future = data_promise.get_future(); /* Expect this callback to be called to Client by the HAL glue layer */ std::vector<uint8_t> media_data_to_send; EXPECT_CALL(mock_hal_sink_event_receiver_, OnAudioDataReady(_)) .Times(AtLeast(1)) .WillOnce(Invoke([&](const std::vector<uint8_t>& data) -> void { media_data_to_send = std::move(data); data_promise.set_value(); })) .WillRepeatedly(DoDefault()); /* Expect LeAudio registered event listener to get called when HAL calls the * audio_hal_client's internal resume callback. */ ASSERT_NE(sink_audio_hal_stream_cb.on_resume_, nullptr); EXPECT_CALL(mock_hal_sink_event_receiver_, OnAudioResume()).Times(1); bool start_media_task = true; ASSERT_TRUE(sink_audio_hal_stream_cb.on_resume_(start_media_task)); audio_source_instance_->ConfirmStreamingRequest(); ASSERT_EQ(future.wait_for(std::chrono::seconds(1)), std::future_status::ready); ASSERT_EQ(data_future.wait_for(std::chrono::seconds(1)), std::future_status::ready); // Check against expected payload size // 24 bit audio stream is sent as unpacked, each sample takes 4 bytes. const uint32_t channel_bytes_per_sample = 4; const uint32_t channel_bytes_per_10ms_at_16000Hz = ((10ms).count() * channel_bytes_per_sample * 16000 /*Hz*/) / (1000ms).count(); // Expect 2 channel (stereo) data ASSERT_EQ(calculated_bytes_per_tick, 2 * channel_bytes_per_10ms_at_16000Hz); // Verify if we got just right amount of data in the callback call ASSERT_EQ(media_data_to_send.size(), calculated_bytes_per_tick); } TEST_F(LeAudioClientAudioTest, testAudioHalClientResumeStartSourceTask) { const LeAudioCodecConfiguration codec_conf{ .num_channels = LeAudioCodecConfiguration::kChannelNumberStereo, Loading
system/bta/le_audio/audio_hal_client/audio_source_hal_client.cc +6 −4 Original line number Diff line number Diff line Loading @@ -109,6 +109,8 @@ public: LeAudioSourceAudioHalClient::Callbacks* audioSourceCallbacks_ = nullptr; std::mutex audioSourceCallbacksMutex_; std::unique_ptr<bluetooth::audio::asrc::SourceAudioHalAsrc> asrc_; base::WeakPtrFactory<SourceImpl> weak_factory_{this}; }; bool SourceImpl::Acquire() { Loading Loading @@ -258,7 +260,7 @@ void SourceImpl::StartAudioTicks() { } audio_timer_.SchedulePeriodic( worker_thread_->GetWeakPtr(), FROM_HERE, base::BindRepeating(&SourceImpl::SendAudioData, base::Unretained(this)), base::BindRepeating(&SourceImpl::SendAudioData, weak_factory_.GetWeakPtr()), std::chrono::microseconds(source_codec_config_.data_interval_us)); } Loading @@ -273,7 +275,7 @@ bool SourceImpl::OnSuspendReq() { if (CodecManager::GetInstance()->GetCodecLocation() == types::CodecLocation::HOST) { if (com::android::bluetooth::flags::run_ble_audio_ticks_in_worker_thread()) { worker_thread_->DoInThread( FROM_HERE, base::BindOnce(&SourceImpl::StopAudioTicks, base::Unretained(this))); FROM_HERE, base::BindOnce(&SourceImpl::StopAudioTicks, weak_factory_.GetWeakPtr())); } else { StopAudioTicks(); } Loading Loading @@ -372,7 +374,7 @@ void SourceImpl::Stop() { if (CodecManager::GetInstance()->GetCodecLocation() == types::CodecLocation::HOST) { if (com::android::bluetooth::flags::run_ble_audio_ticks_in_worker_thread()) { worker_thread_->DoInThread( FROM_HERE, base::BindOnce(&SourceImpl::StopAudioTicks, base::Unretained(this))); FROM_HERE, base::BindOnce(&SourceImpl::StopAudioTicks, weak_factory_.GetWeakPtr())); } else { StopAudioTicks(); } Loading Loading @@ -400,7 +402,7 @@ void SourceImpl::ConfirmStreamingRequest() { if (com::android::bluetooth::flags::run_ble_audio_ticks_in_worker_thread()) { worker_thread_->DoInThread( FROM_HERE, base::BindOnce(&SourceImpl::StartAudioTicks, base::Unretained(this))); FROM_HERE, base::BindOnce(&SourceImpl::StartAudioTicks, weak_factory_.GetWeakPtr())); } else { StartAudioTicks(); } Loading