Use routed devices throughout the audio framework
After you open an audio stream, you can call getRoutedDevice() to
get which output device is actually used.
However, if you play an ALARM with a headset attached, audio comes
out of both the speaker and the headset. This is not properly reflected
with our current APIs.
Throughout the audio framework, we should use DeviceIdVector instead
of a single device when getRoutedDevice(s) are called.
This change touches many files because onAudioDeviceUpdate() has many
callers.
BYPASS_LARGE_CHANGE_WARNING
Bug: 367816690
Test: atest AAudioTests
Test: atest audiorecord_tests
Test: atest audiosystem_tests
Test: atest audiotrack_tests
Test: adb shell /data/fuzz/arm64/libaaudio_fuzzer/libaaudio_fuzzer
Test: adb shell /data/fuzz/arm64/mediaplayer_fuzzer/mediaplayer_fuzzer
Test: adb shell /data/fuzz/arm64/mediarecorder_fuzzer/mediarecorder_fuzzer
Test: OboeTester Test Output with Alarm and USB
Flag: EXEMPT refactor
Change-Id: I5e32ac5d1c24229e60112ef00d82af41d8eff6e7
diff --git a/media/libaaudio/src/Android.bp b/media/libaaudio/src/Android.bp
index ebb7637..cccb096 100644
--- a/media/libaaudio/src/Android.bp
+++ b/media/libaaudio/src/Android.bp
@@ -103,6 +103,7 @@
"framework-permission-aidl-cpp",
"libaaudio_internal",
"libaudioclient",
+ "libaudiofoundation",
"libaudioutils",
"libbinder",
"libcutils",
@@ -166,6 +167,7 @@
"framework-permission-aidl-cpp",
"libaudioclient",
"libaudioclient_aidl_conversion",
+ "libaudiofoundation",
"libaudioutils",
"libbinder",
"libcutils",
diff --git a/media/libaaudio/src/binding/AAudioStreamConfiguration.cpp b/media/libaaudio/src/binding/AAudioStreamConfiguration.cpp
index c53a897..37c1a98 100644
--- a/media/libaaudio/src/binding/AAudioStreamConfiguration.cpp
+++ b/media/libaaudio/src/binding/AAudioStreamConfiguration.cpp
@@ -34,7 +34,16 @@
AAudioStreamConfiguration::AAudioStreamConfiguration(const StreamParameters& parcelable) {
setChannelMask(parcelable.channelMask);
setSampleRate(parcelable.sampleRate);
- setDeviceId(parcelable.deviceId);
+ auto deviceIds = android::convertContainer<android::DeviceIdVector>(
+ parcelable.deviceIds, android::aidl2legacy_int32_t_audio_port_handle_t);
+ if (deviceIds.ok()) {
+ setDeviceIds(deviceIds.value());
+ } else {
+ ALOGE("deviceIds (%s) aidl2legacy conversion failed",
+ android::toString(parcelable.deviceIds).c_str());
+ android::DeviceIdVector emptyDeviceIds;
+ setDeviceIds(emptyDeviceIds);
+ }
static_assert(sizeof(aaudio_sharing_mode_t) == sizeof(parcelable.sharingMode));
setSharingMode(parcelable.sharingMode);
auto convFormat = android::aidl2legacy_AudioFormatDescription_audio_format_t(
@@ -87,7 +96,15 @@
StreamParameters result;
result.channelMask = getChannelMask();
result.sampleRate = getSampleRate();
- result.deviceId = getDeviceId();
+ auto deviceIds = android::convertContainer<std::vector<int32_t>>(
+ getDeviceIds(), android::legacy2aidl_audio_port_handle_t_int32_t);
+ if (deviceIds.ok()) {
+ result.deviceIds = deviceIds.value();
+ } else {
+ ALOGE("deviceIds (%s) legacy2aidl conversion failed",
+ android::toString(getDeviceIds()).c_str());
+ result.deviceIds = {};
+ }
static_assert(sizeof(aaudio_sharing_mode_t) == sizeof(result.sharingMode));
result.sharingMode = getSharingMode();
auto convAudioFormat = android::legacy2aidl_audio_format_t_AudioFormatDescription(getFormat());
diff --git a/media/libaaudio/src/binding/aidl/aaudio/StreamParameters.aidl b/media/libaaudio/src/binding/aidl/aaudio/StreamParameters.aidl
index a301da8..7d7abce 100644
--- a/media/libaaudio/src/binding/aidl/aaudio/StreamParameters.aidl
+++ b/media/libaaudio/src/binding/aidl/aaudio/StreamParameters.aidl
@@ -21,7 +21,7 @@
parcelable StreamParameters {
int channelMask; // = AAUDIO_UNSPECIFIED;
int sampleRate; // = AAUDIO_UNSPECIFIED;
- int deviceId; // = AAUDIO_UNSPECIFIED;
+ int[] deviceIds; // = null;
int /* aaudio_sharing_mode_t */ sharingMode; // = AAUDIO_SHARING_MODE_SHARED;
AudioFormatDescription audioFormat; // = AUDIO_FORMAT_DEFAULT;
int /* aaudio_direction_t */ direction; // = AAUDIO_DIRECTION_OUTPUT;
diff --git a/media/libaaudio/src/client/AudioStreamInternal.cpp b/media/libaaudio/src/client/AudioStreamInternal.cpp
index 99b90e2..6bc7dc2 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternal.cpp
@@ -121,7 +121,7 @@
request.setSharingModeMatchRequired(isSharingModeMatchRequired());
request.setInService(isInService());
- request.getConfiguration().setDeviceId(getDeviceId());
+ request.getConfiguration().setDeviceIds(getDeviceIds());
request.getConfiguration().setSampleRate(getSampleRate());
request.getConfiguration().setDirection(getDirection());
request.getConfiguration().setSharingMode(getSharingMode());
@@ -180,7 +180,7 @@
setChannelMask(configurationOutput.getChannelMask());
}
- setDeviceId(configurationOutput.getDeviceId());
+ setDeviceIds(configurationOutput.getDeviceIds());
setSessionId(configurationOutput.getSessionId());
setSharingMode(configurationOutput.getSharingMode());
diff --git a/media/libaaudio/src/core/AAudioAudio.cpp b/media/libaaudio/src/core/AAudioAudio.cpp
index fb87dd9..64152f0 100644
--- a/media/libaaudio/src/core/AAudioAudio.cpp
+++ b/media/libaaudio/src/core/AAudioAudio.cpp
@@ -95,7 +95,11 @@
int32_t deviceId)
{
AudioStreamBuilder *streamBuilder = convertAAudioBuilderToStreamBuilder(builder);
- streamBuilder->setDeviceId(deviceId);
+ android::DeviceIdVector deviceIds;
+ if (deviceId != AAUDIO_UNSPECIFIED) {
+ deviceIds.push_back(deviceId);
+ }
+ streamBuilder->setDeviceIds(deviceIds);
}
AAUDIO_API void AAudioStreamBuilder_setPackageName(AAudioStreamBuilder* builder,
@@ -537,7 +541,33 @@
AAUDIO_API int32_t AAudioStream_getDeviceId(AAudioStream* stream)
{
AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
- return audioStream->getDeviceId();
+ auto deviceIds = audioStream->getDeviceIds();
+ if (deviceIds.empty()) {
+ return AAUDIO_UNSPECIFIED;
+ }
+ return deviceIds[0];
+}
+
+AAUDIO_API aaudio_result_t AAudioStream_getDeviceIds(AAudioStream* stream, int32_t* ids,
+ int32_t* numIds)
+{
+ if (numIds == nullptr) {
+ return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
+ }
+ AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
+ auto deviceIds = audioStream->getDeviceIds();
+ if (*numIds < deviceIds.size()) {
+ *numIds = deviceIds.size();
+ return AAUDIO_ERROR_OUT_OF_RANGE;
+ }
+ if (ids == nullptr) {
+ return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
+ }
+ for (int i = 0; i < deviceIds.size(); i++) {
+ ids[i] = deviceIds[i];
+ }
+ *numIds = deviceIds.size();
+ return AAUDIO_OK;
}
AAUDIO_API aaudio_sharing_mode_t AAudioStream_getSharingMode(AAudioStream* stream)
diff --git a/media/libaaudio/src/core/AAudioStreamParameters.cpp b/media/libaaudio/src/core/AAudioStreamParameters.cpp
index 056918a..f504fa9 100644
--- a/media/libaaudio/src/core/AAudioStreamParameters.cpp
+++ b/media/libaaudio/src/core/AAudioStreamParameters.cpp
@@ -27,7 +27,7 @@
void AAudioStreamParameters::copyFrom(const AAudioStreamParameters &other) {
mSamplesPerFrame = other.mSamplesPerFrame;
mSampleRate = other.mSampleRate;
- mDeviceId = other.mDeviceId;
+ mDeviceIds = other.mDeviceIds;
mSessionId = other.mSessionId;
mSharingMode = other.mSharingMode;
mAudioFormat = other.mAudioFormat;
@@ -74,9 +74,13 @@
return AAUDIO_ERROR_OUT_OF_RANGE;
}
- if (mDeviceId < 0) {
- ALOGD("deviceId out of range = %d", mDeviceId);
- return AAUDIO_ERROR_OUT_OF_RANGE;
+ // TODO(b/379139078): Query AudioSystem::listAudioPorts
+ for (auto deviceId : mDeviceIds) {
+ if (deviceId < 0) {
+ ALOGE("deviceId out of range = %d, deviceIds = %s", deviceId,
+ android::toString(mDeviceIds).c_str());
+ return AAUDIO_ERROR_OUT_OF_RANGE;
+ }
}
// All Session ID values are legal.
@@ -296,7 +300,7 @@
}
void AAudioStreamParameters::dump() const {
- ALOGD("mDeviceId = %6d", mDeviceId);
+ ALOGD("mDeviceIds = %s", android::toString(mDeviceIds).c_str());
ALOGD("mSessionId = %6d", mSessionId);
ALOGD("mSampleRate = %6d", mSampleRate);
ALOGD("mSamplesPerFrame = %6d", mSamplesPerFrame);
diff --git a/media/libaaudio/src/core/AAudioStreamParameters.h b/media/libaaudio/src/core/AAudioStreamParameters.h
index cad27a7..c4c0a4f 100644
--- a/media/libaaudio/src/core/AAudioStreamParameters.h
+++ b/media/libaaudio/src/core/AAudioStreamParameters.h
@@ -20,6 +20,7 @@
#include <stdint.h>
#include <aaudio/AAudio.h>
+#include <media/AudioContainers.h>
#include <utility/AAudioUtilities.h>
namespace aaudio {
@@ -29,12 +30,12 @@
AAudioStreamParameters() = default;
virtual ~AAudioStreamParameters() = default;
- int32_t getDeviceId() const {
- return mDeviceId;
+ android::DeviceIdVector getDeviceIds() const {
+ return mDeviceIds;
}
- void setDeviceId(int32_t deviceId) {
- mDeviceId = deviceId;
+ void setDeviceIds(const android::DeviceIdVector& deviceIds) {
+ mDeviceIds = deviceIds;
}
int32_t getSampleRate() const {
@@ -225,7 +226,7 @@
int32_t mSamplesPerFrame = AAUDIO_UNSPECIFIED;
int32_t mSampleRate = AAUDIO_UNSPECIFIED;
- int32_t mDeviceId = AAUDIO_UNSPECIFIED;
+ android::DeviceIdVector mDeviceIds;
aaudio_sharing_mode_t mSharingMode = AAUDIO_SHARING_MODE_SHARED;
audio_format_t mAudioFormat = AUDIO_FORMAT_DEFAULT;
aaudio_direction_t mDirection = AAUDIO_DIRECTION_OUTPUT;
diff --git a/media/libaaudio/src/core/AudioStream.cpp b/media/libaaudio/src/core/AudioStream.cpp
index a75a2a1..8e3bcf7 100644
--- a/media/libaaudio/src/core/AudioStream.cpp
+++ b/media/libaaudio/src/core/AudioStream.cpp
@@ -79,7 +79,7 @@
mSamplesPerFrame = builder.getSamplesPerFrame();
mChannelMask = builder.getChannelMask();
mSampleRate = builder.getSampleRate();
- mDeviceId = builder.getDeviceId();
+ mDeviceIds = builder.getDeviceIds();
mFormat = builder.getFormat();
mSharingMode = builder.getSharingMode();
mSharingModeMatchRequired = builder.isSharingModeMatchRequired();
@@ -204,7 +204,7 @@
aaudio_result_t result = requestStart_l();
if (result == AAUDIO_OK) {
// We only call this for logging in "dumpsys audio". So ignore return code.
- (void) mPlayerBase->startWithStatus(getDeviceId());
+ (void) mPlayerBase->startWithStatus(getDeviceIds());
}
return result;
}
diff --git a/media/libaaudio/src/core/AudioStream.h b/media/libaaudio/src/core/AudioStream.h
index 3271882..3354adf 100644
--- a/media/libaaudio/src/core/AudioStream.h
+++ b/media/libaaudio/src/core/AudioStream.h
@@ -27,6 +27,7 @@
#include <utils/StrongPointer.h>
#include <aaudio/AAudio.h>
+#include <media/AudioContainers.h>
#include <media/AudioSystem.h>
#include <media/PlayerBase.h>
#include <media/VolumeShaper.h>
@@ -268,8 +269,8 @@
mPerformanceMode = performanceMode;
}
- int32_t getDeviceId() const {
- return mDeviceId;
+ android::DeviceIdVector getDeviceIds() const {
+ return mDeviceIds;
}
aaudio_sharing_mode_t getSharingMode() const {
@@ -411,7 +412,7 @@
// Implement AudioDeviceCallback
void onAudioDeviceUpdate(audio_io_handle_t audioIo,
- audio_port_handle_t deviceId) override {};
+ const android::DeviceIdVector& deviceIds) override {};
// ============== I/O ===========================
// A Stream will only implement read() or write() depending on its direction.
@@ -632,8 +633,8 @@
}
void setDisconnected();
- void setDeviceId(int32_t deviceId) {
- mDeviceId = deviceId;
+ void setDeviceIds(const android::DeviceIdVector& deviceIds) {
+ mDeviceIds = deviceIds;
}
// This should not be called after the open() call.
@@ -774,7 +775,7 @@
int32_t mSampleRate = AAUDIO_UNSPECIFIED;
int32_t mDeviceSampleRate = AAUDIO_UNSPECIFIED;
int32_t mHardwareSampleRate = AAUDIO_UNSPECIFIED;
- int32_t mDeviceId = AAUDIO_UNSPECIFIED;
+ android::DeviceIdVector mDeviceIds;
aaudio_sharing_mode_t mSharingMode = AAUDIO_SHARING_MODE_SHARED;
bool mSharingModeMatchRequired = false; // must match sharing mode requested
audio_format_t mFormat = AUDIO_FORMAT_DEFAULT;
diff --git a/media/libaaudio/src/core/AudioStreamBuilder.cpp b/media/libaaudio/src/core/AudioStreamBuilder.cpp
index b0dc669..73bd69f 100644
--- a/media/libaaudio/src/core/AudioStreamBuilder.cpp
+++ b/media/libaaudio/src/core/AudioStreamBuilder.cpp
@@ -307,8 +307,8 @@
getSampleRate(), getSamplesPerFrame(), getChannelMask(), getFormat(),
AAudio_convertSharingModeToShortText(getSharingMode()),
AAudio_convertDirectionToText(getDirection()));
- ALOGI("device = %6d, sessionId = %d, perfMode = %d, callback: %s with frames = %d",
- getDeviceId(),
+ ALOGI("devices = %s, sessionId = %d, perfMode = %d, callback: %s with frames = %d",
+ android::toString(getDeviceIds()).c_str(),
getSessionId(),
getPerformanceMode(),
((getDataCallbackProc() != nullptr) ? "ON" : "OFF"),
diff --git a/media/libaaudio/src/legacy/AudioStreamLegacy.cpp b/media/libaaudio/src/legacy/AudioStreamLegacy.cpp
index 255bd0f..dfb9a01 100644
--- a/media/libaaudio/src/legacy/AudioStreamLegacy.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamLegacy.cpp
@@ -260,36 +260,41 @@
}
void AudioStreamLegacy::onAudioDeviceUpdate(audio_io_handle_t /* audioIo */,
- audio_port_handle_t deviceId) {
- // Check for an invalid deviceId. Why change to UNSPECIFIED?
- if (deviceId == AAUDIO_UNSPECIFIED) {
- ALOGE("%s(, deviceId = AAUDIO_UNSPECIFIED)! Why?", __func__);
+ const android::DeviceIdVector& deviceIds) {
+ // Check for empty deviceIds. Callbacks for duplicating threads returns empty devices.
+ if (deviceIds.empty()) {
+ ALOGW("%s(empty deviceIds", __func__);
return;
}
+ android::DeviceIdVector oldDeviceIds = getDeviceIds();
// Device routing is a common source of errors and DISCONNECTS.
// Please leave this log in place. If there is a bug then this might
// get called after the stream has been deleted so log before we
// touch the stream object.
- ALOGD("%s(deviceId = %d)", __func__, (int)deviceId);
- if (getDeviceId() != AAUDIO_UNSPECIFIED
- && getDeviceId() != deviceId
+ ALOGD("%s() devices %s => %s",
+ __func__, android::toString(oldDeviceIds).c_str(),
+ android::toString(deviceIds).c_str());
+ if (!oldDeviceIds.empty()
+ && !android::areDeviceIdsEqual(oldDeviceIds, deviceIds)
&& !isDisconnected()
) {
// Note that isDataCallbackActive() is affected by state so call it before DISCONNECTING.
// If we have a data callback and the stream is active, then ask the data callback
// to DISCONNECT and call the error callback.
if (isDataCallbackActive()) {
- ALOGD("%s() request DISCONNECT in data callback, device %d => %d",
- __func__, (int) getDeviceId(), (int) deviceId);
+ ALOGD("%s() request DISCONNECT in data callback, devices %s => %s",
+ __func__, android::toString(oldDeviceIds).c_str(),
+ android::toString(deviceIds).c_str());
// If the stream is stopped before the data callback has a chance to handle the
// request then the requestStop_l() and requestPause() methods will handle it after
// the callback has stopped.
mRequestDisconnect.request();
} else {
- ALOGD("%s() DISCONNECT the stream now, device %d => %d",
- __func__, (int) getDeviceId(), (int) deviceId);
+ ALOGD("%s() DISCONNECT the stream now, devices %s => %s",
+ __func__, android::toString(oldDeviceIds).c_str(),
+ android::toString(deviceIds).c_str());
forceDisconnect();
}
}
- setDeviceId(deviceId);
+ setDeviceIds(deviceIds);
}
diff --git a/media/libaaudio/src/legacy/AudioStreamLegacy.h b/media/libaaudio/src/legacy/AudioStreamLegacy.h
index 53f6e06..a729161 100644
--- a/media/libaaudio/src/legacy/AudioStreamLegacy.h
+++ b/media/libaaudio/src/legacy/AudioStreamLegacy.h
@@ -95,7 +95,7 @@
android::ExtendedTimestamp *extendedTimestamp);
void onAudioDeviceUpdate(audio_io_handle_t audioIo,
- audio_port_handle_t deviceId) override;
+ const android::DeviceIdVector& deviceIds) override;
/*
* Check to see whether a callback thread has requested a disconnected.
diff --git a/media/libaaudio/src/legacy/AudioStreamRecord.cpp b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
index fe4bf2c..1591f7d 100644
--- a/media/libaaudio/src/legacy/AudioStreamRecord.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
@@ -112,9 +112,7 @@
mCallbackBufferSize = builder.getFramesPerDataCallback();
// Don't call mAudioRecord->setInputDevice() because it will be overwritten by set()!
- audio_port_handle_t selectedDeviceId = (getDeviceId() == AAUDIO_UNSPECIFIED)
- ? AUDIO_PORT_HANDLE_NONE
- : getDeviceId();
+ audio_port_handle_t selectedDeviceId = getFirstDeviceId(getDeviceIds());
const audio_content_type_t contentType =
AAudioConvert_contentTypeToInternal(builder.getContentType());
@@ -198,7 +196,8 @@
AudioGlobal_convertPerformanceModeToText(builder.getPerformanceMode()))
.set(AMEDIAMETRICS_PROP_SHARINGMODE,
AudioGlobal_convertSharingModeToText(builder.getSharingMode()))
- .set(AMEDIAMETRICS_PROP_ENCODINGCLIENT, toString(requestedFormat).c_str()).record();
+ .set(AMEDIAMETRICS_PROP_ENCODINGCLIENT,
+ android::toString(requestedFormat).c_str()).record();
// Get the actual values from the AudioRecord.
setChannelMask(AAudioConvert_androidToAAudioChannelMask(
@@ -275,7 +274,7 @@
perfMode, actualPerformanceMode);
setState(AAUDIO_STREAM_STATE_OPEN);
- setDeviceId(mAudioRecord->getRoutedDeviceId());
+ setDeviceIds(mAudioRecord->getRoutedDeviceIds());
aaudio_session_id_t actualSessionId =
(requestedSessionId == AAUDIO_SESSION_ID_NONE)
diff --git a/media/libaaudio/src/legacy/AudioStreamTrack.cpp b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
index 16c0bcd..2e57f0d 100644
--- a/media/libaaudio/src/legacy/AudioStreamTrack.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
@@ -132,9 +132,7 @@
notificationFrames, (uint)frameCount);
// Don't call mAudioTrack->setDeviceId() because it will be overwritten by set()!
- audio_port_handle_t selectedDeviceId = (getDeviceId() == AAUDIO_UNSPECIFIED)
- ? AUDIO_PORT_HANDLE_NONE
- : getDeviceId();
+ audio_port_handle_t selectedDeviceId = getFirstDeviceId(getDeviceIds());
const audio_content_type_t contentType =
AAudioConvert_contentTypeToInternal(builder.getContentType());
@@ -197,7 +195,8 @@
AudioGlobal_convertPerformanceModeToText(builder.getPerformanceMode()))
.set(AMEDIAMETRICS_PROP_SHARINGMODE,
AudioGlobal_convertSharingModeToText(builder.getSharingMode()))
- .set(AMEDIAMETRICS_PROP_ENCODINGCLIENT, toString(getFormat()).c_str()).record();
+ .set(AMEDIAMETRICS_PROP_ENCODINGCLIENT,
+ android::toString(getFormat()).c_str()).record();
doSetVolume();
@@ -233,7 +232,7 @@
mBlockAdapter = nullptr;
}
- setDeviceId(mAudioTrack->getRoutedDeviceId());
+ setDeviceIds(mAudioTrack->getRoutedDeviceIds());
aaudio_session_id_t actualSessionId =
(requestedSessionId == AAUDIO_SESSION_ID_NONE)
@@ -317,7 +316,7 @@
if (mAudioTrack->channelCount() != getSamplesPerFrame()
|| mAudioTrack->format() != getFormat()
|| mAudioTrack->getSampleRate() != getSampleRate()
- || mAudioTrack->getRoutedDeviceId() != getDeviceId()
+ || !areDeviceIdsEqual(mAudioTrack->getRoutedDeviceIds(), getDeviceIds())
|| getBufferCapacityFromDevice() != getBufferCapacity()
|| getFramesPerBurstFromDevice() != getFramesPerBurst()) {
AudioStreamLegacy::onNewIAudioTrack();
diff --git a/media/libaaudio/src/libaaudio.map.txt b/media/libaaudio/src/libaaudio.map.txt
index 13c19a1..36d76aa 100644
--- a/media/libaaudio/src/libaaudio.map.txt
+++ b/media/libaaudio/src/libaaudio.map.txt
@@ -72,6 +72,7 @@
AAudioStream_getHardwareSampleRate; # introduced=UpsideDownCake
AAudio_getPlatformMMapPolicy; # introduced=36
AAudio_getPlatformMMapExclusivePolicy; #introduced=36
+ AAudioStream_getDeviceIds; # introduced=36
AAudioStreamBuilder_setTags; # systemapi
AAudioStream_getTags; # systemapi