libaudiohal@aidl: Implement setConnectedState
Implement the following methods in DeviceHalAidl:
- getAudioPort (both overloads)
- setAudioPortConfig
- setConnectedState
Add DeviceHalInterface::setSimulateDeviceConnections.
This method only works for the AIDL HAL and allows
testing external device connections in unit tests.
Plumb setSimulateDeviceConnections via the audio
framework to expose to libaudioclient tests.
Make conversions to/from AudioDevice and legacy
to use a corresponding variant for the address.
Fix invalid addresses in audiopolicy_tests.
Bug: 273252382
Test: atest audiopolicy_tests
Test: atest audiosystem_tests
Test: atest audio_aidl_conversion_tests
Change-Id: I9ed13b3a464496740f00a6553b1e03a3f884db74
diff --git a/media/audioaidlconversion/AidlConversionCppNdk.cpp b/media/audioaidlconversion/AidlConversionCppNdk.cpp
index 951a0e7..3b06245 100644
--- a/media/audioaidlconversion/AidlConversionCppNdk.cpp
+++ b/media/audioaidlconversion/AidlConversionCppNdk.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include <stdio.h>
+
#include <algorithm>
#include <map>
#include <utility>
@@ -570,7 +572,6 @@
GET_DEVICE_DESC_CONNECTION(BT_LE));
return pairs;
}();
-#undef GET_DEVICE_DESC_CONNECTION
return pairs;
}
@@ -998,55 +999,161 @@
}
}
+AudioDeviceAddress::Tag suggestDeviceAddressTag(const AudioDeviceDescription& description) {
+ using Tag = AudioDeviceAddress::Tag;
+ if (std::string connection = description.connection;
+ connection == GET_DEVICE_DESC_CONNECTION(BT_A2DP) ||
+ // Note: BT LE Broadcast uses a "group id".
+ (description.type != AudioDeviceType::OUT_BROADCAST &&
+ connection == GET_DEVICE_DESC_CONNECTION(BT_LE)) ||
+ connection == GET_DEVICE_DESC_CONNECTION(BT_SCO) ||
+ connection == GET_DEVICE_DESC_CONNECTION(WIRELESS)) {
+ return Tag::mac;
+ } else if (connection == GET_DEVICE_DESC_CONNECTION(IP_V4)) {
+ return Tag::ipv4;
+ } else if (connection == GET_DEVICE_DESC_CONNECTION(USB)) {
+ return Tag::alsa;
+ }
+ return Tag::id;
+}
+
::android::status_t aidl2legacy_AudioDevice_audio_device(
const AudioDevice& aidl,
audio_devices_t* legacyType, char* legacyAddress) {
- *legacyType = VALUE_OR_RETURN_STATUS(
- aidl2legacy_AudioDeviceDescription_audio_devices_t(aidl.type));
- return aidl2legacy_string(
- aidl.address.get<AudioDeviceAddress::id>(),
- legacyAddress, AUDIO_DEVICE_MAX_ADDRESS_LEN);
+ std::string stringAddress;
+ RETURN_STATUS_IF_ERROR(aidl2legacy_AudioDevice_audio_device(
+ aidl, legacyType, &stringAddress));
+ return aidl2legacy_string(stringAddress, legacyAddress, AUDIO_DEVICE_MAX_ADDRESS_LEN);
}
::android::status_t aidl2legacy_AudioDevice_audio_device(
const AudioDevice& aidl,
audio_devices_t* legacyType, String8* legacyAddress) {
- *legacyType = VALUE_OR_RETURN_STATUS(
- aidl2legacy_AudioDeviceDescription_audio_devices_t(aidl.type));
- *legacyAddress = VALUE_OR_RETURN_STATUS(aidl2legacy_string_view_String8(
- aidl.address.get<AudioDeviceAddress::id>()));
+ std::string stringAddress;
+ RETURN_STATUS_IF_ERROR(aidl2legacy_AudioDevice_audio_device(
+ aidl, legacyType, &stringAddress));
+ *legacyAddress = VALUE_OR_RETURN_STATUS(aidl2legacy_string_view_String8(stringAddress));
return OK;
}
::android::status_t aidl2legacy_AudioDevice_audio_device(
const AudioDevice& aidl,
audio_devices_t* legacyType, std::string* legacyAddress) {
+ using Tag = AudioDeviceAddress::Tag;
*legacyType = VALUE_OR_RETURN_STATUS(
aidl2legacy_AudioDeviceDescription_audio_devices_t(aidl.type));
- *legacyAddress = aidl.address.get<AudioDeviceAddress::id>();
+ char addressBuffer[AUDIO_DEVICE_MAX_ADDRESS_LEN]{};
+ // 'aidl.address' can be empty even when the connection type is not.
+ // This happens for device ports that act as "blueprints". In this case
+ // we pass an empty string using the 'id' variant.
+ switch (aidl.address.getTag()) {
+ case Tag::mac: {
+ const std::vector<uint8_t>& mac = aidl.address.get<AudioDeviceAddress::mac>();
+ if (mac.size() != 6) return BAD_VALUE;
+ snprintf(addressBuffer, AUDIO_DEVICE_MAX_ADDRESS_LEN, "%02X:%02X:%02X:%02X:%02X:%02X",
+ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+ } break;
+ case Tag::ipv4: {
+ const std::vector<uint8_t>& ipv4 = aidl.address.get<AudioDeviceAddress::ipv4>();
+ if (ipv4.size() != 4) return BAD_VALUE;
+ snprintf(addressBuffer, AUDIO_DEVICE_MAX_ADDRESS_LEN, "%u.%u.%u.%u",
+ ipv4[0], ipv4[1], ipv4[2], ipv4[3]);
+ } break;
+ case Tag::ipv6: {
+ const std::vector<int32_t>& ipv6 = aidl.address.get<AudioDeviceAddress::ipv6>();
+ if (ipv6.size() != 8) return BAD_VALUE;
+ snprintf(addressBuffer, AUDIO_DEVICE_MAX_ADDRESS_LEN,
+ "%04X:%04X:%04X:%04X:%04X:%04X:%04X:%04X",
+ ipv6[0], ipv6[1], ipv6[2], ipv6[3], ipv6[4], ipv6[5], ipv6[6], ipv6[7]);
+ } break;
+ case Tag::alsa: {
+ const std::vector<int32_t>& alsa = aidl.address.get<AudioDeviceAddress::alsa>();
+ if (alsa.size() != 2) return BAD_VALUE;
+ snprintf(addressBuffer, AUDIO_DEVICE_MAX_ADDRESS_LEN, "card=%d;device=%d",
+ alsa[0], alsa[1]);
+ } break;
+ case Tag::id: {
+ RETURN_STATUS_IF_ERROR(aidl2legacy_string(aidl.address.get<AudioDeviceAddress::id>(),
+ addressBuffer, AUDIO_DEVICE_MAX_ADDRESS_LEN));
+ } break;
+ }
+ *legacyAddress = addressBuffer;
return OK;
}
ConversionResult<AudioDevice> legacy2aidl_audio_device_AudioDevice(
audio_devices_t legacyType, const char* legacyAddress) {
- AudioDevice aidl;
- aidl.type = VALUE_OR_RETURN(
- legacy2aidl_audio_devices_t_AudioDeviceDescription(legacyType));
- const std::string aidl_id = VALUE_OR_RETURN(
+ const std::string stringAddress = VALUE_OR_RETURN(
legacy2aidl_string(legacyAddress, AUDIO_DEVICE_MAX_ADDRESS_LEN));
- aidl.address = AudioDeviceAddress::make<AudioDeviceAddress::id>(aidl_id);
- return aidl;
+ return legacy2aidl_audio_device_AudioDevice(legacyType, stringAddress);
}
ConversionResult<AudioDevice>
legacy2aidl_audio_device_AudioDevice(
audio_devices_t legacyType, const String8& legacyAddress) {
+ const std::string stringAddress = VALUE_OR_RETURN(legacy2aidl_String8_string(legacyAddress));
+ return legacy2aidl_audio_device_AudioDevice(legacyType, stringAddress);
+}
+
+ConversionResult<AudioDevice>
+legacy2aidl_audio_device_AudioDevice(
+ audio_devices_t legacyType, const std::string& legacyAddress) {
+ using Tag = AudioDeviceAddress::Tag;
AudioDevice aidl;
aidl.type = VALUE_OR_RETURN(
legacy2aidl_audio_devices_t_AudioDeviceDescription(legacyType));
- const std::string aidl_id = VALUE_OR_RETURN(
- legacy2aidl_String8_string(legacyAddress));
- aidl.address = AudioDeviceAddress::make<AudioDeviceAddress::id>(aidl_id);
+ // 'legacyAddress' can be empty even when the connection type is not.
+ // This happens for device ports that act as "blueprints". In this case
+ // we pass an empty string using the 'id' variant.
+ if (!legacyAddress.empty()) {
+ switch (suggestDeviceAddressTag(aidl.type)) {
+ case Tag::mac: {
+ std::vector<uint8_t> mac(6);
+ int status = sscanf(legacyAddress.c_str(), "%hhX:%hhX:%hhX:%hhX:%hhX:%hhX",
+ &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]);
+ if (status != mac.size()) {
+ ALOGE("%s: malformed MAC address: \"%s\"", __func__, legacyAddress.c_str());
+ return unexpected(BAD_VALUE);
+ }
+ aidl.address = AudioDeviceAddress::make<AudioDeviceAddress::mac>(std::move(mac));
+ } break;
+ case Tag::ipv4: {
+ std::vector<uint8_t> ipv4(4);
+ int status = sscanf(legacyAddress.c_str(), "%hhu.%hhu.%hhu.%hhu",
+ &ipv4[0], &ipv4[1], &ipv4[2], &ipv4[3]);
+ if (status != ipv4.size()) {
+ ALOGE("%s: malformed IPv4 address: \"%s\"", __func__, legacyAddress.c_str());
+ return unexpected(BAD_VALUE);
+ }
+ aidl.address = AudioDeviceAddress::make<AudioDeviceAddress::ipv4>(std::move(ipv4));
+ } break;
+ case Tag::ipv6: {
+ std::vector<int32_t> ipv6(8);
+ int status = sscanf(legacyAddress.c_str(), "%X:%X:%X:%X:%X:%X:%X:%X",
+ &ipv6[0], &ipv6[1], &ipv6[2], &ipv6[3], &ipv6[4], &ipv6[5], &ipv6[6],
+ &ipv6[7]);
+ if (status != ipv6.size()) {
+ ALOGE("%s: malformed IPv6 address: \"%s\"", __func__, legacyAddress.c_str());
+ return unexpected(BAD_VALUE);
+ }
+ aidl.address = AudioDeviceAddress::make<AudioDeviceAddress::ipv6>(std::move(ipv6));
+ } break;
+ case Tag::alsa: {
+ std::vector<int32_t> alsa(2);
+ int status = sscanf(legacyAddress.c_str(), "card=%d;device=%d", &alsa[0], &alsa[1]);
+ if (status != alsa.size()) {
+ ALOGE("%s: malformed ALSA address: \"%s\"", __func__, legacyAddress.c_str());
+ return unexpected(BAD_VALUE);
+ }
+ aidl.address = AudioDeviceAddress::make<AudioDeviceAddress::alsa>(std::move(alsa));
+ } break;
+ case Tag::id: {
+ aidl.address = AudioDeviceAddress::make<AudioDeviceAddress::id>(legacyAddress);
+ } break;
+ }
+ } else {
+ aidl.address = AudioDeviceAddress::make<AudioDeviceAddress::id>(legacyAddress);
+ }
return aidl;
}
@@ -3025,6 +3132,8 @@
} // namespace android
+#undef GET_DEVICE_DESC_CONNECTION
+
#if defined(BACKEND_NDK)
} // aidl
#endif
diff --git a/media/audioaidlconversion/include/media/AidlConversionCppNdk-impl.h b/media/audioaidlconversion/include/media/AidlConversionCppNdk-impl.h
index 9100892..ec1f75c 100644
--- a/media/audioaidlconversion/include/media/AidlConversionCppNdk-impl.h
+++ b/media/audioaidlconversion/include/media/AidlConversionCppNdk-impl.h
@@ -190,6 +190,9 @@
ConversionResult<media::audio::common::AudioDeviceDescription>
legacy2aidl_audio_devices_t_AudioDeviceDescription(audio_devices_t legacy);
+media::audio::common::AudioDeviceAddress::Tag suggestDeviceAddressTag(
+ const media::audio::common::AudioDeviceDescription& description);
+
::android::status_t aidl2legacy_AudioDevice_audio_device(
const media::audio::common::AudioDevice& aidl, audio_devices_t* legacyType,
char* legacyAddress);
@@ -204,6 +207,8 @@
audio_devices_t legacyType, const char* legacyAddress);
ConversionResult<media::audio::common::AudioDevice> legacy2aidl_audio_device_AudioDevice(
audio_devices_t legacyType, const ::android::String8& legacyAddress);
+ConversionResult<media::audio::common::AudioDevice> legacy2aidl_audio_device_AudioDevice(
+ audio_devices_t legacyType, const std::string& legacyAddress);
ConversionResult<audio_extra_audio_descriptor>
aidl2legacy_ExtraAudioDescriptor_audio_extra_audio_descriptor(
diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp
index 27be515..b731702 100644
--- a/media/libaudioclient/AudioSystem.cpp
+++ b/media/libaudioclient/AudioSystem.cpp
@@ -264,6 +264,12 @@
return af->setMode(mode);
}
+status_t AudioSystem::setSimulateDeviceConnections(bool enabled) {
+ const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+ if (af == 0) return PERMISSION_DENIED;
+ return af->setSimulateDeviceConnections(enabled);
+}
+
status_t AudioSystem::setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs) {
const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
if (af == 0) return PERMISSION_DENIED;
diff --git a/media/libaudioclient/IAudioFlinger.cpp b/media/libaudioclient/IAudioFlinger.cpp
index bbc39e8..620cdc2 100644
--- a/media/libaudioclient/IAudioFlinger.cpp
+++ b/media/libaudioclient/IAudioFlinger.cpp
@@ -816,6 +816,10 @@
return statusTFromBinderStatus(mDelegate->setDeviceConnectedState(aidlPort, connected));
}
+status_t AudioFlingerClientAdapter::setSimulateDeviceConnections(bool enabled) {
+ return statusTFromBinderStatus(mDelegate->setSimulateDeviceConnections(enabled));
+}
+
status_t AudioFlingerClientAdapter::setRequestedLatencyMode(
audio_io_handle_t output, audio_latency_mode_t mode) {
int32_t outputAidl = VALUE_OR_RETURN_STATUS(legacy2aidl_audio_io_handle_t_int32_t(output));
@@ -1370,6 +1374,10 @@
return Status::fromStatusT(mDelegate->setDeviceConnectedState(&portLegacy, connected));
}
+Status AudioFlingerServerAdapter::setSimulateDeviceConnections(bool enabled) {
+ return Status::fromStatusT(mDelegate->setSimulateDeviceConnections(enabled));
+}
+
Status AudioFlingerServerAdapter::setRequestedLatencyMode(
int32_t output, media::audio::common::AudioLatencyMode modeAidl) {
audio_io_handle_t outputLegacy = VALUE_OR_RETURN_BINDER(
diff --git a/media/libaudioclient/aidl/android/media/IAudioFlingerService.aidl b/media/libaudioclient/aidl/android/media/IAudioFlingerService.aidl
index 568c865..4d9fef4 100644
--- a/media/libaudioclient/aidl/android/media/IAudioFlingerService.aidl
+++ b/media/libaudioclient/aidl/android/media/IAudioFlingerService.aidl
@@ -229,6 +229,9 @@
void setDeviceConnectedState(in AudioPortFw devicePort, boolean connected);
+ // Used for tests only. Requires AIDL HAL to work.
+ void setSimulateDeviceConnections(boolean enabled);
+
/**
* Requests a given latency mode (See AudioLatencyMode.aidl) on an output stream.
* This can be used when some use case on a given mixer/stream can only be enabled
diff --git a/media/libaudioclient/include/media/AudioSystem.h b/media/libaudioclient/include/media/AudioSystem.h
index 027236c..1bfe34d 100644
--- a/media/libaudioclient/include/media/AudioSystem.h
+++ b/media/libaudioclient/include/media/AudioSystem.h
@@ -127,6 +127,9 @@
// set audio mode in audio hardware
static status_t setMode(audio_mode_t mode);
+ // test API: switch HALs into the mode which simulates external device connections
+ static status_t setSimulateDeviceConnections(bool enabled);
+
// returns true in *state if tracks are active on the specified stream or have been active
// in the past inPastMs milliseconds
static status_t isStreamActive(audio_stream_type_t stream, bool *state, uint32_t inPastMs);
diff --git a/media/libaudioclient/include/media/IAudioFlinger.h b/media/libaudioclient/include/media/IAudioFlinger.h
index 02d0511..1803862 100644
--- a/media/libaudioclient/include/media/IAudioFlinger.h
+++ b/media/libaudioclient/include/media/IAudioFlinger.h
@@ -363,6 +363,8 @@
virtual status_t setDeviceConnectedState(const struct audio_port_v7 *port, bool connected) = 0;
+ virtual status_t setSimulateDeviceConnections(bool enabled) = 0;
+
virtual status_t setRequestedLatencyMode(
audio_io_handle_t output, audio_latency_mode_t mode) = 0;
@@ -480,6 +482,7 @@
int32_t getAAudioMixerBurstCount() override;
int32_t getAAudioHardwareBurstMinUsec() override;
status_t setDeviceConnectedState(const struct audio_port_v7 *port, bool connected) override;
+ status_t setSimulateDeviceConnections(bool enabled) override;
status_t setRequestedLatencyMode(audio_io_handle_t output,
audio_latency_mode_t mode) override;
status_t getSupportedLatencyModes(
@@ -578,6 +581,7 @@
GET_AAUDIO_MIXER_BURST_COUNT = media::BnAudioFlingerService::TRANSACTION_getAAudioMixerBurstCount,
GET_AAUDIO_HARDWARE_BURST_MIN_USEC = media::BnAudioFlingerService::TRANSACTION_getAAudioHardwareBurstMinUsec,
SET_DEVICE_CONNECTED_STATE = media::BnAudioFlingerService::TRANSACTION_setDeviceConnectedState,
+ SET_SIMULATE_DEVICE_CONNECTIONS = media::BnAudioFlingerService::TRANSACTION_setSimulateDeviceConnections,
SET_REQUESTED_LATENCY_MODE = media::BnAudioFlingerService::TRANSACTION_setRequestedLatencyMode,
GET_SUPPORTED_LATENCY_MODES = media::BnAudioFlingerService::TRANSACTION_getSupportedLatencyModes,
SET_BLUETOOTH_VARIABLE_LATENCY_ENABLED =
@@ -708,6 +712,7 @@
Status getAAudioMixerBurstCount(int32_t* _aidl_return) override;
Status getAAudioHardwareBurstMinUsec(int32_t* _aidl_return) override;
Status setDeviceConnectedState(const media::AudioPortFw& port, bool connected) override;
+ Status setSimulateDeviceConnections(bool enabled) override;
Status setRequestedLatencyMode(
int output, media::audio::common::AudioLatencyMode mode) override;
Status getSupportedLatencyModes(int output,
diff --git a/media/libaudioclient/tests/Android.bp b/media/libaudioclient/tests/Android.bp
index 2189521..1e8dcca 100644
--- a/media/libaudioclient/tests/Android.bp
+++ b/media/libaudioclient/tests/Android.bp
@@ -14,6 +14,12 @@
"-Wall",
"-Werror",
],
+ shared_libs: [
+ "libbinder",
+ "libcutils",
+ "liblog",
+ "libutils",
+ ],
sanitize: {
misc_undefined: [
"unsigned-integer-overflow",
@@ -22,37 +28,35 @@
},
}
-cc_test {
- name: "audio_aidl_conversion_tests",
+cc_defaults {
+ name: "audio_aidl_conversion_test_defaults",
defaults: [
"libaudioclient_tests_defaults",
"latest_android_media_audio_common_types_cpp_static",
],
- srcs: ["audio_aidl_legacy_conversion_tests.cpp"],
- shared_libs: [
- "libbinder",
- "libcutils",
- "liblog",
- "libutils",
- ],
static_libs: [
- "libaudioclient_aidl_conversion",
- "libaudio_aidl_conversion_common_cpp",
"audioclient-types-aidl-cpp",
"av-types-aidl-cpp",
+ "libaudio_aidl_conversion_common_cpp",
+ "libaudioclient_aidl_conversion",
"libstagefright_foundation",
],
}
cc_test {
+ name: "audio_aidl_conversion_tests",
+ defaults: [
+ "audio_aidl_conversion_test_defaults",
+ ],
+ srcs: ["audio_aidl_legacy_conversion_tests.cpp"],
+}
+
+cc_test {
name: "audio_aidl_status_tests",
defaults: ["libaudioclient_tests_defaults"],
srcs: ["audio_aidl_status_tests.cpp"],
shared_libs: [
"libaudioclient_aidl_conversion",
- "libbinder",
- "libcutils",
- "libutils",
],
}
@@ -70,9 +74,6 @@
shared_libs: [
"framework-permission-aidl-cpp",
"libaudioclient",
- "libbinder",
- "libcutils",
- "libutils",
],
data: ["track_test_input_*.txt"],
}
@@ -89,35 +90,23 @@
"libmediametrics_headers",
],
shared_libs: [
- "libaudioclient",
- "libbinder",
- "libcutils",
- "libutils",
"framework-permission-aidl-cpp",
+ "libaudioclient",
],
data: ["record_test_input_*.txt"],
}
cc_defaults {
name: "libaudioclient_gtests_defaults",
- cflags: [
- "-Wall",
- "-Werror",
- ],
defaults: [
- "latest_android_media_audio_common_types_cpp_static",
+ "audio_aidl_conversion_test_defaults",
],
shared_libs: [
"capture_state_listener-aidl-cpp",
"framework-permission-aidl-cpp",
- "libaudioclient_aidl_conversion",
- "libaudio_aidl_conversion_common_cpp",
"libbase",
- "libbinder",
"libcgrouprc",
- "libcutils",
"libdl",
- "liblog",
"libmedia",
"libmediametrics",
"libmediautils",
@@ -125,8 +114,6 @@
"libnblog",
"libprocessgroup",
"libshmemcompat",
- "libstagefright_foundation",
- "libutils",
"libxml2",
"mediametricsservice-aidl-cpp",
"packagemanager_aidl-cpp",
@@ -148,7 +135,6 @@
],
data: ["bbb*.raw"],
test_config_template: "audio_test_template.xml",
- test_suites: ["device-tests"],
}
cc_test {
diff --git a/media/libaudioclient/tests/audio_aidl_legacy_conversion_tests.cpp b/media/libaudioclient/tests/audio_aidl_legacy_conversion_tests.cpp
index f651a37..0d12f9d 100644
--- a/media/libaudioclient/tests/audio_aidl_legacy_conversion_tests.cpp
+++ b/media/libaudioclient/tests/audio_aidl_legacy_conversion_tests.cpp
@@ -15,6 +15,7 @@
*/
#include <iostream>
+#include <string>
#include <gtest/gtest.h>
@@ -32,6 +33,7 @@
using media::AudioPortType;
using media::audio::common::AudioChannelLayout;
using media::audio::common::AudioDevice;
+using media::audio::common::AudioDeviceAddress;
using media::audio::common::AudioDeviceDescription;
using media::audio::common::AudioDeviceType;
using media::audio::common::AudioEncapsulationMetadataType;
@@ -131,6 +133,14 @@
return make_AudioDeviceDescription(AudioDeviceType::IN_DEFAULT);
}
+AudioDeviceDescription make_ADD_MicIn() {
+ return make_AudioDeviceDescription(AudioDeviceType::IN_MICROPHONE);
+}
+
+AudioDeviceDescription make_ADD_RSubmixIn() {
+ return make_AudioDeviceDescription(AudioDeviceType::IN_SUBMIX);
+}
+
AudioDeviceDescription make_ADD_DefaultOut() {
return make_AudioDeviceDescription(AudioDeviceType::OUT_DEFAULT);
}
@@ -145,6 +155,39 @@
AudioDeviceDescription::CONNECTION_BT_SCO());
}
+AudioDeviceDescription make_ADD_BtA2dpHeadphone() {
+ return make_AudioDeviceDescription(AudioDeviceType::OUT_HEADPHONE,
+ AudioDeviceDescription::CONNECTION_BT_A2DP());
+}
+
+AudioDeviceDescription make_ADD_BtLeHeadset() {
+ return make_AudioDeviceDescription(AudioDeviceType::OUT_HEADSET,
+ AudioDeviceDescription::CONNECTION_BT_LE());
+}
+
+AudioDeviceDescription make_ADD_BtLeBroadcast() {
+ return make_AudioDeviceDescription(AudioDeviceType::OUT_BROADCAST,
+ AudioDeviceDescription::CONNECTION_BT_LE());
+}
+
+AudioDeviceDescription make_ADD_IpV4Device() {
+ return make_AudioDeviceDescription(AudioDeviceType::OUT_DEVICE,
+ AudioDeviceDescription::CONNECTION_IP_V4());
+}
+
+AudioDeviceDescription make_ADD_UsbHeadset() {
+ return make_AudioDeviceDescription(AudioDeviceType::OUT_HEADSET,
+ AudioDeviceDescription::CONNECTION_USB());
+}
+
+AudioDevice make_AudioDevice(const AudioDeviceDescription& type,
+ const AudioDeviceAddress& address) {
+ AudioDevice result;
+ result.type = type;
+ result.address = address;
+ return result;
+}
+
AudioFormatDescription make_AudioFormatDescription(AudioFormatType type) {
AudioFormatDescription result;
result.type = type;
@@ -390,6 +433,48 @@
make_ADD_DefaultOut(), make_ADD_WiredHeadset(),
make_ADD_BtScoHeadset()));
+class AudioDeviceRoundTripTest : public testing::TestWithParam<AudioDevice> {};
+TEST_P(AudioDeviceRoundTripTest, Aidl2Legacy2Aidl) {
+ const auto initial = GetParam();
+ audio_devices_t legacyType;
+ String8 legacyAddress;
+ status_t status = aidl2legacy_AudioDevice_audio_device(initial, &legacyType, &legacyAddress);
+ ASSERT_EQ(OK, status);
+ auto convBack = legacy2aidl_audio_device_AudioDevice(legacyType, legacyAddress);
+ ASSERT_TRUE(convBack.ok());
+ EXPECT_EQ(initial, convBack.value());
+}
+INSTANTIATE_TEST_SUITE_P(
+ AudioDeviceRoundTrip, AudioDeviceRoundTripTest,
+ testing::Values(
+ make_AudioDevice(make_ADD_MicIn(),
+ AudioDeviceAddress::make<AudioDeviceAddress::Tag::id>("bottom")),
+ make_AudioDevice(make_ADD_RSubmixIn(),
+ AudioDeviceAddress::make<AudioDeviceAddress::Tag::id>("1:2-in-3")),
+ // The case of a "blueprint" device port for an external device.
+ make_AudioDevice(make_ADD_BtScoHeadset(),
+ AudioDeviceAddress::make<AudioDeviceAddress::Tag::id>("")),
+ make_AudioDevice(make_ADD_BtScoHeadset(),
+ AudioDeviceAddress::make<AudioDeviceAddress::Tag::mac>(
+ std::vector<uint8_t>{1, 2, 3, 4, 5, 6})),
+ // Another "blueprint"
+ make_AudioDevice(make_ADD_BtA2dpHeadphone(),
+ AudioDeviceAddress::make<AudioDeviceAddress::Tag::id>("")),
+ make_AudioDevice(make_ADD_BtA2dpHeadphone(),
+ AudioDeviceAddress::make<AudioDeviceAddress::Tag::mac>(
+ std::vector<uint8_t>{1, 2, 3, 4, 5, 6})),
+ make_AudioDevice(make_ADD_BtLeHeadset(),
+ AudioDeviceAddress::make<AudioDeviceAddress::Tag::mac>(
+ std::vector<uint8_t>{1, 2, 3, 4, 5, 6})),
+ make_AudioDevice(make_ADD_BtLeBroadcast(),
+ AudioDeviceAddress::make<AudioDeviceAddress::Tag::id>("42")),
+ make_AudioDevice(make_ADD_IpV4Device(),
+ AudioDeviceAddress::make<AudioDeviceAddress::Tag::ipv4>(
+ std::vector<uint8_t>{192, 168, 0, 1})),
+ make_AudioDevice(make_ADD_UsbHeadset(),
+ AudioDeviceAddress::make<AudioDeviceAddress::Tag::alsa>(
+ std::vector<int32_t>{1, 2}))));
+
class AudioFormatDescriptionRoundTripTest : public testing::TestWithParam<AudioFormatDescription> {
};
TEST_P(AudioFormatDescriptionRoundTripTest, Aidl2Legacy2Aidl) {
diff --git a/media/libaudioclient/tests/audiosystem_tests.cpp b/media/libaudioclient/tests/audiosystem_tests.cpp
index 2b9b4fa..45baa94 100644
--- a/media/libaudioclient/tests/audiosystem_tests.cpp
+++ b/media/libaudioclient/tests/audiosystem_tests.cpp
@@ -18,12 +18,19 @@
#include <string.h>
+#include <set>
+
#include <gtest/gtest.h>
+#include <media/AidlConversionCppNdk.h>
#include <media/IAudioFlinger.h>
#include <utils/Log.h>
#include "audio_test_utils.h"
+using android::media::audio::common::AudioDeviceAddress;
+using android::media::audio::common::AudioDeviceDescription;
+using android::media::audio::common::AudioDeviceType;
+using android::media::audio::common::AudioPortExt;
using namespace android;
void anyPatchContainsInputDevice(audio_port_handle_t deviceId, bool& res) {
@@ -579,3 +586,106 @@
EXPECT_EQ(NO_ERROR, AudioSystem::setUserIdDeviceAffinities(userId, outputDevices));
EXPECT_EQ(NO_ERROR, AudioSystem::removeUserIdDeviceAffinities(userId));
}
+
+namespace {
+
+class WithSimulatedDeviceConnections {
+ public:
+ WithSimulatedDeviceConnections()
+ : mIsSupported(AudioSystem::setSimulateDeviceConnections(true) == OK) {}
+ ~WithSimulatedDeviceConnections() {
+ if (mIsSupported) {
+ if (status_t status = AudioSystem::setSimulateDeviceConnections(false); status != OK) {
+ ALOGE("Error restoring device connections simulation state: %d", status);
+ }
+ }
+ }
+ bool isSupported() const { return mIsSupported; }
+
+ private:
+ const bool mIsSupported;
+};
+
+android::media::audio::common::AudioPort GenerateUniqueDeviceAddress(
+ const android::media::audio::common::AudioPort& port) {
+ static int nextId = 0;
+ using Tag = AudioDeviceAddress::Tag;
+ AudioDeviceAddress address;
+ switch (suggestDeviceAddressTag(port.ext.get<AudioPortExt::Tag::device>().device.type)) {
+ case Tag::id:
+ address = AudioDeviceAddress::make<Tag::id>(std::to_string(++nextId));
+ break;
+ case Tag::mac:
+ address = AudioDeviceAddress::make<Tag::mac>(
+ std::vector<uint8_t>{1, 2, 3, 4, 5, static_cast<uint8_t>(++nextId & 0xff)});
+ break;
+ case Tag::ipv4:
+ address = AudioDeviceAddress::make<Tag::ipv4>(
+ std::vector<uint8_t>{192, 168, 0, static_cast<uint8_t>(++nextId & 0xff)});
+ break;
+ case Tag::ipv6:
+ address = AudioDeviceAddress::make<Tag::ipv6>(std::vector<int32_t>{
+ 0xfc00, 0x0123, 0x4567, 0x89ab, 0xcdef, 0, 0, ++nextId & 0xffff});
+ break;
+ case Tag::alsa:
+ address = AudioDeviceAddress::make<Tag::alsa>(std::vector<int32_t>{1, ++nextId});
+ break;
+ }
+ android::media::audio::common::AudioPort result = port;
+ result.ext.get<AudioPortExt::Tag::device>().device.address = std::move(address);
+ return result;
+}
+
+} // namespace
+
+TEST_F(AudioSystemTest, SetDeviceConnectedState) {
+ WithSimulatedDeviceConnections connSim;
+ if (!connSim.isSupported()) {
+ GTEST_SKIP() << "Simulation of external device connections not supported";
+ }
+ std::vector<media::AudioPortFw> ports;
+ ASSERT_EQ(OK, AudioSystem::listDeclaredDevicePorts(media::AudioPortRole::NONE, &ports));
+ if (ports.empty()) {
+ GTEST_SKIP() << "No ports returned by the audio system";
+ }
+ const std::set<AudioDeviceType> typesToUse{
+ AudioDeviceType::IN_DEVICE, AudioDeviceType::IN_HEADSET,
+ AudioDeviceType::IN_MICROPHONE, AudioDeviceType::OUT_DEVICE,
+ AudioDeviceType::OUT_HEADPHONE, AudioDeviceType::OUT_HEADSET,
+ AudioDeviceType::OUT_HEARING_AID, AudioDeviceType::OUT_SPEAKER};
+ std::vector<media::AudioPortFw> externalDevicePorts;
+ for (const auto& port : ports) {
+ if (const auto& device = port.hal.ext.get<AudioPortExt::device>().device;
+ !device.type.connection.empty() && typesToUse.count(device.type.type)) {
+ externalDevicePorts.push_back(port);
+ }
+ }
+ if (externalDevicePorts.empty()) {
+ GTEST_SKIP() << "No ports for considered non-attached devices";
+ }
+ for (auto& port : externalDevicePorts) {
+ android::media::audio::common::AudioPort aidlPort = GenerateUniqueDeviceAddress(port.hal);
+ SCOPED_TRACE(aidlPort.toString());
+ audio_devices_t type;
+ char address[AUDIO_DEVICE_MAX_ADDRESS_LEN];
+ status_t status = aidl2legacy_AudioDevice_audio_device(
+ aidlPort.ext.get<AudioPortExt::Tag::device>().device, &type, address);
+ ASSERT_EQ(OK, status);
+ audio_policy_dev_state_t deviceState = AudioSystem::getDeviceConnectionState(type, address);
+ EXPECT_EQ(AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE, deviceState);
+ if (deviceState != AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE) continue;
+ // !!! Instead of the default format, use each format from 'ext.encodedFormats'
+ // !!! if they are not empty
+ status = AudioSystem::setDeviceConnectionState(AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
+ aidlPort, AUDIO_FORMAT_DEFAULT);
+ EXPECT_EQ(OK, status);
+ if (status != OK) continue;
+ deviceState = AudioSystem::getDeviceConnectionState(type, address);
+ EXPECT_EQ(AUDIO_POLICY_DEVICE_STATE_AVAILABLE, deviceState);
+ status = AudioSystem::setDeviceConnectionState(AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
+ aidlPort, AUDIO_FORMAT_DEFAULT);
+ EXPECT_EQ(OK, status);
+ deviceState = AudioSystem::getDeviceConnectionState(type, address);
+ EXPECT_EQ(AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE, deviceState);
+ }
+}
diff --git a/media/libaudiohal/impl/DeviceHalAidl.cpp b/media/libaudiohal/impl/DeviceHalAidl.cpp
index 62533cb..d9ea061 100644
--- a/media/libaudiohal/impl/DeviceHalAidl.cpp
+++ b/media/libaudiohal/impl/DeviceHalAidl.cpp
@@ -36,10 +36,12 @@
#include "StreamHalAidl.h"
using aidl::android::aidl_utils::statusTFromBinderStatus;
+using aidl::android::media::audio::common::AudioChannelLayout;
using aidl::android::media::audio::common::AudioConfig;
using aidl::android::media::audio::common::AudioDevice;
using aidl::android::media::audio::common::AudioDeviceAddress;
using aidl::android::media::audio::common::AudioDeviceType;
+using aidl::android::media::audio::common::AudioFormatType;
using aidl::android::media::audio::common::AudioInputFlags;
using aidl::android::media::audio::common::AudioIoFlags;
using aidl::android::media::audio::common::AudioLatencyMode;
@@ -54,6 +56,7 @@
using aidl::android::media::audio::common::AudioPortExt;
using aidl::android::media::audio::common::AudioPortMixExt;
using aidl::android::media::audio::common::AudioPortMixExtUseCase;
+using aidl::android::media::audio::common::AudioProfile;
using aidl::android::media::audio::common::AudioSource;
using aidl::android::media::audio::common::Float;
using aidl::android::media::audio::common::Int;
@@ -61,11 +64,13 @@
using aidl::android::media::audio::common::MicrophoneInfo;
using aidl::android::hardware::audio::common::getFrameSizeInBytes;
using aidl::android::hardware::audio::common::isBitPositionFlagSet;
+using aidl::android::hardware::audio::common::isDefaultAudioFormat;
using aidl::android::hardware::audio::common::makeBitPositionFlagMask;
using aidl::android::hardware::audio::common::RecordTrackMetadata;
using aidl::android::hardware::audio::core::AudioPatch;
using aidl::android::hardware::audio::core::IModule;
using aidl::android::hardware::audio::core::ITelephony;
+using aidl::android::hardware::audio::core::ModuleDebug;
using aidl::android::hardware::audio::core::StreamDescriptor;
namespace android {
@@ -332,9 +337,9 @@
AudioPortConfig mixPortConfig;
Cleanups cleanups;
audio_config writableConfig = *config;
- int32_t nominalLatency;
+ AudioPatch aidlPatch;
RETURN_STATUS_IF_ERROR(prepareToOpenStream(0 /*handle*/, aidlDevice, aidlFlags, aidlSource,
- &writableConfig, &cleanups, &aidlConfig, &mixPortConfig, &nominalLatency));
+ &writableConfig, &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
*size = aidlConfig.frameCount *
getFrameSizeInBytes(aidlConfig.base.format, aidlConfig.base.channelMask);
// Do not disarm cleanups to release temporary port configs.
@@ -345,7 +350,11 @@
int32_t aidlHandle, const AudioDevice& aidlDevice, const AudioIoFlags& aidlFlags,
AudioSource aidlSource, struct audio_config* config,
Cleanups* cleanups, AudioConfig* aidlConfig, AudioPortConfig* mixPortConfig,
- int32_t* nominalLatency) {
+ AudioPatch* aidlPatch) {
+ ALOGD("%p %s::%s: handle %d, device %s, flags %s, source %s, config %s, mix port config %s",
+ this, getClassName().c_str(), __func__, aidlHandle, aidlDevice.toString().c_str(),
+ aidlFlags.toString().c_str(), toString(aidlSource).c_str(),
+ aidlConfig->toString().c_str(), mixPortConfig->toString().c_str());
const bool isInput = aidlFlags.getTag() == AudioIoFlags::Tag::input;
// Find / create AudioPortConfigs for the device port and the mix port,
// then find / create a patch between them, and open a stream on the mix port.
@@ -361,20 +370,18 @@
cleanups->emplace_front(this, &DeviceHalAidl::resetPortConfig, mixPortConfig->id);
}
setConfigFromPortConfig(aidlConfig, *mixPortConfig);
- AudioPatch patch;
if (isInput) {
RETURN_STATUS_IF_ERROR(findOrCreatePatch(
- {devicePortConfig.id}, {mixPortConfig->id}, &patch, &created));
+ {devicePortConfig.id}, {mixPortConfig->id}, aidlPatch, &created));
} else {
RETURN_STATUS_IF_ERROR(findOrCreatePatch(
- {mixPortConfig->id}, {devicePortConfig.id}, &patch, &created));
+ {mixPortConfig->id}, {devicePortConfig.id}, aidlPatch, &created));
}
if (created) {
- cleanups->emplace_front(this, &DeviceHalAidl::resetPatch, patch.id);
+ cleanups->emplace_front(this, &DeviceHalAidl::resetPatch, aidlPatch->id);
}
- *nominalLatency = patch.latenciesMs[0];
if (aidlConfig->frameCount <= 0) {
- aidlConfig->frameCount = patch.minimumStreamBufferSizeFrames;
+ aidlConfig->frameCount = aidlPatch->minimumStreamBufferSizeFrames;
}
*config = VALUE_OR_RETURN_STATUS(
::aidl::android::aidl2legacy_AudioConfig_audio_config_t(*aidlConfig, isInput));
@@ -520,10 +527,10 @@
AudioIoFlags aidlFlags = AudioIoFlags::make<AudioIoFlags::Tag::output>(aidlOutputFlags);
AudioPortConfig mixPortConfig;
Cleanups cleanups;
- int32_t nominalLatency;
+ AudioPatch aidlPatch;
RETURN_STATUS_IF_ERROR(prepareToOpenStream(aidlHandle, aidlDevice, aidlFlags,
AudioSource::SYS_RESERVED_INVALID /*only needed for input*/,
- config, &cleanups, &aidlConfig, &mixPortConfig, &nominalLatency));
+ config, &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
::aidl::android::hardware::audio::core::IModule::OpenOutputStreamArguments args;
args.portConfigId = mixPortConfig.id;
const bool isOffload = isBitPositionFlagSet(
@@ -547,8 +554,9 @@
__func__, ret.desc.toString().c_str());
return NO_INIT;
}
- *outStream = sp<StreamOutHalAidl>::make(*config, std::move(context), nominalLatency,
+ *outStream = sp<StreamOutHalAidl>::make(*config, std::move(context), aidlPatch.latenciesMs[0],
std::move(ret.stream), this /*callbackBroker*/);
+ mStreams.insert(std::pair(*outStream, aidlPatch.id));
void* cbCookie = (*outStream).get();
{
std::lock_guard l(mLock);
@@ -585,9 +593,9 @@
::aidl::android::legacy2aidl_audio_source_t_AudioSource(source));
AudioPortConfig mixPortConfig;
Cleanups cleanups;
- int32_t nominalLatency;
+ AudioPatch aidlPatch;
RETURN_STATUS_IF_ERROR(prepareToOpenStream(aidlHandle, aidlDevice, aidlFlags, aidlSource,
- config, &cleanups, &aidlConfig, &mixPortConfig, &nominalLatency));
+ config, &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
::aidl::android::hardware::audio::core::IModule::OpenInputStreamArguments args;
args.portConfigId = mixPortConfig.id;
RecordTrackMetadata aidlTrackMetadata{
@@ -607,8 +615,9 @@
__func__, ret.desc.toString().c_str());
return NO_INIT;
}
- *inStream = sp<StreamInHalAidl>::make(*config, std::move(context), nominalLatency,
+ *inStream = sp<StreamInHalAidl>::make(*config, std::move(context), aidlPatch.latenciesMs[0],
std::move(ret.stream), this /*micInfoProvider*/);
+ mStreams.insert(std::pair(*inStream, aidlPatch.id));
cleanups.disarmAll();
return OK;
}
@@ -724,22 +733,67 @@
return OK;
}
-status_t DeviceHalAidl::getAudioPort(struct audio_port* port __unused) {
- TIME_CHECK();
- ALOGE("%s not implemented yet", __func__);
- return INVALID_OPERATION;
-}
-
-status_t DeviceHalAidl::getAudioPort(struct audio_port_v7 *port __unused) {
- TIME_CHECK();
- ALOGE("%s not implemented yet", __func__);
- return INVALID_OPERATION;
-}
-
-status_t DeviceHalAidl::setAudioPortConfig(const struct audio_port_config* config __unused) {
+status_t DeviceHalAidl::getAudioPort(struct audio_port* port) {
+ ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
TIME_CHECK();
if (!mModule) return NO_INIT;
- ALOGE("%s not implemented yet", __func__);
+ if (port == nullptr) {
+ return BAD_VALUE;
+ }
+ audio_port_v7 portV7;
+ audio_populate_audio_port_v7(port, &portV7);
+ RETURN_STATUS_IF_ERROR(getAudioPort(&portV7));
+ return audio_populate_audio_port(&portV7, port) ? OK : BAD_VALUE;
+}
+
+status_t DeviceHalAidl::getAudioPort(struct audio_port_v7 *port) {
+ ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
+ TIME_CHECK();
+ if (!mModule) return NO_INIT;
+ if (port == nullptr) {
+ return BAD_VALUE;
+ }
+ bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(port->role, port->type)) ==
+ ::aidl::android::AudioPortDirection::INPUT;
+ auto aidlPort = VALUE_OR_RETURN_STATUS(
+ ::aidl::android::legacy2aidl_audio_port_v7_AudioPort(*port, isInput));
+ if (aidlPort.ext.getTag() != AudioPortExt::device) {
+ ALOGE("%s: provided port is not a device port (module %s): %s",
+ __func__, mInstance.c_str(), aidlPort.toString().c_str());
+ return BAD_VALUE;
+ }
+ const auto& matchDevice = aidlPort.ext.get<AudioPortExt::device>().device;
+ // It seems that we don't have to call HAL since all valid ports have been added either
+ // during initialization, or while handling connection of an external device.
+ auto portsIt = findPort(matchDevice);
+ if (portsIt == mPorts.end()) {
+ ALOGE("%s: device port for device %s is not found in the module %s",
+ __func__, matchDevice.toString().c_str(), mInstance.c_str());
+ return BAD_VALUE;
+ }
+ const int32_t fwkId = aidlPort.id;
+ aidlPort = portsIt->second;
+ aidlPort.id = fwkId;
+ *port = VALUE_OR_RETURN_STATUS(::aidl::android::aidl2legacy_AudioPort_audio_port_v7(
+ aidlPort, isInput));
+ return OK;
+}
+
+status_t DeviceHalAidl::setAudioPortConfig(const struct audio_port_config* config) {
+ ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
+ TIME_CHECK();
+ if (!mModule) return NO_INIT;
+ if (config == nullptr) {
+ return BAD_VALUE;
+ }
+ bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
+ config->role, config->type)) == ::aidl::android::AudioPortDirection::INPUT;
+ AudioPortConfig requestedPortConfig = VALUE_OR_RETURN_STATUS(
+ ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
+ *config, isInput, 0 /*portId*/));
+ AudioPortConfig portConfig;
+ bool created = false;
+ RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(requestedPortConfig, &portConfig, &created));
return OK;
}
@@ -885,6 +939,73 @@
return OK;
}
+status_t DeviceHalAidl::setConnectedState(const struct audio_port_v7 *port, bool connected) {
+ TIME_CHECK();
+ if (!mModule) return NO_INIT;
+ if (port == nullptr) {
+ return BAD_VALUE;
+ }
+ bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(port->role, port->type)) ==
+ ::aidl::android::AudioPortDirection::INPUT;
+ AudioPort aidlPort = VALUE_OR_RETURN_STATUS(
+ ::aidl::android::legacy2aidl_audio_port_v7_AudioPort(*port, isInput));
+ if (aidlPort.ext.getTag() != AudioPortExt::device) {
+ ALOGE("%s: provided port is not a device port (module %s): %s",
+ __func__, mInstance.c_str(), aidlPort.toString().c_str());
+ return BAD_VALUE;
+ }
+ if (connected) {
+ AudioDevice matchDevice = aidlPort.ext.get<AudioPortExt::device>().device;
+ // Reset the device address to find the "template" port.
+ matchDevice.address = AudioDeviceAddress::make<AudioDeviceAddress::id>();
+ auto portsIt = findPort(matchDevice);
+ if (portsIt == mPorts.end()) {
+ ALOGW("%s: device port for device %s is not found in the module %s",
+ __func__, matchDevice.toString().c_str(), mInstance.c_str());
+ return BAD_VALUE;
+ }
+ // Use the ID of the "template" port, use all the information from the provided port.
+ aidlPort.id = portsIt->first;
+ AudioPort connectedPort;
+ RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->connectExternalDevice(
+ aidlPort, &connectedPort)));
+ const auto [it, inserted] = mPorts.insert(std::make_pair(connectedPort.id, connectedPort));
+ LOG_ALWAYS_FATAL_IF(!inserted,
+ "%s: module %s, duplicate port ID received from HAL: %s, existing port: %s",
+ __func__, mInstance.c_str(), connectedPort.toString().c_str(),
+ it->second.toString().c_str());
+ } else { // !connected
+ AudioDevice matchDevice = aidlPort.ext.get<AudioPortExt::device>().device;
+ auto portsIt = findPort(matchDevice);
+ if (portsIt == mPorts.end()) {
+ ALOGW("%s: device port for device %s is not found in the module %s",
+ __func__, matchDevice.toString().c_str(), mInstance.c_str());
+ return BAD_VALUE;
+ }
+ // Any streams opened on the external device must be closed by this time,
+ // thus we can clean up patches and port configs that were created for them.
+ resetUnusedPatchesAndPortConfigs();
+ RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->disconnectExternalDevice(
+ portsIt->second.id)));
+ mPorts.erase(portsIt);
+ }
+ return OK;
+}
+
+status_t DeviceHalAidl::setSimulateDeviceConnections(bool enabled) {
+ TIME_CHECK();
+ if (!mModule) return NO_INIT;
+ ModuleDebug debug{ .simulateDeviceConnections = enabled };
+ status_t status = statusTFromBinderStatus(mModule->setModuleDebug(debug));
+ // This is important to log as it affects HAL behavior.
+ if (status == OK) {
+ ALOGI("%s: set enabled: %d", __func__, enabled);
+ } else {
+ ALOGW("%s: set enabled to %d failed: %d", __func__, enabled, status);
+ }
+ return status;
+}
+
bool DeviceHalAidl::audioDeviceMatches(const AudioDevice& device, const AudioPort& p) {
if (p.ext.getTag() != AudioPortExt::Tag::device) return false;
return p.ext.get<AudioPortExt::Tag::device>().device == device;
@@ -1083,18 +1204,22 @@
DeviceHalAidl::Ports::iterator DeviceHalAidl::findPort(
const AudioConfig& config, const AudioIoFlags& flags) {
+ auto belongsToProfile = [&config](const AudioProfile& prof) {
+ return (isDefaultAudioFormat(config.base.format) || prof.format == config.base.format) &&
+ (config.base.channelMask.getTag() == AudioChannelLayout::none ||
+ std::find(prof.channelMasks.begin(), prof.channelMasks.end(),
+ config.base.channelMask) != prof.channelMasks.end()) &&
+ (config.base.sampleRate == 0 ||
+ std::find(prof.sampleRates.begin(), prof.sampleRates.end(),
+ config.base.sampleRate) != prof.sampleRates.end());
+ };
auto matcher = [&](const auto& pair) {
const auto& p = pair.second;
return p.ext.getTag() == AudioPortExt::Tag::mix &&
p.flags == flags &&
- std::find_if(p.profiles.begin(), p.profiles.end(),
- [&](const auto& prof) {
- return prof.format == config.base.format &&
- std::find(prof.channelMasks.begin(), prof.channelMasks.end(),
- config.base.channelMask) != prof.channelMasks.end() &&
- std::find(prof.sampleRates.begin(), prof.sampleRates.end(),
- config.base.sampleRate) != prof.sampleRates.end();
- }) != p.profiles.end(); };
+ (p.profiles.empty() ||
+ std::find_if(p.profiles.begin(), p.profiles.end(), belongsToProfile) !=
+ p.profiles.end()); };
return std::find_if(mPorts.begin(), mPorts.end(), matcher);
}
@@ -1119,34 +1244,7 @@
(!flags.has_value() || p.flags.value() == flags.value()) &&
p.ext.template get<Tag::mix>().handle == ioHandle; });
}
-/*
-DeviceHalAidl::PortConfigs::iterator DeviceHalAidl::findPortConfig(
- const AudioPortConfig& portConfig) {
- using Tag = AudioPortExt::Tag;
- if (portConfig.ext.getTag() == Tag::mix) {
- return std::find_if(mPortConfigs.begin(), mPortConfigs.end(),
- [&](const auto& pair) {
- const auto& p = pair.second;
- LOG_ALWAYS_FATAL_IF(p.ext.getTag() == Tag::mix &&
- !p.sampleRate.has_value() || !p.channelMask.has_value() ||
- !p.format.has_value() || !p.flags.has_value(),
- "%s: stored mix port config is not fully specified: %s",
- __func__, p.toString().c_str());
- return p.ext.getTag() == Tag::mix &&
- (!portConfig.sampleRate.has_value() ||
- p.sampleRate == portConfig.sampleRate) &&
- (!portConfig.channelMask.has_value() ||
- p.channelMask == portConfig.channelMask) &&
- (!portConfig.format.has_value() || p.format == portConfig.format) &&
- (!portConfig.flags.has_value() || p.flags == portConfig.flags) &&
- p.ext.template get<Tag::mix>().handle ==
- portConfig.ext.template get<Tag::mix>().handle; });
- } else if (portConfig.ext.getTag() == Tag::device) {
- return findPortConfig(portConfig.ext.get<Tag::device>().device);
- }
- return mPortConfigs.end();
-}
-*/
+
void DeviceHalAidl::resetPatch(int32_t patchId) {
if (auto it = mPatches.find(patchId); it != mPatches.end()) {
mPatches.erase(it);
@@ -1174,6 +1272,39 @@
ALOGE("%s: port config id %d not found", __func__, portConfigId);
}
+void DeviceHalAidl::resetUnusedPatches() {
+ // Since patches can be created independently of streams via 'createAudioPatch',
+ // here we only clean up patches for released streams.
+ for (auto it = mStreams.begin(); it != mStreams.end(); ) {
+ if (auto streamSp = it->first.promote(); streamSp) {
+ ++it;
+ } else {
+ resetPatch(it->second);
+ it = mStreams.erase(it);
+ }
+ }
+}
+
+void DeviceHalAidl::resetUnusedPatchesAndPortConfigs() {
+ resetUnusedPatches();
+ resetUnusedPortConfigs();
+}
+
+void DeviceHalAidl::resetUnusedPortConfigs() {
+ // The assumption is that port configs are used to create patches
+ // (or to open streams, but that involves creation of patches, too). Thus,
+ // orphaned port configs can and should be reset.
+ std::set<int32_t> portConfigIds;
+ std::transform(mPortConfigs.begin(), mPortConfigs.end(),
+ std::inserter(portConfigIds, portConfigIds.end()),
+ [](const auto& pcPair) { return pcPair.first; });
+ for (const auto& p : mPatches) {
+ for (int32_t id : p.second.sourcePortConfigIds) portConfigIds.erase(id);
+ for (int32_t id : p.second.sinkPortConfigIds) portConfigIds.erase(id);
+ }
+ for (int32_t id : portConfigIds) resetPortConfig(id);
+}
+
void DeviceHalAidl::clearCallbacks(void* cookie) {
std::lock_guard l(mLock);
mCallbacks.erase(cookie);
diff --git a/media/libaudiohal/impl/DeviceHalAidl.h b/media/libaudiohal/impl/DeviceHalAidl.h
index 9687ec9..caa82f1 100644
--- a/media/libaudiohal/impl/DeviceHalAidl.h
+++ b/media/libaudiohal/impl/DeviceHalAidl.h
@@ -25,6 +25,7 @@
#include <android-base/thread_annotations.h>
#include <media/audiohal/DeviceHalInterface.h>
#include <media/audiohal/EffectHalInterface.h>
+#include <media/audiohal/StreamHalInterface.h>
#include "ConversionHelperAidl.h"
@@ -139,7 +140,7 @@
status_t setAudioPortConfig(const struct audio_port_config* config) override;
// List microphones
- status_t getMicrophones(std::vector<audio_microphone_characteristic_t>* microphones);
+ status_t getMicrophones(std::vector<audio_microphone_characteristic_t>* microphones) override;
status_t addDeviceEffect(audio_port_handle_t device, sp<EffectHalInterface> effect) override;
@@ -155,13 +156,17 @@
error::Result<audio_hw_sync_t> getHwAvSync() override;
- status_t dump(int __unused, const Vector<String16>& __unused) override;
-
int32_t supportsBluetoothVariableLatency(bool* supports __unused) override;
status_t getSoundDoseInterface(const std::string& module,
::ndk::SpAIBinder* soundDoseBinder) override;
+ status_t setConnectedState(const struct audio_port_v7 *port, bool connected) override;
+
+ status_t setSimulateDeviceConnections(bool enabled) override;
+
+ status_t dump(int __unused, const Vector<String16>& __unused) override;
+
private:
friend class sp<DeviceHalAidl>;
@@ -180,6 +185,7 @@
using PortConfigs = std::map<int32_t /*port config ID*/,
::aidl::android::media::audio::common::AudioPortConfig>;
using Ports = std::map<int32_t /*port ID*/, ::aidl::android::media::audio::common::AudioPort>;
+ using Streams = std::map<wp<StreamHalInterface>, int32_t /*patch ID*/>;
class Cleanups;
// Must not be constructed directly by clients.
@@ -229,9 +235,6 @@
const ::aidl::android::media::audio::common::AudioConfig& config,
const std::optional<::aidl::android::media::audio::common::AudioIoFlags>& flags,
int32_t ioHandle);
- // Currently unused but may be useful for implementing setAudioPortConfig
- // PortConfigs::iterator findPortConfig(
- // const ::aidl::android::media::audio::common::AudioPortConfig& portConfig);
status_t prepareToOpenStream(
int32_t aidlHandle,
const ::aidl::android::media::audio::common::AudioDevice& aidlDevice,
@@ -241,9 +244,12 @@
Cleanups* cleanups,
::aidl::android::media::audio::common::AudioConfig* aidlConfig,
::aidl::android::media::audio::common::AudioPortConfig* mixPortConfig,
- int32_t* nominalLatency);
+ ::aidl::android::hardware::audio::core::AudioPatch* aidlPatch);
void resetPatch(int32_t patchId);
void resetPortConfig(int32_t portConfigId);
+ void resetUnusedPatches();
+ void resetUnusedPatchesAndPortConfigs();
+ void resetUnusedPortConfigs();
// CallbackBroker implementation
void clearCallbacks(void* cookie) override;
@@ -272,6 +278,7 @@
int32_t mDefaultOutputPortId = -1;
PortConfigs mPortConfigs;
Patches mPatches;
+ Streams mStreams;
Microphones mMicrophones;
std::mutex mLock;
std::map<void*, Callbacks> mCallbacks GUARDED_BY(mLock);
diff --git a/media/libaudiohal/impl/DeviceHalHidl.h b/media/libaudiohal/impl/DeviceHalHidl.h
index 30fbd6d..afaad51 100644
--- a/media/libaudiohal/impl/DeviceHalHidl.h
+++ b/media/libaudiohal/impl/DeviceHalHidl.h
@@ -126,6 +126,11 @@
status_t setConnectedState(const struct audio_port_v7 *port, bool connected) override;
+ status_t setSimulateDeviceConnections(bool enabled __unused) override {
+ // Only supported by AIDL HALs.
+ return INVALID_OPERATION;
+ }
+
error::Result<audio_hw_sync_t> getHwAvSync() override;
status_t dump(int fd, const Vector<String16>& args) override;
diff --git a/media/libaudiohal/include/media/audiohal/DeviceHalInterface.h b/media/libaudiohal/include/media/audiohal/DeviceHalInterface.h
index 2df2f5d..e8d8998 100644
--- a/media/libaudiohal/include/media/audiohal/DeviceHalInterface.h
+++ b/media/libaudiohal/include/media/audiohal/DeviceHalInterface.h
@@ -132,13 +132,14 @@
std::vector<media::audio::common::AudioMMapPolicyInfo> *policyInfos) = 0;
virtual int32_t getAAudioMixerBurstCount() = 0;
virtual int32_t getAAudioHardwareBurstMinUsec() = 0;
+
virtual int32_t supportsBluetoothVariableLatency(bool* supports) = 0;
// Update the connection status of an external device.
- virtual status_t setConnectedState(const struct audio_port_v7* port, bool connected) {
- ALOGE("%s override me port %p connected %d", __func__, port, connected);
- return OK;
- }
+ virtual status_t setConnectedState(const struct audio_port_v7* port, bool connected) = 0;
+
+ // Enable simulation of external devices connection at the HAL level.
+ virtual status_t setSimulateDeviceConnections(bool enabled) = 0;
virtual error::Result<audio_hw_sync_t> getHwAvSync() = 0;
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 57392c9..754b580 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -229,6 +229,7 @@
BINDER_METHOD_ENTRY(getAAudioMixerBurstCount) \
BINDER_METHOD_ENTRY(getAAudioHardwareBurstMinUsec) \
BINDER_METHOD_ENTRY(setDeviceConnectedState) \
+BINDER_METHOD_ENTRY(setSimulateDeviceConnections) \
BINDER_METHOD_ENTRY(setRequestedLatencyMode) \
BINDER_METHOD_ENTRY(getSupportedLatencyModes) \
BINDER_METHOD_ENTRY(setBluetoothVariableLatencyEnabled) \
@@ -502,6 +503,25 @@
return final_result;
}
+status_t AudioFlinger::setSimulateDeviceConnections(bool enabled) {
+ bool at_least_one_succeeded = false;
+ status_t last_error = INVALID_OPERATION;
+ Mutex::Autolock _l(mLock);
+ AutoMutex lock(mHardwareLock);
+ mHardwareStatus = AUDIO_HW_SET_SIMULATE_CONNECTIONS;
+ for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
+ sp<DeviceHalInterface> dev = mAudioHwDevs.valueAt(i)->hwDevice();
+ status_t result = dev->setSimulateDeviceConnections(enabled);
+ if (result == OK) {
+ at_least_one_succeeded = true;
+ } else {
+ last_error = result;
+ }
+ }
+ mHardwareStatus = AUDIO_HW_IDLE;
+ return at_least_one_succeeded ? OK : last_error;
+}
+
// getDefaultVibratorInfo_l must be called with AudioFlinger lock held.
std::optional<media::AudioVibratorInfo> AudioFlinger::getDefaultVibratorInfo_l() {
if (mAudioVibratorInfos.empty()) {
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 2204f8f..eac8190 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -300,6 +300,8 @@
virtual status_t setDeviceConnectedState(const struct audio_port_v7 *port, bool connected);
+ virtual status_t setSimulateDeviceConnections(bool enabled);
+
virtual status_t setRequestedLatencyMode(
audio_io_handle_t output, audio_latency_mode_t mode);
@@ -953,6 +955,7 @@
AUDIO_HW_GET_MASTER_MUTE, // get_master_mute
AUDIO_HW_GET_MICROPHONES, // getMicrophones
AUDIO_HW_SET_CONNECTED_STATE, // setConnectedState
+ AUDIO_HW_SET_SIMULATE_CONNECTIONS, // setSimulateDeviceConnections
};
mutable hardware_call_state mHardwareStatus; // for dump only
diff --git a/services/audiopolicy/tests/audiopolicymanager_tests.cpp b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
index ed77936..583ec1c 100644
--- a/services/audiopolicy/tests/audiopolicymanager_tests.cpp
+++ b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
@@ -2018,19 +2018,19 @@
// 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));
+ "00:11:22:33:44:55", "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));
+ "00:11:22:33:44:55", "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));
+ "00:11:22:33:44:55", "b", AUDIO_FORMAT_DEFAULT));
ASSERT_EQ(2, mClient->getRoutingUpdatedCounter());
// Changing force use should trigger an update
@@ -2158,9 +2158,9 @@
DeviceConnectionTestParams({AUDIO_DEVICE_OUT_HDMI, "test_out_hdmi",
"audio_policy_test_out_hdmi"}),
DeviceConnectionTestParams({AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET, "bt_hfp_in",
- "hfp_client_in"}),
+ "00:11:22:33:44:55"}),
DeviceConnectionTestParams({AUDIO_DEVICE_OUT_BLUETOOTH_SCO, "bt_hfp_out",
- "hfp_client_out"})
+ "00:11:22:33:44:55"})
)
);