Merge "Update the TimeoutAuthenticationMultiSid test" into main
diff --git a/audio/aidl/common/StreamWorker.cpp b/audio/aidl/common/StreamWorker.cpp
index 0d2121c..8107655 100644
--- a/audio/aidl/common/StreamWorker.cpp
+++ b/audio/aidl/common/StreamWorker.cpp
@@ -106,6 +106,9 @@
std::lock_guard<std::mutex> lock(mWorkerLock);
mWorkerState = error.empty() ? WorkerState::RUNNING : WorkerState::STOPPED;
mError = error;
+#if defined(__ANDROID__)
+ mTid = pthread_gettid_np(pthread_self());
+#endif
}
mWorkerCv.notify_one();
if (!error.empty()) return;
diff --git a/audio/aidl/common/include/StreamWorker.h b/audio/aidl/common/include/StreamWorker.h
index e9c1070..efdcc81 100644
--- a/audio/aidl/common/include/StreamWorker.h
+++ b/audio/aidl/common/include/StreamWorker.h
@@ -16,6 +16,8 @@
#pragma once
+#include <sys/types.h>
+
#include <atomic>
#include <condition_variable>
#include <mutex>
@@ -52,6 +54,10 @@
std::lock_guard<std::mutex> lock(mWorkerLock);
return mError;
}
+ pid_t getTid() {
+ std::lock_guard<std::mutex> lock(mWorkerLock);
+ return mTid;
+ }
void stop();
// Direct use of 'join' assumes that the StreamLogic is not intended
// to run forever, and is guaranteed to exit by itself. This normally
@@ -78,6 +84,7 @@
std::condition_variable mWorkerCv;
WorkerState mWorkerState GUARDED_BY(mWorkerLock) = WorkerState::INITIAL;
std::string mError GUARDED_BY(mWorkerLock);
+ pid_t mTid GUARDED_BY(mWorkerLock) = -1;
// The atomic lock-free variable is used to prevent priority inversions
// that can occur when a high priority worker tries to acquire the lock
// which has been taken by a lower priority control thread which in its turn
@@ -143,6 +150,7 @@
void resume() { mThread.resume(); }
bool hasError() { return mThread.hasError(); }
std::string getError() { return mThread.getError(); }
+ pid_t getTid() { return mThread.getTid(); }
void stop() { mThread.stop(); }
void join() { mThread.join(); }
bool waitForAtLeastOneCycle() { return mThread.waitForAtLeastOneCycle(); }
diff --git a/audio/aidl/common/tests/streamworker_tests.cpp b/audio/aidl/common/tests/streamworker_tests.cpp
index f7a30b9..2b65740 100644
--- a/audio/aidl/common/tests/streamworker_tests.cpp
+++ b/audio/aidl/common/tests/streamworker_tests.cpp
@@ -87,6 +87,7 @@
TEST_P(StreamWorkerInvalidTest, Uninitialized) {
EXPECT_FALSE(worker.hasWorkerCycleCalled());
EXPECT_FALSE(worker.hasError());
+ EXPECT_LE(worker.getTid(), 0);
}
TEST_P(StreamWorkerInvalidTest, UninitializedPauseIgnored) {
@@ -105,6 +106,9 @@
EXPECT_FALSE(worker.start());
EXPECT_FALSE(worker.hasWorkerCycleCalled());
EXPECT_TRUE(worker.hasError());
+#if defined(__ANDROID__)
+ EXPECT_GT(worker.getTid(), 0);
+#endif
}
TEST_P(StreamWorkerInvalidTest, PauseIgnored) {
@@ -136,12 +140,16 @@
TEST_P(StreamWorkerTest, Uninitialized) {
EXPECT_FALSE(worker.hasWorkerCycleCalled());
EXPECT_FALSE(worker.hasError());
+ EXPECT_LE(worker.getTid(), 0);
}
TEST_P(StreamWorkerTest, Start) {
ASSERT_TRUE(worker.start());
EXPECT_TRUE(worker.waitForAtLeastOneCycle());
EXPECT_FALSE(worker.hasError());
+#if defined(__ANDROID__)
+ EXPECT_GT(worker.getTid(), 0);
+#endif
}
TEST_P(StreamWorkerTest, StartStop) {
diff --git a/audio/aidl/default/Android.bp b/audio/aidl/default/Android.bp
index 4e583a4..8596466 100644
--- a/audio/aidl/default/Android.bp
+++ b/audio/aidl/default/Android.bp
@@ -82,6 +82,11 @@
"alsa/ModuleAlsa.cpp",
"alsa/StreamAlsa.cpp",
"alsa/Utils.cpp",
+ "bluetooth/DevicePortProxy.cpp",
+ "bluetooth/ModuleBluetooth.cpp",
+ "bluetooth/StreamBluetooth.cpp",
+ "primary/PrimaryMixer.cpp",
+ "primary/StreamPrimary.cpp",
"r_submix/ModuleRemoteSubmix.cpp",
"r_submix/RemoteSubmixUtils.cpp",
"r_submix/SubmixRoute.cpp",
@@ -105,7 +110,9 @@
"audio_policy_engine_configuration_aidl_default",
],
shared_libs: [
+ "android.hardware.bluetooth.audio-V3-ndk",
"libaudio_aidl_conversion_common_ndk",
+ "libbluetooth_audio_session_aidl",
"libmedia_helper",
"libstagefright_foundation",
],
@@ -136,7 +143,9 @@
"libaudioserviceexampleimpl",
],
shared_libs: [
+ "android.hardware.bluetooth.audio-V3-ndk",
"libaudio_aidl_conversion_common_ndk",
+ "libbluetooth_audio_session_aidl",
"libmedia_helper",
"libstagefright_foundation",
],
diff --git a/audio/aidl/default/Bluetooth.cpp b/audio/aidl/default/Bluetooth.cpp
index c32b538..072b89f 100644
--- a/audio/aidl/default/Bluetooth.cpp
+++ b/audio/aidl/default/Bluetooth.cpp
@@ -82,19 +82,18 @@
ndk::ScopedAStatus BluetoothA2dp::isEnabled(bool* _aidl_return) {
*_aidl_return = mEnabled;
- LOG(DEBUG) << __func__ << ": returning " << *_aidl_return;
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus BluetoothA2dp::setEnabled(bool in_enabled) {
mEnabled = in_enabled;
LOG(DEBUG) << __func__ << ": " << mEnabled;
+ if (mHandler) return mHandler();
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus BluetoothA2dp::supportsOffloadReconfiguration(bool* _aidl_return) {
- *_aidl_return = true;
- LOG(DEBUG) << __func__ << ": returning " << *_aidl_return;
+ *_aidl_return = false;
return ndk::ScopedAStatus::ok();
}
@@ -102,24 +101,22 @@
const std::vector<::aidl::android::hardware::audio::core::VendorParameter>& in_parameters
__unused) {
LOG(DEBUG) << __func__ << ": " << ::android::internal::ToString(in_parameters);
- return ndk::ScopedAStatus::ok();
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
ndk::ScopedAStatus BluetoothLe::isEnabled(bool* _aidl_return) {
*_aidl_return = mEnabled;
- LOG(DEBUG) << __func__ << ": returning " << *_aidl_return;
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus BluetoothLe::setEnabled(bool in_enabled) {
mEnabled = in_enabled;
- LOG(DEBUG) << __func__ << ": " << mEnabled;
+ if (mHandler) return mHandler();
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus BluetoothLe::supportsOffloadReconfiguration(bool* _aidl_return) {
- *_aidl_return = true;
- LOG(DEBUG) << __func__ << ": returning " << *_aidl_return;
+ *_aidl_return = false;
return ndk::ScopedAStatus::ok();
}
@@ -127,7 +124,7 @@
const std::vector<::aidl::android::hardware::audio::core::VendorParameter>& in_parameters
__unused) {
LOG(DEBUG) << __func__ << ": " << ::android::internal::ToString(in_parameters);
- return ndk::ScopedAStatus::ok();
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
} // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/Configuration.cpp b/audio/aidl/default/Configuration.cpp
index a71c6ea..0fbf55b 100644
--- a/audio/aidl/default/Configuration.cpp
+++ b/audio/aidl/default/Configuration.cpp
@@ -136,7 +136,7 @@
// Device ports:
// * "Speaker", OUT_SPEAKER, default
// - no profiles specified
-// * "Built-in Mic", IN_MICROPHONE, default
+// * "Built-In Mic", IN_MICROPHONE, default
// - no profiles specified
// * "Telephony Tx", OUT_TELEPHONY_TX
// - no profiles specified
@@ -148,46 +148,35 @@
// Mix ports:
// * "primary output", PRIMARY, 1 max open, 1 max active stream
// - profile PCM 16-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
-// - profile PCM 24-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
-// * "compressed offload", DIRECT|COMPRESS_OFFLOAD|NON_BLOCKING, 1 max open, 1 max active stream
-// - profile MP3; MONO, STEREO; 44100, 48000
-// * "primary input", 2 max open, 2 max active streams
-// - profile PCM 16-bit; MONO, STEREO, FRONT_BACK;
-// 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
-// - profile PCM 24-bit; MONO, STEREO, FRONT_BACK;
-// 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
+// * "primary input", 1 max open, 1 max active stream
+// - profile PCM 16-bit; MONO, STEREO;
+// 8000, 11025, 16000, 32000, 44100, 48000
// * "telephony_tx", 1 max open, 1 max active stream
// - profile PCM 16-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
-// - profile PCM 24-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
// * "telephony_rx", 1 max open, 1 max active stream
// - profile PCM 16-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
-// - profile PCM 24-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
// * "fm_tuner", 1 max open, 1 max active stream
// - profile PCM 16-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
-// - profile PCM 24-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
//
// Routes:
-// "primary out", "compressed offload" -> "Speaker"
-// "Built-in Mic" -> "primary input"
-// "telephony_tx" -> "Telephony Tx"
+// "primary out" -> "Speaker"
+// "Built-In Mic" -> "primary input"
// "Telephony Rx" -> "telephony_rx"
+// "telephony_tx" -> "Telephony Tx"
// "FM Tuner" -> "fm_tuner"
//
// Initial port configs:
-// * "Speaker" device port: PCM 24-bit; STEREO; 48000
-// * "Built-in Mic" device port: PCM 24-bit; MONO; 48000
-// * "Telephony Tx" device port: PCM 24-bit; MONO; 48000
-// * "Telephony Rx" device port: PCM 24-bit; MONO; 48000
-// * "FM Tuner" device port: PCM 24-bit; STEREO; 48000
+// * "Speaker" device port: PCM 16-bit; STEREO; 48000
+// * "Built-In Mic" device port: PCM 16-bit; MONO; 48000
+// * "Telephony Tx" device port: PCM 16-bit; MONO; 48000
+// * "Telephony Rx" device port: PCM 16-bit; MONO; 48000
+// * "FM Tuner" device port: PCM 16-bit; STEREO; 48000
//
std::unique_ptr<Configuration> getPrimaryConfiguration() {
static const Configuration configuration = []() {
const std::vector<AudioProfile> standardPcmAudioProfiles = {
createProfile(PcmType::INT_16_BIT,
{AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO},
- {8000, 11025, 16000, 32000, 44100, 48000}),
- createProfile(PcmType::INT_24_BIT,
- {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO},
{8000, 11025, 16000, 32000, 44100, 48000})};
Configuration c;
@@ -199,17 +188,17 @@
1 << AudioPortDeviceExt::FLAG_INDEX_DEFAULT_DEVICE));
c.ports.push_back(speakerOutDevice);
c.initialConfigs.push_back(
- createPortConfig(speakerOutDevice.id, speakerOutDevice.id, PcmType::INT_24_BIT,
+ createPortConfig(speakerOutDevice.id, speakerOutDevice.id, PcmType::INT_16_BIT,
AudioChannelLayout::LAYOUT_STEREO, 48000, 0, false,
createDeviceExt(AudioDeviceType::OUT_SPEAKER, 0)));
AudioPort micInDevice =
- createPort(c.nextPortId++, "Built-in Mic", 0, true,
+ createPort(c.nextPortId++, "Built-In Mic", 0, true,
createDeviceExt(AudioDeviceType::IN_MICROPHONE,
1 << AudioPortDeviceExt::FLAG_INDEX_DEFAULT_DEVICE));
c.ports.push_back(micInDevice);
c.initialConfigs.push_back(
- createPortConfig(micInDevice.id, micInDevice.id, PcmType::INT_24_BIT,
+ createPortConfig(micInDevice.id, micInDevice.id, PcmType::INT_16_BIT,
AudioChannelLayout::LAYOUT_MONO, 48000, 0, true,
createDeviceExt(AudioDeviceType::IN_MICROPHONE, 0)));
@@ -219,7 +208,7 @@
c.ports.push_back(telephonyTxOutDevice);
c.initialConfigs.push_back(
createPortConfig(telephonyTxOutDevice.id, telephonyTxOutDevice.id,
- PcmType::INT_24_BIT, AudioChannelLayout::LAYOUT_MONO, 48000, 0,
+ PcmType::INT_16_BIT, AudioChannelLayout::LAYOUT_MONO, 48000, 0,
false, createDeviceExt(AudioDeviceType::OUT_TELEPHONY_TX, 0)));
AudioPort telephonyRxInDevice =
@@ -228,14 +217,14 @@
c.ports.push_back(telephonyRxInDevice);
c.initialConfigs.push_back(
createPortConfig(telephonyRxInDevice.id, telephonyRxInDevice.id,
- PcmType::INT_24_BIT, AudioChannelLayout::LAYOUT_MONO, 48000, 0,
+ PcmType::INT_16_BIT, AudioChannelLayout::LAYOUT_MONO, 48000, 0,
true, createDeviceExt(AudioDeviceType::IN_TELEPHONY_RX, 0)));
AudioPort fmTunerInDevice = createPort(c.nextPortId++, "FM Tuner", 0, true,
createDeviceExt(AudioDeviceType::IN_FM_TUNER, 0));
c.ports.push_back(fmTunerInDevice);
c.initialConfigs.push_back(
- createPortConfig(fmTunerInDevice.id, fmTunerInDevice.id, PcmType::INT_24_BIT,
+ createPortConfig(fmTunerInDevice.id, fmTunerInDevice.id, PcmType::INT_16_BIT,
AudioChannelLayout::LAYOUT_STEREO, 48000, 0, true,
createDeviceExt(AudioDeviceType::IN_FM_TUNER, 0)));
@@ -249,30 +238,12 @@
standardPcmAudioProfiles.end());
c.ports.push_back(primaryOutMix);
- AudioPort compressedOffloadOutMix =
- createPort(c.nextPortId++, "compressed offload",
- makeBitPositionFlagMask({AudioOutputFlags::DIRECT,
- AudioOutputFlags::COMPRESS_OFFLOAD,
- AudioOutputFlags::NON_BLOCKING}),
- false, createPortMixExt(1, 1));
- compressedOffloadOutMix.profiles.push_back(
- createProfile(::android::MEDIA_MIMETYPE_AUDIO_MPEG,
- {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO},
- {44100, 48000}));
- c.ports.push_back(compressedOffloadOutMix);
-
AudioPort primaryInMix =
- createPort(c.nextPortId++, "primary input", 0, true, createPortMixExt(2, 2));
+ createPort(c.nextPortId++, "primary input", 0, true, createPortMixExt(1, 1));
primaryInMix.profiles.push_back(
createProfile(PcmType::INT_16_BIT,
- {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO,
- AudioChannelLayout::LAYOUT_FRONT_BACK},
- {8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000}));
- primaryInMix.profiles.push_back(
- createProfile(PcmType::INT_24_BIT,
- {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO,
- AudioChannelLayout::LAYOUT_FRONT_BACK},
- {8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000}));
+ {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO},
+ {8000, 11025, 16000, 32000, 44100, 48000}));
c.ports.push_back(primaryInMix);
AudioPort telephonyTxOutMix =
@@ -296,10 +267,10 @@
standardPcmAudioProfiles.end());
c.ports.push_back(fmTunerInMix);
- c.routes.push_back(createRoute({primaryOutMix, compressedOffloadOutMix}, speakerOutDevice));
+ c.routes.push_back(createRoute({primaryOutMix}, speakerOutDevice));
c.routes.push_back(createRoute({micInDevice}, primaryInMix));
- c.routes.push_back(createRoute({telephonyTxOutMix}, telephonyTxOutDevice));
c.routes.push_back(createRoute({telephonyRxInDevice}, telephonyRxInMix));
+ c.routes.push_back(createRoute({telephonyTxOutMix}, telephonyTxOutDevice));
c.routes.push_back(createRoute({fmTunerInDevice}, fmTunerInMix));
c.portConfigs.insert(c.portConfigs.end(), c.initialConfigs.begin(), c.initialConfigs.end());
@@ -320,15 +291,15 @@
//
// Device ports:
// * "Remote Submix Out", OUT_SUBMIX
-// - profile PCM 24-bit; STEREO; 48000
+// - profile PCM 16-bit; STEREO; 48000
// * "Remote Submix In", IN_SUBMIX
-// - profile PCM 24-bit; STEREO; 48000
+// - profile PCM 16-bit; STEREO; 48000
//
// Mix ports:
-// * "r_submix output", stream count unlimited
-// - profile PCM 24-bit; STEREO; 48000
-// * "r_submix input", stream count unlimited
-// - profile PCM 24-bit; STEREO; 48000
+// * "r_submix output", 1 max open, 1 max active stream
+// - profile PCM 16-bit; STEREO; 48000
+// * "r_submix input", 1 max open, 1 max active stream
+// - profile PCM 16-bit; STEREO; 48000
//
// Routes:
// "r_submix output" -> "Remote Submix Out"
@@ -345,27 +316,27 @@
createDeviceExt(AudioDeviceType::OUT_SUBMIX, 0,
AudioDeviceDescription::CONNECTION_VIRTUAL));
rsubmixOutDevice.profiles.push_back(
- createProfile(PcmType::INT_24_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {48000}));
+ createProfile(PcmType::INT_16_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {48000}));
c.ports.push_back(rsubmixOutDevice);
AudioPort rsubmixInDevice = createPort(c.nextPortId++, "Remote Submix In", 0, true,
createDeviceExt(AudioDeviceType::IN_SUBMIX, 0));
rsubmixInDevice.profiles.push_back(
- createProfile(PcmType::INT_24_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {48000}));
+ createProfile(PcmType::INT_16_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {48000}));
c.ports.push_back(rsubmixInDevice);
// Mix ports
AudioPort rsubmixOutMix =
- createPort(c.nextPortId++, "r_submix output", 0, false, createPortMixExt(0, 0));
+ createPort(c.nextPortId++, "r_submix output", 0, false, createPortMixExt(1, 1));
rsubmixOutMix.profiles.push_back(
- createProfile(PcmType::INT_24_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {48000}));
+ createProfile(PcmType::INT_16_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {48000}));
c.ports.push_back(rsubmixOutMix);
AudioPort rsubmixInMix =
- createPort(c.nextPortId++, "r_submix input", 0, true, createPortMixExt(0, 0));
+ createPort(c.nextPortId++, "r_submix input", 0, true, createPortMixExt(1, 1));
rsubmixInMix.profiles.push_back(
- createProfile(PcmType::INT_24_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {48000}));
+ createProfile(PcmType::INT_16_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {48000}));
c.ports.push_back(rsubmixInMix);
c.routes.push_back(createRoute({rsubmixOutMix}, rsubmixOutDevice));
@@ -479,14 +450,17 @@
// Mix ports:
// * "test output", 1 max open, 1 max active stream
// - profile PCM 24-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
-// * "compressed offload", DIRECT|COMPRESS_OFFLOAD|NON_BLOCKING, 1 max open, 1 max active stream
+// * "test fast output", 1 max open, 1 max active stream
+// - profile PCM 24-bit; STEREO; 44100, 48000
+// * "test compressed offload", DIRECT|COMPRESS_OFFLOAD|NON_BLOCKING, 1 max open, 1 max active
+// stream
// - profile MP3; MONO, STEREO; 44100, 48000
// * "test input", 2 max open, 2 max active streams
// - profile PCM 24-bit; MONO, STEREO, FRONT_BACK;
-// 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
+// 8000, 11025, 16000, 22050, 32000, 44100, 48000
//
// Routes:
-// "test output", "compressed offload" -> "Test Out"
+// "test output", "test fast output", "test compressed offload" -> "Test Out"
// "Test In" -> "test input"
//
// Initial port configs:
@@ -525,8 +499,15 @@
{8000, 11025, 16000, 32000, 44100, 48000}));
c.ports.push_back(testOutMix);
+ AudioPort testFastOutMix = createPort(c.nextPortId++, "test fast output",
+ makeBitPositionFlagMask({AudioOutputFlags::FAST}),
+ false, createPortMixExt(1, 1));
+ testFastOutMix.profiles.push_back(createProfile(
+ PcmType::INT_24_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {44100, 48000}));
+ c.ports.push_back(testFastOutMix);
+
AudioPort compressedOffloadOutMix =
- createPort(c.nextPortId++, "compressed offload",
+ createPort(c.nextPortId++, "test compressed offload",
makeBitPositionFlagMask({AudioOutputFlags::DIRECT,
AudioOutputFlags::COMPRESS_OFFLOAD,
AudioOutputFlags::NON_BLOCKING}),
@@ -543,15 +524,16 @@
createProfile(PcmType::INT_16_BIT,
{AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO,
AudioChannelLayout::LAYOUT_FRONT_BACK},
- {8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000}));
+ {8000, 11025, 16000, 22050, 32000, 44100, 48000}));
testInMIx.profiles.push_back(
createProfile(PcmType::INT_24_BIT,
{AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO,
AudioChannelLayout::LAYOUT_FRONT_BACK},
- {8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000}));
+ {8000, 11025, 16000, 22050, 32000, 44100, 48000}));
c.ports.push_back(testInMIx);
- c.routes.push_back(createRoute({testOutMix, compressedOffloadOutMix}, testOutDevice));
+ c.routes.push_back(
+ createRoute({testOutMix, testFastOutMix, compressedOffloadOutMix}, testOutDevice));
c.routes.push_back(createRoute({testInDevice}, testInMIx));
c.portConfigs.insert(c.portConfigs.end(), c.initialConfigs.begin(), c.initialConfigs.end());
@@ -561,4 +543,94 @@
return std::make_unique<Configuration>(configuration);
}
+// Bluetooth configuration:
+//
+// Device ports:
+// * "BT A2DP Out", OUT_DEVICE, CONNECTION_BT_A2DP
+// - profile PCM 16-bit; STEREO; 44100, 48000, 88200, 96000
+// * "BT A2DP Headphones", OUT_HEADPHONE, CONNECTION_BT_A2DP
+// - profile PCM 16-bit; STEREO; 44100, 48000, 88200, 96000
+// * "BT A2DP Speaker", OUT_SPEAKER, CONNECTION_BT_A2DP
+// - profile PCM 16-bit; STEREO; 44100, 48000, 88200, 96000
+// * "BT Hearing Aid Out", OUT_HEARING_AID, CONNECTION_WIRELESS
+// - no profiles specified
+//
+// Mix ports:
+// * "a2dp output", 1 max open, 1 max active stream
+// - no profiles specified
+// * "hearing aid output", 1 max open, 1 max active stream
+// - profile PCM 16-bit; STEREO; 16000, 24000
+//
+// Routes:
+// "a2dp output" -> "BT A2DP Out"
+// "a2dp output" -> "BT A2DP Headphones"
+// "a2dp output" -> "BT A2DP Speaker"
+// "hearing aid output" -> "BT Hearing Aid Out"
+//
+std::unique_ptr<Configuration> getBluetoothConfiguration() {
+ static const Configuration configuration = []() {
+ const std::vector<AudioProfile> standardPcmAudioProfiles = {
+ createProfile(PcmType::INT_16_BIT, {AudioChannelLayout::LAYOUT_STEREO},
+ {44100, 48000, 88200, 96000})};
+ Configuration c;
+
+ // Device ports
+ AudioPort btOutDevice =
+ createPort(c.nextPortId++, "BT A2DP Out", 0, false,
+ createDeviceExt(AudioDeviceType::OUT_DEVICE, 0,
+ AudioDeviceDescription::CONNECTION_BT_A2DP));
+ btOutDevice.profiles.insert(btOutDevice.profiles.begin(), standardPcmAudioProfiles.begin(),
+ standardPcmAudioProfiles.end());
+ c.ports.push_back(btOutDevice);
+ c.connectedProfiles[btOutDevice.id] = standardPcmAudioProfiles;
+
+ AudioPort btOutHeadphone =
+ createPort(c.nextPortId++, "BT A2DP Headphones", 0, false,
+ createDeviceExt(AudioDeviceType::OUT_HEADPHONE, 0,
+ AudioDeviceDescription::CONNECTION_BT_A2DP));
+ btOutHeadphone.profiles.insert(btOutHeadphone.profiles.begin(),
+ standardPcmAudioProfiles.begin(),
+ standardPcmAudioProfiles.end());
+ c.ports.push_back(btOutHeadphone);
+ c.connectedProfiles[btOutHeadphone.id] = standardPcmAudioProfiles;
+
+ AudioPort btOutSpeaker =
+ createPort(c.nextPortId++, "BT A2DP Speaker", 0, false,
+ createDeviceExt(AudioDeviceType::OUT_SPEAKER, 0,
+ AudioDeviceDescription::CONNECTION_BT_A2DP));
+ btOutSpeaker.profiles.insert(btOutSpeaker.profiles.begin(),
+ standardPcmAudioProfiles.begin(),
+ standardPcmAudioProfiles.end());
+ c.ports.push_back(btOutSpeaker);
+ c.connectedProfiles[btOutSpeaker.id] = standardPcmAudioProfiles;
+
+ AudioPort btOutHearingAid =
+ createPort(c.nextPortId++, "BT Hearing Aid Out", 0, false,
+ createDeviceExt(AudioDeviceType::OUT_HEARING_AID, 0,
+ AudioDeviceDescription::CONNECTION_WIRELESS));
+ c.ports.push_back(btOutHearingAid);
+ c.connectedProfiles[btOutHearingAid.id] = std::vector<AudioProfile>(
+ {createProfile(PcmType::INT_16_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {16000})});
+
+ // Mix ports
+ AudioPort btOutMix =
+ createPort(c.nextPortId++, "a2dp output", 0, false, createPortMixExt(1, 1));
+ c.ports.push_back(btOutMix);
+
+ AudioPort btHearingOutMix =
+ createPort(c.nextPortId++, "hearing aid output", 0, false, createPortMixExt(1, 1));
+ btHearingOutMix.profiles.push_back(createProfile(
+ PcmType::INT_16_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {16000, 24000}));
+ c.ports.push_back(btHearingOutMix);
+
+ c.routes.push_back(createRoute({btOutMix}, btOutDevice));
+ c.routes.push_back(createRoute({btOutMix}, btOutHeadphone));
+ c.routes.push_back(createRoute({btOutMix}, btOutSpeaker));
+ c.routes.push_back(createRoute({btHearingOutMix}, btOutHearingAid));
+
+ return c;
+ }();
+ return std::make_unique<Configuration>(configuration);
+}
+
} // namespace aidl::android::hardware::audio::core::internal
diff --git a/audio/aidl/default/Module.cpp b/audio/aidl/default/Module.cpp
index b59bd7c..f81095e 100644
--- a/audio/aidl/default/Module.cpp
+++ b/audio/aidl/default/Module.cpp
@@ -26,6 +26,7 @@
#include <error/expected_utils.h>
#include "core-impl/Module.h"
+#include "core-impl/ModuleBluetooth.h"
#include "core-impl/ModulePrimary.h"
#include "core-impl/ModuleRemoteSubmix.h"
#include "core-impl/ModuleStub.h"
@@ -117,6 +118,8 @@
return ndk::SharedRefBase::make<ModuleStub>();
case Type::USB:
return ndk::SharedRefBase::make<ModuleUsb>();
+ case Type::BLUETOOTH:
+ return ndk::SharedRefBase::make<ModuleBluetooth>();
}
}
@@ -134,6 +137,9 @@
case Module::Type::USB:
os << "usb";
break;
+ case Module::Type::BLUETOOTH:
+ os << "bluetooth";
+ break;
}
return os;
}
@@ -301,6 +307,9 @@
case Type::USB:
config = std::move(internal::getUsbConfiguration());
break;
+ case Type::BLUETOOTH:
+ config = std::move(internal::getBluetoothConfiguration());
+ break;
}
return config;
}
@@ -1362,4 +1371,13 @@
return ndk::ScopedAStatus::ok();
}
+Module::BtProfileHandles Module::getBtProfileManagerHandles() {
+ return std::make_tuple(std::weak_ptr<IBluetooth>(), std::weak_ptr<IBluetoothA2dp>(),
+ std::weak_ptr<IBluetoothLe>());
+}
+
+ndk::ScopedAStatus Module::bluetoothParametersUpdated() {
+ return mStreams.bluetoothParametersUpdated();
+}
+
} // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/ModulePrimary.cpp b/audio/aidl/default/ModulePrimary.cpp
index 29e8126..9919c7f 100644
--- a/audio/aidl/default/ModulePrimary.cpp
+++ b/audio/aidl/default/ModulePrimary.cpp
@@ -21,7 +21,7 @@
#include <android-base/logging.h>
#include "core-impl/ModulePrimary.h"
-#include "core-impl/StreamStub.h"
+#include "core-impl/StreamPrimary.h"
#include "core-impl/Telephony.h"
using aidl::android::hardware::audio::common::SinkMetadata;
@@ -47,15 +47,15 @@
const SinkMetadata& sinkMetadata,
const std::vector<MicrophoneInfo>& microphones,
std::shared_ptr<StreamIn>* result) {
- return createStreamInstance<StreamInStub>(result, std::move(context), sinkMetadata,
- microphones);
+ return createStreamInstance<StreamInPrimary>(result, std::move(context), sinkMetadata,
+ microphones);
}
ndk::ScopedAStatus ModulePrimary::createOutputStream(
StreamContext&& context, const SourceMetadata& sourceMetadata,
const std::optional<AudioOffloadInfo>& offloadInfo, std::shared_ptr<StreamOut>* result) {
- return createStreamInstance<StreamOutStub>(result, std::move(context), sourceMetadata,
- offloadInfo);
+ return createStreamInstance<StreamOutPrimary>(result, std::move(context), sourceMetadata,
+ offloadInfo);
}
} // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/Stream.cpp b/audio/aidl/default/Stream.cpp
index d2be48c..af89f5f 100644
--- a/audio/aidl/default/Stream.cpp
+++ b/audio/aidl/default/Stream.cpp
@@ -27,12 +27,16 @@
using aidl::android::hardware::audio::common::AudioOffloadMetadata;
using aidl::android::hardware::audio::common::getChannelCount;
using aidl::android::hardware::audio::common::getFrameSizeInBytes;
+using aidl::android::hardware::audio::common::isBitPositionFlagSet;
using aidl::android::hardware::audio::common::SinkMetadata;
using aidl::android::hardware::audio::common::SourceMetadata;
using aidl::android::media::audio::common::AudioDevice;
using aidl::android::media::audio::common::AudioDualMonoMode;
+using aidl::android::media::audio::common::AudioInputFlags;
+using aidl::android::media::audio::common::AudioIoFlags;
using aidl::android::media::audio::common::AudioLatencyMode;
using aidl::android::media::audio::common::AudioOffloadInfo;
+using aidl::android::media::audio::common::AudioOutputFlags;
using aidl::android::media::audio::common::AudioPlaybackRate;
using aidl::android::media::audio::common::MicrophoneDynamicInfo;
using aidl::android::media::audio::common::MicrophoneInfo;
@@ -117,7 +121,7 @@
if (isConnected) {
reply->observable.frames = mContext->getFrameCount();
reply->observable.timeNs = ::android::elapsedRealtimeNano();
- if (auto status = mDriver->getPosition(&reply->observable); status == ::android::OK) {
+ if (auto status = mDriver->refinePosition(&reply->observable); status == ::android::OK) {
return;
}
}
@@ -238,8 +242,8 @@
break;
case Tag::standby:
if (mState == StreamDescriptor::State::IDLE) {
+ populateReply(&reply, mIsConnected);
if (::android::status_t status = mDriver->standby(); status == ::android::OK) {
- populateReply(&reply, mIsConnected);
mState = StreamDescriptor::State::STANDBY;
} else {
LOG(ERROR) << __func__ << ": standby failed: " << status;
@@ -492,8 +496,8 @@
break;
case Tag::standby:
if (mState == StreamDescriptor::State::IDLE) {
+ populateReply(&reply, mIsConnected);
if (::android::status_t status = mDriver->standby(); status == ::android::OK) {
- populateReply(&reply, mIsConnected);
mState = StreamDescriptor::State::STANDBY;
} else {
LOG(ERROR) << __func__ << ": standby failed: " << status;
@@ -610,8 +614,30 @@
ndk::ScopedAStatus StreamCommonImpl::initInstance(
const std::shared_ptr<StreamCommonInterface>& delegate) {
mCommon = ndk::SharedRefBase::make<StreamCommonDelegator>(delegate);
- return mWorker->start() ? ndk::ScopedAStatus::ok()
- : ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+ if (!mWorker->start()) {
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+ }
+ if (auto flags = getContext().getFlags();
+ (flags.getTag() == AudioIoFlags::Tag::input &&
+ isBitPositionFlagSet(flags.template get<AudioIoFlags::Tag::input>(),
+ AudioInputFlags::FAST)) ||
+ (flags.getTag() == AudioIoFlags::Tag::output &&
+ isBitPositionFlagSet(flags.template get<AudioIoFlags::Tag::output>(),
+ AudioOutputFlags::FAST))) {
+ // FAST workers should be run with a SCHED_FIFO scheduler, however the host process
+ // might be lacking the capability to request it, thus a failure to set is not an error.
+ pid_t workerTid = mWorker->getTid();
+ if (workerTid > 0) {
+ struct sched_param param;
+ param.sched_priority = 3; // Must match SchedulingPolicyService.PRIORITY_MAX (Java).
+ if (sched_setscheduler(workerTid, SCHED_FIFO | SCHED_RESET_ON_FORK, ¶m) != 0) {
+ PLOG(WARNING) << __func__ << ": failed to set FIFO scheduler for a fast thread";
+ }
+ } else {
+ LOG(WARNING) << __func__ << ": invalid worker tid: " << workerTid;
+ }
+ }
+ return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus StreamCommonImpl::getStreamCommonCommon(
@@ -723,6 +749,11 @@
return ndk::ScopedAStatus::ok();
}
+ndk::ScopedAStatus StreamCommonImpl::bluetoothParametersUpdated() {
+ LOG(DEBUG) << __func__;
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
namespace {
static std::map<AudioDevice, std::string> transformMicrophones(
const std::vector<MicrophoneInfo>& microphones) {
@@ -734,12 +765,12 @@
} // namespace
StreamIn::StreamIn(StreamContext&& context, const std::vector<MicrophoneInfo>& microphones)
- : mContext(std::move(context)), mMicrophones(transformMicrophones(microphones)) {
+ : mContextInstance(std::move(context)), mMicrophones(transformMicrophones(microphones)) {
LOG(DEBUG) << __func__;
}
void StreamIn::defaultOnClose() {
- mContext.reset();
+ mContextInstance.reset();
}
ndk::ScopedAStatus StreamIn::getActiveMicrophones(
@@ -794,13 +825,39 @@
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
+StreamInHwGainHelper::StreamInHwGainHelper(const StreamContext* context)
+ : mChannelCount(getChannelCount(context->getChannelLayout())) {}
+
+ndk::ScopedAStatus StreamInHwGainHelper::getHwGainImpl(std::vector<float>* _aidl_return) {
+ *_aidl_return = mHwGains;
+ LOG(DEBUG) << __func__ << ": returning " << ::android::internal::ToString(*_aidl_return);
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus StreamInHwGainHelper::setHwGainImpl(const std::vector<float>& in_channelGains) {
+ LOG(DEBUG) << __func__ << ": gains " << ::android::internal::ToString(in_channelGains);
+ if (in_channelGains.size() != mChannelCount) {
+ LOG(ERROR) << __func__
+ << ": channel count does not match stream channel count: " << mChannelCount;
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ for (float gain : in_channelGains) {
+ if (gain < StreamIn::HW_GAIN_MIN || gain > StreamIn::HW_GAIN_MAX) {
+ LOG(ERROR) << __func__ << ": gain value out of range: " << gain;
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ }
+ mHwGains = in_channelGains;
+ return ndk::ScopedAStatus::ok();
+}
+
StreamOut::StreamOut(StreamContext&& context, const std::optional<AudioOffloadInfo>& offloadInfo)
- : mContext(std::move(context)), mOffloadInfo(offloadInfo) {
+ : mContextInstance(std::move(context)), mOffloadInfo(offloadInfo) {
LOG(DEBUG) << __func__;
}
void StreamOut::defaultOnClose() {
- mContext.reset();
+ mContextInstance.reset();
}
ndk::ScopedAStatus StreamOut::updateOffloadMetadata(
@@ -899,4 +956,31 @@
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
+StreamOutHwVolumeHelper::StreamOutHwVolumeHelper(const StreamContext* context)
+ : mChannelCount(getChannelCount(context->getChannelLayout())) {}
+
+ndk::ScopedAStatus StreamOutHwVolumeHelper::getHwVolumeImpl(std::vector<float>* _aidl_return) {
+ *_aidl_return = mHwVolumes;
+ LOG(DEBUG) << __func__ << ": returning " << ::android::internal::ToString(*_aidl_return);
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus StreamOutHwVolumeHelper::setHwVolumeImpl(
+ const std::vector<float>& in_channelVolumes) {
+ LOG(DEBUG) << __func__ << ": volumes " << ::android::internal::ToString(in_channelVolumes);
+ if (in_channelVolumes.size() != mChannelCount) {
+ LOG(ERROR) << __func__
+ << ": channel count does not match stream channel count: " << mChannelCount;
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ for (float volume : in_channelVolumes) {
+ if (volume < StreamOut::HW_VOLUME_MIN || volume > StreamOut::HW_VOLUME_MAX) {
+ LOG(ERROR) << __func__ << ": volume value out of range: " << volume;
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ }
+ mHwVolumes = in_channelVolumes;
+ return ndk::ScopedAStatus::ok();
+}
+
} // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/StreamSwitcher.cpp b/audio/aidl/default/StreamSwitcher.cpp
index e00c34b..8ba15a8 100644
--- a/audio/aidl/default/StreamSwitcher.cpp
+++ b/audio/aidl/default/StreamSwitcher.cpp
@@ -126,11 +126,10 @@
LOG(ERROR) << __func__ << ": stream was closed";
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
}
- for (auto it = mEffects.begin(); it != mEffects.end();) {
+ for (auto it = mEffects.begin(); it != mEffects.end(); ++it) {
if ((*it)->asBinder() == in_effect->asBinder()) {
- it = mEffects.erase(it);
- } else {
- ++it;
+ mEffects.erase(it);
+ break;
}
}
return !mIsStubStream ? mStream->removeEffect(in_effect) : ndk::ScopedAStatus::ok();
@@ -201,6 +200,10 @@
}
// The delegate is null because StreamSwitcher handles IStreamCommon methods by itself.
if (ndk::ScopedAStatus status = mStream->initInstance(nullptr); !status.isOk()) {
+ if (mIsStubStream) {
+ LOG(FATAL) << __func__
+ << ": failed to initialize stub stream: " << status.getDescription();
+ }
// Need to close the current failed stream, and report an error.
// Since we can't operate without a stream implementation, put a stub in.
RETURN_STATUS_IF_ERROR(closeCurrentStream(false /*validateStreamState*/));
@@ -233,8 +236,28 @@
<< status.getDescription();
}
}
+ if (mBluetoothParametersUpdated) {
+ if (auto status = mStream->bluetoothParametersUpdated(); !status.isOk()) {
+ LOG(WARNING) << __func__
+ << ": error while updating BT parameters for a new stream: "
+ << status.getDescription();
+ }
+ }
+ mBluetoothParametersUpdated = false;
}
return ndk::ScopedAStatus::ok();
}
+ndk::ScopedAStatus StreamSwitcher::bluetoothParametersUpdated() {
+ if (mStream == nullptr) {
+ LOG(ERROR) << __func__ << ": stream was closed";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+ }
+ if (mIsStubStream) {
+ mBluetoothParametersUpdated = true;
+ return ndk::ScopedAStatus::ok();
+ }
+ return mStream->bluetoothParametersUpdated();
+}
+
} // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/alsa/Mixer.h b/audio/aidl/default/alsa/Mixer.h
index 78728c2..8fba1e0 100644
--- a/audio/aidl/default/alsa/Mixer.h
+++ b/audio/aidl/default/alsa/Mixer.h
@@ -72,7 +72,7 @@
std::mutex mMixerAccess;
// The mixer object is owned by ALSA and will be released when the mixer is closed.
struct mixer* const mMixer;
- // `mMixerControls` will only be initialized in constructor. After that, it wil only be
+ // `mMixerControls` will only be initialized in constructor. After that, it will only be
// read but not be modified. Each mixer_ctl object is owned by ALSA, it's life span is
// the same as of the mixer itself.
const Controls mMixerControls;
diff --git a/audio/aidl/default/alsa/StreamAlsa.cpp b/audio/aidl/default/alsa/StreamAlsa.cpp
index 00a7a84..0605d6f 100644
--- a/audio/aidl/default/alsa/StreamAlsa.cpp
+++ b/audio/aidl/default/alsa/StreamAlsa.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include <cmath>
#include <limits>
#define LOG_TAG "AHAL_StreamAlsa"
@@ -29,7 +30,9 @@
StreamAlsa::StreamAlsa(StreamContext* context, const Metadata& metadata, int readWriteRetries)
: StreamCommonImpl(context, metadata),
+ mBufferSizeFrames(getContext().getBufferSizeInFrames()),
mFrameSizeBytes(getContext().getFrameSize()),
+ mSampleRate(getContext().getSampleRate()),
mIsInput(isInput(metadata)),
mConfig(alsa::getPcmConfig(getContext(), mIsInput)),
mReadWriteRetries(readWriteRetries) {}
@@ -39,17 +42,20 @@
}
::android::status_t StreamAlsa::drain(StreamDescriptor::DrainMode) {
- usleep(1000);
+ if (!mIsInput) {
+ static constexpr float kMicrosPerSecond = MICROS_PER_SECOND;
+ const size_t delayUs = static_cast<size_t>(
+ std::roundf(mBufferSizeFrames * kMicrosPerSecond / mSampleRate));
+ usleep(delayUs);
+ }
return ::android::OK;
}
::android::status_t StreamAlsa::flush() {
- usleep(1000);
return ::android::OK;
}
::android::status_t StreamAlsa::pause() {
- usleep(1000);
return ::android::OK;
}
@@ -59,6 +65,10 @@
}
::android::status_t StreamAlsa::start() {
+ if (!mAlsaDeviceProxies.empty()) {
+ // This is a resume after a pause.
+ return ::android::OK;
+ }
decltype(mAlsaDeviceProxies) alsaDeviceProxies;
for (const auto& device : getDeviceProfiles()) {
alsa::DeviceProxy proxy;
@@ -71,8 +81,7 @@
true /*require_exact_match*/);
} else {
proxy = alsa::openProxyForAttachedDevice(
- device, const_cast<struct pcm_config*>(&mConfig.value()),
- getContext().getBufferSizeInFrames());
+ device, const_cast<struct pcm_config*>(&mConfig.value()), mBufferSizeFrames);
}
if (!proxy) {
return ::android::NO_INIT;
@@ -85,13 +94,13 @@
::android::status_t StreamAlsa::transfer(void* buffer, size_t frameCount, size_t* actualFrameCount,
int32_t* latencyMs) {
+ if (mAlsaDeviceProxies.empty()) {
+ LOG(FATAL) << __func__ << ": no opened devices";
+ return ::android::NO_INIT;
+ }
const size_t bytesToTransfer = frameCount * mFrameSizeBytes;
unsigned maxLatency = 0;
if (mIsInput) {
- if (mAlsaDeviceProxies.empty()) {
- LOG(FATAL) << __func__ << ": no input devices";
- return ::android::NO_INIT;
- }
// For input case, only support single device.
proxy_read_with_retries(mAlsaDeviceProxies[0].get(), buffer, bytesToTransfer,
mReadWriteRetries);
@@ -108,11 +117,14 @@
return ::android::OK;
}
-::android::status_t StreamAlsa::getPosition(StreamDescriptor::Position* position) {
+::android::status_t StreamAlsa::refinePosition(StreamDescriptor::Position* position) {
if (mAlsaDeviceProxies.empty()) {
- LOG(FATAL) << __func__ << ": no input devices";
+ LOG(FATAL) << __func__ << ": no opened devices";
return ::android::NO_INIT;
}
+ // Since the proxy can only count transferred frames since its creation,
+ // we override its counter value with ours and let it to correct for buffered frames.
+ alsa::resetTransferredFrames(mAlsaDeviceProxies[0], position->frames);
if (mIsInput) {
if (int ret = proxy_get_capture_position(mAlsaDeviceProxies[0].get(), &position->frames,
&position->timeNs);
diff --git a/audio/aidl/default/alsa/Utils.cpp b/audio/aidl/default/alsa/Utils.cpp
index 20f7797..9dcd024 100644
--- a/audio/aidl/default/alsa/Utils.cpp
+++ b/audio/aidl/default/alsa/Utils.cpp
@@ -262,12 +262,14 @@
}
DeviceProxy makeDeviceProxy() {
- return DeviceProxy(new alsa_device_proxy, [](alsa_device_proxy* proxy) {
+ DeviceProxy proxy(new alsa_device_proxy, [](alsa_device_proxy* proxy) {
if (proxy != nullptr) {
proxy_close(proxy);
delete proxy;
}
});
+ memset(proxy.get(), 0, sizeof(alsa_device_proxy));
+ return proxy;
}
DeviceProxy openProxyForAttachedDevice(const DeviceProfile& deviceProfile,
@@ -334,6 +336,12 @@
return profile;
}
+void resetTransferredFrames(DeviceProxy& proxy, uint64_t frames) {
+ if (proxy != nullptr) {
+ proxy->transferred = frames;
+ }
+}
+
AudioFormatDescription c2aidl_pcm_format_AudioFormatDescription(enum pcm_format legacy) {
return findValueOrDefault(getPcmFormatToAudioFormatDescMap(), legacy, AudioFormatDescription());
}
diff --git a/audio/aidl/default/alsa/Utils.h b/audio/aidl/default/alsa/Utils.h
index 615e657..37414b3 100644
--- a/audio/aidl/default/alsa/Utils.h
+++ b/audio/aidl/default/alsa/Utils.h
@@ -66,6 +66,7 @@
DeviceProxy openProxyForExternalDevice(const DeviceProfile& deviceProfile,
struct pcm_config* pcmConfig, bool requireExactMatch);
std::optional<alsa_device_profile> readAlsaDeviceInfo(const DeviceProfile& deviceProfile);
+void resetTransferredFrames(DeviceProxy& proxy, uint64_t frames);
::aidl::android::media::audio::common::AudioFormatDescription
c2aidl_pcm_format_AudioFormatDescription(enum pcm_format legacy);
diff --git a/audio/aidl/default/android.hardware.audio.service-aidl.example.rc b/audio/aidl/default/android.hardware.audio.service-aidl.example.rc
index 2068735..757976f 100644
--- a/audio/aidl/default/android.hardware.audio.service-aidl.example.rc
+++ b/audio/aidl/default/android.hardware.audio.service-aidl.example.rc
@@ -3,7 +3,7 @@
user audioserver
# media gid needed for /dev/fm (radio) and for /data/misc/media (tee)
group audio camera drmrpc inet media mediadrm net_bt net_bt_admin net_bw_acct wakelock context_hub
- capabilities BLOCK_SUSPEND
+ capabilities BLOCK_SUSPEND SYS_NICE
# setting RLIMIT_RTPRIO allows binder RT priority inheritance
rlimit rtprio 10 10
ioprio rt 4
diff --git a/audio/aidl/default/android.hardware.audio.service-aidl.xml b/audio/aidl/default/android.hardware.audio.service-aidl.xml
index c9d6314..9db6061 100644
--- a/audio/aidl/default/android.hardware.audio.service-aidl.xml
+++ b/audio/aidl/default/android.hardware.audio.service-aidl.xml
@@ -22,6 +22,11 @@
<hal format="aidl">
<name>android.hardware.audio.core</name>
<version>1</version>
+ <fqname>IModule/bluetooth</fqname>
+ </hal>
+ <hal format="aidl">
+ <name>android.hardware.audio.core</name>
+ <version>1</version>
<fqname>IConfig/default</fqname>
</hal>
</manifest>
diff --git a/audio/aidl/default/bluetooth/DevicePortProxy.cpp b/audio/aidl/default/bluetooth/DevicePortProxy.cpp
new file mode 100644
index 0000000..12e204a
--- /dev/null
+++ b/audio/aidl/default/bluetooth/DevicePortProxy.cpp
@@ -0,0 +1,577 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AHAL_BluetoothPortProxy"
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <audio_utils/primitives.h>
+#include <inttypes.h>
+#include <log/log.h>
+
+#include "core-impl/DevicePortProxy.h"
+
+namespace android::bluetooth::audio::aidl {
+
+namespace {
+
+// The maximum time to wait in std::condition_variable::wait_for()
+constexpr unsigned int kMaxWaitingTimeMs = 4500;
+
+} // namespace
+
+using ::aidl::android::hardware::audio::common::SinkMetadata;
+using ::aidl::android::hardware::audio::common::SourceMetadata;
+using ::aidl::android::hardware::bluetooth::audio::AudioConfiguration;
+using ::aidl::android::hardware::bluetooth::audio::BluetoothAudioSessionControl;
+using ::aidl::android::hardware::bluetooth::audio::BluetoothAudioStatus;
+using ::aidl::android::hardware::bluetooth::audio::ChannelMode;
+using ::aidl::android::hardware::bluetooth::audio::PcmConfiguration;
+using ::aidl::android::hardware::bluetooth::audio::PortStatusCallbacks;
+using ::aidl::android::hardware::bluetooth::audio::PresentationPosition;
+using ::aidl::android::hardware::bluetooth::audio::SessionType;
+using ::aidl::android::media::audio::common::AudioDeviceDescription;
+using ::aidl::android::media::audio::common::AudioDeviceType;
+using ::android::base::StringPrintf;
+
+std::ostream& operator<<(std::ostream& os, const BluetoothStreamState& state) {
+ switch (state) {
+ case BluetoothStreamState::DISABLED:
+ return os << "DISABLED";
+ case BluetoothStreamState::STANDBY:
+ return os << "STANDBY";
+ case BluetoothStreamState::STARTING:
+ return os << "STARTING";
+ case BluetoothStreamState::STARTED:
+ return os << "STARTED";
+ case BluetoothStreamState::SUSPENDING:
+ return os << "SUSPENDING";
+ case BluetoothStreamState::UNKNOWN:
+ return os << "UNKNOWN";
+ default:
+ return os << android::base::StringPrintf("%#hhx", state);
+ }
+}
+
+BluetoothAudioPortAidl::BluetoothAudioPortAidl()
+ : mCookie(::aidl::android::hardware::bluetooth::audio::kObserversCookieUndefined),
+ mState(BluetoothStreamState::DISABLED),
+ mSessionType(SessionType::UNKNOWN) {}
+
+BluetoothAudioPortAidl::~BluetoothAudioPortAidl() {
+ unregisterPort();
+}
+
+bool BluetoothAudioPortAidl::registerPort(const AudioDeviceDescription& description) {
+ if (inUse()) {
+ LOG(ERROR) << __func__ << debugMessage() << " already in use";
+ return false;
+ }
+
+ if (!initSessionType(description)) return false;
+
+ auto control_result_cb = [port = this](uint16_t cookie, bool start_resp,
+ const BluetoothAudioStatus& status) {
+ (void)start_resp;
+ port->controlResultHandler(cookie, status);
+ };
+ auto session_changed_cb = [port = this](uint16_t cookie) {
+ port->sessionChangedHandler(cookie);
+ };
+ // TODO: Add audio_config_changed_cb
+ PortStatusCallbacks cbacks = {
+ .control_result_cb_ = control_result_cb,
+ .session_changed_cb_ = session_changed_cb,
+ };
+ mCookie = BluetoothAudioSessionControl::RegisterControlResultCback(mSessionType, cbacks);
+ auto isOk = (mCookie != ::aidl::android::hardware::bluetooth::audio::kObserversCookieUndefined);
+ if (isOk) {
+ std::lock_guard guard(mCvMutex);
+ mState = BluetoothStreamState::STANDBY;
+ }
+ LOG(DEBUG) << __func__ << debugMessage();
+ return isOk;
+}
+
+bool BluetoothAudioPortAidl::initSessionType(const AudioDeviceDescription& description) {
+ if (description.connection == AudioDeviceDescription::CONNECTION_BT_A2DP &&
+ (description.type == AudioDeviceType::OUT_DEVICE ||
+ description.type == AudioDeviceType::OUT_HEADPHONE ||
+ description.type == AudioDeviceType::OUT_SPEAKER)) {
+ LOG(VERBOSE) << __func__
+ << ": device=AUDIO_DEVICE_OUT_BLUETOOTH_A2DP (HEADPHONES/SPEAKER) ("
+ << description.toString() << ")";
+ mSessionType = SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH;
+ } else if (description.connection == AudioDeviceDescription::CONNECTION_WIRELESS &&
+ description.type == AudioDeviceType::OUT_HEARING_AID) {
+ LOG(VERBOSE) << __func__ << ": device=AUDIO_DEVICE_OUT_HEARING_AID (MEDIA/VOICE) ("
+ << description.toString() << ")";
+ mSessionType = SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH;
+ } else if (description.connection == AudioDeviceDescription::CONNECTION_BT_LE &&
+ description.type == AudioDeviceType::OUT_HEADSET) {
+ LOG(VERBOSE) << __func__ << ": device=AUDIO_DEVICE_OUT_BLE_HEADSET (MEDIA/VOICE) ("
+ << description.toString() << ")";
+ mSessionType = SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH;
+ } else if (description.connection == AudioDeviceDescription::CONNECTION_BT_LE &&
+ description.type == AudioDeviceType::OUT_SPEAKER) {
+ LOG(VERBOSE) << __func__ << ": device=AUDIO_DEVICE_OUT_BLE_SPEAKER (MEDIA) ("
+ << description.toString() << ")";
+ mSessionType = SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH;
+ } else if (description.connection == AudioDeviceDescription::CONNECTION_BT_LE &&
+ description.type == AudioDeviceType::IN_HEADSET) {
+ LOG(VERBOSE) << __func__ << ": device=AUDIO_DEVICE_IN_BLE_HEADSET (VOICE) ("
+ << description.toString() << ")";
+ mSessionType = SessionType::LE_AUDIO_SOFTWARE_DECODING_DATAPATH;
+ } else if (description.connection == AudioDeviceDescription::CONNECTION_BT_LE &&
+ description.type == AudioDeviceType::OUT_BROADCAST) {
+ LOG(VERBOSE) << __func__ << ": device=AUDIO_DEVICE_OUT_BLE_BROADCAST (MEDIA) ("
+ << description.toString() << ")";
+ mSessionType = SessionType::LE_AUDIO_BROADCAST_SOFTWARE_ENCODING_DATAPATH;
+ } else {
+ LOG(ERROR) << __func__ << ": unknown device=" << description.toString();
+ return false;
+ }
+
+ if (!BluetoothAudioSessionControl::IsSessionReady(mSessionType)) {
+ LOG(ERROR) << __func__ << ": device=" << description.toString()
+ << ", session_type=" << toString(mSessionType) << " is not ready";
+ return false;
+ }
+ return true;
+}
+
+void BluetoothAudioPortAidl::unregisterPort() {
+ if (!inUse()) {
+ LOG(WARNING) << __func__ << ": BluetoothAudioPortAidl is not in use";
+ return;
+ }
+ BluetoothAudioSessionControl::UnregisterControlResultCback(mSessionType, mCookie);
+ mCookie = ::aidl::android::hardware::bluetooth::audio::kObserversCookieUndefined;
+ LOG(VERBOSE) << __func__ << debugMessage() << " port unregistered";
+}
+
+void BluetoothAudioPortAidl::controlResultHandler(uint16_t cookie,
+ const BluetoothAudioStatus& status) {
+ std::lock_guard guard(mCvMutex);
+ if (!inUse()) {
+ LOG(ERROR) << "control_result_cb: BluetoothAudioPortAidl is not in use";
+ return;
+ }
+ if (mCookie != cookie) {
+ LOG(ERROR) << "control_result_cb: proxy of device port (cookie="
+ << StringPrintf("%#hx", cookie) << ") is corrupted";
+ return;
+ }
+ BluetoothStreamState previous_state = mState;
+ LOG(INFO) << "control_result_cb:" << debugMessage() << ", previous_state=" << previous_state
+ << ", status=" << toString(status);
+
+ switch (previous_state) {
+ case BluetoothStreamState::STARTED:
+ /* Only Suspend signal can be send in STARTED state*/
+ if (status == BluetoothAudioStatus::RECONFIGURATION ||
+ status == BluetoothAudioStatus::SUCCESS) {
+ mState = BluetoothStreamState::STANDBY;
+ } else {
+ LOG(WARNING) << StringPrintf(
+ "control_result_cb: status=%s failure for session_type= %s, cookie=%#hx, "
+ "previous_state=%#hhx",
+ toString(status).c_str(), toString(mSessionType).c_str(), mCookie,
+ previous_state);
+ }
+ break;
+ case BluetoothStreamState::STARTING:
+ if (status == BluetoothAudioStatus::SUCCESS) {
+ mState = BluetoothStreamState::STARTED;
+ } else {
+ // Set to standby since the stack may be busy switching between outputs
+ LOG(WARNING) << StringPrintf(
+ "control_result_cb: status=%s failure for session_type= %s, cookie=%#hx, "
+ "previous_state=%#hhx",
+ toString(status).c_str(), toString(mSessionType).c_str(), mCookie,
+ previous_state);
+ mState = BluetoothStreamState::STANDBY;
+ }
+ break;
+ case BluetoothStreamState::SUSPENDING:
+ if (status == BluetoothAudioStatus::SUCCESS) {
+ mState = BluetoothStreamState::STANDBY;
+ } else {
+ // It will be failed if the headset is disconnecting, and set to disable
+ // to wait for re-init again
+ LOG(WARNING) << StringPrintf(
+ "control_result_cb: status=%s failure for session_type= %s, cookie=%#hx, "
+ "previous_state=%#hhx",
+ toString(status).c_str(), toString(mSessionType).c_str(), mCookie,
+ previous_state);
+ mState = BluetoothStreamState::DISABLED;
+ }
+ break;
+ default:
+ LOG(ERROR) << "control_result_cb: unexpected previous_state="
+ << StringPrintf(
+ "control_result_cb: status=%s failure for session_type= %s, "
+ "cookie=%#hx, previous_state=%#hhx",
+ toString(status).c_str(), toString(mSessionType).c_str(), mCookie,
+ previous_state);
+ return;
+ }
+ mInternalCv.notify_all();
+}
+
+void BluetoothAudioPortAidl::sessionChangedHandler(uint16_t cookie) {
+ std::lock_guard guard(mCvMutex);
+ if (!inUse()) {
+ LOG(ERROR) << "session_changed_cb: BluetoothAudioPortAidl is not in use";
+ return;
+ }
+ if (mCookie != cookie) {
+ LOG(ERROR) << "session_changed_cb: proxy of device port (cookie="
+ << StringPrintf("%#hx", cookie) << ") is corrupted";
+ return;
+ }
+ BluetoothStreamState previous_state = mState;
+ LOG(VERBOSE) << "session_changed_cb:" << debugMessage()
+ << ", previous_state=" << previous_state;
+ mState = BluetoothStreamState::DISABLED;
+ mInternalCv.notify_all();
+}
+
+bool BluetoothAudioPortAidl::inUse() const {
+ return (mCookie != ::aidl::android::hardware::bluetooth::audio::kObserversCookieUndefined);
+}
+
+bool BluetoothAudioPortAidl::getPreferredDataIntervalUs(size_t* interval_us) const {
+ if (!interval_us) {
+ LOG(ERROR) << __func__ << ": bad input arg";
+ return false;
+ }
+
+ if (!inUse()) {
+ LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use";
+ return false;
+ }
+
+ const AudioConfiguration& hal_audio_cfg =
+ BluetoothAudioSessionControl::GetAudioConfig(mSessionType);
+ if (hal_audio_cfg.getTag() != AudioConfiguration::pcmConfig) {
+ LOG(ERROR) << __func__ << ": unsupported audio cfg tag";
+ return false;
+ }
+
+ *interval_us = hal_audio_cfg.get<AudioConfiguration::pcmConfig>().dataIntervalUs;
+ return true;
+}
+
+bool BluetoothAudioPortAidl::loadAudioConfig(PcmConfiguration* audio_cfg) const {
+ if (!audio_cfg) {
+ LOG(ERROR) << __func__ << ": bad input arg";
+ return false;
+ }
+
+ if (!inUse()) {
+ LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use";
+ return false;
+ }
+
+ const AudioConfiguration& hal_audio_cfg =
+ BluetoothAudioSessionControl::GetAudioConfig(mSessionType);
+ if (hal_audio_cfg.getTag() != AudioConfiguration::pcmConfig) {
+ LOG(ERROR) << __func__ << ": unsupported audio cfg tag";
+ return false;
+ }
+ *audio_cfg = hal_audio_cfg.get<AudioConfiguration::pcmConfig>();
+ LOG(VERBOSE) << __func__ << debugMessage() << ", state*=" << getState() << ", PcmConfig=["
+ << audio_cfg->toString() << "]";
+ if (audio_cfg->channelMode == ChannelMode::UNKNOWN) {
+ return false;
+ }
+ return true;
+}
+
+bool BluetoothAudioPortAidl::standby() {
+ if (!inUse()) {
+ LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use";
+ return false;
+ }
+ std::lock_guard guard(mCvMutex);
+ LOG(VERBOSE) << __func__ << debugMessage() << ", state=" << getState() << " request";
+ if (mState == BluetoothStreamState::DISABLED) {
+ mState = BluetoothStreamState::STANDBY;
+ LOG(VERBOSE) << __func__ << debugMessage() << ", state=" << getState() << " done";
+ return true;
+ }
+ return false;
+}
+
+bool BluetoothAudioPortAidl::condWaitState(BluetoothStreamState state) {
+ const auto waitTime = std::chrono::milliseconds(kMaxWaitingTimeMs);
+ std::unique_lock lock(mCvMutex);
+ base::ScopedLockAssertion lock_assertion(mCvMutex);
+ switch (state) {
+ case BluetoothStreamState::STARTING: {
+ LOG(VERBOSE) << __func__ << debugMessage() << " waiting for STARTED";
+ mInternalCv.wait_for(lock, waitTime, [this] {
+ base::ScopedLockAssertion lock_assertion(mCvMutex);
+ return mState != BluetoothStreamState::STARTING;
+ });
+ return mState == BluetoothStreamState::STARTED;
+ }
+ case BluetoothStreamState::SUSPENDING: {
+ LOG(VERBOSE) << __func__ << debugMessage() << " waiting for SUSPENDED";
+ mInternalCv.wait_for(lock, waitTime, [this] {
+ base::ScopedLockAssertion lock_assertion(mCvMutex);
+ return mState != BluetoothStreamState::SUSPENDING;
+ });
+ return mState == BluetoothStreamState::STANDBY;
+ }
+ default:
+ LOG(WARNING) << __func__ << debugMessage() << " waiting for KNOWN";
+ return false;
+ }
+ return false;
+}
+
+bool BluetoothAudioPortAidl::start() {
+ if (!inUse()) {
+ LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use";
+ return false;
+ }
+ LOG(VERBOSE) << __func__ << debugMessage() << ", state=" << getState()
+ << ", mono=" << (mIsStereoToMono ? "true" : "false") << " request";
+
+ {
+ std::unique_lock lock(mCvMutex);
+ base::ScopedLockAssertion lock_assertion(mCvMutex);
+ if (mState == BluetoothStreamState::STARTED) {
+ return true; // nop, return
+ } else if (mState == BluetoothStreamState::SUSPENDING ||
+ mState == BluetoothStreamState::STARTING) {
+ /* If port is in transient state, give some time to respond */
+ auto state_ = mState;
+ lock.unlock();
+ if (!condWaitState(state_)) {
+ LOG(ERROR) << __func__ << debugMessage() << ", state=" << getState() << " failure";
+ return false;
+ }
+ }
+ }
+
+ bool retval = false;
+ {
+ std::unique_lock lock(mCvMutex);
+ base::ScopedLockAssertion lock_assertion(mCvMutex);
+ if (mState == BluetoothStreamState::STARTED) {
+ retval = true;
+ } else if (mState == BluetoothStreamState::STANDBY) {
+ mState = BluetoothStreamState::STARTING;
+ lock.unlock();
+ if (BluetoothAudioSessionControl::StartStream(mSessionType)) {
+ retval = condWaitState(BluetoothStreamState::STARTING);
+ } else {
+ LOG(ERROR) << __func__ << debugMessage() << ", state=" << getState()
+ << " Hal fails";
+ }
+ }
+ }
+
+ if (retval) {
+ LOG(INFO) << __func__ << debugMessage() << ", state=" << getState()
+ << ", mono=" << (mIsStereoToMono ? "true" : "false") << " done";
+ } else {
+ LOG(ERROR) << __func__ << debugMessage() << ", state=" << getState() << " failure";
+ }
+
+ return retval; // false if any failure like timeout
+}
+
+bool BluetoothAudioPortAidl::suspend() {
+ if (!inUse()) {
+ LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use";
+ return false;
+ }
+ LOG(VERBOSE) << __func__ << debugMessage() << ", state=" << getState() << " request";
+
+ {
+ std::unique_lock lock(mCvMutex);
+ base::ScopedLockAssertion lock_assertion(mCvMutex);
+ if (mState == BluetoothStreamState::STANDBY) {
+ return true; // nop, return
+ } else if (mState == BluetoothStreamState::SUSPENDING ||
+ mState == BluetoothStreamState::STARTING) {
+ /* If port is in transient state, give some time to respond */
+ auto state_ = mState;
+ lock.unlock();
+ if (!condWaitState(state_)) {
+ LOG(ERROR) << __func__ << debugMessage() << ", state=" << getState() << " failure";
+ return false;
+ }
+ }
+ }
+
+ bool retval = false;
+ {
+ std::unique_lock lock(mCvMutex);
+ base::ScopedLockAssertion lock_assertion(mCvMutex);
+ if (mState == BluetoothStreamState::STANDBY) {
+ retval = true;
+ } else if (mState == BluetoothStreamState::STARTED) {
+ mState = BluetoothStreamState::SUSPENDING;
+ lock.unlock();
+ if (BluetoothAudioSessionControl::SuspendStream(mSessionType)) {
+ retval = condWaitState(BluetoothStreamState::SUSPENDING);
+ } else {
+ LOG(ERROR) << __func__ << debugMessage() << ", state=" << getState()
+ << " Hal fails";
+ }
+ }
+ }
+
+ if (retval) {
+ LOG(INFO) << __func__ << debugMessage() << ", state=" << getState() << " done";
+ } else {
+ LOG(ERROR) << __func__ << debugMessage() << ", state=" << getState() << " failure";
+ }
+
+ return retval; // false if any failure like timeout
+}
+
+void BluetoothAudioPortAidl::stop() {
+ if (!inUse()) {
+ LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use";
+ return;
+ }
+ std::lock_guard guard(mCvMutex);
+ LOG(VERBOSE) << __func__ << debugMessage() << ", state=" << getState() << " request";
+ if (mState != BluetoothStreamState::DISABLED) {
+ BluetoothAudioSessionControl::StopStream(mSessionType);
+ mState = BluetoothStreamState::DISABLED;
+ }
+ LOG(VERBOSE) << __func__ << debugMessage() << ", state=" << getState() << " done";
+}
+
+size_t BluetoothAudioPortAidlOut::writeData(const void* buffer, size_t bytes) const {
+ if (!buffer) {
+ LOG(ERROR) << __func__ << ": bad input arg";
+ return 0;
+ }
+
+ if (!inUse()) {
+ LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use";
+ return 0;
+ }
+
+ if (!mIsStereoToMono) {
+ return BluetoothAudioSessionControl::OutWritePcmData(mSessionType, buffer, bytes);
+ }
+
+ // WAR to mix the stereo into Mono (16 bits per sample)
+ const size_t write_frames = bytes >> 2;
+ if (write_frames == 0) return 0;
+ auto src = static_cast<const int16_t*>(buffer);
+ std::unique_ptr<int16_t[]> dst{new int16_t[write_frames]};
+ downmix_to_mono_i16_from_stereo_i16(dst.get(), src, write_frames);
+ // a frame is 16 bits, and the size of a mono frame is equal to half a stereo.
+ auto totalWrite = BluetoothAudioSessionControl::OutWritePcmData(mSessionType, dst.get(),
+ write_frames * 2);
+ return totalWrite * 2;
+}
+
+size_t BluetoothAudioPortAidlIn::readData(void* buffer, size_t bytes) const {
+ if (!buffer) {
+ LOG(ERROR) << __func__ << ": bad input arg";
+ return 0;
+ }
+
+ if (!inUse()) {
+ LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use";
+ return 0;
+ }
+
+ return BluetoothAudioSessionControl::InReadPcmData(mSessionType, buffer, bytes);
+}
+
+bool BluetoothAudioPortAidl::getPresentationPosition(
+ PresentationPosition& presentation_position) const {
+ if (!inUse()) {
+ LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use";
+ return false;
+ }
+ bool retval = BluetoothAudioSessionControl::GetPresentationPosition(mSessionType,
+ presentation_position);
+ LOG(VERBOSE) << __func__ << debugMessage() << ", state=" << getState()
+ << presentation_position.toString();
+
+ return retval;
+}
+
+bool BluetoothAudioPortAidl::updateSourceMetadata(const SourceMetadata& source_metadata) const {
+ if (!inUse()) {
+ LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use";
+ return false;
+ }
+ LOG(DEBUG) << __func__ << debugMessage() << ", state=" << getState() << ", "
+ << source_metadata.tracks.size() << " track(s)";
+ if (source_metadata.tracks.size() == 0) return true;
+ return BluetoothAudioSessionControl::UpdateSourceMetadata(mSessionType, source_metadata);
+}
+
+bool BluetoothAudioPortAidl::updateSinkMetadata(const SinkMetadata& sink_metadata) const {
+ if (!inUse()) {
+ LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use";
+ return false;
+ }
+ LOG(DEBUG) << __func__ << debugMessage() << ", state=" << getState() << ", "
+ << sink_metadata.tracks.size() << " track(s)";
+ if (sink_metadata.tracks.size() == 0) return true;
+ return BluetoothAudioSessionControl::UpdateSinkMetadata(mSessionType, sink_metadata);
+}
+
+BluetoothStreamState BluetoothAudioPortAidl::getState() const {
+ return mState;
+}
+
+bool BluetoothAudioPortAidl::setState(BluetoothStreamState state) {
+ if (!inUse()) {
+ LOG(ERROR) << __func__ << ": BluetoothAudioPortAidl is not in use";
+ return false;
+ }
+ std::lock_guard guard(mCvMutex);
+ LOG(DEBUG) << __func__ << ": BluetoothAudioPortAidl old state = " << mState
+ << " new state = " << state;
+ mState = state;
+ return true;
+}
+
+bool BluetoothAudioPortAidl::isA2dp() const {
+ return mSessionType == SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH ||
+ mSessionType == SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH;
+}
+
+bool BluetoothAudioPortAidl::isLeAudio() const {
+ return mSessionType == SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH ||
+ mSessionType == SessionType::LE_AUDIO_SOFTWARE_DECODING_DATAPATH ||
+ mSessionType == SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH ||
+ mSessionType == SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH ||
+ mSessionType == SessionType::LE_AUDIO_BROADCAST_SOFTWARE_ENCODING_DATAPATH ||
+ mSessionType == SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH;
+}
+
+std::string BluetoothAudioPortAidl::debugMessage() const {
+ return StringPrintf(": session_type=%s, cookie=%#hx", toString(mSessionType).c_str(), mCookie);
+}
+
+} // namespace android::bluetooth::audio::aidl
diff --git a/audio/aidl/default/bluetooth/ModuleBluetooth.cpp b/audio/aidl/default/bluetooth/ModuleBluetooth.cpp
new file mode 100644
index 0000000..bfe7ca0
--- /dev/null
+++ b/audio/aidl/default/bluetooth/ModuleBluetooth.cpp
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AHAL_ModuleBluetooth"
+
+#include <android-base/logging.h>
+
+#include "core-impl/ModuleBluetooth.h"
+#include "core-impl/StreamBluetooth.h"
+
+namespace aidl::android::hardware::audio::core {
+
+using aidl::android::hardware::audio::common::SinkMetadata;
+using aidl::android::hardware::audio::common::SourceMetadata;
+using aidl::android::media::audio::common::AudioOffloadInfo;
+using aidl::android::media::audio::common::MicrophoneInfo;
+
+ndk::ScopedAStatus ModuleBluetooth::getBluetoothA2dp(
+ std::shared_ptr<IBluetoothA2dp>* _aidl_return) {
+ if (!mBluetoothA2dp) {
+ auto handle = ndk::SharedRefBase::make<BluetoothA2dp>();
+ handle->registerHandler(std::bind(&ModuleBluetooth::bluetoothParametersUpdated, this));
+ mBluetoothA2dp = handle;
+ }
+ *_aidl_return = mBluetoothA2dp.getInstance();
+ LOG(DEBUG) << __func__ << ": returning instance of IBluetoothA2dp: " << _aidl_return->get();
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus ModuleBluetooth::getBluetoothLe(std::shared_ptr<IBluetoothLe>* _aidl_return) {
+ if (!mBluetoothLe) {
+ auto handle = ndk::SharedRefBase::make<BluetoothLe>();
+ handle->registerHandler(std::bind(&ModuleBluetooth::bluetoothParametersUpdated, this));
+ mBluetoothLe = handle;
+ }
+ *_aidl_return = mBluetoothLe.getInstance();
+ LOG(DEBUG) << __func__ << ": returning instance of IBluetoothLe: " << _aidl_return->get();
+ return ndk::ScopedAStatus::ok();
+}
+
+Module::BtProfileHandles ModuleBluetooth::getBtProfileManagerHandles() {
+ return std::make_tuple(std::weak_ptr<IBluetooth>(), mBluetoothA2dp.getInstance(),
+ mBluetoothLe.getInstance());
+}
+
+ndk::ScopedAStatus ModuleBluetooth::getMicMute(bool* _aidl_return __unused) {
+ LOG(DEBUG) << __func__ << ": is not supported";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus ModuleBluetooth::setMicMute(bool in_mute __unused) {
+ LOG(DEBUG) << __func__ << ": is not supported";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus ModuleBluetooth::createInputStream(
+ StreamContext&& context, const SinkMetadata& sinkMetadata,
+ const std::vector<MicrophoneInfo>& microphones, std::shared_ptr<StreamIn>* result) {
+ return createStreamInstance<StreamInBluetooth>(result, std::move(context), sinkMetadata,
+ microphones, getBtProfileManagerHandles());
+}
+
+ndk::ScopedAStatus ModuleBluetooth::createOutputStream(
+ StreamContext&& context, const SourceMetadata& sourceMetadata,
+ const std::optional<AudioOffloadInfo>& offloadInfo, std::shared_ptr<StreamOut>* result) {
+ return createStreamInstance<StreamOutBluetooth>(result, std::move(context), sourceMetadata,
+ offloadInfo, getBtProfileManagerHandles());
+}
+
+ndk::ScopedAStatus ModuleBluetooth::onMasterMuteChanged(bool) {
+ LOG(DEBUG) << __func__ << ": is not supported";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus ModuleBluetooth::onMasterVolumeChanged(float) {
+ LOG(DEBUG) << __func__ << ": is not supported";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+} // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/bluetooth/StreamBluetooth.cpp b/audio/aidl/default/bluetooth/StreamBluetooth.cpp
new file mode 100644
index 0000000..91a33c2
--- /dev/null
+++ b/audio/aidl/default/bluetooth/StreamBluetooth.cpp
@@ -0,0 +1,338 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AHAL_StreamBluetooth"
+
+#include <Utils.h>
+#include <android-base/logging.h>
+#include <audio_utils/clock.h>
+
+#include "BluetoothAudioSessionControl.h"
+#include "core-impl/StreamBluetooth.h"
+
+namespace aidl::android::hardware::audio::core {
+
+using ::aidl::android::hardware::audio::common::SinkMetadata;
+using ::aidl::android::hardware::audio::common::SourceMetadata;
+using ::aidl::android::hardware::audio::core::VendorParameter;
+using ::aidl::android::hardware::bluetooth::audio::ChannelMode;
+using ::aidl::android::hardware::bluetooth::audio::PcmConfiguration;
+using ::aidl::android::hardware::bluetooth::audio::PresentationPosition;
+using ::aidl::android::media::audio::common::AudioChannelLayout;
+using ::aidl::android::media::audio::common::AudioDevice;
+using ::aidl::android::media::audio::common::AudioDeviceAddress;
+using ::aidl::android::media::audio::common::AudioFormatDescription;
+using ::aidl::android::media::audio::common::AudioFormatType;
+using ::aidl::android::media::audio::common::AudioOffloadInfo;
+using ::aidl::android::media::audio::common::MicrophoneDynamicInfo;
+using ::aidl::android::media::audio::common::MicrophoneInfo;
+using ::android::bluetooth::audio::aidl::BluetoothAudioPortAidl;
+using ::android::bluetooth::audio::aidl::BluetoothAudioPortAidlIn;
+using ::android::bluetooth::audio::aidl::BluetoothAudioPortAidlOut;
+using ::android::bluetooth::audio::aidl::BluetoothStreamState;
+
+constexpr int kBluetoothDefaultInputBufferMs = 20;
+constexpr int kBluetoothDefaultOutputBufferMs = 10;
+// constexpr int kBluetoothSpatializerOutputBufferMs = 10;
+
+size_t getFrameCount(uint64_t durationUs, uint32_t sampleRate) {
+ return (durationUs * sampleRate) / 1000000;
+}
+
+// pcm configuration params are not really used by the module
+StreamBluetooth::StreamBluetooth(StreamContext* context, const Metadata& metadata,
+ Module::BtProfileHandles&& btHandles)
+ : StreamCommonImpl(context, metadata),
+ mSampleRate(getContext().getSampleRate()),
+ mChannelLayout(getContext().getChannelLayout()),
+ mFormat(getContext().getFormat()),
+ mFrameSizeBytes(getContext().getFrameSize()),
+ mIsInput(isInput(metadata)),
+ mBluetoothA2dp(std::move(std::get<Module::BtInterface::BTA2DP>(btHandles))),
+ mBluetoothLe(std::move(std::get<Module::BtInterface::BTLE>(btHandles))) {
+ mPreferredDataIntervalUs =
+ mIsInput ? kBluetoothDefaultInputBufferMs : kBluetoothDefaultOutputBufferMs;
+ mPreferredFrameCount = getFrameCount(mPreferredDataIntervalUs, mSampleRate);
+ mIsInitialized = false;
+ mIsReadyToClose = false;
+}
+
+::android::status_t StreamBluetooth::init() {
+ return ::android::OK; // defering this till we get AudioDeviceDescription
+}
+
+const StreamCommonInterface::ConnectedDevices& StreamBluetooth::getConnectedDevices() const {
+ std::lock_guard guard(mLock);
+ return StreamCommonImpl::getConnectedDevices();
+}
+
+ndk::ScopedAStatus StreamBluetooth::setConnectedDevices(
+ const std::vector<AudioDevice>& connectedDevices) {
+ if (mIsInput && connectedDevices.size() > 1) {
+ LOG(ERROR) << __func__ << ": wrong device size(" << connectedDevices.size()
+ << ") for input stream";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+ }
+ for (const auto& connectedDevice : connectedDevices) {
+ if (connectedDevice.address.getTag() != AudioDeviceAddress::mac) {
+ LOG(ERROR) << __func__ << ": bad device address" << connectedDevice.address.toString();
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ }
+ std::lock_guard guard(mLock);
+ RETURN_STATUS_IF_ERROR(StreamCommonImpl::setConnectedDevices(connectedDevices));
+ mIsInitialized = false; // updated connected device list, need initialization
+ return ndk::ScopedAStatus::ok();
+}
+
+::android::status_t StreamBluetooth::drain(StreamDescriptor::DrainMode) {
+ usleep(1000);
+ return ::android::OK;
+}
+
+::android::status_t StreamBluetooth::flush() {
+ usleep(1000);
+ return ::android::OK;
+}
+
+::android::status_t StreamBluetooth::pause() {
+ return standby();
+}
+
+::android::status_t StreamBluetooth::transfer(void* buffer, size_t frameCount,
+ size_t* actualFrameCount, int32_t* latencyMs) {
+ std::lock_guard guard(mLock);
+ if (!mIsInitialized || mIsReadyToClose) {
+ // 'setConnectedDevices' has been called or stream is ready to close, so no transfers
+ *actualFrameCount = 0;
+ *latencyMs = StreamDescriptor::LATENCY_UNKNOWN;
+ return ::android::OK;
+ }
+ *actualFrameCount = 0;
+ *latencyMs = 0;
+ for (auto proxy : mBtDeviceProxies) {
+ if (!proxy->start()) {
+ LOG(ERROR) << __func__ << ": state = " << proxy->getState() << " failed to start ";
+ return -EIO;
+ }
+ const size_t fc = std::min(frameCount, mPreferredFrameCount);
+ const size_t bytesToTransfer = fc * mFrameSizeBytes;
+ if (mIsInput) {
+ const size_t totalRead = proxy->readData(buffer, bytesToTransfer);
+ *actualFrameCount = std::max(*actualFrameCount, totalRead / mFrameSizeBytes);
+ } else {
+ const size_t totalWrite = proxy->writeData(buffer, bytesToTransfer);
+ *actualFrameCount = std::max(*actualFrameCount, totalWrite / mFrameSizeBytes);
+ }
+ PresentationPosition presentation_position;
+ if (!proxy->getPresentationPosition(presentation_position)) {
+ LOG(ERROR) << __func__ << ": getPresentationPosition returned error ";
+ return ::android::UNKNOWN_ERROR;
+ }
+ *latencyMs =
+ std::max(*latencyMs, (int32_t)(presentation_position.remoteDeviceAudioDelayNanos /
+ NANOS_PER_MILLISECOND));
+ }
+ return ::android::OK;
+}
+
+::android::status_t StreamBluetooth::initialize() {
+ if (!::aidl::android::hardware::bluetooth::audio::BluetoothAudioSession::IsAidlAvailable()) {
+ LOG(ERROR) << __func__ << ": IBluetoothAudioProviderFactory service not available";
+ return ::android::UNKNOWN_ERROR;
+ }
+ if (StreamCommonImpl::getConnectedDevices().empty()) {
+ LOG(ERROR) << __func__ << ", has no connected devices";
+ return ::android::NO_INIT;
+ }
+ // unregister older proxies (if any)
+ for (auto proxy : mBtDeviceProxies) {
+ proxy->stop();
+ proxy->unregisterPort();
+ }
+ mBtDeviceProxies.clear();
+ for (auto it = StreamCommonImpl::getConnectedDevices().begin();
+ it != StreamCommonImpl::getConnectedDevices().end(); ++it) {
+ std::shared_ptr<BluetoothAudioPortAidl> proxy =
+ mIsInput ? std::shared_ptr<BluetoothAudioPortAidl>(
+ std::make_shared<BluetoothAudioPortAidlIn>())
+ : std::shared_ptr<BluetoothAudioPortAidl>(
+ std::make_shared<BluetoothAudioPortAidlOut>());
+ if (proxy->registerPort(it->type)) {
+ LOG(ERROR) << __func__ << ": cannot init HAL";
+ return ::android::UNKNOWN_ERROR;
+ }
+ PcmConfiguration config;
+ if (!proxy->loadAudioConfig(&config)) {
+ LOG(ERROR) << __func__ << ": state=" << proxy->getState()
+ << " failed to get audio config";
+ return ::android::UNKNOWN_ERROR;
+ }
+ // TODO: Ensure minimum duration for spatialized output?
+ // WAR to support Mono / 16 bits per sample as the Bluetooth stack required
+ if (!mIsInput && config.channelMode == ChannelMode::MONO && config.bitsPerSample == 16) {
+ proxy->forcePcmStereoToMono(true);
+ config.channelMode = ChannelMode::STEREO;
+ LOG(INFO) << __func__ << ": force channels = to be AUDIO_CHANNEL_OUT_STEREO";
+ }
+ if (!checkConfigParams(config)) {
+ LOG(ERROR) << __func__ << " checkConfigParams failed";
+ return ::android::UNKNOWN_ERROR;
+ }
+ mBtDeviceProxies.push_back(std::move(proxy));
+ }
+ mIsInitialized = true;
+ return ::android::OK;
+}
+
+bool StreamBluetooth::checkConfigParams(
+ ::aidl::android::hardware::bluetooth::audio::PcmConfiguration& config) {
+ if ((int)mSampleRate != config.sampleRateHz) {
+ LOG(ERROR) << __func__ << ": Sample Rate mismatch, stream val = " << mSampleRate
+ << " hal val = " << config.sampleRateHz;
+ return false;
+ }
+ auto channelCount = aidl::android::hardware::audio::common::getChannelCount(mChannelLayout);
+ if ((config.channelMode == ChannelMode::MONO && channelCount != 1) ||
+ (config.channelMode == ChannelMode::STEREO && channelCount != 2)) {
+ LOG(ERROR) << __func__ << ": Channel count mismatch, stream val = " << channelCount
+ << " hal val = " << toString(config.channelMode);
+ return false;
+ }
+ if (mFormat.type != AudioFormatType::PCM) {
+ LOG(ERROR) << __func__ << ": unexpected format type "
+ << aidl::android::media::audio::common::toString(mFormat.type);
+ return false;
+ }
+ int8_t bps = aidl::android::hardware::audio::common::getPcmSampleSizeInBytes(mFormat.pcm) * 8;
+ if (bps != config.bitsPerSample) {
+ LOG(ERROR) << __func__ << ": bits per sample mismatch, stream val = " << bps
+ << " hal val = " << config.bitsPerSample;
+ return false;
+ }
+ if (config.dataIntervalUs > 0) {
+ mPreferredDataIntervalUs =
+ std::min((int32_t)mPreferredDataIntervalUs, config.dataIntervalUs);
+ mPreferredFrameCount = getFrameCount(mPreferredDataIntervalUs, mSampleRate);
+ }
+ return true;
+}
+
+ndk::ScopedAStatus StreamBluetooth::prepareToClose() {
+ std::lock_guard guard(mLock);
+ mIsReadyToClose = true;
+ return ndk::ScopedAStatus::ok();
+}
+
+::android::status_t StreamBluetooth::standby() {
+ std::lock_guard guard(mLock);
+ if (!mIsInitialized) {
+ if (auto status = initialize(); status != ::android::OK) return status;
+ }
+ for (auto proxy : mBtDeviceProxies) {
+ if (!proxy->suspend()) {
+ LOG(ERROR) << __func__ << ": state = " << proxy->getState() << " failed to stand by ";
+ return -EIO;
+ }
+ }
+ return ::android::OK;
+}
+
+::android::status_t StreamBluetooth::start() {
+ std::lock_guard guard(mLock);
+ if (!mIsInitialized) return initialize();
+ return ::android::OK;
+}
+
+void StreamBluetooth::shutdown() {
+ std::lock_guard guard(mLock);
+ for (auto proxy : mBtDeviceProxies) {
+ proxy->stop();
+ proxy->unregisterPort();
+ }
+ mBtDeviceProxies.clear();
+}
+
+ndk::ScopedAStatus StreamBluetooth::updateMetadataCommon(const Metadata& metadata) {
+ std::lock_guard guard(mLock);
+ if (!mIsInitialized) return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+ bool isOk = true;
+ if (isInput(metadata)) {
+ isOk = mBtDeviceProxies[0]->updateSinkMetadata(std::get<SinkMetadata>(metadata));
+ } else {
+ for (auto proxy : mBtDeviceProxies) {
+ if (!proxy->updateSourceMetadata(std::get<SourceMetadata>(metadata))) isOk = false;
+ }
+ }
+ return isOk ? ndk::ScopedAStatus::ok()
+ : ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus StreamBluetooth::bluetoothParametersUpdated() {
+ if (mIsInput) {
+ LOG(WARNING) << __func__ << ": not handled";
+ return ndk::ScopedAStatus::ok();
+ }
+ auto applyParam = [](const std::shared_ptr<BluetoothAudioPortAidl>& proxy,
+ bool isEnabled) -> bool {
+ if (!isEnabled) {
+ if (proxy->suspend()) return proxy->setState(BluetoothStreamState::DISABLED);
+ return false;
+ }
+ return proxy->standby();
+ };
+ bool hasA2dpParam, enableA2dp;
+ auto btA2dp = mBluetoothA2dp.lock();
+ hasA2dpParam = btA2dp != nullptr && btA2dp->isEnabled(&enableA2dp).isOk();
+ bool hasLeParam, enableLe;
+ auto btLe = mBluetoothLe.lock();
+ hasLeParam = btLe != nullptr && btLe->isEnabled(&enableLe).isOk();
+ std::unique_lock lock(mLock);
+ ::android::base::ScopedLockAssertion lock_assertion(mLock);
+ if (!mIsInitialized) {
+ LOG(WARNING) << __func__ << ": init not done";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+ }
+ for (auto proxy : mBtDeviceProxies) {
+ if ((hasA2dpParam && proxy->isA2dp() && !applyParam(proxy, enableA2dp)) ||
+ (hasLeParam && proxy->isLeAudio() && !applyParam(proxy, enableLe))) {
+ LOG(DEBUG) << __func__ << ": applyParam failed";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+ }
+ }
+ return ndk::ScopedAStatus::ok();
+}
+
+StreamInBluetooth::StreamInBluetooth(StreamContext&& context, const SinkMetadata& sinkMetadata,
+ const std::vector<MicrophoneInfo>& microphones,
+ Module::BtProfileHandles&& btProfileHandles)
+ : StreamIn(std::move(context), microphones),
+ StreamBluetooth(&mContextInstance, sinkMetadata, std::move(btProfileHandles)) {}
+
+ndk::ScopedAStatus StreamInBluetooth::getActiveMicrophones(
+ std::vector<MicrophoneDynamicInfo>* _aidl_return __unused) {
+ LOG(DEBUG) << __func__ << ": not supported";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+StreamOutBluetooth::StreamOutBluetooth(StreamContext&& context,
+ const SourceMetadata& sourceMetadata,
+ const std::optional<AudioOffloadInfo>& offloadInfo,
+ Module::BtProfileHandles&& btProfileHandles)
+ : StreamOut(std::move(context), offloadInfo),
+ StreamBluetooth(&mContextInstance, sourceMetadata, std::move(btProfileHandles)) {}
+
+} // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/config/audioPolicy/engine/api/current.txt b/audio/aidl/default/config/audioPolicy/engine/api/current.txt
index 59574f3..063b05d 100644
--- a/audio/aidl/default/config/audioPolicy/engine/api/current.txt
+++ b/audio/aidl/default/config/audioPolicy/engine/api/current.txt
@@ -209,11 +209,13 @@
public enum UsageEnumType {
method @NonNull public String getRawName();
enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_ALARM;
+ enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_ANNOUNCEMENT;
enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY;
enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE;
enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_ASSISTANCE_SONIFICATION;
enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_ASSISTANT;
enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_CALL_ASSISTANT;
+ enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_EMERGENCY;
enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_GAME;
enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_MEDIA;
enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_NOTIFICATION;
@@ -222,7 +224,9 @@
enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST;
enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_NOTIFICATION_EVENT;
enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE;
+ enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_SAFETY;
enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_UNKNOWN;
+ enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_VEHICLE_STATUS;
enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_VIRTUAL_SOURCE;
enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_VOICE_COMMUNICATION;
enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING;
diff --git a/audio/aidl/default/config/audioPolicy/engine/audio_policy_engine_configuration.xsd b/audio/aidl/default/config/audioPolicy/engine/audio_policy_engine_configuration.xsd
index b58a6c8..40396bb 100644
--- a/audio/aidl/default/config/audioPolicy/engine/audio_policy_engine_configuration.xsd
+++ b/audio/aidl/default/config/audioPolicy/engine/audio_policy_engine_configuration.xsd
@@ -359,6 +359,10 @@
<xs:enumeration value="AUDIO_USAGE_VIRTUAL_SOURCE"/>
<xs:enumeration value="AUDIO_USAGE_ASSISTANT"/>
<xs:enumeration value="AUDIO_USAGE_CALL_ASSISTANT"/>
+ <xs:enumeration value="AUDIO_USAGE_EMERGENCY" />
+ <xs:enumeration value="AUDIO_USAGE_SAFETY" />
+ <xs:enumeration value="AUDIO_USAGE_VEHICLE_STATUS" />
+ <xs:enumeration value="AUDIO_USAGE_ANNOUNCEMENT" />
</xs:restriction>
</xs:simpleType>
diff --git a/audio/aidl/default/include/core-impl/Bluetooth.h b/audio/aidl/default/include/core-impl/Bluetooth.h
index 10e9045..44899bc 100644
--- a/audio/aidl/default/include/core-impl/Bluetooth.h
+++ b/audio/aidl/default/include/core-impl/Bluetooth.h
@@ -22,6 +22,15 @@
namespace aidl::android::hardware::audio::core {
+class ParamChangeHandler {
+ public:
+ ParamChangeHandler() = default;
+ void registerHandler(std::function<ndk::ScopedAStatus()> handler) { mHandler = handler; }
+
+ protected:
+ std::function<ndk::ScopedAStatus()> mHandler = nullptr;
+};
+
class Bluetooth : public BnBluetooth {
public:
Bluetooth();
@@ -34,7 +43,7 @@
HfpConfig mHfpConfig;
};
-class BluetoothA2dp : public BnBluetoothA2dp {
+class BluetoothA2dp : public BnBluetoothA2dp, public ParamChangeHandler {
public:
BluetoothA2dp() = default;
@@ -49,7 +58,7 @@
bool mEnabled = false;
};
-class BluetoothLe : public BnBluetoothLe {
+class BluetoothLe : public BnBluetoothLe, public ParamChangeHandler {
public:
BluetoothLe() = default;
diff --git a/audio/aidl/default/include/core-impl/Configuration.h b/audio/aidl/default/include/core-impl/Configuration.h
index 25bf7af..6277c38 100644
--- a/audio/aidl/default/include/core-impl/Configuration.h
+++ b/audio/aidl/default/include/core-impl/Configuration.h
@@ -47,5 +47,6 @@
std::unique_ptr<Configuration> getRSubmixConfiguration();
std::unique_ptr<Configuration> getStubConfiguration();
std::unique_ptr<Configuration> getUsbConfiguration();
+std::unique_ptr<Configuration> getBluetoothConfiguration();
} // namespace aidl::android::hardware::audio::core::internal
diff --git a/audio/aidl/default/include/core-impl/DevicePortProxy.h b/audio/aidl/default/include/core-impl/DevicePortProxy.h
new file mode 100644
index 0000000..13b8c91
--- /dev/null
+++ b/audio/aidl/default/include/core-impl/DevicePortProxy.h
@@ -0,0 +1,242 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <condition_variable>
+#include <mutex>
+
+#include <android-base/thread_annotations.h>
+
+#include <aidl/android/hardware/audio/common/SinkMetadata.h>
+#include <aidl/android/hardware/audio/common/SourceMetadata.h>
+#include <aidl/android/hardware/bluetooth/audio/BluetoothAudioStatus.h>
+#include <aidl/android/hardware/bluetooth/audio/PcmConfiguration.h>
+#include <aidl/android/hardware/bluetooth/audio/SessionType.h>
+#include <aidl/android/media/audio/common/AudioDeviceDescription.h>
+
+#include "BluetoothAudioSessionControl.h"
+
+namespace android::bluetooth::audio::aidl {
+
+enum class BluetoothStreamState : uint8_t {
+ DISABLED = 0, // This stream is closing or Bluetooth profiles (A2DP/LE) is disabled
+ STANDBY,
+ STARTING,
+ STARTED,
+ SUSPENDING,
+ UNKNOWN,
+};
+
+std::ostream& operator<<(std::ostream& os, const BluetoothStreamState& state);
+
+/**
+ * Proxy for Bluetooth Audio HW Module to communicate with Bluetooth Audio
+ * Session Control. All methods are not thread safe, so users must acquire a
+ * lock. Note: currently, getState() of DevicePortProxy is only used for
+ * verbose logging, it is not locked, so the state may not be synchronized.
+ */
+class BluetoothAudioPort {
+ public:
+ BluetoothAudioPort() = default;
+ virtual ~BluetoothAudioPort() = default;
+
+ /**
+ * Fetch output control / data path of BluetoothAudioPort and setup
+ * callbacks into BluetoothAudioProvider. If registerPort() returns false, the audio
+ * HAL must delete this BluetoothAudioPort and return EINVAL to caller
+ */
+ virtual bool registerPort(
+ const ::aidl::android::media::audio::common::AudioDeviceDescription&) = 0;
+
+ /**
+ * Unregister this BluetoothAudioPort from BluetoothAudioSessionControl.
+ * Audio HAL must delete this BluetoothAudioPort after calling this.
+ */
+ virtual void unregisterPort() = 0;
+
+ /**
+ * When the Audio framework / HAL tries to query audio config about format,
+ * channel mask and sample rate, it uses this function to fetch from the
+ * Bluetooth stack
+ */
+ virtual bool loadAudioConfig(
+ ::aidl::android::hardware::bluetooth::audio::PcmConfiguration*) const = 0;
+
+ /**
+ * WAR to support Mono mode / 16 bits per sample
+ */
+ virtual void forcePcmStereoToMono(bool) = 0;
+
+ /**
+ * When the Audio framework / HAL wants to change the stream state, it invokes
+ * these 4 functions to control the Bluetooth stack (Audio Control Path).
+ * Note: standby(), start() and suspend() will return true when there are no errors.
+
+ * Called by Audio framework / HAL to change the state to stand by. When A2DP/LE profile is
+ * disabled, the port is first set to STANDBY by calling suspend and then mState is set to
+ * DISABLED. To reset the state back to STANDBY this method is called.
+ */
+ virtual bool standby() = 0;
+
+ /**
+ * Called by Audio framework / HAL to start the stream
+ */
+ virtual bool start() = 0;
+
+ /**
+ * Called by Audio framework / HAL to suspend the stream
+ */
+ virtual bool suspend() = 0;
+
+ /**
+ * Called by Audio framework / HAL to stop the stream
+ */
+ virtual void stop() = 0;
+
+ /**
+ * Called by the Audio framework / HAL to fetch information about audio frames
+ * presented to an external sink, or frames presented fror an internal sink
+ */
+ virtual bool getPresentationPosition(
+ ::aidl::android::hardware::bluetooth::audio::PresentationPosition&) const = 0;
+
+ /**
+ * Called by the Audio framework / HAL when the metadata of the stream's
+ * source has been changed.
+ */
+ virtual bool updateSourceMetadata(
+ const ::aidl::android::hardware::audio::common::SourceMetadata&) const {
+ return false;
+ }
+
+ /**
+ * Called by the Audio framework / HAL when the metadata of the stream's
+ * sink has been changed.
+ */
+ virtual bool updateSinkMetadata(
+ const ::aidl::android::hardware::audio::common::SinkMetadata&) const {
+ return false;
+ }
+
+ /**
+ * Return the current BluetoothStreamState
+ */
+ virtual BluetoothStreamState getState() const = 0;
+
+ /**
+ * Set the current BluetoothStreamState
+ */
+ virtual bool setState(BluetoothStreamState) = 0;
+
+ virtual bool isA2dp() const = 0;
+
+ virtual bool isLeAudio() const = 0;
+
+ virtual bool getPreferredDataIntervalUs(size_t*) const = 0;
+
+ virtual size_t writeData(const void*, size_t) const { return 0; }
+
+ virtual size_t readData(void*, size_t) const { return 0; }
+};
+
+class BluetoothAudioPortAidl : public BluetoothAudioPort {
+ public:
+ BluetoothAudioPortAidl();
+ virtual ~BluetoothAudioPortAidl();
+
+ bool registerPort(const ::aidl::android::media::audio::common::AudioDeviceDescription&
+ description) override;
+
+ void unregisterPort() override;
+
+ bool loadAudioConfig(::aidl::android::hardware::bluetooth::audio::PcmConfiguration* audio_cfg)
+ const override;
+
+ void forcePcmStereoToMono(bool force) override { mIsStereoToMono = force; }
+
+ bool standby() override;
+ bool start() override;
+ bool suspend() override;
+ void stop() override;
+
+ bool getPresentationPosition(::aidl::android::hardware::bluetooth::audio::PresentationPosition&
+ presentation_position) const override;
+
+ bool updateSourceMetadata(const ::aidl::android::hardware::audio::common::SourceMetadata&
+ sourceMetadata) const override;
+
+ bool updateSinkMetadata(const ::aidl::android::hardware::audio::common::SinkMetadata&
+ sinkMetadata) const override;
+
+ /**
+ * Return the current BluetoothStreamState
+ * Note: This method is used for logging, does not lock, so value returned may not be latest
+ */
+ BluetoothStreamState getState() const override NO_THREAD_SAFETY_ANALYSIS;
+
+ bool setState(BluetoothStreamState state) override;
+
+ bool isA2dp() const override;
+
+ bool isLeAudio() const override;
+
+ bool getPreferredDataIntervalUs(size_t* interval_us) const override;
+
+ protected:
+ uint16_t mCookie;
+ BluetoothStreamState mState GUARDED_BY(mCvMutex);
+ ::aidl::android::hardware::bluetooth::audio::SessionType mSessionType;
+ // WR to support Mono: True if fetching Stereo and mixing into Mono
+ bool mIsStereoToMono = false;
+
+ bool inUse() const;
+
+ std::string debugMessage() const;
+
+ private:
+ // start()/suspend() report state change status via callback. Wait until kMaxWaitingTimeMs or a
+ // state change after a call to start()/suspend() and analyse the returned status. Below mutex,
+ // conditional variable serves this purpose.
+ mutable std::mutex mCvMutex;
+ std::condition_variable mInternalCv GUARDED_BY(mCvMutex);
+
+ // Check and initialize session type for |devices| If failed, this
+ // BluetoothAudioPortAidl is not initialized and must be deleted.
+ bool initSessionType(
+ const ::aidl::android::media::audio::common::AudioDeviceDescription& description);
+
+ bool condWaitState(BluetoothStreamState state);
+
+ void controlResultHandler(
+ uint16_t cookie,
+ const ::aidl::android::hardware::bluetooth::audio::BluetoothAudioStatus& status);
+ void sessionChangedHandler(uint16_t cookie);
+};
+
+class BluetoothAudioPortAidlOut : public BluetoothAudioPortAidl {
+ public:
+ // The audio data path to the Bluetooth stack (Software encoding)
+ size_t writeData(const void* buffer, size_t bytes) const override;
+};
+
+class BluetoothAudioPortAidlIn : public BluetoothAudioPortAidl {
+ public:
+ // The audio data path from the Bluetooth stack (Software decoded)
+ size_t readData(void* buffer, size_t bytes) const override;
+};
+
+} // namespace android::bluetooth::audio::aidl
\ No newline at end of file
diff --git a/audio/aidl/default/include/core-impl/Module.h b/audio/aidl/default/include/core-impl/Module.h
index 539221d..fb3eef2 100644
--- a/audio/aidl/default/include/core-impl/Module.h
+++ b/audio/aidl/default/include/core-impl/Module.h
@@ -33,12 +33,17 @@
public:
// This value is used for all AudioPatches and reported by all streams.
static constexpr int32_t kLatencyMs = 10;
- enum Type : int { DEFAULT, R_SUBMIX, STUB, USB };
+ enum Type : int { DEFAULT, R_SUBMIX, STUB, USB, BLUETOOTH };
+ enum BtInterface : int { BTCONF, BTA2DP, BTLE };
static std::shared_ptr<Module> createInstance(Type type);
explicit Module(Type type) : mType(type) {}
+ typedef std::tuple<std::weak_ptr<IBluetooth>, std::weak_ptr<IBluetoothA2dp>,
+ std::weak_ptr<IBluetoothLe>>
+ BtProfileHandles;
+
protected:
// The vendor extension done via inheritance can override interface methods and augment
// a call to the base implementation.
@@ -185,6 +190,7 @@
virtual std::unique_ptr<internal::Configuration> initializeConfig();
// Utility and helper functions accessible to subclasses.
+ ndk::ScopedAStatus bluetoothParametersUpdated();
void cleanUpPatch(int32_t patchId);
ndk::ScopedAStatus createStreamContext(
int32_t in_portConfigId, int64_t in_bufferSizeFrames,
@@ -196,6 +202,7 @@
std::set<int32_t> findConnectedPortConfigIds(int32_t portConfigId);
ndk::ScopedAStatus findPortIdForNewStream(
int32_t in_portConfigId, ::aidl::android::media::audio::common::AudioPort** port);
+ virtual BtProfileHandles getBtProfileManagerHandles();
internal::Configuration& getConfig();
const ConnectedDevicePorts& getConnectedDevicePorts() const { return mConnectedDevicePorts; }
bool getMasterMute() const { return mMasterMute; }
diff --git a/audio/aidl/default/include/core-impl/ModuleBluetooth.h b/audio/aidl/default/include/core-impl/ModuleBluetooth.h
new file mode 100644
index 0000000..68b4e6b
--- /dev/null
+++ b/audio/aidl/default/include/core-impl/ModuleBluetooth.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "core-impl/Bluetooth.h"
+#include "core-impl/Module.h"
+
+namespace aidl::android::hardware::audio::core {
+
+class ModuleBluetooth final : public Module {
+ public:
+ ModuleBluetooth() : Module(Type::BLUETOOTH) {}
+
+ private:
+ BtProfileHandles getBtProfileManagerHandles() override;
+
+ ndk::ScopedAStatus getBluetoothA2dp(std::shared_ptr<IBluetoothA2dp>* _aidl_return) override;
+ ndk::ScopedAStatus getBluetoothLe(std::shared_ptr<IBluetoothLe>* _aidl_return) override;
+ ndk::ScopedAStatus getMicMute(bool* _aidl_return) override;
+ ndk::ScopedAStatus setMicMute(bool in_mute) override;
+
+ ndk::ScopedAStatus createInputStream(
+ StreamContext&& context,
+ const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
+ const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones,
+ std::shared_ptr<StreamIn>* result) override;
+ ndk::ScopedAStatus createOutputStream(
+ StreamContext&& context,
+ const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
+ const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
+ offloadInfo,
+ std::shared_ptr<StreamOut>* result) override;
+ ndk::ScopedAStatus onMasterMuteChanged(bool mute) override;
+ ndk::ScopedAStatus onMasterVolumeChanged(float volume) override;
+
+ ChildInterface<IBluetoothA2dp> mBluetoothA2dp;
+ ChildInterface<IBluetoothLe> mBluetoothLe;
+};
+
+} // namespace aidl::android::hardware::audio::core
\ No newline at end of file
diff --git a/audio/aidl/default/include/core-impl/Stream.h b/audio/aidl/default/include/core-impl/Stream.h
index fa2b760..a02655f 100644
--- a/audio/aidl/default/include/core-impl/Stream.h
+++ b/audio/aidl/default/include/core-impl/Stream.h
@@ -195,10 +195,10 @@
virtual ::android::status_t start() = 0;
virtual ::android::status_t transfer(void* buffer, size_t frameCount, size_t* actualFrameCount,
int32_t* latencyMs) = 0;
- // No need to implement 'getPosition' unless the driver can provide more precise
+ // No need to implement 'refinePosition' unless the driver can provide more precise
// data than just total frame count. For example, the driver may correctly account
// for any intermediate buffers.
- virtual ::android::status_t getPosition(StreamDescriptor::Position* /*position*/) {
+ virtual ::android::status_t refinePosition(StreamDescriptor::Position* /*position*/) {
return ::android::OK;
}
virtual void shutdown() = 0; // This function is only called once.
@@ -262,6 +262,7 @@
virtual void setIsConnected(bool isConnected) = 0;
virtual StreamDescriptor::State setClosed() = 0;
virtual bool start() = 0;
+ virtual pid_t getTid() = 0;
virtual void stop() = 0;
};
@@ -277,8 +278,10 @@
void setIsConnected(bool isConnected) override { WorkerImpl::setIsConnected(isConnected); }
StreamDescriptor::State setClosed() override { return WorkerImpl::setClosed(); }
bool start() override {
- return WorkerImpl::start(WorkerImpl::kThreadName, ANDROID_PRIORITY_AUDIO);
+ // This is an "audio service thread," must have elevated priority.
+ return WorkerImpl::start(WorkerImpl::kThreadName, ANDROID_PRIORITY_URGENT_AUDIO);
}
+ pid_t getTid() override { return WorkerImpl::getTid(); }
void stop() override { return WorkerImpl::stop(); }
};
@@ -354,6 +357,7 @@
virtual const ConnectedDevices& getConnectedDevices() const = 0;
virtual ndk::ScopedAStatus setConnectedDevices(
const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) = 0;
+ virtual ndk::ScopedAStatus bluetoothParametersUpdated() = 0;
};
// This is equivalent to automatically generated 'IStreamCommonDelegator' but uses
@@ -454,6 +458,7 @@
ndk::ScopedAStatus setConnectedDevices(
const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices)
override;
+ ndk::ScopedAStatus bluetoothParametersUpdated() override;
protected:
static StreamWorkerInterface::CreateInstance getDefaultInWorkerCreator() {
@@ -505,10 +510,21 @@
StreamIn(StreamContext&& context,
const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones);
- StreamContext mContext;
+ StreamContext mContextInstance;
const std::map<::aidl::android::media::audio::common::AudioDevice, std::string> mMicrophones;
};
+class StreamInHwGainHelper {
+ protected:
+ explicit StreamInHwGainHelper(const StreamContext* context);
+
+ ndk::ScopedAStatus getHwGainImpl(std::vector<float>* _aidl_return);
+ ndk::ScopedAStatus setHwGainImpl(const std::vector<float>& in_channelGains);
+
+ const size_t mChannelCount;
+ std::vector<float> mHwGains;
+};
+
class StreamOut : virtual public StreamCommonInterface, public BnStreamOut {
protected:
void defaultOnClose();
@@ -550,11 +566,22 @@
const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
offloadInfo);
- StreamContext mContext;
+ StreamContext mContextInstance;
const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo> mOffloadInfo;
std::optional<::aidl::android::hardware::audio::common::AudioOffloadMetadata> mOffloadMetadata;
};
+class StreamOutHwVolumeHelper {
+ protected:
+ explicit StreamOutHwVolumeHelper(const StreamContext* context);
+
+ ndk::ScopedAStatus getHwVolumeImpl(std::vector<float>* _aidl_return);
+ ndk::ScopedAStatus setHwVolumeImpl(const std::vector<float>& in_channelVolumes);
+
+ const size_t mChannelCount;
+ std::vector<float> mHwVolumes;
+};
+
// The recommended way to create a stream instance.
// 'StreamImpl' is the concrete stream implementation, 'StreamInOrOut' is either 'StreamIn' or
// 'StreamOut', the rest are the arguments forwarded to the constructor of 'StreamImpl'.
@@ -584,6 +611,11 @@
if (s) return s->setConnectedDevices(devices);
return ndk::ScopedAStatus::ok();
}
+ ndk::ScopedAStatus bluetoothParametersUpdated() {
+ auto s = mStream.lock();
+ if (s) return s->bluetoothParametersUpdated();
+ return ndk::ScopedAStatus::ok();
+ }
private:
std::weak_ptr<StreamCommonInterface> mStream;
@@ -612,6 +644,14 @@
}
return ndk::ScopedAStatus::ok();
}
+ ndk::ScopedAStatus bluetoothParametersUpdated() {
+ bool isOk = true;
+ for (auto& it : mStreams) {
+ if (!it.second.bluetoothParametersUpdated().isOk()) isOk = false;
+ }
+ return isOk ? ndk::ScopedAStatus::ok()
+ : ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+ }
private:
// Maps port ids and port config ids to streams. Multimap because a port
diff --git a/audio/aidl/default/include/core-impl/StreamAlsa.h b/audio/aidl/default/include/core-impl/StreamAlsa.h
index f98a922..2c3b284 100644
--- a/audio/aidl/default/include/core-impl/StreamAlsa.h
+++ b/audio/aidl/default/include/core-impl/StreamAlsa.h
@@ -41,14 +41,16 @@
::android::status_t start() override;
::android::status_t transfer(void* buffer, size_t frameCount, size_t* actualFrameCount,
int32_t* latencyMs) override;
- ::android::status_t getPosition(StreamDescriptor::Position* position) override;
+ ::android::status_t refinePosition(StreamDescriptor::Position* position) override;
void shutdown() override;
protected:
// Called from 'start' to initialize 'mAlsaDeviceProxies', the vector must be non-empty.
virtual std::vector<alsa::DeviceProfile> getDeviceProfiles() = 0;
+ const size_t mBufferSizeFrames;
const size_t mFrameSizeBytes;
+ const int mSampleRate;
const bool mIsInput;
const std::optional<struct pcm_config> mConfig;
const int mReadWriteRetries;
diff --git a/audio/aidl/default/include/core-impl/StreamBluetooth.h b/audio/aidl/default/include/core-impl/StreamBluetooth.h
new file mode 100644
index 0000000..c2f8c1d
--- /dev/null
+++ b/audio/aidl/default/include/core-impl/StreamBluetooth.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <mutex>
+#include <vector>
+
+#include <aidl/android/hardware/audio/core/IBluetooth.h>
+#include <aidl/android/hardware/audio/core/IBluetoothA2dp.h>
+#include <aidl/android/hardware/audio/core/IBluetoothLe.h>
+
+#include "core-impl/DevicePortProxy.h"
+#include "core-impl/Module.h"
+#include "core-impl/Stream.h"
+
+namespace aidl::android::hardware::audio::core {
+
+class StreamBluetooth : public StreamCommonImpl {
+ public:
+ StreamBluetooth(StreamContext* context, const Metadata& metadata,
+ Module::BtProfileHandles&& btHandles);
+ // Methods of 'DriverInterface'.
+ ::android::status_t init() override;
+ ::android::status_t drain(StreamDescriptor::DrainMode) override;
+ ::android::status_t flush() override;
+ ::android::status_t pause() override;
+ ::android::status_t standby() override;
+ ::android::status_t start() override;
+ ::android::status_t transfer(void* buffer, size_t frameCount, size_t* actualFrameCount,
+ int32_t* latencyMs) override;
+ void shutdown() override;
+
+ // Overridden methods of 'StreamCommonImpl', called on a Binder thread.
+ ndk::ScopedAStatus updateMetadataCommon(const Metadata& metadata) override;
+ ndk::ScopedAStatus prepareToClose() override;
+ const ConnectedDevices& getConnectedDevices() const override;
+ ndk::ScopedAStatus setConnectedDevices(const ConnectedDevices& devices) override;
+ ndk::ScopedAStatus bluetoothParametersUpdated() override;
+
+ private:
+ // Audio Pcm Config
+ const uint32_t mSampleRate;
+ const ::aidl::android::media::audio::common::AudioChannelLayout mChannelLayout;
+ const ::aidl::android::media::audio::common::AudioFormatDescription mFormat;
+ const size_t mFrameSizeBytes;
+ const bool mIsInput;
+ const std::weak_ptr<IBluetoothA2dp> mBluetoothA2dp;
+ const std::weak_ptr<IBluetoothLe> mBluetoothLe;
+ size_t mPreferredDataIntervalUs;
+ size_t mPreferredFrameCount;
+
+ mutable std::mutex mLock;
+ bool mIsInitialized GUARDED_BY(mLock);
+ bool mIsReadyToClose GUARDED_BY(mLock);
+ std::vector<std::shared_ptr<::android::bluetooth::audio::aidl::BluetoothAudioPortAidl>>
+ mBtDeviceProxies GUARDED_BY(mLock);
+
+ ::android::status_t initialize() REQUIRES(mLock);
+ bool checkConfigParams(::aidl::android::hardware::bluetooth::audio::PcmConfiguration& config);
+};
+
+class StreamInBluetooth final : public StreamIn, public StreamBluetooth {
+ public:
+ friend class ndk::SharedRefBase;
+ StreamInBluetooth(
+ StreamContext&& context,
+ const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
+ const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones,
+ Module::BtProfileHandles&& btHandles);
+
+ private:
+ void onClose(StreamDescriptor::State) override { defaultOnClose(); }
+ ndk::ScopedAStatus getActiveMicrophones(
+ std::vector<::aidl::android::media::audio::common::MicrophoneDynamicInfo>* _aidl_return)
+ override;
+};
+
+class StreamOutBluetooth final : public StreamOut, public StreamBluetooth {
+ public:
+ friend class ndk::SharedRefBase;
+ StreamOutBluetooth(
+ StreamContext&& context,
+ const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
+ const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
+ offloadInfo,
+ Module::BtProfileHandles&& btHandles);
+
+ private:
+ void onClose(StreamDescriptor::State) override { defaultOnClose(); }
+};
+
+} // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/include/core-impl/StreamPrimary.h b/audio/aidl/default/include/core-impl/StreamPrimary.h
new file mode 100644
index 0000000..b3ddd0b
--- /dev/null
+++ b/audio/aidl/default/include/core-impl/StreamPrimary.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <vector>
+
+#include "StreamAlsa.h"
+#include "StreamSwitcher.h"
+
+namespace aidl::android::hardware::audio::core {
+
+class StreamPrimary : public StreamAlsa {
+ public:
+ StreamPrimary(StreamContext* context, const Metadata& metadata);
+
+ protected:
+ std::vector<alsa::DeviceProfile> getDeviceProfiles() override;
+
+ const bool mIsInput;
+};
+
+class StreamInPrimary final : public StreamIn, public StreamSwitcher, public StreamInHwGainHelper {
+ public:
+ friend class ndk::SharedRefBase;
+ StreamInPrimary(
+ StreamContext&& context,
+ const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
+ const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones);
+
+ private:
+ static bool useStubStream(const ::aidl::android::media::audio::common::AudioDevice& device);
+
+ DeviceSwitchBehavior switchCurrentStream(
+ const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices)
+ override;
+ std::unique_ptr<StreamCommonInterfaceEx> createNewStream(
+ const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices,
+ StreamContext* context, const Metadata& metadata) override;
+ void onClose(StreamDescriptor::State) override { defaultOnClose(); }
+
+ ndk::ScopedAStatus getHwGain(std::vector<float>* _aidl_return) override;
+ ndk::ScopedAStatus setHwGain(const std::vector<float>& in_channelGains) override;
+};
+
+class StreamOutPrimary final : public StreamOut,
+ public StreamSwitcher,
+ public StreamOutHwVolumeHelper {
+ public:
+ friend class ndk::SharedRefBase;
+ StreamOutPrimary(StreamContext&& context,
+ const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
+ const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
+ offloadInfo);
+
+ private:
+ static bool useStubStream(const ::aidl::android::media::audio::common::AudioDevice& device);
+
+ DeviceSwitchBehavior switchCurrentStream(
+ const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices)
+ override;
+ std::unique_ptr<StreamCommonInterfaceEx> createNewStream(
+ const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices,
+ StreamContext* context, const Metadata& metadata) override;
+ void onClose(StreamDescriptor::State) override { defaultOnClose(); }
+
+ ndk::ScopedAStatus getHwVolume(std::vector<float>* _aidl_return) override;
+ ndk::ScopedAStatus setHwVolume(const std::vector<float>& in_channelVolumes) override;
+};
+
+} // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h b/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h
index 74854c6..94404a1 100644
--- a/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h
+++ b/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h
@@ -39,7 +39,7 @@
::android::status_t start() override;
::android::status_t transfer(void* buffer, size_t frameCount, size_t* actualFrameCount,
int32_t* latencyMs) override;
- ::android::status_t getPosition(StreamDescriptor::Position* position) override;
+ ::android::status_t refinePosition(StreamDescriptor::Position* position) override;
void shutdown() override;
// Overridden methods of 'StreamCommonImpl', called on a Binder thread.
diff --git a/audio/aidl/default/include/core-impl/StreamStub.h b/audio/aidl/default/include/core-impl/StreamStub.h
index a8a3fc4..3857e0e 100644
--- a/audio/aidl/default/include/core-impl/StreamStub.h
+++ b/audio/aidl/default/include/core-impl/StreamStub.h
@@ -35,6 +35,7 @@
void shutdown() override;
private:
+ const size_t mBufferSizeFrames;
const size_t mFrameSizeBytes;
const int mSampleRate;
const bool mIsAsynchronous;
diff --git a/audio/aidl/default/include/core-impl/StreamSwitcher.h b/audio/aidl/default/include/core-impl/StreamSwitcher.h
index 2cb8470..5764ad6 100644
--- a/audio/aidl/default/include/core-impl/StreamSwitcher.h
+++ b/audio/aidl/default/include/core-impl/StreamSwitcher.h
@@ -20,7 +20,7 @@
namespace aidl::android::hardware::audio::core {
-// 'StreamSwitcher' is implementation of 'StreamCommonInterface' which allows
+// 'StreamSwitcher' is an implementation of 'StreamCommonInterface' which allows
// dynamically switching the underlying stream implementation based on currently
// connected devices. This is achieved by replacing inheritance from
// 'StreamCommonImpl' with owning an instance of it. StreamSwitcher must be
@@ -129,6 +129,7 @@
ndk::ScopedAStatus setConnectedDevices(
const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices)
override;
+ ndk::ScopedAStatus bluetoothParametersUpdated() override;
protected:
// Since switching a stream requires closing down the current stream, StreamSwitcher
@@ -187,6 +188,7 @@
std::optional<int32_t> mHwAvSyncId;
std::vector<VndParam> mMissedParameters;
std::vector<std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>> mEffects;
+ bool mBluetoothParametersUpdated = false;
};
} // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/include/core-impl/StreamUsb.h b/audio/aidl/default/include/core-impl/StreamUsb.h
index 74e30ff..608f27d 100644
--- a/audio/aidl/default/include/core-impl/StreamUsb.h
+++ b/audio/aidl/default/include/core-impl/StreamUsb.h
@@ -59,7 +59,7 @@
override;
};
-class StreamOutUsb final : public StreamOut, public StreamUsb {
+class StreamOutUsb final : public StreamOut, public StreamUsb, public StreamOutHwVolumeHelper {
public:
friend class ndk::SharedRefBase;
StreamOutUsb(StreamContext&& context,
@@ -71,9 +71,6 @@
void onClose(StreamDescriptor::State) override { defaultOnClose(); }
ndk::ScopedAStatus getHwVolume(std::vector<float>* _aidl_return) override;
ndk::ScopedAStatus setHwVolume(const std::vector<float>& in_channelVolumes) override;
-
- const int mChannelCount;
- std::vector<float> mHwVolumes;
};
} // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/main.cpp b/audio/aidl/default/main.cpp
index 93fb366..a0c0fab 100644
--- a/audio/aidl/default/main.cpp
+++ b/audio/aidl/default/main.cpp
@@ -65,7 +65,8 @@
return std::make_pair(module, moduleBinder);
};
auto modules = {createModule(Module::Type::DEFAULT), createModule(Module::Type::R_SUBMIX),
- createModule(Module::Type::USB), createModule(Module::Type::STUB)};
+ createModule(Module::Type::USB), createModule(Module::Type::STUB),
+ createModule(Module::Type::BLUETOOTH)};
(void)modules;
ABinderProcess_joinThreadPool();
diff --git a/audio/aidl/default/primary/PrimaryMixer.cpp b/audio/aidl/default/primary/PrimaryMixer.cpp
new file mode 100644
index 0000000..577d010
--- /dev/null
+++ b/audio/aidl/default/primary/PrimaryMixer.cpp
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AHAL_PrimaryMixer"
+
+#include "PrimaryMixer.h"
+
+namespace aidl::android::hardware::audio::core::primary {
+
+// static
+PrimaryMixer& PrimaryMixer::getInstance() {
+ static PrimaryMixer gInstance;
+ return gInstance;
+}
+
+} // namespace aidl::android::hardware::audio::core::primary
diff --git a/audio/aidl/default/primary/PrimaryMixer.h b/audio/aidl/default/primary/PrimaryMixer.h
new file mode 100644
index 0000000..3806428
--- /dev/null
+++ b/audio/aidl/default/primary/PrimaryMixer.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <map>
+#include <memory>
+#include <mutex>
+#include <vector>
+
+#include <android-base/thread_annotations.h>
+#include <android/binder_auto_utils.h>
+
+#include "alsa/Mixer.h"
+
+namespace aidl::android::hardware::audio::core::primary {
+
+class PrimaryMixer : public alsa::Mixer {
+ public:
+ static constexpr int kAlsaCard = 0;
+ static constexpr int kAlsaDevice = 0;
+
+ static PrimaryMixer& getInstance();
+
+ private:
+ PrimaryMixer() : alsa::Mixer(kAlsaCard) {}
+};
+
+} // namespace aidl::android::hardware::audio::core::primary
diff --git a/audio/aidl/default/primary/StreamPrimary.cpp b/audio/aidl/default/primary/StreamPrimary.cpp
new file mode 100644
index 0000000..e01be8a
--- /dev/null
+++ b/audio/aidl/default/primary/StreamPrimary.cpp
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <limits>
+
+#define LOG_TAG "AHAL_StreamPrimary"
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <error/expected_utils.h>
+
+#include "PrimaryMixer.h"
+#include "core-impl/StreamPrimary.h"
+#include "core-impl/StreamStub.h"
+
+using aidl::android::hardware::audio::common::SinkMetadata;
+using aidl::android::hardware::audio::common::SourceMetadata;
+using aidl::android::media::audio::common::AudioDevice;
+using aidl::android::media::audio::common::AudioDeviceDescription;
+using aidl::android::media::audio::common::AudioDeviceType;
+using aidl::android::media::audio::common::AudioOffloadInfo;
+using aidl::android::media::audio::common::MicrophoneInfo;
+using android::base::GetBoolProperty;
+
+namespace aidl::android::hardware::audio::core {
+
+StreamPrimary::StreamPrimary(StreamContext* context, const Metadata& metadata)
+ : StreamAlsa(context, metadata, 3 /*readWriteRetries*/), mIsInput(isInput(metadata)) {}
+
+std::vector<alsa::DeviceProfile> StreamPrimary::getDeviceProfiles() {
+ static const std::vector<alsa::DeviceProfile> kBuiltInSource{
+ alsa::DeviceProfile{.card = primary::PrimaryMixer::kAlsaCard,
+ .device = primary::PrimaryMixer::kAlsaDevice,
+ .direction = PCM_IN,
+ .isExternal = false}};
+ static const std::vector<alsa::DeviceProfile> kBuiltInSink{
+ alsa::DeviceProfile{.card = primary::PrimaryMixer::kAlsaCard,
+ .device = primary::PrimaryMixer::kAlsaDevice,
+ .direction = PCM_OUT,
+ .isExternal = false}};
+ return mIsInput ? kBuiltInSource : kBuiltInSink;
+}
+
+StreamInPrimary::StreamInPrimary(StreamContext&& context, const SinkMetadata& sinkMetadata,
+ const std::vector<MicrophoneInfo>& microphones)
+ : StreamIn(std::move(context), microphones),
+ StreamSwitcher(&mContextInstance, sinkMetadata),
+ StreamInHwGainHelper(&mContextInstance) {}
+
+bool StreamInPrimary::useStubStream(const AudioDevice& device) {
+ static const bool kSimulateInput =
+ GetBoolProperty("ro.boot.audio.tinyalsa.simulate_input", false);
+ return kSimulateInput || device.type.type == AudioDeviceType::IN_TELEPHONY_RX ||
+ device.type.type == AudioDeviceType::IN_FM_TUNER ||
+ device.type.connection == AudioDeviceDescription::CONNECTION_BUS;
+}
+
+StreamSwitcher::DeviceSwitchBehavior StreamInPrimary::switchCurrentStream(
+ const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) {
+ LOG(DEBUG) << __func__;
+ if (devices.size() > 1) {
+ LOG(ERROR) << __func__ << ": primary stream can only be connected to one device, got: "
+ << devices.size();
+ return DeviceSwitchBehavior::UNSUPPORTED_DEVICES;
+ }
+ if (devices.empty() || useStubStream(devices[0]) == isStubStream()) {
+ return DeviceSwitchBehavior::USE_CURRENT_STREAM;
+ }
+ return DeviceSwitchBehavior::CREATE_NEW_STREAM;
+}
+
+std::unique_ptr<StreamCommonInterfaceEx> StreamInPrimary::createNewStream(
+ const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices,
+ StreamContext* context, const Metadata& metadata) {
+ if (devices.empty()) {
+ LOG(FATAL) << __func__ << ": called with empty devices"; // see 'switchCurrentStream'
+ }
+ if (useStubStream(devices[0])) {
+ return std::unique_ptr<StreamCommonInterfaceEx>(
+ new InnerStreamWrapper<StreamStub>(context, metadata));
+ }
+ return std::unique_ptr<StreamCommonInterfaceEx>(
+ new InnerStreamWrapper<StreamPrimary>(context, metadata));
+}
+
+ndk::ScopedAStatus StreamInPrimary::getHwGain(std::vector<float>* _aidl_return) {
+ if (isStubStream()) {
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+ }
+ return getHwGainImpl(_aidl_return);
+}
+
+ndk::ScopedAStatus StreamInPrimary::setHwGain(const std::vector<float>& in_channelGains) {
+ if (isStubStream()) {
+ LOG(DEBUG) << __func__ << ": gains " << ::android::internal::ToString(in_channelGains);
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+ }
+ auto currentGains = mHwGains;
+ RETURN_STATUS_IF_ERROR(setHwGainImpl(in_channelGains));
+ if (in_channelGains.size() < 1) {
+ LOG(FATAL) << __func__ << ": unexpected gain vector size: " << in_channelGains.size();
+ }
+ if (auto status = primary::PrimaryMixer::getInstance().setMicGain(in_channelGains[0]);
+ !status.isOk()) {
+ mHwGains = currentGains;
+ return status;
+ }
+ return ndk::ScopedAStatus::ok();
+}
+
+StreamOutPrimary::StreamOutPrimary(StreamContext&& context, const SourceMetadata& sourceMetadata,
+ const std::optional<AudioOffloadInfo>& offloadInfo)
+ : StreamOut(std::move(context), offloadInfo),
+ StreamSwitcher(&mContextInstance, sourceMetadata),
+ StreamOutHwVolumeHelper(&mContextInstance) {}
+
+bool StreamOutPrimary::useStubStream(const AudioDevice& device) {
+ static const bool kSimulateOutput =
+ GetBoolProperty("ro.boot.audio.tinyalsa.ignore_output", false);
+ return kSimulateOutput || device.type.type == AudioDeviceType::OUT_TELEPHONY_TX ||
+ device.type.connection == AudioDeviceDescription::CONNECTION_BUS;
+}
+
+StreamSwitcher::DeviceSwitchBehavior StreamOutPrimary::switchCurrentStream(
+ const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) {
+ LOG(DEBUG) << __func__;
+ if (devices.size() > 1) {
+ LOG(ERROR) << __func__ << ": primary stream can only be connected to one device, got: "
+ << devices.size();
+ return DeviceSwitchBehavior::UNSUPPORTED_DEVICES;
+ }
+ if (devices.empty() || useStubStream(devices[0]) == isStubStream()) {
+ return DeviceSwitchBehavior::USE_CURRENT_STREAM;
+ }
+ return DeviceSwitchBehavior::CREATE_NEW_STREAM;
+}
+
+std::unique_ptr<StreamCommonInterfaceEx> StreamOutPrimary::createNewStream(
+ const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices,
+ StreamContext* context, const Metadata& metadata) {
+ if (devices.empty()) {
+ LOG(FATAL) << __func__ << ": called with empty devices"; // see 'switchCurrentStream'
+ }
+ if (useStubStream(devices[0])) {
+ return std::unique_ptr<StreamCommonInterfaceEx>(
+ new InnerStreamWrapper<StreamStub>(context, metadata));
+ }
+ return std::unique_ptr<StreamCommonInterfaceEx>(
+ new InnerStreamWrapper<StreamPrimary>(context, metadata));
+}
+
+ndk::ScopedAStatus StreamOutPrimary::getHwVolume(std::vector<float>* _aidl_return) {
+ if (isStubStream()) {
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+ }
+ return getHwVolumeImpl(_aidl_return);
+}
+
+ndk::ScopedAStatus StreamOutPrimary::setHwVolume(const std::vector<float>& in_channelVolumes) {
+ if (isStubStream()) {
+ LOG(DEBUG) << __func__ << ": volumes " << ::android::internal::ToString(in_channelVolumes);
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+ }
+ auto currentVolumes = mHwVolumes;
+ RETURN_STATUS_IF_ERROR(setHwVolumeImpl(in_channelVolumes));
+ if (auto status = primary::PrimaryMixer::getInstance().setVolumes(in_channelVolumes);
+ !status.isOk()) {
+ mHwVolumes = currentVolumes;
+ return status;
+ }
+ return ndk::ScopedAStatus::ok();
+}
+
+} // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp b/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp
index 74dea53..11838f8 100644
--- a/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp
+++ b/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp
@@ -184,7 +184,7 @@
: outWrite(buffer, frameCount, actualFrameCount));
}
-::android::status_t StreamRemoteSubmix::getPosition(StreamDescriptor::Position* position) {
+::android::status_t StreamRemoteSubmix::refinePosition(StreamDescriptor::Position* position) {
sp<MonoPipeReader> source = mCurrentRoute->getSource();
if (source == nullptr) {
return ::android::NO_INIT;
@@ -280,14 +280,18 @@
size_t* actualFrameCount) {
// about to read from audio source
sp<MonoPipeReader> source = mCurrentRoute->getSource();
- if (source == nullptr) {
- int readErrorCount = mCurrentRoute->notifyReadError();
- if (readErrorCount < kMaxReadErrorLogs) {
- LOG(ERROR)
- << __func__
- << ": no audio pipe yet we're trying to read! (not all errors will be logged)";
+ if (source == nullptr || source->availableToRead() == 0) {
+ if (source == nullptr) {
+ int readErrorCount = mCurrentRoute->notifyReadError();
+ if (readErrorCount < kMaxReadErrorLogs) {
+ LOG(ERROR) << __func__
+ << ": no audio pipe yet we're trying to read! (not all errors will be "
+ "logged)";
+ } else {
+ LOG(ERROR) << __func__ << ": Read errors " << readErrorCount;
+ }
} else {
- LOG(ERROR) << __func__ << ": Read errors " << readErrorCount;
+ LOG(INFO) << __func__ << ": no data to read yet, providing empty data";
}
const size_t delayUs = static_cast<size_t>(
std::roundf(frameCount * MICROS_PER_SECOND / mStreamConfig.sampleRate));
@@ -344,11 +348,9 @@
// recording (including this call): it's converted to usec and compared to how long we've been
// recording for, which gives us how long we must wait to sync the projected recording time, and
// the observed recording time.
- static constexpr float kScaleFactor = .8f;
- const size_t projectedVsObservedOffsetUs =
- kScaleFactor * (static_cast<size_t>(std::roundf((readCounterFrames * MICROS_PER_SECOND /
- mStreamConfig.sampleRate) -
- recordDurationUs.count())));
+ const size_t projectedVsObservedOffsetUs = static_cast<size_t>(
+ std::roundf((readCounterFrames * MICROS_PER_SECOND / mStreamConfig.sampleRate) -
+ recordDurationUs.count()));
LOG(VERBOSE) << __func__ << ": record duration " << recordDurationUs.count()
<< " microseconds, will wait: " << projectedVsObservedOffsetUs << " microseconds";
@@ -361,8 +363,7 @@
StreamInRemoteSubmix::StreamInRemoteSubmix(StreamContext&& context,
const SinkMetadata& sinkMetadata,
const std::vector<MicrophoneInfo>& microphones)
- : StreamIn(std::move(context), microphones),
- StreamSwitcher(&(StreamIn::mContext), sinkMetadata) {}
+ : StreamIn(std::move(context), microphones), StreamSwitcher(&mContextInstance, sinkMetadata) {}
ndk::ScopedAStatus StreamInRemoteSubmix::getActiveMicrophones(
std::vector<MicrophoneDynamicInfo>* _aidl_return) {
@@ -403,7 +404,7 @@
const SourceMetadata& sourceMetadata,
const std::optional<AudioOffloadInfo>& offloadInfo)
: StreamOut(std::move(context), offloadInfo),
- StreamSwitcher(&(StreamOut::mContext), sourceMetadata) {}
+ StreamSwitcher(&mContextInstance, sourceMetadata) {}
StreamSwitcher::DeviceSwitchBehavior StreamOutRemoteSubmix::switchCurrentStream(
const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) {
diff --git a/audio/aidl/default/stub/StreamStub.cpp b/audio/aidl/default/stub/StreamStub.cpp
index 66f4605..660a51e 100644
--- a/audio/aidl/default/stub/StreamStub.cpp
+++ b/audio/aidl/default/stub/StreamStub.cpp
@@ -33,6 +33,7 @@
StreamStub::StreamStub(StreamContext* context, const Metadata& metadata)
: StreamCommonImpl(context, metadata),
+ mBufferSizeFrames(getContext().getBufferSizeInFrames()),
mFrameSizeBytes(getContext().getFrameSize()),
mSampleRate(getContext().getSampleRate()),
mIsAsynchronous(!!getContext().getAsyncCallback()),
@@ -40,7 +41,6 @@
::android::status_t StreamStub::init() {
mIsInitialized = true;
- usleep(500);
return ::android::OK;
}
@@ -48,7 +48,16 @@
if (!mIsInitialized) {
LOG(FATAL) << __func__ << ": must not happen for an uninitialized driver";
}
- usleep(500);
+ if (!mIsInput) {
+ if (!mIsAsynchronous) {
+ static constexpr float kMicrosPerSecond = MICROS_PER_SECOND;
+ const size_t delayUs = static_cast<size_t>(
+ std::roundf(mBufferSizeFrames * kMicrosPerSecond / mSampleRate));
+ usleep(delayUs);
+ } else {
+ usleep(500);
+ }
+ }
return ::android::OK;
}
@@ -56,7 +65,6 @@
if (!mIsInitialized) {
LOG(FATAL) << __func__ << ": must not happen for an uninitialized driver";
}
- usleep(500);
return ::android::OK;
}
@@ -64,7 +72,6 @@
if (!mIsInitialized) {
LOG(FATAL) << __func__ << ": must not happen for an uninitialized driver";
}
- usleep(500);
return ::android::OK;
}
@@ -120,11 +127,10 @@
StreamInStub::StreamInStub(StreamContext&& context, const SinkMetadata& sinkMetadata,
const std::vector<MicrophoneInfo>& microphones)
- : StreamIn(std::move(context), microphones), StreamStub(&(StreamIn::mContext), sinkMetadata) {}
+ : StreamIn(std::move(context), microphones), StreamStub(&mContextInstance, sinkMetadata) {}
StreamOutStub::StreamOutStub(StreamContext&& context, const SourceMetadata& sourceMetadata,
const std::optional<AudioOffloadInfo>& offloadInfo)
- : StreamOut(std::move(context), offloadInfo),
- StreamStub(&(StreamOut::mContext), sourceMetadata) {}
+ : StreamOut(std::move(context), offloadInfo), StreamStub(&mContextInstance, sourceMetadata) {}
} // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/usb/StreamUsb.cpp b/audio/aidl/default/usb/StreamUsb.cpp
index 9684a87..b60b4fd 100644
--- a/audio/aidl/default/usb/StreamUsb.cpp
+++ b/audio/aidl/default/usb/StreamUsb.cpp
@@ -18,14 +18,11 @@
#define LOG_TAG "AHAL_StreamUsb"
#include <android-base/logging.h>
-
-#include <Utils.h>
#include <error/expected_utils.h>
#include "UsbAlsaMixerControl.h"
#include "core-impl/StreamUsb.h"
-using aidl::android::hardware::audio::common::getChannelCount;
using aidl::android::hardware::audio::common::SinkMetadata;
using aidl::android::hardware::audio::common::SourceMetadata;
using aidl::android::media::audio::common::AudioDevice;
@@ -85,7 +82,7 @@
StreamInUsb::StreamInUsb(StreamContext&& context, const SinkMetadata& sinkMetadata,
const std::vector<MicrophoneInfo>& microphones)
- : StreamIn(std::move(context), microphones), StreamUsb(&(StreamIn::mContext), sinkMetadata) {}
+ : StreamIn(std::move(context), microphones), StreamUsb(&mContextInstance, sinkMetadata) {}
ndk::ScopedAStatus StreamInUsb::getActiveMicrophones(
std::vector<MicrophoneDynamicInfo>* _aidl_return __unused) {
@@ -96,15 +93,16 @@
StreamOutUsb::StreamOutUsb(StreamContext&& context, const SourceMetadata& sourceMetadata,
const std::optional<AudioOffloadInfo>& offloadInfo)
: StreamOut(std::move(context), offloadInfo),
- StreamUsb(&(StreamOut::mContext), sourceMetadata),
- mChannelCount(getChannelCount(getContext().getChannelLayout())) {}
+ StreamUsb(&mContextInstance, sourceMetadata),
+ StreamOutHwVolumeHelper(&mContextInstance) {}
ndk::ScopedAStatus StreamOutUsb::getHwVolume(std::vector<float>* _aidl_return) {
- *_aidl_return = mHwVolumes;
- return ndk::ScopedAStatus::ok();
+ return getHwVolumeImpl(_aidl_return);
}
ndk::ScopedAStatus StreamOutUsb::setHwVolume(const std::vector<float>& in_channelVolumes) {
+ auto currentVolumes = mHwVolumes;
+ RETURN_STATUS_IF_ERROR(setHwVolumeImpl(in_channelVolumes));
// Avoid using mConnectedDeviceProfiles because it requires a lock.
for (const auto& device : getConnectedDevices()) {
if (auto deviceProfile = alsa::getDeviceProfile(device, mIsInput);
@@ -114,11 +112,11 @@
!result.isOk()) {
LOG(ERROR) << __func__
<< ": failed to set volume for device address=" << *deviceProfile;
+ mHwVolumes = currentVolumes;
return result;
}
}
}
- mHwVolumes = in_channelVolumes;
return ndk::ScopedAStatus::ok();
}
diff --git a/audio/aidl/vts/Android.bp b/audio/aidl/vts/Android.bp
index 852255d..f7cf4ce 100644
--- a/audio/aidl/vts/Android.bp
+++ b/audio/aidl/vts/Android.bp
@@ -55,6 +55,7 @@
"VtsHalAudioCoreConfigTargetTest.cpp",
"VtsHalAudioCoreModuleTargetTest.cpp",
],
+ test_config: "VtsHalAudioCoreTargetTest.xml",
}
cc_test {
diff --git a/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp b/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
index a2e2ef7..6ad130e 100644
--- a/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
@@ -3189,10 +3189,17 @@
std::string mUnexpectedTransition;
};
-enum { NAMED_CMD_NAME, NAMED_CMD_DELAY_MS, NAMED_CMD_STREAM_TYPE, NAMED_CMD_CMDS };
+enum {
+ NAMED_CMD_NAME,
+ NAMED_CMD_DELAY_MS,
+ NAMED_CMD_STREAM_TYPE,
+ NAMED_CMD_CMDS,
+ NAMED_CMD_VALIDATE_POS_INCREASE
+};
enum class StreamTypeFilter { ANY, SYNC, ASYNC };
using NamedCommandSequence =
- std::tuple<std::string, int, StreamTypeFilter, std::shared_ptr<StateSequence>>;
+ std::tuple<std::string, int /*cmdDelayMs*/, StreamTypeFilter,
+ std::shared_ptr<StateSequence>, bool /*validatePositionIncrease*/>;
enum { PARAM_MODULE_NAME, PARAM_CMD_SEQ, PARAM_SETUP_SEQ };
using StreamIoTestParameters =
std::tuple<std::string /*moduleName*/, NamedCommandSequence, bool /*useSetupSequence2*/>;
@@ -3236,10 +3243,14 @@
ASSERT_NO_FATAL_FAILURE(delayTransientStates.SetUp(module.get()));
const auto& commandsAndStates =
std::get<NAMED_CMD_CMDS>(std::get<PARAM_CMD_SEQ>(GetParam()));
+ const bool validatePositionIncrease =
+ std::get<NAMED_CMD_VALIDATE_POS_INCREASE>(std::get<PARAM_CMD_SEQ>(GetParam()));
if (!std::get<PARAM_SETUP_SEQ>(GetParam())) {
- ASSERT_NO_FATAL_FAILURE(RunStreamIoCommandsImplSeq1(portConfig, commandsAndStates));
+ ASSERT_NO_FATAL_FAILURE(RunStreamIoCommandsImplSeq1(portConfig, commandsAndStates,
+ validatePositionIncrease));
} else {
- ASSERT_NO_FATAL_FAILURE(RunStreamIoCommandsImplSeq2(portConfig, commandsAndStates));
+ ASSERT_NO_FATAL_FAILURE(RunStreamIoCommandsImplSeq2(portConfig, commandsAndStates,
+ validatePositionIncrease));
}
if (isNonBlocking) {
// Also try running the same sequence with "aosp.forceTransientBurst" set.
@@ -3250,11 +3261,11 @@
if (forceTransientBurst.SetUpNoChecks(module.get(), true /*failureExpected*/)
.isOk()) {
if (!std::get<PARAM_SETUP_SEQ>(GetParam())) {
- ASSERT_NO_FATAL_FAILURE(
- RunStreamIoCommandsImplSeq1(portConfig, commandsAndStates));
+ ASSERT_NO_FATAL_FAILURE(RunStreamIoCommandsImplSeq1(
+ portConfig, commandsAndStates, validatePositionIncrease));
} else {
- ASSERT_NO_FATAL_FAILURE(
- RunStreamIoCommandsImplSeq2(portConfig, commandsAndStates));
+ ASSERT_NO_FATAL_FAILURE(RunStreamIoCommandsImplSeq2(
+ portConfig, commandsAndStates, validatePositionIncrease));
}
}
} else if (!IOTraits<Stream>::is_input) {
@@ -3267,11 +3278,11 @@
if (forceSynchronousDrain.SetUpNoChecks(module.get(), true /*failureExpected*/)
.isOk()) {
if (!std::get<PARAM_SETUP_SEQ>(GetParam())) {
- ASSERT_NO_FATAL_FAILURE(
- RunStreamIoCommandsImplSeq1(portConfig, commandsAndStates));
+ ASSERT_NO_FATAL_FAILURE(RunStreamIoCommandsImplSeq1(
+ portConfig, commandsAndStates, validatePositionIncrease));
} else {
- ASSERT_NO_FATAL_FAILURE(
- RunStreamIoCommandsImplSeq2(portConfig, commandsAndStates));
+ ASSERT_NO_FATAL_FAILURE(RunStreamIoCommandsImplSeq2(
+ portConfig, commandsAndStates, validatePositionIncrease));
}
}
}
@@ -3285,11 +3296,13 @@
// Set up a patch first, then open a stream.
void RunStreamIoCommandsImplSeq1(const AudioPortConfig& portConfig,
- std::shared_ptr<StateSequence> commandsAndStates) {
+ std::shared_ptr<StateSequence> commandsAndStates,
+ bool validatePositionIncrease) {
auto devicePorts = moduleConfig->getAttachedDevicesPortsForMixPort(
IOTraits<Stream>::is_input, portConfig);
ASSERT_FALSE(devicePorts.empty());
auto devicePortConfig = moduleConfig->getSingleConfigForDevicePort(devicePorts[0]);
+ SCOPED_TRACE(devicePortConfig.toString());
WithAudioPatch patch(IOTraits<Stream>::is_input, portConfig, devicePortConfig);
ASSERT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
@@ -3307,14 +3320,17 @@
EXPECT_FALSE(worker.hasError()) << worker.getError();
EXPECT_EQ("", driver.getUnexpectedStateTransition());
if (ValidateObservablePosition(devicePortConfig)) {
- EXPECT_TRUE(driver.hasObservablePositionIncrease());
+ if (validatePositionIncrease) {
+ EXPECT_TRUE(driver.hasObservablePositionIncrease());
+ }
EXPECT_FALSE(driver.hasRetrogradeObservablePosition());
}
}
// Open a stream, then set up a patch for it.
void RunStreamIoCommandsImplSeq2(const AudioPortConfig& portConfig,
- std::shared_ptr<StateSequence> commandsAndStates) {
+ std::shared_ptr<StateSequence> commandsAndStates,
+ bool validatePositionIncrease) {
WithStream<Stream> stream(portConfig);
ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
StreamLogicDefaultDriver driver(commandsAndStates,
@@ -3326,6 +3342,7 @@
IOTraits<Stream>::is_input, portConfig);
ASSERT_FALSE(devicePorts.empty());
auto devicePortConfig = moduleConfig->getSingleConfigForDevicePort(devicePorts[0]);
+ SCOPED_TRACE(devicePortConfig.toString());
WithAudioPatch patch(IOTraits<Stream>::is_input, stream.getPortConfig(), devicePortConfig);
ASSERT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
@@ -3336,7 +3353,9 @@
EXPECT_FALSE(worker.hasError()) << worker.getError();
EXPECT_EQ("", driver.getUnexpectedStateTransition());
if (ValidateObservablePosition(devicePortConfig)) {
- EXPECT_TRUE(driver.hasObservablePositionIncrease());
+ if (validatePositionIncrease) {
+ EXPECT_TRUE(driver.hasObservablePositionIncrease());
+ }
EXPECT_FALSE(driver.hasRetrogradeObservablePosition());
}
}
@@ -3668,22 +3687,28 @@
using State = StreamDescriptor::State;
auto d = std::make_unique<StateDag>();
StateDag::Node last = d->makeFinalNode(State::ACTIVE);
- StateDag::Node active = d->makeNode(State::ACTIVE, kBurstCommand, last);
+ // Use a couple of bursts to ensure that the driver starts reporting the position.
+ StateDag::Node active2 = d->makeNode(State::ACTIVE, kBurstCommand, last);
+ StateDag::Node active = d->makeNode(State::ACTIVE, kBurstCommand, active2);
StateDag::Node idle = d->makeNode(State::IDLE, kBurstCommand, active);
if (!isSync) {
// Allow optional routing via the TRANSFERRING state on bursts.
- active.children().push_back(d->makeNode(State::TRANSFERRING, kTransferReadyEvent, last));
+ active2.children().push_back(d->makeNode(State::TRANSFERRING, kTransferReadyEvent, last));
+ active.children().push_back(d->makeNode(State::TRANSFERRING, kTransferReadyEvent, active2));
idle.children().push_back(d->makeNode(State::TRANSFERRING, kTransferReadyEvent, active));
}
d->makeNode(State::STANDBY, kStartCommand, idle);
return std::make_shared<StateSequenceFollower>(std::move(d));
}
static const NamedCommandSequence kReadSeq =
- std::make_tuple(std::string("Read"), 0, StreamTypeFilter::ANY, makeBurstCommands(true));
+ std::make_tuple(std::string("Read"), 0, StreamTypeFilter::ANY, makeBurstCommands(true),
+ true /*validatePositionIncrease*/);
static const NamedCommandSequence kWriteSyncSeq =
- std::make_tuple(std::string("Write"), 0, StreamTypeFilter::SYNC, makeBurstCommands(true));
+ std::make_tuple(std::string("Write"), 0, StreamTypeFilter::SYNC, makeBurstCommands(true),
+ true /*validatePositionIncrease*/);
static const NamedCommandSequence kWriteAsyncSeq =
- std::make_tuple(std::string("Write"), 0, StreamTypeFilter::ASYNC, makeBurstCommands(false));
+ std::make_tuple(std::string("Write"), 0, StreamTypeFilter::ASYNC, makeBurstCommands(false),
+ true /*validatePositionIncrease*/);
std::shared_ptr<StateSequence> makeAsyncDrainCommands(bool isInput) {
using State = StreamDescriptor::State;
@@ -3711,11 +3736,12 @@
}
return std::make_shared<StateSequenceFollower>(std::move(d));
}
-static const NamedCommandSequence kWriteDrainAsyncSeq =
- std::make_tuple(std::string("WriteDrain"), kStreamTransientStateTransitionDelayMs,
- StreamTypeFilter::ASYNC, makeAsyncDrainCommands(false));
-static const NamedCommandSequence kDrainInSeq = std::make_tuple(
- std::string("Drain"), 0, StreamTypeFilter::ANY, makeAsyncDrainCommands(true));
+static const NamedCommandSequence kWriteDrainAsyncSeq = std::make_tuple(
+ std::string("WriteDrain"), kStreamTransientStateTransitionDelayMs, StreamTypeFilter::ASYNC,
+ makeAsyncDrainCommands(false), false /*validatePositionIncrease*/);
+static const NamedCommandSequence kDrainInSeq =
+ std::make_tuple(std::string("Drain"), 0, StreamTypeFilter::ANY,
+ makeAsyncDrainCommands(true), false /*validatePositionIncrease*/);
std::shared_ptr<StateSequence> makeDrainOutCommands(bool isSync) {
using State = StreamDescriptor::State;
@@ -3735,10 +3761,12 @@
d->makeNode(State::STANDBY, kStartCommand, idle);
return std::make_shared<StateSequenceFollower>(std::move(d));
}
-static const NamedCommandSequence kDrainOutSyncSeq = std::make_tuple(
- std::string("Drain"), 0, StreamTypeFilter::SYNC, makeDrainOutCommands(true));
-static const NamedCommandSequence kDrainOutAsyncSeq = std::make_tuple(
- std::string("Drain"), 0, StreamTypeFilter::ASYNC, makeDrainOutCommands(false));
+static const NamedCommandSequence kDrainOutSyncSeq =
+ std::make_tuple(std::string("Drain"), 0, StreamTypeFilter::SYNC, makeDrainOutCommands(true),
+ false /*validatePositionIncrease*/);
+static const NamedCommandSequence kDrainOutAsyncSeq =
+ std::make_tuple(std::string("Drain"), 0, StreamTypeFilter::ASYNC,
+ makeDrainOutCommands(false), false /*validatePositionIncrease*/);
std::shared_ptr<StateSequence> makeDrainPauseOutCommands(bool isSync) {
using State = StreamDescriptor::State;
@@ -3759,12 +3787,12 @@
d->makeNode(State::STANDBY, kStartCommand, idle);
return std::make_shared<StateSequenceFollower>(std::move(d));
}
-static const NamedCommandSequence kDrainPauseOutSyncSeq =
- std::make_tuple(std::string("DrainPause"), kStreamTransientStateTransitionDelayMs,
- StreamTypeFilter::SYNC, makeDrainPauseOutCommands(true));
-static const NamedCommandSequence kDrainPauseOutAsyncSeq =
- std::make_tuple(std::string("DrainPause"), kStreamTransientStateTransitionDelayMs,
- StreamTypeFilter::ASYNC, makeDrainPauseOutCommands(false));
+static const NamedCommandSequence kDrainPauseOutSyncSeq = std::make_tuple(
+ std::string("DrainPause"), kStreamTransientStateTransitionDelayMs, StreamTypeFilter::SYNC,
+ makeDrainPauseOutCommands(true), false /*validatePositionIncrease*/);
+static const NamedCommandSequence kDrainPauseOutAsyncSeq = std::make_tuple(
+ std::string("DrainPause"), kStreamTransientStateTransitionDelayMs, StreamTypeFilter::ASYNC,
+ makeDrainPauseOutCommands(false), false /*validatePositionIncrease*/);
// This sequence also verifies that the capture / presentation position is not reset on standby.
std::shared_ptr<StateSequence> makeStandbyCommands(bool isInput, bool isSync) {
@@ -3805,13 +3833,15 @@
}
return std::make_shared<StateSequenceFollower>(std::move(d));
}
-static const NamedCommandSequence kStandbyInSeq = std::make_tuple(
- std::string("Standby"), 0, StreamTypeFilter::ANY, makeStandbyCommands(true, false));
-static const NamedCommandSequence kStandbyOutSyncSeq = std::make_tuple(
- std::string("Standby"), 0, StreamTypeFilter::SYNC, makeStandbyCommands(false, true));
-static const NamedCommandSequence kStandbyOutAsyncSeq =
- std::make_tuple(std::string("Standby"), kStreamTransientStateTransitionDelayMs,
- StreamTypeFilter::ASYNC, makeStandbyCommands(false, false));
+static const NamedCommandSequence kStandbyInSeq =
+ std::make_tuple(std::string("Standby"), 0, StreamTypeFilter::ANY,
+ makeStandbyCommands(true, false), false /*validatePositionIncrease*/);
+static const NamedCommandSequence kStandbyOutSyncSeq =
+ std::make_tuple(std::string("Standby"), 0, StreamTypeFilter::SYNC,
+ makeStandbyCommands(false, true), false /*validatePositionIncrease*/);
+static const NamedCommandSequence kStandbyOutAsyncSeq = std::make_tuple(
+ std::string("Standby"), kStreamTransientStateTransitionDelayMs, StreamTypeFilter::ASYNC,
+ makeStandbyCommands(false, false), false /*validatePositionIncrease*/);
std::shared_ptr<StateSequence> makePauseCommands(bool isInput, bool isSync) {
using State = StreamDescriptor::State;
@@ -3846,13 +3876,15 @@
}
return std::make_shared<StateSequenceFollower>(std::move(d));
}
-static const NamedCommandSequence kPauseInSeq = std::make_tuple(
- std::string("Pause"), 0, StreamTypeFilter::ANY, makePauseCommands(true, false));
-static const NamedCommandSequence kPauseOutSyncSeq = std::make_tuple(
- std::string("Pause"), 0, StreamTypeFilter::SYNC, makePauseCommands(false, true));
-static const NamedCommandSequence kPauseOutAsyncSeq =
- std::make_tuple(std::string("Pause"), kStreamTransientStateTransitionDelayMs,
- StreamTypeFilter::ASYNC, makePauseCommands(false, false));
+static const NamedCommandSequence kPauseInSeq =
+ std::make_tuple(std::string("Pause"), 0, StreamTypeFilter::ANY,
+ makePauseCommands(true, false), false /*validatePositionIncrease*/);
+static const NamedCommandSequence kPauseOutSyncSeq =
+ std::make_tuple(std::string("Pause"), 0, StreamTypeFilter::SYNC,
+ makePauseCommands(false, true), false /*validatePositionIncrease*/);
+static const NamedCommandSequence kPauseOutAsyncSeq = std::make_tuple(
+ std::string("Pause"), kStreamTransientStateTransitionDelayMs, StreamTypeFilter::ASYNC,
+ makePauseCommands(false, false), false /*validatePositionIncrease*/);
std::shared_ptr<StateSequence> makeFlushCommands(bool isInput, bool isSync) {
using State = StreamDescriptor::State;
@@ -3879,13 +3911,15 @@
}
return std::make_shared<StateSequenceFollower>(std::move(d));
}
-static const NamedCommandSequence kFlushInSeq = std::make_tuple(
- std::string("Flush"), 0, StreamTypeFilter::ANY, makeFlushCommands(true, false));
-static const NamedCommandSequence kFlushOutSyncSeq = std::make_tuple(
- std::string("Flush"), 0, StreamTypeFilter::SYNC, makeFlushCommands(false, true));
-static const NamedCommandSequence kFlushOutAsyncSeq =
- std::make_tuple(std::string("Flush"), kStreamTransientStateTransitionDelayMs,
- StreamTypeFilter::ASYNC, makeFlushCommands(false, false));
+static const NamedCommandSequence kFlushInSeq =
+ std::make_tuple(std::string("Flush"), 0, StreamTypeFilter::ANY,
+ makeFlushCommands(true, false), false /*validatePositionIncrease*/);
+static const NamedCommandSequence kFlushOutSyncSeq =
+ std::make_tuple(std::string("Flush"), 0, StreamTypeFilter::SYNC,
+ makeFlushCommands(false, true), false /*validatePositionIncrease*/);
+static const NamedCommandSequence kFlushOutAsyncSeq = std::make_tuple(
+ std::string("Flush"), kStreamTransientStateTransitionDelayMs, StreamTypeFilter::ASYNC,
+ makeFlushCommands(false, false), false /*validatePositionIncrease*/);
std::shared_ptr<StateSequence> makeDrainPauseFlushOutCommands(bool isSync) {
using State = StreamDescriptor::State;
@@ -3906,10 +3940,12 @@
}
static const NamedCommandSequence kDrainPauseFlushOutSyncSeq =
std::make_tuple(std::string("DrainPauseFlush"), kStreamTransientStateTransitionDelayMs,
- StreamTypeFilter::SYNC, makeDrainPauseFlushOutCommands(true));
+ StreamTypeFilter::SYNC, makeDrainPauseFlushOutCommands(true),
+ false /*validatePositionIncrease*/);
static const NamedCommandSequence kDrainPauseFlushOutAsyncSeq =
std::make_tuple(std::string("DrainPauseFlush"), kStreamTransientStateTransitionDelayMs,
- StreamTypeFilter::ASYNC, makeDrainPauseFlushOutCommands(false));
+ StreamTypeFilter::ASYNC, makeDrainPauseFlushOutCommands(false),
+ false /*validatePositionIncrease*/);
// Note, this isn't the "official" enum printer, it is only used to make the test name suffix.
std::string PrintStreamFilterToString(StreamTypeFilter filter) {
diff --git a/audio/aidl/vts/VtsHalAudioCoreTargetTest.xml b/audio/aidl/vts/VtsHalAudioCoreTargetTest.xml
index dfc1039..9d3adc1 100644
--- a/audio/aidl/vts/VtsHalAudioCoreTargetTest.xml
+++ b/audio/aidl/vts/VtsHalAudioCoreTargetTest.xml
@@ -25,6 +25,11 @@
<option name="teardown-command" value="setprop vts.native_server.on 0"/>
</target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push" value="VtsHalAudioCoreTargetTest->/data/local/tmp/VtsHalAudioCoreTargetTest" />
+ </target_preparer>
+
<test class="com.android.tradefed.testtype.GTest" >
<option name="native-test-device-path" value="/data/local/tmp" />
<option name="module-name" value="VtsHalAudioCoreTargetTest" />
diff --git a/audio/policy/1.0/xml/api/current.txt b/audio/policy/1.0/xml/api/current.txt
index 84a2b71..01d77d7 100644
--- a/audio/policy/1.0/xml/api/current.txt
+++ b/audio/policy/1.0/xml/api/current.txt
@@ -209,11 +209,13 @@
public enum UsageEnumType {
method public String getRawName();
enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_ALARM;
+ enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_ANNOUNCEMENT;
enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY;
enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE;
enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_ASSISTANCE_SONIFICATION;
enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_ASSISTANT;
enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_CALL_ASSISTANT;
+ enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_EMERGENCY;
enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_GAME;
enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_MEDIA;
enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_NOTIFICATION;
@@ -222,7 +224,9 @@
enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST;
enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_NOTIFICATION_EVENT;
enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE;
+ enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_SAFETY;
enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_UNKNOWN;
+ enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_VEHICLE_STATUS;
enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_VIRTUAL_SOURCE;
enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_VOICE_COMMUNICATION;
enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING;
diff --git a/audio/policy/1.0/xml/audio_policy_engine_configuration.xsd b/audio/policy/1.0/xml/audio_policy_engine_configuration.xsd
index b58a6c8..40396bb 100644
--- a/audio/policy/1.0/xml/audio_policy_engine_configuration.xsd
+++ b/audio/policy/1.0/xml/audio_policy_engine_configuration.xsd
@@ -359,6 +359,10 @@
<xs:enumeration value="AUDIO_USAGE_VIRTUAL_SOURCE"/>
<xs:enumeration value="AUDIO_USAGE_ASSISTANT"/>
<xs:enumeration value="AUDIO_USAGE_CALL_ASSISTANT"/>
+ <xs:enumeration value="AUDIO_USAGE_EMERGENCY" />
+ <xs:enumeration value="AUDIO_USAGE_SAFETY" />
+ <xs:enumeration value="AUDIO_USAGE_VEHICLE_STATUS" />
+ <xs:enumeration value="AUDIO_USAGE_ANNOUNCEMENT" />
</xs:restriction>
</xs:simpleType>
diff --git a/automotive/audiocontrol/aidl/default/audiocontrol-default.xml b/automotive/audiocontrol/aidl/default/audiocontrol-default.xml
index e82f6fa..3452ae9 100644
--- a/automotive/audiocontrol/aidl/default/audiocontrol-default.xml
+++ b/automotive/audiocontrol/aidl/default/audiocontrol-default.xml
@@ -1,5 +1,6 @@
<manifest version="2.0" type="device">
<hal format="aidl">
+ <version>2</version>
<name>android.hardware.automotive.audiocontrol</name>
<fqname>IAudioControl/default</fqname>
</hal>
diff --git a/automotive/vehicle/aidl/impl/vhal/include/ConnectedClient.h b/automotive/vehicle/aidl/impl/vhal/include/ConnectedClient.h
index 2e7298f..b3f4a0f 100644
--- a/automotive/vehicle/aidl/impl/vhal/include/ConnectedClient.h
+++ b/automotive/vehicle/aidl/impl/vhal/include/ConnectedClient.h
@@ -107,12 +107,18 @@
// Gets the callback to be called when the request for this client has finished.
std::shared_ptr<const IVehicleHardware::GetValuesCallback> getResultCallback();
- // Marshals the updated values into largeParcelable and sents it through {@code onPropertyEvent}
+ // Marshals the updated values into largeParcelable and sends it through {@code onPropertyEvent}
// callback.
static void sendUpdatedValues(
CallbackType callback,
std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropValue>&&
updatedValues);
+ // Marshals the set property error events into largeParcelable and sends it through
+ // {@code onPropertySetError} callback.
+ static void sendPropertySetErrors(
+ CallbackType callback,
+ std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropError>&&
+ vehiclePropErrors);
protected:
// Gets the callback to be called when the request for this client has timeout.
diff --git a/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h b/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h
index 9c29816..b6dbbc1 100644
--- a/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h
+++ b/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h
@@ -247,10 +247,14 @@
const CallbackType& callback, std::shared_ptr<PendingRequestPool> pendingRequestPool);
static void onPropertyChangeEvent(
- std::weak_ptr<SubscriptionManager> subscriptionManager,
+ const std::weak_ptr<SubscriptionManager>& subscriptionManager,
const std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropValue>&
updatedValues);
+ static void onPropertySetErrorEvent(
+ const std::weak_ptr<SubscriptionManager>& subscriptionManager,
+ const std::vector<SetValueErrorEvent>& errorEvents);
+
static void checkHealth(IVehicleHardware* hardware,
std::weak_ptr<SubscriptionManager> subscriptionManager);
diff --git a/automotive/vehicle/aidl/impl/vhal/include/SubscriptionManager.h b/automotive/vehicle/aidl/impl/vhal/include/SubscriptionManager.h
index 7c8f1b4..4912093 100644
--- a/automotive/vehicle/aidl/impl/vhal/include/SubscriptionManager.h
+++ b/automotive/vehicle/aidl/impl/vhal/include/SubscriptionManager.h
@@ -103,6 +103,11 @@
// property has not been subscribed before or is not a continuous property.
std::optional<float> getSampleRate(const ClientIdType& clientId, int32_t propId,
int32_t areaId);
+ // For a list of set property error events, returns a map that maps clients subscribing to the
+ // properties to a list of errors for each client.
+ std::unordered_map<CallbackType,
+ std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropError>>
+ getSubscribedClientsForErrorEvents(const std::vector<SetValueErrorEvent>& errorEvents);
// Checks whether the sample rate is valid.
static bool checkSampleRate(float sampleRate);
diff --git a/automotive/vehicle/aidl/impl/vhal/src/ConnectedClient.cpp b/automotive/vehicle/aidl/impl/vhal/src/ConnectedClient.cpp
index 81d231c..fb23a25 100644
--- a/automotive/vehicle/aidl/impl/vhal/src/ConnectedClient.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/src/ConnectedClient.cpp
@@ -38,6 +38,8 @@
using ::aidl::android::hardware::automotive::vehicle::SetValueResult;
using ::aidl::android::hardware::automotive::vehicle::SetValueResults;
using ::aidl::android::hardware::automotive::vehicle::StatusCode;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropError;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropErrors;
using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
using ::aidl::android::hardware::automotive::vehicle::VehiclePropValues;
using ::android::base::Result;
@@ -300,7 +302,34 @@
if (ScopedAStatus callbackStatus =
callback->onPropertyEvent(vehiclePropValues, sharedMemoryFileCount);
!callbackStatus.isOk()) {
- ALOGE("subscribe: failed to call UpdateValues callback, client ID: %p, error: %s, "
+ ALOGE("subscribe: failed to call onPropertyEvent callback, client ID: %p, error: %s, "
+ "exception: %d, service specific error: %d",
+ callback->asBinder().get(), callbackStatus.getMessage(),
+ callbackStatus.getExceptionCode(), callbackStatus.getServiceSpecificError());
+ }
+}
+
+void SubscriptionClient::sendPropertySetErrors(std::shared_ptr<IVehicleCallback> callback,
+ std::vector<VehiclePropError>&& vehiclePropErrors) {
+ if (vehiclePropErrors.empty()) {
+ return;
+ }
+
+ VehiclePropErrors vehiclePropErrorsLargeParcelable;
+ ScopedAStatus status = vectorToStableLargeParcelable(std::move(vehiclePropErrors),
+ &vehiclePropErrorsLargeParcelable);
+ if (!status.isOk()) {
+ int statusCode = status.getServiceSpecificError();
+ ALOGE("subscribe: failed to marshal result into large parcelable, error: "
+ "%s, code: %d",
+ status.getMessage(), statusCode);
+ return;
+ }
+
+ if (ScopedAStatus callbackStatus =
+ callback->onPropertySetError(vehiclePropErrorsLargeParcelable);
+ !callbackStatus.isOk()) {
+ ALOGE("subscribe: failed to call onPropertySetError callback, client ID: %p, error: %s, "
"exception: %d, service specific error: %d",
callback->asBinder().get(), callbackStatus.getMessage(),
callbackStatus.getExceptionCode(), callbackStatus.getServiceSpecificError());
diff --git a/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp b/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
index b191aef..2e9a4b6 100644
--- a/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
@@ -156,6 +156,11 @@
[subscriptionManagerCopy](std::vector<VehiclePropValue> updatedValues) {
onPropertyChangeEvent(subscriptionManagerCopy, updatedValues);
}));
+ mVehicleHardware->registerOnPropertySetErrorEvent(
+ std::make_unique<IVehicleHardware::PropertySetErrorCallback>(
+ [subscriptionManagerCopy](std::vector<SetValueErrorEvent> errorEvents) {
+ onPropertySetErrorEvent(subscriptionManagerCopy, errorEvents);
+ }));
// Register heartbeat event.
mRecurrentAction =
@@ -189,7 +194,7 @@
}
void DefaultVehicleHal::onPropertyChangeEvent(
- std::weak_ptr<SubscriptionManager> subscriptionManager,
+ const std::weak_ptr<SubscriptionManager>& subscriptionManager,
const std::vector<VehiclePropValue>& updatedValues) {
auto manager = subscriptionManager.lock();
if (manager == nullptr) {
@@ -206,6 +211,20 @@
}
}
+void DefaultVehicleHal::onPropertySetErrorEvent(
+ const std::weak_ptr<SubscriptionManager>& subscriptionManager,
+ const std::vector<SetValueErrorEvent>& errorEvents) {
+ auto manager = subscriptionManager.lock();
+ if (manager == nullptr) {
+ ALOGW("the SubscriptionManager is destroyed, DefaultVehicleHal is ending");
+ return;
+ }
+ auto vehiclePropErrorsByClient = manager->getSubscribedClientsForErrorEvents(errorEvents);
+ for (auto& [callback, vehiclePropErrors] : vehiclePropErrorsByClient) {
+ SubscriptionClient::sendPropertySetErrors(callback, std::move(vehiclePropErrors));
+ }
+}
+
template <class T>
std::shared_ptr<T> DefaultVehicleHal::getOrCreateClient(
std::unordered_map<const AIBinder*, std::shared_ptr<T>>* clients,
@@ -669,15 +688,19 @@
// Create a new SubscriptionClient if there isn't an existing one.
mSubscriptionClients->maybeAddClient(callback);
- // Since we have already check the sample rates, the following functions must succeed.
if (!onChangeSubscriptions.empty()) {
- return toScopedAStatus(mSubscriptionManager->subscribe(callback, onChangeSubscriptions,
- /*isContinuousProperty=*/false));
+ auto result = mSubscriptionManager->subscribe(callback, onChangeSubscriptions,
+ /*isContinuousProperty=*/false);
+ if (!result.ok()) {
+ return toScopedAStatus(result);
+ }
}
if (!continuousSubscriptions.empty()) {
- return toScopedAStatus(mSubscriptionManager->subscribe(callback,
- continuousSubscriptions,
- /*isContinuousProperty=*/true));
+ auto result = mSubscriptionManager->subscribe(callback, continuousSubscriptions,
+ /*isContinuousProperty=*/true);
+ if (!result.ok()) {
+ return toScopedAStatus(result);
+ }
}
}
return ScopedAStatus::ok();
diff --git a/automotive/vehicle/aidl/impl/vhal/src/SubscriptionManager.cpp b/automotive/vehicle/aidl/impl/vhal/src/SubscriptionManager.cpp
index 2694401..566c303 100644
--- a/automotive/vehicle/aidl/impl/vhal/src/SubscriptionManager.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/src/SubscriptionManager.cpp
@@ -36,6 +36,7 @@
using ::aidl::android::hardware::automotive::vehicle::IVehicleCallback;
using ::aidl::android::hardware::automotive::vehicle::StatusCode;
using ::aidl::android::hardware::automotive::vehicle::SubscribeOptions;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropError;
using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
using ::android::base::Error;
using ::android::base::Result;
@@ -281,6 +282,32 @@
return clients;
}
+std::unordered_map<std::shared_ptr<IVehicleCallback>, std::vector<VehiclePropError>>
+SubscriptionManager::getSubscribedClientsForErrorEvents(
+ const std::vector<SetValueErrorEvent>& errorEvents) {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+ std::unordered_map<std::shared_ptr<IVehicleCallback>, std::vector<VehiclePropError>> clients;
+
+ for (const auto& errorEvent : errorEvents) {
+ PropIdAreaId propIdAreaId{
+ .propId = errorEvent.propId,
+ .areaId = errorEvent.areaId,
+ };
+ if (mClientsByPropIdArea.find(propIdAreaId) == mClientsByPropIdArea.end()) {
+ continue;
+ }
+
+ for (const auto& [_, client] : mClientsByPropIdArea[propIdAreaId]) {
+ clients[client].push_back({
+ .propId = errorEvent.propId,
+ .areaId = errorEvent.areaId,
+ .errorCode = errorEvent.errorCode,
+ });
+ }
+ }
+ return clients;
+}
+
bool SubscriptionManager::isEmpty() {
std::scoped_lock<std::mutex> lockGuard(mLock);
return mSubscribedPropsByClient.empty() && mClientsByPropIdArea.empty();
diff --git a/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp b/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp
index f48b906..76b57c7 100644
--- a/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp
@@ -62,6 +62,7 @@
using ::aidl::android::hardware::automotive::vehicle::VehicleAreaWindow;
using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig;
using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfigs;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropError;
using ::aidl::android::hardware::automotive::vehicle::VehiclePropErrors;
using ::aidl::android::hardware::automotive::vehicle::VehicleProperty;
using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyAccess;
@@ -1656,6 +1657,63 @@
ASSERT_EQ(msg.find("Vehicle HAL State: "), std::string::npos);
}
+TEST_F(DefaultVehicleHalTest, testOnPropertySetErrorEvent) {
+ std::vector<SubscribeOptions> options = {
+ {
+ .propId = GLOBAL_ON_CHANGE_PROP,
+ .areaIds = {0},
+ },
+ {
+ .propId = GLOBAL_CONTINUOUS_PROP,
+ .areaIds = {0},
+ .sampleRate = 1,
+ },
+ };
+ auto status = getClient()->subscribe(getCallbackClient(), options, 0);
+ ASSERT_TRUE(status.isOk()) << "subscribe failed: " << status.getMessage();
+ std::vector<SetValueErrorEvent> errorEvents = {
+ {
+ .propId = GLOBAL_ON_CHANGE_PROP,
+ .areaId = 0,
+ .errorCode = StatusCode::INTERNAL_ERROR,
+ },
+ {
+ .propId = GLOBAL_ON_CHANGE_PROP,
+ .areaId = 0,
+ .errorCode = StatusCode::ACCESS_DENIED,
+ },
+ {
+ .propId = GLOBAL_CONTINUOUS_PROP,
+ .areaId = 0,
+ .errorCode = StatusCode::INVALID_ARG,
+ },
+ };
+ std::vector<VehiclePropError> expectedResults = {
+ {
+ .propId = GLOBAL_ON_CHANGE_PROP,
+ .areaId = 0,
+ .errorCode = StatusCode::INTERNAL_ERROR,
+ },
+ {
+ .propId = GLOBAL_ON_CHANGE_PROP,
+ .areaId = 0,
+ .errorCode = StatusCode::ACCESS_DENIED,
+ },
+ {
+ .propId = GLOBAL_CONTINUOUS_PROP,
+ .areaId = 0,
+ .errorCode = StatusCode::INVALID_ARG,
+ },
+ };
+ getHardware()->sendOnPropertySetErrorEvent(errorEvents);
+
+ ASSERT_EQ(getCallback()->countOnPropertySetErrorResults(), 1u);
+ auto maybeVehiclePropErrors = getCallback()->nextOnPropertySetErrorResults();
+ ASSERT_TRUE(maybeVehiclePropErrors.has_value());
+ const auto& vehiclePropErrors = maybeVehiclePropErrors.value();
+ ASSERT_THAT(vehiclePropErrors.payloads, UnorderedElementsAreArray(expectedResults));
+}
+
} // namespace vehicle
} // namespace automotive
} // namespace hardware
diff --git a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.cpp b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.cpp
index 0e46357..75b8257 100644
--- a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.cpp
@@ -63,8 +63,9 @@
return storeResults(results, &mOnPropertyEventResults);
}
-ScopedAStatus MockVehicleCallback::onPropertySetError(const VehiclePropErrors&) {
- return ScopedAStatus::ok();
+ScopedAStatus MockVehicleCallback::onPropertySetError(const VehiclePropErrors& results) {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+ return storeResults(results, &mOnPropertySetErrorResults);
}
std::optional<GetValueResults> MockVehicleCallback::nextGetValueResults() {
@@ -87,6 +88,16 @@
return mOnPropertyEventResults.size();
}
+std::optional<VehiclePropErrors> MockVehicleCallback::nextOnPropertySetErrorResults() {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+ return pop(mOnPropertySetErrorResults);
+}
+
+size_t MockVehicleCallback::countOnPropertySetErrorResults() {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+ return mOnPropertySetErrorResults.size();
+}
+
} // namespace vehicle
} // namespace automotive
} // namespace hardware
diff --git a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.h b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.h
index 0faaa1f..91dbb7e 100644
--- a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.h
+++ b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.h
@@ -62,6 +62,9 @@
nextSetValueResults();
std::optional<aidl::android::hardware::automotive::vehicle::VehiclePropValues>
nextOnPropertyEventResults();
+ size_t countOnPropertySetErrorResults();
+ std::optional<aidl::android::hardware::automotive::vehicle::VehiclePropErrors>
+ nextOnPropertySetErrorResults();
size_t countOnPropertyEventResults();
private:
@@ -73,6 +76,8 @@
std::list<aidl::android::hardware::automotive::vehicle::VehiclePropValues>
mOnPropertyEventResults GUARDED_BY(mLock);
int32_t mSharedMemoryFileCount GUARDED_BY(mLock);
+ std::list<aidl::android::hardware::automotive::vehicle::VehiclePropErrors>
+ mOnPropertySetErrorResults GUARDED_BY(mLock);
};
} // namespace vehicle
diff --git a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.cpp b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.cpp
index 4df4e1a..ba0d33d 100644
--- a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.cpp
@@ -131,8 +131,9 @@
}
void MockVehicleHardware::registerOnPropertySetErrorEvent(
- std::unique_ptr<const PropertySetErrorCallback>) {
- // TODO(b/200737967): mock this.
+ std::unique_ptr<const PropertySetErrorCallback> callback) {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+ mPropertySetErrorCallback = std::move(callback);
}
void MockVehicleHardware::setPropertyConfigs(const std::vector<VehiclePropConfig>& configs) {
@@ -254,6 +255,12 @@
std::list<std::vector<SetValueRequest>>* storedRequests,
std::list<std::vector<SetValueResult>>* storedResponses) const;
+void MockVehicleHardware::sendOnPropertySetErrorEvent(
+ const std::vector<SetValueErrorEvent>& errorEvents) {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+ (*mPropertySetErrorCallback)(errorEvents);
+}
+
} // namespace vehicle
} // namespace automotive
} // namespace hardware
diff --git a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.h b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.h
index 743841c..46b30b9 100644
--- a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.h
+++ b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.h
@@ -85,6 +85,7 @@
aidl::android::hardware::automotive::vehicle::StatusCode status);
void setSleepTime(int64_t timeInNano);
void setDumpResult(DumpResult result);
+ void sendOnPropertySetErrorEvent(const std::vector<SetValueErrorEvent>& errorEvents);
private:
mutable std::mutex mLock;
@@ -104,6 +105,7 @@
mStatusByFunctions GUARDED_BY(mLock);
int64_t mSleepTime GUARDED_BY(mLock) = 0;
std::unique_ptr<const PropertyChangeCallback> mPropertyChangeCallback GUARDED_BY(mLock);
+ std::unique_ptr<const PropertySetErrorCallback> mPropertySetErrorCallback GUARDED_BY(mLock);
std::function<aidl::android::hardware::automotive::vehicle::StatusCode(
std::shared_ptr<const GetValuesCallback>,
const std::vector<aidl::android::hardware::automotive::vehicle::GetValueRequest>&)>
diff --git a/bluetooth/audio/aidl/Android.bp b/bluetooth/audio/aidl/Android.bp
index 32f8cca..16b22fe 100644
--- a/bluetooth/audio/aidl/Android.bp
+++ b/bluetooth/audio/aidl/Android.bp
@@ -29,7 +29,7 @@
imports: [
"android.hardware.common-V2",
"android.hardware.common.fmq-V1",
- "android.hardware.audio.common-V1",
+ "android.hardware.audio.common-V2",
],
backend: {
cpp: {
@@ -69,7 +69,7 @@
imports: [
"android.hardware.common-V2",
"android.hardware.common.fmq-V1",
- "android.hardware.audio.common-V1",
+ "android.hardware.audio.common-V2",
],
},
diff --git a/bluetooth/audio/aidl/vts/Android.bp b/bluetooth/audio/aidl/vts/Android.bp
index 3e6953f..fa85fa8 100644
--- a/bluetooth/audio/aidl/vts/Android.bp
+++ b/bluetooth/audio/aidl/vts/Android.bp
@@ -16,7 +16,7 @@
tidy_timeout_srcs: ["VtsHalBluetoothAudioTargetTest.cpp"],
srcs: ["VtsHalBluetoothAudioTargetTest.cpp"],
static_libs: [
- "android.hardware.audio.common-V1-ndk",
+ "android.hardware.audio.common-V2-ndk",
"android.hardware.bluetooth.audio-V3-ndk",
"android.hardware.common-V2-ndk",
"android.hardware.common.fmq-V1-ndk",
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp b/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp
index 2b0caad..1777f77 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp
+++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp
@@ -20,6 +20,7 @@
#include <android-base/logging.h>
#include <android-base/stringprintf.h>
#include <android/binder_manager.h>
+#include <hardware/audio.h>
#include "BluetoothAudioSession.h"
@@ -502,6 +503,16 @@
void BluetoothAudioSession::ReportLowLatencyModeAllowedChanged(bool allowed) {
std::lock_guard<std::recursive_mutex> guard(mutex_);
low_latency_allowed_ = allowed;
+ // TODO(b/294498919): Remove this after there is API to update latency mode
+ // after audio session started. If low_latency_allowed_ is true, the session
+ // can support LOW_LATENCY and FREE LatencyMode.
+ if (low_latency_allowed_) {
+ if (std::find(latency_modes_.begin(), latency_modes_.end(),
+ LatencyMode::LOW_LATENCY) == latency_modes_.end()) {
+ LOG(INFO) << __func__ << " - insert LOW_LATENCY LatencyMode";
+ latency_modes_.push_back(LatencyMode::LOW_LATENCY);
+ }
+ }
if (observers_.empty()) {
LOG(WARNING) << __func__ << " - SessionType=" << toString(session_type_)
<< " has NO port state observer";
@@ -538,23 +549,9 @@
void BluetoothAudioSession::UpdateSourceMetadata(
const struct source_metadata& source_metadata) {
- std::lock_guard<std::recursive_mutex> guard(mutex_);
- if (!IsSessionReady()) {
- LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_)
- << " has NO session";
- return;
- }
-
ssize_t track_count = source_metadata.track_count;
LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_) << ","
<< track_count << " track(s)";
- if (session_type_ == SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH ||
- session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH ||
- session_type_ == SessionType::A2DP_SOFTWARE_DECODING_DATAPATH ||
- session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH) {
- return;
- }
-
SourceMetadata hal_source_metadata;
hal_source_metadata.tracks.resize(track_count);
for (int i = 0; i < track_count; i++) {
@@ -571,33 +568,14 @@
<< toString(hal_source_metadata.tracks[i].contentType)
<< ", gain=" << hal_source_metadata.tracks[i].gain;
}
-
- auto hal_retval = stack_iface_->updateSourceMetadata(hal_source_metadata);
- if (!hal_retval.isOk()) {
- LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
- << toString(session_type_) << " failed";
- }
+ UpdateSourceMetadata(hal_source_metadata);
}
void BluetoothAudioSession::UpdateSinkMetadata(
const struct sink_metadata& sink_metadata) {
- std::lock_guard<std::recursive_mutex> guard(mutex_);
- if (!IsSessionReady()) {
- LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_)
- << " has NO session";
- return;
- }
-
ssize_t track_count = sink_metadata.track_count;
LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_) << ","
<< track_count << " track(s)";
- if (session_type_ == SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH ||
- session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH ||
- session_type_ == SessionType::A2DP_SOFTWARE_DECODING_DATAPATH ||
- session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH) {
- return;
- }
-
SinkMetadata hal_sink_metadata;
hal_sink_metadata.tracks.resize(track_count);
for (int i = 0; i < track_count; i++) {
@@ -612,12 +590,57 @@
<< ", dest_device_address="
<< sink_metadata.tracks[i].dest_device_address;
}
+ UpdateSinkMetadata(hal_sink_metadata);
+}
+
+bool BluetoothAudioSession::UpdateSourceMetadata(
+ const SourceMetadata& hal_source_metadata) {
+ std::lock_guard<std::recursive_mutex> guard(mutex_);
+ if (!IsSessionReady()) {
+ LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_)
+ << " has NO session";
+ return false;
+ }
+
+ if (session_type_ == SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH ||
+ session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH ||
+ session_type_ == SessionType::A2DP_SOFTWARE_DECODING_DATAPATH ||
+ session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH) {
+ return false;
+ }
+
+ auto hal_retval = stack_iface_->updateSourceMetadata(hal_source_metadata);
+ if (!hal_retval.isOk()) {
+ LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
+ << toString(session_type_) << " failed";
+ return false;
+ }
+ return true;
+}
+
+bool BluetoothAudioSession::UpdateSinkMetadata(
+ const SinkMetadata& hal_sink_metadata) {
+ std::lock_guard<std::recursive_mutex> guard(mutex_);
+ if (!IsSessionReady()) {
+ LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_)
+ << " has NO session";
+ return false;
+ }
+
+ if (session_type_ == SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH ||
+ session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH ||
+ session_type_ == SessionType::A2DP_SOFTWARE_DECODING_DATAPATH ||
+ session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH) {
+ return false;
+ }
auto hal_retval = stack_iface_->updateSinkMetadata(hal_sink_metadata);
if (!hal_retval.isOk()) {
LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
<< toString(session_type_) << " failed";
+ return false;
}
+ return true;
}
std::vector<LatencyMode> BluetoothAudioSession::GetSupportedLatencyModes() {
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.h b/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.h
index faf4ffb..25c676a 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.h
+++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.h
@@ -23,12 +23,15 @@
#include <aidl/android/hardware/bluetooth/audio/LatencyMode.h>
#include <aidl/android/hardware/bluetooth/audio/SessionType.h>
#include <fmq/AidlMessageQueue.h>
-#include <hardware/audio.h>
#include <mutex>
#include <unordered_map>
#include <vector>
+// To avoid inclusion of hardware/audio.h
+struct sink_metadata;
+struct source_metadata;
+
namespace aidl {
namespace android {
namespace hardware {
@@ -196,6 +199,9 @@
bool GetPresentationPosition(PresentationPosition& presentation_position);
void UpdateSourceMetadata(const struct source_metadata& source_metadata);
void UpdateSinkMetadata(const struct sink_metadata& sink_metadata);
+ // New versions for AIDL-only clients.
+ bool UpdateSourceMetadata(const SourceMetadata& hal_source_metadata);
+ bool UpdateSinkMetadata(const SinkMetadata& hal_sink_metadata);
std::vector<LatencyMode> GetSupportedLatencyModes();
void SetLatencyMode(const LatencyMode& latency_mode);
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioSessionControl.h b/bluetooth/audio/utils/aidl_session/BluetoothAudioSessionControl.h
index 881c6c1..6c60a3b 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothAudioSessionControl.h
+++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioSessionControl.h
@@ -175,6 +175,26 @@
}
}
+ static bool UpdateSourceMetadata(const SessionType& session_type,
+ const SourceMetadata& source_metadata) {
+ std::shared_ptr<BluetoothAudioSession> session_ptr =
+ BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+ if (session_ptr != nullptr) {
+ return session_ptr->UpdateSourceMetadata(source_metadata);
+ }
+ return false;
+ }
+
+ static bool UpdateSinkMetadata(const SessionType& session_type,
+ const SinkMetadata& sink_metadata) {
+ std::shared_ptr<BluetoothAudioSession> session_ptr =
+ BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+ if (session_ptr != nullptr) {
+ return session_ptr->UpdateSinkMetadata(sink_metadata);
+ }
+ return false;
+ }
+
static std::vector<LatencyMode> GetSupportedLatencyModes(
const SessionType& session_type) {
std::shared_ptr<BluetoothAudioSession> session_ptr =
diff --git a/cas/1.0/default/android.hardware.cas@1.0-service-lazy.rc b/cas/1.0/default/android.hardware.cas@1.0-service-lazy.rc
index 622ee8f..1a08ebc 100644
--- a/cas/1.0/default/android.hardware.cas@1.0-service-lazy.rc
+++ b/cas/1.0/default/android.hardware.cas@1.0-service-lazy.rc
@@ -5,5 +5,6 @@
class hal
user media
group mediadrm drmrpc
+ capabilities SYS_NICE
ioprio rt 4
task_profiles ProcessCapacityHigh
diff --git a/cas/1.0/default/android.hardware.cas@1.0-service.rc b/cas/1.0/default/android.hardware.cas@1.0-service.rc
index 5df4825..a65160a 100644
--- a/cas/1.0/default/android.hardware.cas@1.0-service.rc
+++ b/cas/1.0/default/android.hardware.cas@1.0-service.rc
@@ -2,5 +2,6 @@
class hal
user media
group mediadrm drmrpc
+ capabilities SYS_NICE
ioprio rt 4
task_profiles ProcessCapacityHigh
diff --git a/cas/1.1/default/android.hardware.cas@1.1-service-lazy.rc b/cas/1.1/default/android.hardware.cas@1.1-service-lazy.rc
index 0721dc3..9fca8fd 100644
--- a/cas/1.1/default/android.hardware.cas@1.1-service-lazy.rc
+++ b/cas/1.1/default/android.hardware.cas@1.1-service-lazy.rc
@@ -6,5 +6,6 @@
class hal
user media
group mediadrm drmrpc
+ capabilities SYS_NICE
ioprio rt 4
task_profiles ProcessCapacityHigh
diff --git a/cas/1.1/default/android.hardware.cas@1.1-service.rc b/cas/1.1/default/android.hardware.cas@1.1-service.rc
index 132d943..19fd031 100644
--- a/cas/1.1/default/android.hardware.cas@1.1-service.rc
+++ b/cas/1.1/default/android.hardware.cas@1.1-service.rc
@@ -2,5 +2,6 @@
class hal
user media
group mediadrm drmrpc
+ capabilities SYS_NICE
ioprio rt 4
task_profiles ProcessCapacityHigh
diff --git a/cas/1.2/default/android.hardware.cas@1.2-service-lazy.rc b/cas/1.2/default/android.hardware.cas@1.2-service-lazy.rc
index d91fdce..8c2a894 100644
--- a/cas/1.2/default/android.hardware.cas@1.2-service-lazy.rc
+++ b/cas/1.2/default/android.hardware.cas@1.2-service-lazy.rc
@@ -7,5 +7,6 @@
class hal
user media
group mediadrm drmrpc
+ capabilities SYS_NICE
ioprio rt 4
task_profiles ProcessCapacityHigh
diff --git a/cas/1.2/default/android.hardware.cas@1.2-service.rc b/cas/1.2/default/android.hardware.cas@1.2-service.rc
index b22971a..4b638bc 100644
--- a/cas/1.2/default/android.hardware.cas@1.2-service.rc
+++ b/cas/1.2/default/android.hardware.cas@1.2-service.rc
@@ -2,5 +2,6 @@
class hal
user media
group mediadrm drmrpc
+ capabilities SYS_NICE
ioprio rt 4
task_profiles ProcessCapacityHigh
diff --git a/cas/aidl/default/cas-default-lazy.rc b/cas/aidl/default/cas-default-lazy.rc
index 60b59ca..7321cf0 100644
--- a/cas/aidl/default/cas-default-lazy.rc
+++ b/cas/aidl/default/cas-default-lazy.rc
@@ -3,6 +3,7 @@
class hal
user media
group mediadrm drmrpc
+ capabilities SYS_NICE
ioprio rt 4
task_profiles ProcessCapacityHigh
oneshot
diff --git a/cas/aidl/default/cas-default.rc b/cas/aidl/default/cas-default.rc
index e00b9c5..5a60368 100644
--- a/cas/aidl/default/cas-default.rc
+++ b/cas/aidl/default/cas-default.rc
@@ -3,5 +3,6 @@
class hal
user media
group mediadrm drmrpc
+ capabilities SYS_NICE
ioprio rt 4
task_profiles ProcessCapacityHigh
diff --git a/compatibility_matrices/compatibility_matrix.7.xml b/compatibility_matrices/compatibility_matrix.7.xml
index 33c3148..e20fcec 100644
--- a/compatibility_matrices/compatibility_matrix.7.xml
+++ b/compatibility_matrices/compatibility_matrix.7.xml
@@ -43,6 +43,7 @@
</hal>
<hal format="aidl" optional="true">
<name>android.hardware.automotive.audiocontrol</name>
+ <version>1-2</version>
<interface>
<name>IAudioControl</name>
<instance>default</instance>
diff --git a/compatibility_matrices/compatibility_matrix.8.xml b/compatibility_matrices/compatibility_matrix.8.xml
index 387648c..09d3fda 100644
--- a/compatibility_matrices/compatibility_matrix.8.xml
+++ b/compatibility_matrices/compatibility_matrix.8.xml
@@ -60,16 +60,9 @@
<instance>default</instance>
</interface>
</hal>
- <hal format="hidl" optional="true">
- <name>android.hardware.authsecret</name>
- <version>1.0</version>
- <interface>
- <name>IAuthSecret</name>
- <instance>default</instance>
- </interface>
- </hal>
<hal format="aidl" optional="true">
<name>android.hardware.automotive.audiocontrol</name>
+ <version>2</version>
<interface>
<name>IAudioControl</name>
<instance>default</instance>
diff --git a/compatibility_matrices/compatibility_matrix.9.xml b/compatibility_matrices/compatibility_matrix.9.xml
index f616bdb..77e5cb4 100644
--- a/compatibility_matrices/compatibility_matrix.9.xml
+++ b/compatibility_matrices/compatibility_matrix.9.xml
@@ -70,6 +70,7 @@
</hal>
<hal format="aidl" optional="true">
<name>android.hardware.automotive.audiocontrol</name>
+ <version>2</version>
<interface>
<name>IAudioControl</name>
<instance>default</instance>
diff --git a/compatibility_matrices/exclude/fcm_exclude.cpp b/compatibility_matrices/exclude/fcm_exclude.cpp
index ccce449..cfc8345 100644
--- a/compatibility_matrices/exclude/fcm_exclude.cpp
+++ b/compatibility_matrices/exclude/fcm_exclude.cpp
@@ -24,9 +24,7 @@
namespace android::vintf::details {
// The predicate to VintfObject::checkMissingHalsInMatrices.
-bool ShouldCheckMissingHalsInFcm(const std::string& package) {
- using std::placeholders::_1;
-
+bool ShouldCheckMissingHidlHalsInFcm(const std::string& packageAndVersion) {
static std::vector<std::string> included_prefixes{
// Other AOSP HALs (e.g. android.frameworks.*) are not added because only framework
// matrix is checked.
@@ -51,28 +49,11 @@
"android.hardware.media.bufferpool@1.0",
"android.hardware.media.bufferpool@2.0",
"android.hardware.radio.config@1.2",
- // AIDL
- "android.hardware.audio.common",
- "android.hardware.audio.core.sounddose",
- "android.hardware.biometrics.common",
- "android.hardware.camera.metadata",
- "android.hardware.camera.device",
- "android.hardware.camera.common",
- "android.hardware.common",
- "android.hardware.common.fmq",
- "android.hardware.graphics.common",
- "android.hardware.input.common",
- "android.hardware.keymaster",
- "android.hardware.media.bufferpool2",
- "android.hardware.radio",
- "android.hardware.uwb.fira_android",
// Fastboot HAL is only used by recovery. Recovery is owned by OEM. Framework
// does not depend on this HAL, hence it is not declared in any manifests or matrices.
"android.hardware.fastboot@1.0",
"android.hardware.fastboot@1.1",
- // Fastboot AIDL
- "android.hardware.fastboot",
// Deprecated HALs.
// HIDL
@@ -106,6 +87,60 @@
};
auto package_has_prefix = [&](const std::string& prefix) {
+ return android::base::StartsWith(packageAndVersion, prefix);
+ };
+
+ // Only check packageAndVersions that are in the include list and not in the exclude list.
+ if (!std::any_of(included_prefixes.begin(), included_prefixes.end(), package_has_prefix)) {
+ return false;
+ }
+
+ if (std::find(excluded_exact.begin(), excluded_exact.end(), packageAndVersion) !=
+ excluded_exact.end()) {
+ return false;
+ }
+
+ return !std::any_of(excluded_prefixes.begin(), excluded_prefixes.end(), package_has_prefix);
+}
+
+// The predicate to VintfObject::checkMissingHalsInMatrices.
+bool ShouldCheckMissingAidlHalsInFcm(const std::string& package) {
+ static std::vector<std::string> included_prefixes{
+ // Other AOSP HALs (e.g. android.frameworks.*) are not added because only framework
+ // matrix is checked.
+ "android.hardware.",
+ };
+
+ static std::vector<std::string> excluded_prefixes{
+ // Test packages are exempted.
+ "android.hardware.tests.",
+ };
+
+ static std::vector<std::string> excluded_exact{
+ // Packages without top level interfaces (including types-only packages) are exempted.
+
+ // AIDL
+ "android.hardware.audio.common",
+ "android.hardware.audio.core.sounddose",
+ "android.hardware.biometrics.common",
+ "android.hardware.camera.metadata",
+ "android.hardware.camera.device",
+ "android.hardware.camera.common",
+ "android.hardware.common",
+ "android.hardware.common.fmq",
+ "android.hardware.graphics.common",
+ "android.hardware.input.common",
+ "android.hardware.keymaster",
+ "android.hardware.media.bufferpool2",
+ "android.hardware.radio",
+ "android.hardware.uwb.fira_android",
+
+ // Fastboot HAL is only used by recovery. Recovery is owned by OEM. Framework
+ // does not depend on this HAL, hence it is not declared in any manifests or matrices.
+ "android.hardware.fastboot",
+ };
+
+ auto package_has_prefix = [&](const std::string& prefix) {
return android::base::StartsWith(package, prefix);
};
diff --git a/compatibility_matrices/exclude/include/vintf/fcm_exclude.h b/compatibility_matrices/exclude/include/vintf/fcm_exclude.h
index f74c217..9ee057b 100644
--- a/compatibility_matrices/exclude/include/vintf/fcm_exclude.h
+++ b/compatibility_matrices/exclude/include/vintf/fcm_exclude.h
@@ -25,6 +25,7 @@
// |package| can be a HIDL package and version like
// "android.hardware.foo@1.0", or an AIDL package name like
// "android.hardware.foo".
-bool ShouldCheckMissingHalsInFcm(const std::string& package);
+bool ShouldCheckMissingHidlHalsInFcm(const std::string& packageAndVersion);
+bool ShouldCheckMissingAidlHalsInFcm(const std::string& package);
} // namespace android::vintf::details
diff --git a/gatekeeper/aidl/vts/functional/VtsHalGatekeeperTargetTest.cpp b/gatekeeper/aidl/vts/functional/VtsHalGatekeeperTargetTest.cpp
index c89243b..032f7e2 100644
--- a/gatekeeper/aidl/vts/functional/VtsHalGatekeeperTargetTest.cpp
+++ b/gatekeeper/aidl/vts/functional/VtsHalGatekeeperTargetTest.cpp
@@ -221,6 +221,47 @@
}
/**
+ * Ensure that passwords containing a NUL byte aren't truncated
+ */
+TEST_P(GatekeeperAidlTest, PasswordIsBinaryData) {
+ GatekeeperEnrollResponse enrollRsp;
+ GatekeeperVerifyResponse verifyRsp;
+ std::vector<uint8_t> rightPassword = {'A', 'B', 'C', '\0', 'D', 'E', 'F'};
+ std::vector<uint8_t> wrongPassword = {'A', 'B', 'C', '\0', '\0', '\0', '\0'};
+
+ ALOGI("Testing Enroll+Verify of password with embedded NUL (expected success)");
+ enrollNewPassword(rightPassword, enrollRsp, true);
+ verifyPassword(rightPassword, enrollRsp.data, 1, verifyRsp, true);
+
+ ALOGI("Testing Verify of wrong password (expected failure)");
+ verifyPassword(wrongPassword, enrollRsp.data, 1, verifyRsp, false);
+
+ ALOGI("PasswordIsBinaryData test done");
+}
+
+/**
+ * Ensure that long passwords aren't truncated
+ */
+TEST_P(GatekeeperAidlTest, LongPassword) {
+ GatekeeperEnrollResponse enrollRsp;
+ GatekeeperVerifyResponse verifyRsp;
+ std::vector<uint8_t> password;
+
+ password.resize(64); // maximum length used by Android
+ memset(password.data(), 'A', password.size());
+
+ ALOGI("Testing Enroll+Verify of long password (expected success)");
+ enrollNewPassword(password, enrollRsp, true);
+ verifyPassword(password, enrollRsp.data, 1, verifyRsp, true);
+
+ ALOGI("Testing Verify of wrong password (expected failure)");
+ password[password.size() - 1] ^= 1;
+ verifyPassword(password, enrollRsp.data, 1, verifyRsp, false);
+
+ ALOGI("LongPassword test done");
+}
+
+/**
* Ensure we can securely update password (keep the same
* secure user_id) if we prove we know old password
*/
diff --git a/security/keymint/aidl/vts/functional/AttestKeyTest.cpp b/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
index 8a8eaa4..8aef9d9 100644
--- a/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
+++ b/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
@@ -919,7 +919,9 @@
.Authorization(TAG_ATTESTATION_ID_MODEL, "malicious-model");
if (isSecondImeiIdAttestationRequired()) {
- attestation_id_tags.Authorization(TAG_ATTESTATION_ID_SECOND_IMEI, "invalid-second-imei");
+ // Note: the invalid value here is < 16 bytes long to avoid triggering any implementation
+ // checks on valid IMEI lengths.
+ attestation_id_tags.Authorization(TAG_ATTESTATION_ID_SECOND_IMEI, "invalid-imei2");
}
vector<uint8_t> key_blob;
vector<KeyCharacteristics> key_characteristics;
diff --git a/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl b/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
index ff9c247..21951b6 100644
--- a/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
+++ b/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
@@ -45,6 +45,7 @@
CCC_SUPPORTED_RAN_MULTIPLIER = 0xA7,
CCC_SUPPORTED_MAX_RANGING_SESSION_NUMBER = 0xA8,
CCC_SUPPORTED_MIN_UWB_INITIATION_TIME_MS = 0xA9,
+ CCC_PRIORITIZED_CHANNEL_LIST = 0xAA,
RADAR_SUPPORT = 0xB0,
SUPPORTED_AOA_RESULT_REQ_ANTENNA_INTERLEAVING = 0xE3,
SUPPORTED_MIN_RANGING_INTERVAL_MS = 0xE4,
diff --git a/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
index ceef1be..2141b5a 100644
--- a/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
+++ b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
@@ -149,6 +149,11 @@
*/
CCC_SUPPORTED_MIN_UWB_INITIATION_TIME_MS = 0xA9,
+ /**
+ * Byte array of channels supported by the device, ordered by priority from highest to lowest.
+ */
+ CCC_PRIORITIZED_CHANNEL_LIST = 0xAA,
+
/*********************************************
* RADAR specific
********************************************/