Loading android/app/src/com/android/bluetooth/le_audio/LeAudioService.java +125 −72 Original line number Diff line number Diff line Loading @@ -117,6 +117,9 @@ public class LeAudioService extends ProfileService { // Timeout for state machine thread join, to prevent potential ANR. private static final int SM_THREAD_JOIN_TIMEOUT_MS = 1000; /* 5 seconds timeout for Broadcast streaming state transition */ private static final int CREATE_BROADCAST_TIMEOUT_MS = 5000; private static LeAudioService sLeAudioService; /** Indicates group audio support for none direction */ Loading Loading @@ -151,9 +154,6 @@ public class LeAudioService extends ProfileService { .setSampleRate(BluetoothLeAudioCodecConfig.SAMPLE_RATE_48000) .build(); /* 5 seconds timeout for Broadcast streaming state transition */ private static final int DIALING_OUT_TIMEOUT_MS = 5000; private AdapterService mAdapterService; private DatabaseManager mDatabaseManager; private HandlerThread mStateMachinesThread; Loading @@ -165,6 +165,8 @@ public class LeAudioService extends ProfileService { private final ReentrantReadWriteLock mGroupReadWriteLock = new ReentrantReadWriteLock(); private final Lock mGroupReadLock = mGroupReadWriteLock.readLock(); private final Lock mGroupWriteLock = mGroupReadWriteLock.writeLock(); private CreateBroadcastTimeoutEvent mCreateBroadcastTimeoutEvent; ServiceFactory mServiceFactory = new ServiceFactory(); private final LeAudioNativeInterface mNativeInterface; Loading @@ -182,7 +184,6 @@ public class LeAudioService extends ProfileService { BluetoothDevice mLeAudioDeviceInactivatedForHfpHandover = null; LeAudioBroadcasterNativeInterface mLeAudioBroadcasterNativeInterface = null; private DialingOutTimeoutEvent mDialingOutTimeoutEvent = null; @VisibleForTesting AudioManager mAudioManager; LeAudioTmapGattServer mTmapGattServer; int mTmapRoleMask; Loading Loading @@ -653,7 +654,7 @@ public class LeAudioService extends ProfileService { mIsSinkStreamMonitorModeEnabled = false; mIsBroadcastPausedFromOutside = false; clearBroadcastTimeoutCallback(); clearCreateBroadcastTimeoutCallback(); if (!Flags.leaudioSynchronizeStart()) { mHandler.removeCallbacks(this::init); Loading Loading @@ -1148,29 +1149,48 @@ public class LeAudioService extends ProfileService { return LE_AUDIO_GROUP_ID_INVALID; } /** * Creates LeAudio Broadcast instance with BluetoothLeBroadcastSettings. * * @param broadcastSettings broadcast settings for this broadcast source */ public void createBroadcast(BluetoothLeBroadcastSettings broadcastSettings) { private int canBroadcastBeCreated(BluetoothLeBroadcastSettings broadcastSettings) { if (mBroadcastDescriptors.size() >= getMaximumNumberOfBroadcasts()) { Log.w( TAG, "createBroadcast reached maximum allowed broadcasts number: " + getMaximumNumberOfBroadcasts()); mHandler.post( () -> notifyBroadcastStartFailed( BluetoothStatusCodes.ERROR_LOCAL_NOT_ENOUGH_RESOURCES)); return; return BluetoothStatusCodes.ERROR_LOCAL_NOT_ENOUGH_RESOURCES; } byte[] broadcastCode = broadcastSettings.getBroadcastCode(); if (broadcastCode != null && ((broadcastCode.length > 16) || (broadcastCode.length < 4))) { Log.e(TAG, "Invalid broadcast code length. Should be from 4 to 16 octets long."); return BluetoothStatusCodes.ERROR_LE_BROADCAST_INVALID_CODE; } List<BluetoothLeBroadcastSubgroupSettings> settingsList = broadcastSettings.getSubgroupSettings(); if (settingsList == null || settingsList.size() < 1) { Log.d(TAG, "subgroup settings is not valid value"); return BluetoothStatusCodes.ERROR_BAD_PARAMETERS; } return BluetoothStatusCodes.SUCCESS; } /** * Creates LeAudio Broadcast instance with BluetoothLeBroadcastSettings. * * @param broadcastSettings broadcast settings for this broadcast source */ public void createBroadcast(BluetoothLeBroadcastSettings broadcastSettings) { if (mLeAudioBroadcasterNativeInterface == null) { Log.w(TAG, "Native interface not available."); return; } int canBroadcastBeCreatedReturnCode = canBroadcastBeCreated(broadcastSettings); if (canBroadcastBeCreatedReturnCode != BluetoothStatusCodes.SUCCESS) { mHandler.post(() -> notifyBroadcastStartFailed(canBroadcastBeCreatedReturnCode)); return; } if (mAwaitingBroadcastCreateResponse) { mCreateBroadcastQueue.add(broadcastSettings); Log.i(TAG, "Broadcast creation queued due to waiting for a previous request response."); Loading @@ -1192,21 +1212,6 @@ public class LeAudioService extends ProfileService { } } byte[] broadcastCode = broadcastSettings.getBroadcastCode(); boolean isEncrypted = (broadcastCode != null) && (broadcastCode.length != 0); if (isEncrypted) { if ((broadcastCode.length > 16) || (broadcastCode.length < 4)) { Log.e(TAG, "Invalid broadcast code length. Should be from 4 to 16 octets long."); return; } } List<BluetoothLeBroadcastSubgroupSettings> settingsList = broadcastSettings.getSubgroupSettings(); if (settingsList == null || settingsList.size() < 1) { Log.d(TAG, "subgroup settings is not valid value"); return; } mBroadcastSessionStats.put( INVALID_BROADCAST_ID, new LeAudioBroadcastSessionStats(broadcastSettings, SystemClock.elapsedRealtime())); Loading @@ -1214,19 +1219,37 @@ public class LeAudioService extends ProfileService { BluetoothLeAudioContentMetadata publicMetadata = broadcastSettings.getPublicBroadcastMetadata(); Log.i(TAG, "createBroadcast: isEncrypted=" + (isEncrypted ? "true" : "false")); byte[] broadcastCode = broadcastSettings.getBroadcastCode(); Log.i( TAG, "createBroadcast: isEncrypted=" + (((broadcastCode != null) && (broadcastCode.length != 0)) ? "true" : "false")); mAwaitingBroadcastCreateResponse = true; if (leaudioBigDependsOnAudioState()) { mCreateBroadcastQueue.add(broadcastSettings); } if (leaudioBigDependsOnAudioState()) { /* Start timeout to recover from stucked/error create Broadcast operation */ if (mCreateBroadcastTimeoutEvent != null) { Log.w(TAG, "CreateBroadcastTimeoutEvent already scheduled"); } else { mCreateBroadcastTimeoutEvent = new CreateBroadcastTimeoutEvent(); mHandler.postDelayed(mCreateBroadcastTimeoutEvent, CREATE_BROADCAST_TIMEOUT_MS); } } mLeAudioBroadcasterNativeInterface.createBroadcast( broadcastSettings.isPublicBroadcast(), broadcastSettings.getBroadcastName(), broadcastCode, publicMetadata == null ? null : publicMetadata.getRawMetadata(), getBroadcastAudioQualityPerSinkCapabilities(settingsList), settingsList.stream() getBroadcastAudioQualityPerSinkCapabilities( broadcastSettings.getSubgroupSettings()), broadcastSettings.getSubgroupSettings().stream() .map(s -> s.getContentMetadata().getRawMetadata()) .toArray(byte[][]::new)); } Loading Loading @@ -1280,8 +1303,8 @@ public class LeAudioService extends ProfileService { Log.d(TAG, "startBroadcast"); /* Start timeout to recover from stucked/error start Broadcast operation */ mDialingOutTimeoutEvent = new DialingOutTimeoutEvent(broadcastId); mHandler.postDelayed(mDialingOutTimeoutEvent, DIALING_OUT_TIMEOUT_MS); mCreateBroadcastTimeoutEvent = new CreateBroadcastTimeoutEvent(broadcastId); mHandler.postDelayed(mCreateBroadcastTimeoutEvent, CREATE_BROADCAST_TIMEOUT_MS); mLeAudioBroadcasterNativeInterface.startBroadcast(broadcastId); } Loading Loading @@ -3181,19 +3204,19 @@ public class LeAudioService extends ProfileService { setActiveDevice(unicastDevice); } void clearBroadcastTimeoutCallback() { private void clearCreateBroadcastTimeoutCallback() { if (mHandler == null) { Log.e(TAG, "No callback handler"); return; } /* Timeout callback already cleared */ if (mDialingOutTimeoutEvent == null) { if (mCreateBroadcastTimeoutEvent == null) { return; } mHandler.removeCallbacks(mDialingOutTimeoutEvent); mDialingOutTimeoutEvent = null; mHandler.removeCallbacks(mCreateBroadcastTimeoutEvent); mCreateBroadcastTimeoutEvent = null; } void notifyAudioFrameworkForCodecConfigUpdate( Loading Loading @@ -3669,7 +3692,10 @@ public class LeAudioService extends ProfileService { if (!leaudioUseAudioModeListener()) { mQueuedInCallValue = Optional.empty(); } startBroadcast(mBroadcastIdDeactivatedForUnicastTransition.get()); if (!leaudioBigDependsOnAudioState()) { startBroadcast( mBroadcastIdDeactivatedForUnicastTransition.get()); } mBroadcastIdDeactivatedForUnicastTransition = Optional.empty(); } Loading Loading @@ -3729,9 +3755,10 @@ public class LeAudioService extends ProfileService { mBroadcastSessionStats.put(broadcastId, sessionStats); } if (!leaudioBigDependsOnAudioState()) { // Start sending the actual stream startBroadcast(broadcastId); } } else { // TODO: Improve reason reporting or extend the native stack event with reason code Log.e( Loading @@ -3744,7 +3771,9 @@ public class LeAudioService extends ProfileService { if ((mUnicastGroupIdDeactivatedForBroadcastTransition != LE_AUDIO_GROUP_ID_INVALID) && mCreateBroadcastQueue.isEmpty() && (!Objects.equals(device, mActiveBroadcastAudioDevice))) { clearBroadcastTimeoutCallback(); if (!leaudioBigDependsOnAudioState()) { clearCreateBroadcastTimeoutCallback(); } updateBroadcastActiveDevice(null, mActiveBroadcastAudioDevice, false); } Loading @@ -3755,6 +3784,9 @@ public class LeAudioService extends ProfileService { .BROADCAST_AUDIO_SESSION_REPORTED__SESSION_SETUP_STATUS__SETUP_STATUS_CREATE_FAILED); } if (leaudioBigDependsOnAudioState()) { clearCreateBroadcastTimeoutCallback(); } mAwaitingBroadcastCreateResponse = false; // In case if there were additional calls to create broadcast Loading Loading @@ -3883,7 +3915,9 @@ public class LeAudioService extends ProfileService { sessionStats.updateSessionStreamingTime(SystemClock.elapsedRealtime()); } clearBroadcastTimeoutCallback(); if (!leaudioBigDependsOnAudioState()) { clearCreateBroadcastTimeoutCallback(); } if (previousState == LeAudioStackEvent.BROADCAST_STATE_PAUSED) { if (bassClientService != null) { Loading Loading @@ -5279,21 +5313,38 @@ public class LeAudioService extends ProfileService { return audioFrameworkCalls; } class DialingOutTimeoutEvent implements Runnable { private class CreateBroadcastTimeoutEvent implements Runnable { Integer mBroadcastId; DialingOutTimeoutEvent(Integer broadcastId) { CreateBroadcastTimeoutEvent() {} CreateBroadcastTimeoutEvent(Integer broadcastId) { mBroadcastId = broadcastId; } @Override public void run() { if (leaudioBigDependsOnAudioState()) { Log.w(TAG, "Failed to start Broadcast in time"); if (getLeAudioService() == null) { Log.e(TAG, "CreateBroadcastTimeoutEvent: No LE Audio service"); return; } if (sLeAudioService.mHandler == null) { Log.w(TAG, "CreateBroadcastTimeoutEvent: No handler"); return; } mHandler.post(() -> notifyBroadcastStartFailed(BluetoothStatusCodes.ERROR_TIMEOUT)); } else { Log.w(TAG, "Failed to start Broadcast in time: " + mBroadcastId); mDialingOutTimeoutEvent = null; mCreateBroadcastTimeoutEvent = null; if (getLeAudioService() == null) { Log.e(TAG, "DialingOutTimeoutEvent: No LE Audio service"); Log.e(TAG, "CreateBroadcastTimeoutEvent: No LE Audio service"); return; } Loading @@ -5313,7 +5364,8 @@ public class LeAudioService extends ProfileService { updateBroadcastActiveDevice(null, mActiveBroadcastAudioDevice, false); } mHandler.post(() -> notifyBroadcastStartFailed(BluetoothStatusCodes.ERROR_TIMEOUT)); mHandler.post( () -> notifyBroadcastStartFailed(BluetoothStatusCodes.ERROR_TIMEOUT)); logBroadcastSessionStatsWithStatus( mBroadcastId, BluetoothStatsLog Loading @@ -5321,6 +5373,7 @@ public class LeAudioService extends ProfileService { } } } } class AudioModeChangeListener implements AudioManager.OnModeChangedListener { @Override Loading android/app/tests/unit/src/com/android/bluetooth/le_audio/LeAudioBroadcastServiceTest.java +164 −140 File changed.Preview size limit exceeded, changes collapsed. Show changes system/bta/le_audio/broadcaster/broadcaster.cc +8 −5 Original line number Diff line number Diff line Loading @@ -913,6 +913,7 @@ public: is_iso_running_ = is_active; log::info("is_iso_running: {}", is_iso_running_); if (!is_iso_running_) { if (!com::android::bluetooth::flags::leaudio_big_depends_on_audio_state()) { if (queued_start_broadcast_request_) { auto broadcast_id = *queued_start_broadcast_request_; queued_start_broadcast_request_ = std::nullopt; Loading @@ -920,6 +921,8 @@ public: log::info("Start queued broadcast."); StartAudioBroadcast(broadcast_id); } } if (queued_create_broadcast_request_) { auto broadcast_msg = std::move(*queued_create_broadcast_request_); queued_create_broadcast_request_ = std::nullopt; Loading system/bta/le_audio/broadcaster/broadcaster_test.cc +36 −63 Original line number Diff line number Diff line Loading @@ -533,8 +533,19 @@ TEST_F(BroadcasterTest, CreateAudioBroadcastMultiGroups) { TEST_F(BroadcasterTest, SuspendAudioBroadcast) { EXPECT_CALL(*mock_codec_manager_, UpdateActiveBroadcastAudioHalClient(mock_audio_source_, true)) .Times(1); LeAudioSourceAudioHalClient::Callbacks* audio_receiver; EXPECT_CALL(*mock_audio_source_, Start) .WillOnce(DoAll(SaveArg<1>(&audio_receiver), Return(true))) .WillRepeatedly(Return(false)); auto broadcast_id = InstantiateBroadcast(); if (com::android::bluetooth::flags::leaudio_big_depends_on_audio_state()) { ASSERT_NE(audio_receiver, nullptr); audio_receiver->OnAudioResume(); } else { LeAudioBroadcaster::Get()->StartAudioBroadcast(broadcast_id); } Mock::VerifyAndClearExpectations(mock_codec_manager_); EXPECT_CALL(mock_broadcaster_callbacks_, Loading @@ -559,7 +570,9 @@ TEST_F(BroadcasterTest, StartAudioBroadcast) { EXPECT_CALL(*mock_codec_manager_, UpdateActiveBroadcastAudioHalClient(mock_audio_source_, true)) .Times(1); auto broadcast_id = InstantiateBroadcast(); ASSERT_NE(audio_receiver, nullptr); Mock::VerifyAndClearExpectations(mock_codec_manager_); EXPECT_CALL(*mock_codec_manager_, UpdateActiveBroadcastAudioHalClient(mock_audio_source_, true)) Loading @@ -575,8 +588,7 @@ TEST_F(BroadcasterTest, StartAudioBroadcast) { ASSERT_TRUE(big_terminate_timer_->cb == nullptr); ASSERT_TRUE(broadcast_stop_timer_->cb == nullptr); LeAudioBroadcaster::Get()->StartAudioBroadcast(broadcast_id); ASSERT_NE(audio_receiver, nullptr); audio_receiver->OnAudioResume(); // NOTICE: This is really an implementation specific part, we fake the BIG // config as the mocked state machine does not even call the Loading Loading @@ -609,6 +621,7 @@ TEST_F(BroadcasterTest, StartAudioBroadcastMedia) { .Times(1); auto broadcast_id = InstantiateBroadcast(media_metadata, default_code, {bluetooth::le_audio::QUALITY_HIGH}); ASSERT_NE(audio_receiver, nullptr); Mock::VerifyAndClearExpectations(mock_codec_manager_); LeAudioBroadcaster::Get()->StopAudioBroadcast(broadcast_id); Loading @@ -626,8 +639,7 @@ TEST_F(BroadcasterTest, StartAudioBroadcastMedia) { EXPECT_CALL(*mock_codec_manager_, UpdateActiveBroadcastAudioHalClient(mock_audio_source_, false)) .Times(0); LeAudioBroadcaster::Get()->StartAudioBroadcast(broadcast_id); ASSERT_NE(audio_receiver, nullptr); audio_receiver->OnAudioResume(); // NOTICE: This is really an implementation specific part, we fake the BIG // config as the mocked state machine does not even call the Loading @@ -651,8 +663,18 @@ TEST_F(BroadcasterTest, StartAudioBroadcastMedia) { TEST_F(BroadcasterTest, StopAudioBroadcast) { EXPECT_CALL(*mock_codec_manager_, UpdateActiveBroadcastAudioHalClient(mock_audio_source_, true)) .Times(1); LeAudioSourceAudioHalClient::Callbacks* audio_receiver; EXPECT_CALL(*mock_audio_source_, Start) .WillOnce(DoAll(SaveArg<1>(&audio_receiver), Return(true))) .WillRepeatedly(Return(false)); auto broadcast_id = InstantiateBroadcast(); if (com::android::bluetooth::flags::leaudio_big_depends_on_audio_state()) { ASSERT_NE(audio_receiver, nullptr); audio_receiver->OnAudioResume(); } else { LeAudioBroadcaster::Get()->StartAudioBroadcast(broadcast_id); } // NOTICE: This is really an implementation specific part, we fake the BIG // config as the mocked state machine does not even call the Loading Loading @@ -712,7 +734,6 @@ TEST_F(BroadcasterTest, DestroyAudioBroadcast) { LeAudioBroadcaster::Get()->StopAudioBroadcast(broadcast_id); EXPECT_CALL(*mock_audio_source_, Start).Times(0); LeAudioBroadcaster::Get()->StartAudioBroadcast(broadcast_id); EXPECT_CALL(*mock_audio_source_, Stop).Times(0); LeAudioBroadcaster::Get()->SuspendAudioBroadcast(broadcast_id); Loading Loading @@ -846,8 +867,8 @@ TEST_F(BroadcasterTest, UpdateMetadataFromAudioTrackMetadata) { ContentControlIdKeeper::GetInstance()->SetCcid(LeAudioContextType::MEDIA, media_ccid); auto broadcast_id = InstantiateBroadcast(); LeAudioBroadcaster::Get()->StartAudioBroadcast(broadcast_id); ASSERT_NE(audio_receiver, nullptr); audio_receiver->OnAudioResume(); auto sm = MockBroadcastStateMachine::GetLastInstance(); std::vector<uint8_t> ccid_list; Loading Loading @@ -1204,6 +1225,7 @@ TEST_F(BroadcasterTest, AudioActiveState) { .WillRepeatedly(Return(false)); auto broadcast_id = InstantiateBroadcast(); ASSERT_NE(audio_receiver, nullptr); auto sm = MockBroadcastStateMachine::GetLastInstance(); pb_announcement = sm->GetPublicBroadcastAnnouncement(); auto created_public_meta = types::LeAudioLtvMap(pb_announcement.metadata).RawPacket(); Loading @@ -1218,9 +1240,6 @@ TEST_F(BroadcasterTest, AudioActiveState) { }); ON_CALL(*sm, GetPublicBroadcastAnnouncement()).WillByDefault(ReturnRef(pb_announcement)); LeAudioBroadcaster::Get()->StartAudioBroadcast(broadcast_id); ASSERT_NE(audio_receiver, nullptr); // Update to true Audio Active State while audio resumed EXPECT_CALL(*sm, UpdatePublicBroadcastAnnouncement); audio_receiver->OnAudioResume(); Loading Loading @@ -1278,32 +1297,12 @@ TEST_F(BroadcasterTest, BigTerminationAndBroadcastStopWhenNoSoundFromTheBeginnin auto broadcast_id = InstantiateBroadcast(); EXPECT_CALL(mock_broadcaster_callbacks_, OnBroadcastStateChanged(broadcast_id, BroadcastState::STREAMING)) .Times(1); .Times(0); // Timers not started ASSERT_TRUE(big_terminate_timer_->cb == nullptr); ASSERT_TRUE(broadcast_stop_timer_->cb == nullptr); // Start Broadcast LeAudioBroadcaster::Get()->StartAudioBroadcast(broadcast_id); // Timers started ASSERT_EQ(2, get_func_call_count("alarm_set_on_mloop")); ASSERT_TRUE(big_terminate_timer_->cb != nullptr); ASSERT_TRUE(broadcast_stop_timer_->cb != nullptr); ASSERT_EQ(0, get_func_call_count("alarm_set_on_mloop")); ASSERT_NE(audio_receiver, nullptr); // BIG termination timer execution, state machine go to CONFIGURED state so BIG terminated EXPECT_CALL(mock_broadcaster_callbacks_, OnBroadcastStateChanged(broadcast_id, BroadcastState::CONFIGURED)) .Times(1); // Imitate execution of BIG termination timer big_terminate_timer_->cb(big_terminate_timer_->data); // Broadcast stop timer execution, state machine go to STOPPED state EXPECT_CALL(mock_broadcaster_callbacks_, OnBroadcastStateChanged(broadcast_id, BroadcastState::STOPPED)) .Times(1); // Imitate execution of BIG termination timer broadcast_stop_timer_->cb(broadcast_stop_timer_->data); } TEST_F(BroadcasterTest, BigTerminationAndBroadcastStopWhenNoSoundAfterSuspend) { Loading @@ -1326,24 +1325,11 @@ TEST_F(BroadcasterTest, BigTerminationAndBroadcastStopWhenNoSoundAfterSuspend) { ASSERT_TRUE(broadcast_stop_timer_->cb == nullptr); // Start Broadcast LeAudioBroadcaster::Get()->StartAudioBroadcast(broadcast_id); // Timers started ASSERT_EQ(2, get_func_call_count("alarm_set_on_mloop")); ASSERT_TRUE(big_terminate_timer_->cb != nullptr); ASSERT_TRUE(broadcast_stop_timer_->cb != nullptr); ASSERT_NE(audio_receiver, nullptr); // First onAudioResume when BIG already created, not cause any state change EXPECT_CALL(mock_broadcaster_callbacks_, OnBroadcastStateChanged(broadcast_id, _)).Times(0); audio_receiver->OnAudioResume(); // Timers cancelled ASSERT_EQ(2, get_func_call_count("alarm_cancel")); ASSERT_TRUE(big_terminate_timer_->cb == nullptr); ASSERT_TRUE(broadcast_stop_timer_->cb == nullptr); // OnAudioSuspend cause starting the BIG termination timer audio_receiver->OnAudioSuspend(); ASSERT_EQ(4, get_func_call_count("alarm_set_on_mloop")); ASSERT_EQ(2, get_func_call_count("alarm_set_on_mloop")); ASSERT_TRUE(big_terminate_timer_->cb != nullptr); ASSERT_TRUE(broadcast_stop_timer_->cb != nullptr); Loading @@ -1357,7 +1343,7 @@ TEST_F(BroadcasterTest, BigTerminationAndBroadcastStopWhenNoSoundAfterSuspend) { // OnAudioSuspend cause starting the BIG termination timer audio_receiver->OnAudioSuspend(); ASSERT_EQ(6, get_func_call_count("alarm_set_on_mloop")); ASSERT_EQ(4, get_func_call_count("alarm_set_on_mloop")); ASSERT_TRUE(big_terminate_timer_->cb != nullptr); ASSERT_TRUE(broadcast_stop_timer_->cb != nullptr); Loading Loading @@ -1396,24 +1382,11 @@ TEST_F(BroadcasterTest, BigCreationTerminationDependsOnAudioResumeSuspend) { ASSERT_TRUE(broadcast_stop_timer_->cb == nullptr); // Start Broadcast LeAudioBroadcaster::Get()->StartAudioBroadcast(broadcast_id); // Timers started ASSERT_EQ(2, get_func_call_count("alarm_set_on_mloop")); ASSERT_TRUE(big_terminate_timer_->cb != nullptr); ASSERT_TRUE(broadcast_stop_timer_->cb != nullptr); ASSERT_NE(audio_receiver, nullptr); // First onAudioResume when BIG already created, not cause any state change EXPECT_CALL(mock_broadcaster_callbacks_, OnBroadcastStateChanged(broadcast_id, _)).Times(0); audio_receiver->OnAudioResume(); // Timers cancelled ASSERT_EQ(2, get_func_call_count("alarm_cancel")); ASSERT_TRUE(big_terminate_timer_->cb == nullptr); ASSERT_TRUE(broadcast_stop_timer_->cb == nullptr); // OnAudioSuspend cause starting the BIG termination timer audio_receiver->OnAudioSuspend(); ASSERT_EQ(4, get_func_call_count("alarm_set_on_mloop")); ASSERT_EQ(2, get_func_call_count("alarm_set_on_mloop")); ASSERT_TRUE(big_terminate_timer_->cb != nullptr); ASSERT_TRUE(broadcast_stop_timer_->cb != nullptr); Loading @@ -1427,7 +1400,7 @@ TEST_F(BroadcasterTest, BigCreationTerminationDependsOnAudioResumeSuspend) { // OnAudioSuspend cause starting the BIG termination timer audio_receiver->OnAudioSuspend(); ASSERT_EQ(6, get_func_call_count("alarm_set_on_mloop")); ASSERT_EQ(4, get_func_call_count("alarm_set_on_mloop")); ASSERT_TRUE(big_terminate_timer_->cb != nullptr); ASSERT_TRUE(broadcast_stop_timer_->cb != nullptr); Loading system/bta/le_audio/broadcaster/mock_state_machine.h +1 −0 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ public: advertising_sid_ = ++instance_counter_; ON_CALL(*this, Initialize).WillByDefault([this]() { SetState(State::CONFIGURED); this->cb->OnStateMachineCreateStatus(this->cfg.broadcast_id, result_); return result_; }); Loading Loading
android/app/src/com/android/bluetooth/le_audio/LeAudioService.java +125 −72 Original line number Diff line number Diff line Loading @@ -117,6 +117,9 @@ public class LeAudioService extends ProfileService { // Timeout for state machine thread join, to prevent potential ANR. private static final int SM_THREAD_JOIN_TIMEOUT_MS = 1000; /* 5 seconds timeout for Broadcast streaming state transition */ private static final int CREATE_BROADCAST_TIMEOUT_MS = 5000; private static LeAudioService sLeAudioService; /** Indicates group audio support for none direction */ Loading Loading @@ -151,9 +154,6 @@ public class LeAudioService extends ProfileService { .setSampleRate(BluetoothLeAudioCodecConfig.SAMPLE_RATE_48000) .build(); /* 5 seconds timeout for Broadcast streaming state transition */ private static final int DIALING_OUT_TIMEOUT_MS = 5000; private AdapterService mAdapterService; private DatabaseManager mDatabaseManager; private HandlerThread mStateMachinesThread; Loading @@ -165,6 +165,8 @@ public class LeAudioService extends ProfileService { private final ReentrantReadWriteLock mGroupReadWriteLock = new ReentrantReadWriteLock(); private final Lock mGroupReadLock = mGroupReadWriteLock.readLock(); private final Lock mGroupWriteLock = mGroupReadWriteLock.writeLock(); private CreateBroadcastTimeoutEvent mCreateBroadcastTimeoutEvent; ServiceFactory mServiceFactory = new ServiceFactory(); private final LeAudioNativeInterface mNativeInterface; Loading @@ -182,7 +184,6 @@ public class LeAudioService extends ProfileService { BluetoothDevice mLeAudioDeviceInactivatedForHfpHandover = null; LeAudioBroadcasterNativeInterface mLeAudioBroadcasterNativeInterface = null; private DialingOutTimeoutEvent mDialingOutTimeoutEvent = null; @VisibleForTesting AudioManager mAudioManager; LeAudioTmapGattServer mTmapGattServer; int mTmapRoleMask; Loading Loading @@ -653,7 +654,7 @@ public class LeAudioService extends ProfileService { mIsSinkStreamMonitorModeEnabled = false; mIsBroadcastPausedFromOutside = false; clearBroadcastTimeoutCallback(); clearCreateBroadcastTimeoutCallback(); if (!Flags.leaudioSynchronizeStart()) { mHandler.removeCallbacks(this::init); Loading Loading @@ -1148,29 +1149,48 @@ public class LeAudioService extends ProfileService { return LE_AUDIO_GROUP_ID_INVALID; } /** * Creates LeAudio Broadcast instance with BluetoothLeBroadcastSettings. * * @param broadcastSettings broadcast settings for this broadcast source */ public void createBroadcast(BluetoothLeBroadcastSettings broadcastSettings) { private int canBroadcastBeCreated(BluetoothLeBroadcastSettings broadcastSettings) { if (mBroadcastDescriptors.size() >= getMaximumNumberOfBroadcasts()) { Log.w( TAG, "createBroadcast reached maximum allowed broadcasts number: " + getMaximumNumberOfBroadcasts()); mHandler.post( () -> notifyBroadcastStartFailed( BluetoothStatusCodes.ERROR_LOCAL_NOT_ENOUGH_RESOURCES)); return; return BluetoothStatusCodes.ERROR_LOCAL_NOT_ENOUGH_RESOURCES; } byte[] broadcastCode = broadcastSettings.getBroadcastCode(); if (broadcastCode != null && ((broadcastCode.length > 16) || (broadcastCode.length < 4))) { Log.e(TAG, "Invalid broadcast code length. Should be from 4 to 16 octets long."); return BluetoothStatusCodes.ERROR_LE_BROADCAST_INVALID_CODE; } List<BluetoothLeBroadcastSubgroupSettings> settingsList = broadcastSettings.getSubgroupSettings(); if (settingsList == null || settingsList.size() < 1) { Log.d(TAG, "subgroup settings is not valid value"); return BluetoothStatusCodes.ERROR_BAD_PARAMETERS; } return BluetoothStatusCodes.SUCCESS; } /** * Creates LeAudio Broadcast instance with BluetoothLeBroadcastSettings. * * @param broadcastSettings broadcast settings for this broadcast source */ public void createBroadcast(BluetoothLeBroadcastSettings broadcastSettings) { if (mLeAudioBroadcasterNativeInterface == null) { Log.w(TAG, "Native interface not available."); return; } int canBroadcastBeCreatedReturnCode = canBroadcastBeCreated(broadcastSettings); if (canBroadcastBeCreatedReturnCode != BluetoothStatusCodes.SUCCESS) { mHandler.post(() -> notifyBroadcastStartFailed(canBroadcastBeCreatedReturnCode)); return; } if (mAwaitingBroadcastCreateResponse) { mCreateBroadcastQueue.add(broadcastSettings); Log.i(TAG, "Broadcast creation queued due to waiting for a previous request response."); Loading @@ -1192,21 +1212,6 @@ public class LeAudioService extends ProfileService { } } byte[] broadcastCode = broadcastSettings.getBroadcastCode(); boolean isEncrypted = (broadcastCode != null) && (broadcastCode.length != 0); if (isEncrypted) { if ((broadcastCode.length > 16) || (broadcastCode.length < 4)) { Log.e(TAG, "Invalid broadcast code length. Should be from 4 to 16 octets long."); return; } } List<BluetoothLeBroadcastSubgroupSettings> settingsList = broadcastSettings.getSubgroupSettings(); if (settingsList == null || settingsList.size() < 1) { Log.d(TAG, "subgroup settings is not valid value"); return; } mBroadcastSessionStats.put( INVALID_BROADCAST_ID, new LeAudioBroadcastSessionStats(broadcastSettings, SystemClock.elapsedRealtime())); Loading @@ -1214,19 +1219,37 @@ public class LeAudioService extends ProfileService { BluetoothLeAudioContentMetadata publicMetadata = broadcastSettings.getPublicBroadcastMetadata(); Log.i(TAG, "createBroadcast: isEncrypted=" + (isEncrypted ? "true" : "false")); byte[] broadcastCode = broadcastSettings.getBroadcastCode(); Log.i( TAG, "createBroadcast: isEncrypted=" + (((broadcastCode != null) && (broadcastCode.length != 0)) ? "true" : "false")); mAwaitingBroadcastCreateResponse = true; if (leaudioBigDependsOnAudioState()) { mCreateBroadcastQueue.add(broadcastSettings); } if (leaudioBigDependsOnAudioState()) { /* Start timeout to recover from stucked/error create Broadcast operation */ if (mCreateBroadcastTimeoutEvent != null) { Log.w(TAG, "CreateBroadcastTimeoutEvent already scheduled"); } else { mCreateBroadcastTimeoutEvent = new CreateBroadcastTimeoutEvent(); mHandler.postDelayed(mCreateBroadcastTimeoutEvent, CREATE_BROADCAST_TIMEOUT_MS); } } mLeAudioBroadcasterNativeInterface.createBroadcast( broadcastSettings.isPublicBroadcast(), broadcastSettings.getBroadcastName(), broadcastCode, publicMetadata == null ? null : publicMetadata.getRawMetadata(), getBroadcastAudioQualityPerSinkCapabilities(settingsList), settingsList.stream() getBroadcastAudioQualityPerSinkCapabilities( broadcastSettings.getSubgroupSettings()), broadcastSettings.getSubgroupSettings().stream() .map(s -> s.getContentMetadata().getRawMetadata()) .toArray(byte[][]::new)); } Loading Loading @@ -1280,8 +1303,8 @@ public class LeAudioService extends ProfileService { Log.d(TAG, "startBroadcast"); /* Start timeout to recover from stucked/error start Broadcast operation */ mDialingOutTimeoutEvent = new DialingOutTimeoutEvent(broadcastId); mHandler.postDelayed(mDialingOutTimeoutEvent, DIALING_OUT_TIMEOUT_MS); mCreateBroadcastTimeoutEvent = new CreateBroadcastTimeoutEvent(broadcastId); mHandler.postDelayed(mCreateBroadcastTimeoutEvent, CREATE_BROADCAST_TIMEOUT_MS); mLeAudioBroadcasterNativeInterface.startBroadcast(broadcastId); } Loading Loading @@ -3181,19 +3204,19 @@ public class LeAudioService extends ProfileService { setActiveDevice(unicastDevice); } void clearBroadcastTimeoutCallback() { private void clearCreateBroadcastTimeoutCallback() { if (mHandler == null) { Log.e(TAG, "No callback handler"); return; } /* Timeout callback already cleared */ if (mDialingOutTimeoutEvent == null) { if (mCreateBroadcastTimeoutEvent == null) { return; } mHandler.removeCallbacks(mDialingOutTimeoutEvent); mDialingOutTimeoutEvent = null; mHandler.removeCallbacks(mCreateBroadcastTimeoutEvent); mCreateBroadcastTimeoutEvent = null; } void notifyAudioFrameworkForCodecConfigUpdate( Loading Loading @@ -3669,7 +3692,10 @@ public class LeAudioService extends ProfileService { if (!leaudioUseAudioModeListener()) { mQueuedInCallValue = Optional.empty(); } startBroadcast(mBroadcastIdDeactivatedForUnicastTransition.get()); if (!leaudioBigDependsOnAudioState()) { startBroadcast( mBroadcastIdDeactivatedForUnicastTransition.get()); } mBroadcastIdDeactivatedForUnicastTransition = Optional.empty(); } Loading Loading @@ -3729,9 +3755,10 @@ public class LeAudioService extends ProfileService { mBroadcastSessionStats.put(broadcastId, sessionStats); } if (!leaudioBigDependsOnAudioState()) { // Start sending the actual stream startBroadcast(broadcastId); } } else { // TODO: Improve reason reporting or extend the native stack event with reason code Log.e( Loading @@ -3744,7 +3771,9 @@ public class LeAudioService extends ProfileService { if ((mUnicastGroupIdDeactivatedForBroadcastTransition != LE_AUDIO_GROUP_ID_INVALID) && mCreateBroadcastQueue.isEmpty() && (!Objects.equals(device, mActiveBroadcastAudioDevice))) { clearBroadcastTimeoutCallback(); if (!leaudioBigDependsOnAudioState()) { clearCreateBroadcastTimeoutCallback(); } updateBroadcastActiveDevice(null, mActiveBroadcastAudioDevice, false); } Loading @@ -3755,6 +3784,9 @@ public class LeAudioService extends ProfileService { .BROADCAST_AUDIO_SESSION_REPORTED__SESSION_SETUP_STATUS__SETUP_STATUS_CREATE_FAILED); } if (leaudioBigDependsOnAudioState()) { clearCreateBroadcastTimeoutCallback(); } mAwaitingBroadcastCreateResponse = false; // In case if there were additional calls to create broadcast Loading Loading @@ -3883,7 +3915,9 @@ public class LeAudioService extends ProfileService { sessionStats.updateSessionStreamingTime(SystemClock.elapsedRealtime()); } clearBroadcastTimeoutCallback(); if (!leaudioBigDependsOnAudioState()) { clearCreateBroadcastTimeoutCallback(); } if (previousState == LeAudioStackEvent.BROADCAST_STATE_PAUSED) { if (bassClientService != null) { Loading Loading @@ -5279,21 +5313,38 @@ public class LeAudioService extends ProfileService { return audioFrameworkCalls; } class DialingOutTimeoutEvent implements Runnable { private class CreateBroadcastTimeoutEvent implements Runnable { Integer mBroadcastId; DialingOutTimeoutEvent(Integer broadcastId) { CreateBroadcastTimeoutEvent() {} CreateBroadcastTimeoutEvent(Integer broadcastId) { mBroadcastId = broadcastId; } @Override public void run() { if (leaudioBigDependsOnAudioState()) { Log.w(TAG, "Failed to start Broadcast in time"); if (getLeAudioService() == null) { Log.e(TAG, "CreateBroadcastTimeoutEvent: No LE Audio service"); return; } if (sLeAudioService.mHandler == null) { Log.w(TAG, "CreateBroadcastTimeoutEvent: No handler"); return; } mHandler.post(() -> notifyBroadcastStartFailed(BluetoothStatusCodes.ERROR_TIMEOUT)); } else { Log.w(TAG, "Failed to start Broadcast in time: " + mBroadcastId); mDialingOutTimeoutEvent = null; mCreateBroadcastTimeoutEvent = null; if (getLeAudioService() == null) { Log.e(TAG, "DialingOutTimeoutEvent: No LE Audio service"); Log.e(TAG, "CreateBroadcastTimeoutEvent: No LE Audio service"); return; } Loading @@ -5313,7 +5364,8 @@ public class LeAudioService extends ProfileService { updateBroadcastActiveDevice(null, mActiveBroadcastAudioDevice, false); } mHandler.post(() -> notifyBroadcastStartFailed(BluetoothStatusCodes.ERROR_TIMEOUT)); mHandler.post( () -> notifyBroadcastStartFailed(BluetoothStatusCodes.ERROR_TIMEOUT)); logBroadcastSessionStatsWithStatus( mBroadcastId, BluetoothStatsLog Loading @@ -5321,6 +5373,7 @@ public class LeAudioService extends ProfileService { } } } } class AudioModeChangeListener implements AudioManager.OnModeChangedListener { @Override Loading
android/app/tests/unit/src/com/android/bluetooth/le_audio/LeAudioBroadcastServiceTest.java +164 −140 File changed.Preview size limit exceeded, changes collapsed. Show changes
system/bta/le_audio/broadcaster/broadcaster.cc +8 −5 Original line number Diff line number Diff line Loading @@ -913,6 +913,7 @@ public: is_iso_running_ = is_active; log::info("is_iso_running: {}", is_iso_running_); if (!is_iso_running_) { if (!com::android::bluetooth::flags::leaudio_big_depends_on_audio_state()) { if (queued_start_broadcast_request_) { auto broadcast_id = *queued_start_broadcast_request_; queued_start_broadcast_request_ = std::nullopt; Loading @@ -920,6 +921,8 @@ public: log::info("Start queued broadcast."); StartAudioBroadcast(broadcast_id); } } if (queued_create_broadcast_request_) { auto broadcast_msg = std::move(*queued_create_broadcast_request_); queued_create_broadcast_request_ = std::nullopt; Loading
system/bta/le_audio/broadcaster/broadcaster_test.cc +36 −63 Original line number Diff line number Diff line Loading @@ -533,8 +533,19 @@ TEST_F(BroadcasterTest, CreateAudioBroadcastMultiGroups) { TEST_F(BroadcasterTest, SuspendAudioBroadcast) { EXPECT_CALL(*mock_codec_manager_, UpdateActiveBroadcastAudioHalClient(mock_audio_source_, true)) .Times(1); LeAudioSourceAudioHalClient::Callbacks* audio_receiver; EXPECT_CALL(*mock_audio_source_, Start) .WillOnce(DoAll(SaveArg<1>(&audio_receiver), Return(true))) .WillRepeatedly(Return(false)); auto broadcast_id = InstantiateBroadcast(); if (com::android::bluetooth::flags::leaudio_big_depends_on_audio_state()) { ASSERT_NE(audio_receiver, nullptr); audio_receiver->OnAudioResume(); } else { LeAudioBroadcaster::Get()->StartAudioBroadcast(broadcast_id); } Mock::VerifyAndClearExpectations(mock_codec_manager_); EXPECT_CALL(mock_broadcaster_callbacks_, Loading @@ -559,7 +570,9 @@ TEST_F(BroadcasterTest, StartAudioBroadcast) { EXPECT_CALL(*mock_codec_manager_, UpdateActiveBroadcastAudioHalClient(mock_audio_source_, true)) .Times(1); auto broadcast_id = InstantiateBroadcast(); ASSERT_NE(audio_receiver, nullptr); Mock::VerifyAndClearExpectations(mock_codec_manager_); EXPECT_CALL(*mock_codec_manager_, UpdateActiveBroadcastAudioHalClient(mock_audio_source_, true)) Loading @@ -575,8 +588,7 @@ TEST_F(BroadcasterTest, StartAudioBroadcast) { ASSERT_TRUE(big_terminate_timer_->cb == nullptr); ASSERT_TRUE(broadcast_stop_timer_->cb == nullptr); LeAudioBroadcaster::Get()->StartAudioBroadcast(broadcast_id); ASSERT_NE(audio_receiver, nullptr); audio_receiver->OnAudioResume(); // NOTICE: This is really an implementation specific part, we fake the BIG // config as the mocked state machine does not even call the Loading Loading @@ -609,6 +621,7 @@ TEST_F(BroadcasterTest, StartAudioBroadcastMedia) { .Times(1); auto broadcast_id = InstantiateBroadcast(media_metadata, default_code, {bluetooth::le_audio::QUALITY_HIGH}); ASSERT_NE(audio_receiver, nullptr); Mock::VerifyAndClearExpectations(mock_codec_manager_); LeAudioBroadcaster::Get()->StopAudioBroadcast(broadcast_id); Loading @@ -626,8 +639,7 @@ TEST_F(BroadcasterTest, StartAudioBroadcastMedia) { EXPECT_CALL(*mock_codec_manager_, UpdateActiveBroadcastAudioHalClient(mock_audio_source_, false)) .Times(0); LeAudioBroadcaster::Get()->StartAudioBroadcast(broadcast_id); ASSERT_NE(audio_receiver, nullptr); audio_receiver->OnAudioResume(); // NOTICE: This is really an implementation specific part, we fake the BIG // config as the mocked state machine does not even call the Loading @@ -651,8 +663,18 @@ TEST_F(BroadcasterTest, StartAudioBroadcastMedia) { TEST_F(BroadcasterTest, StopAudioBroadcast) { EXPECT_CALL(*mock_codec_manager_, UpdateActiveBroadcastAudioHalClient(mock_audio_source_, true)) .Times(1); LeAudioSourceAudioHalClient::Callbacks* audio_receiver; EXPECT_CALL(*mock_audio_source_, Start) .WillOnce(DoAll(SaveArg<1>(&audio_receiver), Return(true))) .WillRepeatedly(Return(false)); auto broadcast_id = InstantiateBroadcast(); if (com::android::bluetooth::flags::leaudio_big_depends_on_audio_state()) { ASSERT_NE(audio_receiver, nullptr); audio_receiver->OnAudioResume(); } else { LeAudioBroadcaster::Get()->StartAudioBroadcast(broadcast_id); } // NOTICE: This is really an implementation specific part, we fake the BIG // config as the mocked state machine does not even call the Loading Loading @@ -712,7 +734,6 @@ TEST_F(BroadcasterTest, DestroyAudioBroadcast) { LeAudioBroadcaster::Get()->StopAudioBroadcast(broadcast_id); EXPECT_CALL(*mock_audio_source_, Start).Times(0); LeAudioBroadcaster::Get()->StartAudioBroadcast(broadcast_id); EXPECT_CALL(*mock_audio_source_, Stop).Times(0); LeAudioBroadcaster::Get()->SuspendAudioBroadcast(broadcast_id); Loading Loading @@ -846,8 +867,8 @@ TEST_F(BroadcasterTest, UpdateMetadataFromAudioTrackMetadata) { ContentControlIdKeeper::GetInstance()->SetCcid(LeAudioContextType::MEDIA, media_ccid); auto broadcast_id = InstantiateBroadcast(); LeAudioBroadcaster::Get()->StartAudioBroadcast(broadcast_id); ASSERT_NE(audio_receiver, nullptr); audio_receiver->OnAudioResume(); auto sm = MockBroadcastStateMachine::GetLastInstance(); std::vector<uint8_t> ccid_list; Loading Loading @@ -1204,6 +1225,7 @@ TEST_F(BroadcasterTest, AudioActiveState) { .WillRepeatedly(Return(false)); auto broadcast_id = InstantiateBroadcast(); ASSERT_NE(audio_receiver, nullptr); auto sm = MockBroadcastStateMachine::GetLastInstance(); pb_announcement = sm->GetPublicBroadcastAnnouncement(); auto created_public_meta = types::LeAudioLtvMap(pb_announcement.metadata).RawPacket(); Loading @@ -1218,9 +1240,6 @@ TEST_F(BroadcasterTest, AudioActiveState) { }); ON_CALL(*sm, GetPublicBroadcastAnnouncement()).WillByDefault(ReturnRef(pb_announcement)); LeAudioBroadcaster::Get()->StartAudioBroadcast(broadcast_id); ASSERT_NE(audio_receiver, nullptr); // Update to true Audio Active State while audio resumed EXPECT_CALL(*sm, UpdatePublicBroadcastAnnouncement); audio_receiver->OnAudioResume(); Loading Loading @@ -1278,32 +1297,12 @@ TEST_F(BroadcasterTest, BigTerminationAndBroadcastStopWhenNoSoundFromTheBeginnin auto broadcast_id = InstantiateBroadcast(); EXPECT_CALL(mock_broadcaster_callbacks_, OnBroadcastStateChanged(broadcast_id, BroadcastState::STREAMING)) .Times(1); .Times(0); // Timers not started ASSERT_TRUE(big_terminate_timer_->cb == nullptr); ASSERT_TRUE(broadcast_stop_timer_->cb == nullptr); // Start Broadcast LeAudioBroadcaster::Get()->StartAudioBroadcast(broadcast_id); // Timers started ASSERT_EQ(2, get_func_call_count("alarm_set_on_mloop")); ASSERT_TRUE(big_terminate_timer_->cb != nullptr); ASSERT_TRUE(broadcast_stop_timer_->cb != nullptr); ASSERT_EQ(0, get_func_call_count("alarm_set_on_mloop")); ASSERT_NE(audio_receiver, nullptr); // BIG termination timer execution, state machine go to CONFIGURED state so BIG terminated EXPECT_CALL(mock_broadcaster_callbacks_, OnBroadcastStateChanged(broadcast_id, BroadcastState::CONFIGURED)) .Times(1); // Imitate execution of BIG termination timer big_terminate_timer_->cb(big_terminate_timer_->data); // Broadcast stop timer execution, state machine go to STOPPED state EXPECT_CALL(mock_broadcaster_callbacks_, OnBroadcastStateChanged(broadcast_id, BroadcastState::STOPPED)) .Times(1); // Imitate execution of BIG termination timer broadcast_stop_timer_->cb(broadcast_stop_timer_->data); } TEST_F(BroadcasterTest, BigTerminationAndBroadcastStopWhenNoSoundAfterSuspend) { Loading @@ -1326,24 +1325,11 @@ TEST_F(BroadcasterTest, BigTerminationAndBroadcastStopWhenNoSoundAfterSuspend) { ASSERT_TRUE(broadcast_stop_timer_->cb == nullptr); // Start Broadcast LeAudioBroadcaster::Get()->StartAudioBroadcast(broadcast_id); // Timers started ASSERT_EQ(2, get_func_call_count("alarm_set_on_mloop")); ASSERT_TRUE(big_terminate_timer_->cb != nullptr); ASSERT_TRUE(broadcast_stop_timer_->cb != nullptr); ASSERT_NE(audio_receiver, nullptr); // First onAudioResume when BIG already created, not cause any state change EXPECT_CALL(mock_broadcaster_callbacks_, OnBroadcastStateChanged(broadcast_id, _)).Times(0); audio_receiver->OnAudioResume(); // Timers cancelled ASSERT_EQ(2, get_func_call_count("alarm_cancel")); ASSERT_TRUE(big_terminate_timer_->cb == nullptr); ASSERT_TRUE(broadcast_stop_timer_->cb == nullptr); // OnAudioSuspend cause starting the BIG termination timer audio_receiver->OnAudioSuspend(); ASSERT_EQ(4, get_func_call_count("alarm_set_on_mloop")); ASSERT_EQ(2, get_func_call_count("alarm_set_on_mloop")); ASSERT_TRUE(big_terminate_timer_->cb != nullptr); ASSERT_TRUE(broadcast_stop_timer_->cb != nullptr); Loading @@ -1357,7 +1343,7 @@ TEST_F(BroadcasterTest, BigTerminationAndBroadcastStopWhenNoSoundAfterSuspend) { // OnAudioSuspend cause starting the BIG termination timer audio_receiver->OnAudioSuspend(); ASSERT_EQ(6, get_func_call_count("alarm_set_on_mloop")); ASSERT_EQ(4, get_func_call_count("alarm_set_on_mloop")); ASSERT_TRUE(big_terminate_timer_->cb != nullptr); ASSERT_TRUE(broadcast_stop_timer_->cb != nullptr); Loading Loading @@ -1396,24 +1382,11 @@ TEST_F(BroadcasterTest, BigCreationTerminationDependsOnAudioResumeSuspend) { ASSERT_TRUE(broadcast_stop_timer_->cb == nullptr); // Start Broadcast LeAudioBroadcaster::Get()->StartAudioBroadcast(broadcast_id); // Timers started ASSERT_EQ(2, get_func_call_count("alarm_set_on_mloop")); ASSERT_TRUE(big_terminate_timer_->cb != nullptr); ASSERT_TRUE(broadcast_stop_timer_->cb != nullptr); ASSERT_NE(audio_receiver, nullptr); // First onAudioResume when BIG already created, not cause any state change EXPECT_CALL(mock_broadcaster_callbacks_, OnBroadcastStateChanged(broadcast_id, _)).Times(0); audio_receiver->OnAudioResume(); // Timers cancelled ASSERT_EQ(2, get_func_call_count("alarm_cancel")); ASSERT_TRUE(big_terminate_timer_->cb == nullptr); ASSERT_TRUE(broadcast_stop_timer_->cb == nullptr); // OnAudioSuspend cause starting the BIG termination timer audio_receiver->OnAudioSuspend(); ASSERT_EQ(4, get_func_call_count("alarm_set_on_mloop")); ASSERT_EQ(2, get_func_call_count("alarm_set_on_mloop")); ASSERT_TRUE(big_terminate_timer_->cb != nullptr); ASSERT_TRUE(broadcast_stop_timer_->cb != nullptr); Loading @@ -1427,7 +1400,7 @@ TEST_F(BroadcasterTest, BigCreationTerminationDependsOnAudioResumeSuspend) { // OnAudioSuspend cause starting the BIG termination timer audio_receiver->OnAudioSuspend(); ASSERT_EQ(6, get_func_call_count("alarm_set_on_mloop")); ASSERT_EQ(4, get_func_call_count("alarm_set_on_mloop")); ASSERT_TRUE(big_terminate_timer_->cb != nullptr); ASSERT_TRUE(broadcast_stop_timer_->cb != nullptr); Loading
system/bta/le_audio/broadcaster/mock_state_machine.h +1 −0 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ public: advertising_sid_ = ++instance_counter_; ON_CALL(*this, Initialize).WillByDefault([this]() { SetState(State::CONFIGURED); this->cb->OnStateMachineCreateStatus(this->cfg.broadcast_id, result_); return result_; }); Loading