audio: Add Dual Mono Mode and Audio Description Mix Level to IStreamOut
These properties are mainly used on TV platforms.
Bug: 133526565
Test: atest VtsHalAudioV6_0TargetTest
Change-Id: I5dd2fe9cb987bf8435b8e5da96f8590288e5707c
diff --git a/audio/6.0/IStreamOut.hal b/audio/6.0/IStreamOut.hal
index 941ba61..91668ba 100644
--- a/audio/6.0/IStreamOut.hal
+++ b/audio/6.0/IStreamOut.hal
@@ -276,4 +276,61 @@
*/
selectPresentation(int32_t presentationId, int32_t programId)
generates (Result retval);
+
+ /**
+ * Returns the Dual Mono mode presentation setting.
+ *
+ * Optional method
+ *
+ * @return retval operation completion status.
+ * @return mode current setting of Dual Mono mode.
+ */
+ getDualMonoMode() generates (Result retval, DualMonoMode mode);
+
+ /**
+ * Sets the Dual Mono mode presentation on the output device.
+ *
+ * The Dual Mono mode is generally applied to stereo audio streams
+ * where the left and right channels come from separate sources.
+ *
+ * Optional method
+ *
+ * @param mode selected Dual Mono mode.
+ * @return retval operation completion status.
+ */
+ setDualMonoMode(DualMonoMode mode) generates (Result retval);
+
+ /**
+ * Returns the Audio Description Mix level in dB.
+ *
+ * The level is applied to streams incorporating a secondary Audio
+ * Description stream. It specifies the relative level of mixing for
+ * the Audio Description with a reference to the Main Audio.
+ *
+ * Optional method
+ *
+ * The value of the relative level is in the range from negative infinity
+ * to +48.
+ *
+ * @return retval operation completion status.
+ * @return leveldB the current Audio Description Mix Level in dB.
+ */
+ getAudioDescriptionMixLevel() generates (Result retval, float leveldB);
+
+ /**
+ * Sets the Audio Description Mix level in dB.
+ *
+ * For streams incorporating a secondary Audio Description stream
+ * the relative level of mixing of the Audio Description to the Main Audio
+ * is controlled by this method.
+ *
+ * Optional method
+ *
+ * The value of the relative level must be in the range from negative
+ * infinity to +48.
+ *
+ * @param leveldB Audio Description Mix Level in dB
+ * @return retval operation completion status.
+ */
+ setAudioDescriptionMixLevel(float leveldB) generates (Result retval);
};
diff --git a/audio/6.0/types.hal b/audio/6.0/types.hal
index 1a704f8..efc3ea5 100644
--- a/audio/6.0/types.hal
+++ b/audio/6.0/types.hal
@@ -247,3 +247,53 @@
*/
EXTERNAL = 3,
};
+
+
+/* Dual Mono handling is used when a stereo audio stream
+ * contains separate audio content on the left and right channels.
+ * Such information about the content of the stream may be found, for example,
+ * in ITU T-REC-J.94-201610 A.6.2.3 Component descriptor.
+ */
+@export(name="audio_dual_mono_mode_t", value_prefix="AUDIO_DUAL_MONO_MODE_")
+enum DualMonoMode : int32_t {
+ // Need to be in sync with DUAL_MONO_MODE* constants in
+ // frameworks/base/media/java/android/media/AudioTrack.java
+ /**
+ * Disable any Dual Mono presentation effect.
+ *
+ */
+ OFF = 0,
+ /**
+ * This mode indicates that a stereo stream should be presented
+ * with the left and right audio channels blended together
+ * and delivered to both channels.
+ *
+ * Behavior for non-stereo streams is implementation defined.
+ * A suggested guideline is that the left-right stereo symmetric
+ * channels are pairwise blended, the other channels such as center
+ * are left alone.
+ */
+ LR = 1,
+ /**
+ * This mode indicates that a stereo stream should be presented
+ * with the left audio channel replicated into the right audio channel.
+ *
+ * Behavior for non-stereo streams is implementation defined.
+ * A suggested guideline is that all channels with left-right
+ * stereo symmetry will have the left channel position replicated
+ * into the right channel position. The center channels (with no
+ * left/right symmetry) or unbalanced channels are left alone.
+ */
+ LL = 2,
+ /**
+ * This mode indicates that a stereo stream should be presented
+ * with the right audio channel replicated into the left audio channel.
+ *
+ * Behavior for non-stereo streams is implementation defined.
+ * A suggested guideline is that all channels with left-right
+ * stereo symmetry will have the right channel position replicated
+ * into the left channel position. The center channels (with no
+ * left/right symmetry) or unbalanced channels are left alone.
+ */
+ RR = 3,
+};
diff --git a/audio/core/all-versions/default/StreamOut.cpp b/audio/core/all-versions/default/StreamOut.cpp
index 1a2a764..cfbee34 100644
--- a/audio/core/all-versions/default/StreamOut.cpp
+++ b/audio/core/all-versions/default/StreamOut.cpp
@@ -582,6 +582,26 @@
}
#endif
+#if MAJOR_VERSION >= 6
+Return<void> StreamOut::getDualMonoMode(getDualMonoMode_cb _hidl_cb) {
+ _hidl_cb(Result::NOT_SUPPORTED, DualMonoMode::OFF);
+ return Void();
+}
+
+Return<Result> StreamOut::setDualMonoMode(DualMonoMode /*mode*/) {
+ return Result::NOT_SUPPORTED;
+}
+
+Return<void> StreamOut::getAudioDescriptionMixLevel(getAudioDescriptionMixLevel_cb _hidl_cb) {
+ _hidl_cb(Result::NOT_SUPPORTED, -std::numeric_limits<float>::infinity());
+ return Void();
+}
+
+Return<Result> StreamOut::setAudioDescriptionMixLevel(float /*leveldB*/) {
+ return Result::NOT_SUPPORTED;
+}
+#endif
+
} // namespace implementation
} // namespace CPP_VERSION
} // namespace audio
diff --git a/audio/core/all-versions/default/include/core/default/StreamOut.h b/audio/core/all-versions/default/include/core/default/StreamOut.h
index 6334785..294867c 100644
--- a/audio/core/all-versions/default/include/core/default/StreamOut.h
+++ b/audio/core/all-versions/default/include/core/default/StreamOut.h
@@ -121,6 +121,12 @@
Return<void> updateSourceMetadata(const SourceMetadata& sourceMetadata) override;
Return<Result> selectPresentation(int32_t presentationId, int32_t programId) override;
#endif
+#if MAJOR_VERSION >= 6
+ Return<void> getDualMonoMode(getDualMonoMode_cb _hidl_cb) override;
+ Return<Result> setDualMonoMode(DualMonoMode mode) override;
+ Return<void> getAudioDescriptionMixLevel(getAudioDescriptionMixLevel_cb _hidl_cb) override;
+ Return<Result> setAudioDescriptionMixLevel(float leveldB) override;
+#endif
static Result getPresentationPositionImpl(audio_stream_out_t* stream, uint64_t* frames,
TimeSpec* timeStamp);
diff --git a/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp
index 09ef330..c9ba509 100644
--- a/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp
+++ b/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp
@@ -190,3 +190,30 @@
hidl_vec<AudioPortConfig>(), hidl_vec<AudioPortConfig>(), returnIn(res, ignored)));
ASSERT_RESULT(Result::INVALID_ARGUMENTS, res);
}
+
+using DualMonoModeAccessorHidlTest = AccessorHidlTest<DualMonoMode, OutputStreamTest>;
+TEST_P(DualMonoModeAccessorHidlTest, DualMonoModeTest) {
+ doc::test("Check that dual mono mode can be set and retrieved");
+ testAccessors<OPTIONAL>(&OutputStreamTest::getStream, "dual mono mode",
+ Initial{DualMonoMode::OFF},
+ {DualMonoMode::LR, DualMonoMode::LL, DualMonoMode::RR},
+ &IStreamOut::setDualMonoMode, &IStreamOut::getDualMonoMode);
+}
+
+INSTANTIATE_TEST_CASE_P(DualMonoModeHidl, DualMonoModeAccessorHidlTest,
+ ::testing::ValuesIn(getOutputDeviceConfigParameters()),
+ &DeviceConfigParameterToString);
+
+using AudioDescriptionMixLevelHidlTest = AccessorHidlTest<float, OutputStreamTest>;
+TEST_P(AudioDescriptionMixLevelHidlTest, AudioDescriptionMixLevelTest) {
+ doc::test("Check that audio description mix level can be set and retrieved");
+ testAccessors<OPTIONAL>(
+ &OutputStreamTest::getStream, "audio description mix level",
+ Initial{-std::numeric_limits<float>::infinity()}, {-48.0f, -1.0f, 0.0f, 1.0f, 48.0f},
+ &IStreamOut::setAudioDescriptionMixLevel, &IStreamOut::getAudioDescriptionMixLevel,
+ {48.5f, 1000.0f, std::numeric_limits<float>::infinity()});
+}
+
+INSTANTIATE_TEST_CASE_P(AudioDescriptionMixLevelHidl, AudioDescriptionMixLevelHidlTest,
+ ::testing::ValuesIn(getOutputDeviceConfigParameters()),
+ &DeviceConfigParameterToString);
diff --git a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
index d0d39e8..b77aec9 100644
--- a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
+++ b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
@@ -140,6 +140,11 @@
class HidlTest : public HidlTestBase {
public:
virtual ~HidlTest() = default;
+ // public access to avoid annoyances when using this method in template classes
+ // derived from test classes
+ sp<IDevice> getDevice() const {
+ return DeviceManager::getInstance().get(getFactoryName(), getDeviceName());
+ }
protected:
// Factory and device name getters to be overridden in subclasses.
@@ -149,9 +154,6 @@
sp<IDevicesFactory> getDevicesFactory() const {
return DevicesFactoryManager::getInstance().get(getFactoryName());
}
- sp<IDevice> getDevice() const {
- return DeviceManager::getInstance().get(getFactoryName(), getDeviceName());
- }
bool resetDevice() const {
return DeviceManager::getInstance().reset(getFactoryName(), getDeviceName());
}
@@ -419,7 +421,8 @@
ASSERT_TRUE(getDevice() != nullptr);
}
- protected:
+ // public access to avoid annoyances when using this method in template classes
+ // derived from test classes
sp<IPrimaryDevice> getDevice() const {
return DeviceManager::getInstance().getPrimary(getFactoryName());
}
@@ -450,15 +453,15 @@
/** Test a property getter and setter.
* The getter and/or the setter may return NOT_SUPPORTED if optionality == OPTIONAL.
*/
- template <Optionality optionality = REQUIRED, class Getter, class Setter>
- void testAccessors(const string& propertyName, const Initial expectedInitial,
- list<Property> valuesToTest, Setter setter, Getter getter,
- const vector<Property>& invalidValues = {}) {
+ template <Optionality optionality = REQUIRED, class IUTGetter, class Getter, class Setter>
+ void testAccessors(IUTGetter iutGetter, const string& propertyName,
+ const Initial expectedInitial, list<Property> valuesToTest, Setter setter,
+ Getter getter, const vector<Property>& invalidValues = {}) {
const auto expectedResults = {Result::OK,
optionality == OPTIONAL ? Result::NOT_SUPPORTED : Result::OK};
Property initialValue = expectedInitial.value;
- ASSERT_OK((BaseTestClass::getDevice().get()->*getter)(returnIn(res, initialValue)));
+ ASSERT_OK(((this->*iutGetter)().get()->*getter)(returnIn(res, initialValue)));
ASSERT_RESULT(expectedResults, res);
if (res == Result::OK && expectedInitial.check == REQUIRED) {
EXPECT_EQ(expectedInitial.value, initialValue);
@@ -469,7 +472,7 @@
for (Property setValue : valuesToTest) {
SCOPED_TRACE("Test " + propertyName + " getter and setter for " +
testing::PrintToString(setValue));
- auto ret = (BaseTestClass::getDevice().get()->*setter)(setValue);
+ auto ret = ((this->*iutGetter)().get()->*setter)(setValue);
ASSERT_RESULT(expectedResults, ret);
if (ret == Result::NOT_SUPPORTED) {
doc::partialTest(propertyName + " setter is not supported");
@@ -477,7 +480,7 @@
}
Property getValue;
// Make sure the getter returns the same value just set
- ASSERT_OK((BaseTestClass::getDevice().get()->*getter)(returnIn(res, getValue)));
+ ASSERT_OK(((this->*iutGetter)().get()->*getter)(returnIn(res, getValue)));
ASSERT_RESULT(expectedResults, res);
if (res == Result::NOT_SUPPORTED) {
doc::partialTest(propertyName + " getter is not supported");
@@ -490,11 +493,18 @@
SCOPED_TRACE("Try to set " + propertyName + " with the invalid value " +
testing::PrintToString(invalidValue));
EXPECT_RESULT(invalidArgsOrNotSupported,
- (BaseTestClass::getDevice().get()->*setter)(invalidValue));
+ ((this->*iutGetter)().get()->*setter)(invalidValue));
}
// Restore initial value
- EXPECT_RESULT(expectedResults, (BaseTestClass::getDevice().get()->*setter)(initialValue));
+ EXPECT_RESULT(expectedResults, ((this->*iutGetter)().get()->*setter)(initialValue));
+ }
+ template <Optionality optionality = REQUIRED, class Getter, class Setter>
+ void testAccessors(const string& propertyName, const Initial expectedInitial,
+ list<Property> valuesToTest, Setter setter, Getter getter,
+ const vector<Property>& invalidValues = {}) {
+ testAccessors<optionality>(&BaseTestClass::getDevice, propertyName, expectedInitial,
+ valuesToTest, setter, getter, invalidValues);
}
};
@@ -872,6 +882,11 @@
template <class Stream>
class OpenStreamTest : public AudioHidlTestWithDeviceConfigParameter {
+ public:
+ // public access to avoid annoyances when using this method in template classes
+ // derived from test classes
+ sp<Stream> getStream() const { return stream; }
+
protected:
OpenStreamTest() : AudioHidlTestWithDeviceConfigParameter(), helper(stream) {}
template <class Open>