Audio policy: notify system_server of routing change
Callback into AudioPolicyClientInterface to notify of routing
update whenever output is re-evaluated.
Add native test to verify callback is invoked on device
(dis)connection and setForceUse.
Bug: 162448412
Test: atest AudioServiceHostTest#testPreferredDeviceRouting
Test: atest AudioServiceHostTest#testDevicesForAttributes
Test: atest audiopolicy_tests:AudioPolicyManagerTestDeviceConnection#RoutingUpdate
Change-Id: Ia1a985b996bf8f2f63e72c4110f62f65f9f42f21
diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp
index 84a75dd..2187635 100644
--- a/media/libaudioclient/AudioSystem.cpp
+++ b/media/libaudioclient/AudioSystem.cpp
@@ -53,6 +53,7 @@
std::set<audio_error_callback> AudioSystem::gAudioErrorCallbacks;
dynamic_policy_callback AudioSystem::gDynPolicyCallback = NULL;
record_config_callback AudioSystem::gRecordConfigCallback = NULL;
+routing_callback AudioSystem::gRoutingCallback = NULL;
// Required to be held while calling into gSoundTriggerCaptureStateListener.
class CaptureStateListenerImpl;
@@ -771,6 +772,12 @@
gRecordConfigCallback = cb;
}
+/*static*/ void AudioSystem::setRoutingCallback(routing_callback cb)
+{
+ Mutex::Autolock _l(gLock);
+ gRoutingCallback = cb;
+}
+
// client singleton for AudioPolicyService binder interface
// protected by gLockAPS
sp<IAudioPolicyService> AudioSystem::gAudioPolicyService;
@@ -1914,6 +1921,19 @@
return Status::ok();
}
+Status AudioSystem::AudioPolicyServiceClient::onRoutingUpdated() {
+ routing_callback cb = NULL;
+ {
+ Mutex::Autolock _l(AudioSystem::gLock);
+ cb = gRoutingCallback;
+ }
+
+ if (cb != NULL) {
+ cb();
+ }
+ return Status::ok();
+}
+
void AudioSystem::AudioPolicyServiceClient::binderDied(const wp<IBinder>& who __unused)
{
{
diff --git a/media/libaudioclient/aidl/android/media/IAudioPolicyServiceClient.aidl b/media/libaudioclient/aidl/android/media/IAudioPolicyServiceClient.aidl
index a8d79b5..a7782b8 100644
--- a/media/libaudioclient/aidl/android/media/IAudioPolicyServiceClient.aidl
+++ b/media/libaudioclient/aidl/android/media/IAudioPolicyServiceClient.aidl
@@ -44,4 +44,6 @@
in EffectDescriptor[] effects,
int /* audio_patch_handle_t */ patchHandle,
AudioSourceType source);
+ /** Notifies a change of audio routing */
+ void onRoutingUpdated();
}
diff --git a/media/libaudioclient/include/media/AudioSystem.h b/media/libaudioclient/include/media/AudioSystem.h
index 17ce56e..71b1e33 100644
--- a/media/libaudioclient/include/media/AudioSystem.h
+++ b/media/libaudioclient/include/media/AudioSystem.h
@@ -65,6 +65,7 @@
std::vector<effect_descriptor_t> effects,
audio_patch_handle_t patchHandle,
audio_source_t source);
+typedef void (*routing_callback)();
class IAudioFlinger;
class IAudioPolicyService;
@@ -138,6 +139,7 @@
static void setDynPolicyCallback(dynamic_policy_callback cb);
static void setRecordConfigCallback(record_config_callback);
+ static void setRoutingCallback(routing_callback cb);
// helper function to obtain AudioFlinger service handle
static const sp<IAudioFlinger> get_audio_flinger();
@@ -630,6 +632,7 @@
const std::vector<media::EffectDescriptor>& effects,
int32_t patchHandle,
media::AudioSourceType source) override;
+ binder::Status onRoutingUpdated();
private:
Mutex mLock;
@@ -656,6 +659,7 @@
static std::set<audio_error_callback> gAudioErrorCallbacks;
static dynamic_policy_callback gDynPolicyCallback;
static record_config_callback gRecordConfigCallback;
+ static routing_callback gRoutingCallback;
static size_t gInBuffSize;
// previous parameters for recording buffer size queries
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index f753836..9d5a0a0 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -439,6 +439,8 @@
audio_patch_handle_t patchHandle,
audio_source_t source) = 0;
+ virtual void onRoutingUpdated() = 0;
+
// Used to notify the sound trigger module that an audio capture is about to
// take place. This should typically result in any active recognition
// sessions to be preempted on modules that do not support sound trigger
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 69f9a69..633686d 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -5362,6 +5362,8 @@
if (mHwModules.getModuleFromName(AUDIO_HARDWARE_MODULE_ID_MSD) != 0) {
setMsdPatch();
}
+ // an event that changed routing likely occurred, inform upper layers
+ mpClientInterface->onRoutingUpdated();
}
bool AudioPolicyManager::followsSameRouting(const audio_attributes_t &lAttr,
diff --git a/services/audiopolicy/service/AudioPolicyClientImpl.cpp b/services/audiopolicy/service/AudioPolicyClientImpl.cpp
index 90b93e2..77b5200 100644
--- a/services/audiopolicy/service/AudioPolicyClientImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyClientImpl.cpp
@@ -266,6 +266,11 @@
mAudioPolicyService->onAudioVolumeGroupChanged(group, flags);
}
+void AudioPolicyService::AudioPolicyClient::onRoutingUpdated()
+{
+ mAudioPolicyService->onRoutingUpdated();
+}
+
audio_unique_id_t AudioPolicyService::AudioPolicyClient::newAudioUniqueId(audio_unique_id_use_t use)
{
return AudioSystem::newAudioUniqueId(use);
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index d71a317..a898dff 100644
--- a/services/audiopolicy/service/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -275,6 +275,19 @@
}
}
+void AudioPolicyService::onRoutingUpdated()
+{
+ mOutputCommandThread->routingChangedCommand();
+}
+
+void AudioPolicyService::doOnRoutingUpdated()
+{
+ Mutex::Autolock _l(mNotificationClientsLock);
+ for (size_t i = 0; i < mNotificationClients.size(); i++) {
+ mNotificationClients.valueAt(i)->onRoutingUpdated();
+ }
+}
+
status_t AudioPolicyService::clientCreateAudioPatch(const struct audio_patch *patch,
audio_patch_handle_t *handle,
int delayMs)
@@ -404,6 +417,13 @@
mAudioVolumeGroupCallbacksEnabled = enabled;
}
+void AudioPolicyService::NotificationClient::onRoutingUpdated()
+{
+ if (mAudioPolicyServiceClient != 0 && isServiceUid(mUid)) {
+ mAudioPolicyServiceClient->onRoutingUpdated();
+ }
+}
+
void AudioPolicyService::binderDied(const wp<IBinder>& who) {
ALOGW("binderDied() %p, calling pid %d", who.unsafe_get(),
IPCThreadState::self()->getCallingPid());
@@ -1414,6 +1434,16 @@
svc->doOnNewAudioModulesAvailable();
mLock.lock();
} break;
+ case ROUTING_UPDATED: {
+ ALOGV("AudioCommandThread() processing routing update");
+ svc = mService.promote();
+ if (svc == 0) {
+ break;
+ }
+ mLock.unlock();
+ svc->doOnRoutingUpdated();
+ mLock.lock();
+ } break;
default:
ALOGW("AudioCommandThread() unknown command %d", command->mCommand);
@@ -1710,6 +1740,14 @@
sendCommand(command);
}
+void AudioPolicyService::AudioCommandThread::routingChangedCommand()
+{
+ sp<AudioCommand>command = new AudioCommand();
+ command->mCommand = ROUTING_UPDATED;
+ ALOGV("AudioCommandThread() adding routing update");
+ sendCommand(command);
+}
+
status_t AudioPolicyService::AudioCommandThread::sendCommand(sp<AudioCommand>& command, int delayMs)
{
{
@@ -1873,6 +1911,10 @@
} break;
+ case ROUTING_UPDATED: {
+
+ } break;
+
default:
break;
}
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index c0e29ee..db84d54 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -345,6 +345,10 @@
void onAudioVolumeGroupChanged(volume_group_t group, int flags);
void doOnAudioVolumeGroupChanged(volume_group_t group, int flags);
+
+ void onRoutingUpdated();
+ void doOnRoutingUpdated();
+
void setEffectSuspended(int effectId,
audio_session_t sessionId,
bool suspended);
@@ -497,6 +501,7 @@
RECORDING_CONFIGURATION_UPDATE,
SET_EFFECT_SUSPENDED,
AUDIO_MODULES_UPDATE,
+ ROUTING_UPDATED,
};
AudioCommandThread (String8 name, const wp<AudioPolicyService>& service);
@@ -543,6 +548,7 @@
audio_session_t sessionId,
bool suspended);
void audioModulesUpdateCommand();
+ void routingChangedCommand();
void insertCommand_l(AudioCommand *command, int delayMs = 0);
private:
class AudioCommandData;
@@ -761,6 +767,8 @@
virtual void onAudioVolumeGroupChanged(volume_group_t group, int flags);
+ virtual void onRoutingUpdated();
+
virtual audio_unique_id_t newAudioUniqueId(audio_unique_id_use_t use);
void setSoundTriggerCaptureState(bool active) override;
@@ -793,6 +801,7 @@
std::vector<effect_descriptor_t> effects,
audio_patch_handle_t patchHandle,
audio_source_t source);
+ void onRoutingUpdated();
void setAudioPortCallbacksEnabled(bool enabled);
void setAudioVolumeGroupCallbacksEnabled(bool enabled);
diff --git a/services/audiopolicy/tests/AudioPolicyManagerTestClient.h b/services/audiopolicy/tests/AudioPolicyManagerTestClient.h
index 433a6ff..e2d7d17 100644
--- a/services/audiopolicy/tests/AudioPolicyManagerTestClient.h
+++ b/services/audiopolicy/tests/AudioPolicyManagerTestClient.h
@@ -123,6 +123,17 @@
virtual void addSupportedFormat(audio_format_t /* format */) {}
+ void onRoutingUpdated() override {
+ mRoutingUpdatedUpdateCount++;
+ }
+
+ void resetRoutingUpdatedCounter() {
+ mRoutingUpdatedUpdateCount = 0;
+ }
+
+ size_t getRoutingUpdatedCounter() const {
+ return mRoutingUpdatedUpdateCount; }
+
private:
audio_module_handle_t mNextModuleHandle = AUDIO_MODULE_HANDLE_NONE + 1;
audio_io_handle_t mNextIoHandle = AUDIO_IO_HANDLE_NONE + 1;
@@ -130,6 +141,7 @@
std::map<audio_patch_handle_t, struct audio_patch> mActivePatches;
std::set<std::string> mAllowedModuleNames;
size_t mAudioPortListUpdateCount = 0;
+ size_t mRoutingUpdatedUpdateCount = 0;
};
} // namespace android
diff --git a/services/audiopolicy/tests/AudioPolicyTestClient.h b/services/audiopolicy/tests/AudioPolicyTestClient.h
index fa6b90f..d289e15 100644
--- a/services/audiopolicy/tests/AudioPolicyTestClient.h
+++ b/services/audiopolicy/tests/AudioPolicyTestClient.h
@@ -83,6 +83,7 @@
std::vector<effect_descriptor_t> effects __unused,
audio_patch_handle_t patchHandle __unused,
audio_source_t source __unused) override { }
+ void onRoutingUpdated() override { }
void setEffectSuspended(int effectId __unused,
audio_session_t sessionId __unused,
bool suspended __unused) {}
diff --git a/services/audiopolicy/tests/audiopolicymanager_tests.cpp b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
index 889efac..6b82968 100644
--- a/services/audiopolicy/tests/audiopolicymanager_tests.cpp
+++ b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
@@ -1184,6 +1184,34 @@
dumpToLog();
}
+TEST_F(AudioPolicyManagerTestDeviceConnection, RoutingUpdate) {
+ mClient->resetRoutingUpdatedCounter();
+ // Connecting a valid output device with valid parameters should trigger a routing update
+ ASSERT_EQ(NO_ERROR, mManager->setDeviceConnectionState(
+ AUDIO_DEVICE_OUT_BLUETOOTH_SCO, AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
+ "a", "b", AUDIO_FORMAT_DEFAULT));
+ ASSERT_EQ(1, mClient->getRoutingUpdatedCounter());
+
+ // Disconnecting a connected device should succeed and trigger a routing update
+ ASSERT_EQ(NO_ERROR, mManager->setDeviceConnectionState(
+ AUDIO_DEVICE_OUT_BLUETOOTH_SCO, AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
+ "a", "b", AUDIO_FORMAT_DEFAULT));
+ ASSERT_EQ(2, mClient->getRoutingUpdatedCounter());
+
+ // Disconnecting a disconnected device should fail and not trigger a routing update
+ ASSERT_EQ(INVALID_OPERATION, mManager->setDeviceConnectionState(
+ AUDIO_DEVICE_OUT_BLUETOOTH_SCO, AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
+ "a", "b", AUDIO_FORMAT_DEFAULT));
+ ASSERT_EQ(2, mClient->getRoutingUpdatedCounter());
+
+ // Changing force use should trigger an update
+ auto config = mManager->getForceUse(AUDIO_POLICY_FORCE_FOR_MEDIA);
+ auto newConfig = config == AUDIO_POLICY_FORCE_BT_A2DP ?
+ AUDIO_POLICY_FORCE_NONE : AUDIO_POLICY_FORCE_BT_A2DP;
+ mManager->setForceUse(AUDIO_POLICY_FORCE_FOR_MEDIA, newConfig);
+ ASSERT_EQ(3, mClient->getRoutingUpdatedCounter());
+}
+
TEST_P(AudioPolicyManagerTestDeviceConnection, SetDeviceConnectionState) {
const audio_devices_t type = std::get<0>(GetParam());
const std::string name = std::get<1>(GetParam());