1 /*
2 * Copyright 2023 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <algorithm>
18 #include <memory>
19 #include <mutex>
20 #include <string>
21 #include <vector>
22
23 #define LOG_TAG "CoreAudioHalAidlTest"
24 #include <gtest/gtest.h>
25
26 #include <DeviceHalAidl.h>
27 #include <Hal2AidlMapper.h>
28 #include <StreamHalAidl.h>
29 #include <aidl/android/hardware/audio/core/BnModule.h>
30 #include <aidl/android/hardware/audio/core/BnStreamCommon.h>
31 #include <aidl/android/media/audio/BnHalAdapterVendorExtension.h>
32 #include <aidl/android/media/audio/common/AudioGainMode.h>
33 #include <aidl/android/media/audio/common/Int.h>
34 #include <utils/Log.h>
35
36 namespace {
37
38 using ::aidl::android::hardware::audio::core::AudioPatch;
39 using ::aidl::android::hardware::audio::core::AudioRoute;
40 using ::aidl::android::hardware::audio::core::VendorParameter;
41 using ::aidl::android::media::audio::common::AudioChannelLayout;
42 using ::aidl::android::media::audio::common::AudioConfig;
43 using ::aidl::android::media::audio::common::AudioDevice;
44 using ::aidl::android::media::audio::common::AudioDeviceDescription;
45 using ::aidl::android::media::audio::common::AudioDeviceType;
46 using ::aidl::android::media::audio::common::AudioFormatDescription;
47 using ::aidl::android::media::audio::common::AudioFormatType;
48 using ::aidl::android::media::audio::common::AudioGainConfig;
49 using ::aidl::android::media::audio::common::AudioGainMode;
50 using ::aidl::android::media::audio::common::AudioIoFlags;
51 using ::aidl::android::media::audio::common::AudioPort;
52 using ::aidl::android::media::audio::common::AudioPortConfig;
53 using ::aidl::android::media::audio::common::AudioPortDeviceExt;
54 using ::aidl::android::media::audio::common::AudioPortExt;
55 using ::aidl::android::media::audio::common::AudioPortMixExt;
56 using ::aidl::android::media::audio::common::AudioProfile;
57 using ::aidl::android::media::audio::common::AudioSource;
58 using ::aidl::android::media::audio::common::PcmType;
59
60 class VendorParameterMock {
61 public:
getRetrievedParameterIds() const62 const std::vector<std::string>& getRetrievedParameterIds() const { return mGetParameterIds; }
getAsyncParameters() const63 const std::vector<VendorParameter>& getAsyncParameters() const { return mAsyncParameters; }
getSyncParameters() const64 const std::vector<VendorParameter>& getSyncParameters() const { return mSyncParameters; }
65
66 protected:
getVendorParametersImpl(const std::vector<std::string> & in_parameterIds)67 ndk::ScopedAStatus getVendorParametersImpl(const std::vector<std::string>& in_parameterIds) {
68 mGetParameterIds.insert(mGetParameterIds.end(), in_parameterIds.begin(),
69 in_parameterIds.end());
70 return ndk::ScopedAStatus::ok();
71 }
setVendorParametersImpl(const std::vector<VendorParameter> & in_parameters,bool async)72 ndk::ScopedAStatus setVendorParametersImpl(const std::vector<VendorParameter>& in_parameters,
73 bool async) {
74 if (async) {
75 mAsyncParameters.insert(mAsyncParameters.end(), in_parameters.begin(),
76 in_parameters.end());
77 } else {
78 mSyncParameters.insert(mSyncParameters.end(), in_parameters.begin(),
79 in_parameters.end());
80 }
81 return ndk::ScopedAStatus::ok();
82 }
83
84 private:
85 std::vector<std::string> mGetParameterIds;
86 std::vector<VendorParameter> mAsyncParameters;
87 std::vector<VendorParameter> mSyncParameters;
88 };
89
90 struct Configuration {
91 std::vector<AudioPort> ports;
92 std::vector<AudioPortConfig> portConfigs;
93 std::vector<AudioRoute> routes;
94 std::vector<AudioPatch> patches;
95 int32_t nextPortId = 1;
96 int32_t nextPatchId = 1;
97 };
98
fillProfile(AudioProfile * profile,const std::vector<int32_t> & channelLayouts,const std::vector<int32_t> & sampleRates)99 void fillProfile(AudioProfile* profile, const std::vector<int32_t>& channelLayouts,
100 const std::vector<int32_t>& sampleRates) {
101 for (auto layout : channelLayouts) {
102 profile->channelMasks.push_back(
103 AudioChannelLayout::make<AudioChannelLayout::layoutMask>(layout));
104 }
105 profile->sampleRates.insert(profile->sampleRates.end(), sampleRates.begin(), sampleRates.end());
106 }
107
createProfile(PcmType pcmType,const std::vector<int32_t> & channelLayouts,const std::vector<int32_t> & sampleRates)108 AudioProfile createProfile(PcmType pcmType, const std::vector<int32_t>& channelLayouts,
109 const std::vector<int32_t>& sampleRates) {
110 AudioProfile profile;
111 profile.format.type = AudioFormatType::PCM;
112 profile.format.pcm = pcmType;
113 fillProfile(&profile, channelLayouts, sampleRates);
114 return profile;
115 }
116
createPortDeviceExt(AudioDeviceType devType,int32_t flags,std::string connection="")117 AudioPortExt createPortDeviceExt(AudioDeviceType devType, int32_t flags,
118 std::string connection = "") {
119 AudioPortDeviceExt deviceExt;
120 deviceExt.device.type.type = devType;
121 if (devType == AudioDeviceType::IN_MICROPHONE && connection.empty()) {
122 deviceExt.device.address = "bottom";
123 } else if (devType == AudioDeviceType::IN_MICROPHONE_BACK && connection.empty()) {
124 deviceExt.device.address = "back";
125 }
126 deviceExt.device.type.connection = std::move(connection);
127 deviceExt.flags = flags;
128 return AudioPortExt::make<AudioPortExt::device>(deviceExt);
129 }
130
createPortMixExt(int32_t maxOpenStreamCount,int32_t maxActiveStreamCount)131 AudioPortExt createPortMixExt(int32_t maxOpenStreamCount, int32_t maxActiveStreamCount) {
132 AudioPortMixExt mixExt;
133 mixExt.maxOpenStreamCount = maxOpenStreamCount;
134 mixExt.maxActiveStreamCount = maxActiveStreamCount;
135 return AudioPortExt::make<AudioPortExt::mix>(mixExt);
136 }
137
createPort(int32_t id,const std::string & name,int32_t flags,bool isInput,const AudioPortExt & ext)138 AudioPort createPort(int32_t id, const std::string& name, int32_t flags, bool isInput,
139 const AudioPortExt& ext) {
140 AudioPort port;
141 port.id = id;
142 port.name = name;
143 port.flags = isInput ? AudioIoFlags::make<AudioIoFlags::input>(flags)
144 : AudioIoFlags::make<AudioIoFlags::output>(flags);
145 port.ext = ext;
146 return port;
147 }
148
createRoute(const std::vector<AudioPort> & sources,const AudioPort & sink)149 AudioRoute createRoute(const std::vector<AudioPort>& sources, const AudioPort& sink) {
150 AudioRoute route;
151 route.sinkPortId = sink.id;
152 std::transform(sources.begin(), sources.end(), std::back_inserter(route.sourcePortIds),
153 [](const auto& port) { return port.id; });
154 return route;
155 }
156
157 template <typename T>
findById(std::vector<T> & v,int32_t id)158 auto findById(std::vector<T>& v, int32_t id) {
159 return std::find_if(v.begin(), v.end(), [&](const auto& e) { return e.id == id; });
160 }
161
getTestConfiguration()162 Configuration getTestConfiguration() {
163 const std::vector<AudioProfile> standardPcmAudioProfiles = {
164 createProfile(PcmType::INT_16_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {48000})};
165 Configuration c;
166
167 AudioPort micInDevice =
168 createPort(c.nextPortId++, "Built-In Mic", 0, true,
169 createPortDeviceExt(AudioDeviceType::IN_MICROPHONE,
170 1 << AudioPortDeviceExt::FLAG_INDEX_DEFAULT_DEVICE));
171 micInDevice.profiles = standardPcmAudioProfiles;
172 c.ports.push_back(micInDevice);
173
174 AudioPort micInBackDevice =
175 createPort(c.nextPortId++, "Built-In Back Mic", 0, true,
176 createPortDeviceExt(AudioDeviceType::IN_MICROPHONE_BACK, 0));
177 micInDevice.profiles = standardPcmAudioProfiles;
178 c.ports.push_back(micInBackDevice);
179
180 AudioPort primaryInMix =
181 createPort(c.nextPortId++, "primary input", 0, true, createPortMixExt(0, 1));
182 primaryInMix.profiles = standardPcmAudioProfiles;
183 c.ports.push_back(primaryInMix);
184
185 AudioPort speakerOutDevice = createPort(c.nextPortId++, "Speaker", 0, false,
186 createPortDeviceExt(AudioDeviceType::OUT_SPEAKER, 0));
187 speakerOutDevice.profiles = standardPcmAudioProfiles;
188 c.ports.push_back(speakerOutDevice);
189
190 AudioPort btOutDevice =
191 createPort(c.nextPortId++, "BT A2DP Out", 0, false,
192 createPortDeviceExt(AudioDeviceType::OUT_DEVICE, 0,
193 AudioDeviceDescription::CONNECTION_BT_A2DP));
194 btOutDevice.profiles = standardPcmAudioProfiles;
195 c.ports.push_back(btOutDevice);
196
197 AudioPort btOutMix =
198 createPort(c.nextPortId++, "a2dp output", 0, false, createPortMixExt(1, 1));
199 btOutMix.profiles = standardPcmAudioProfiles;
200 c.ports.push_back(btOutMix);
201
202 c.routes.push_back(createRoute({micInDevice, micInBackDevice}, primaryInMix));
203 c.routes.push_back(createRoute({btOutMix}, btOutDevice));
204
205 return c;
206 }
207
208 class ModuleMock : public ::aidl::android::hardware::audio::core::BnModule,
209 public VendorParameterMock {
210 public:
211 ModuleMock() = default;
ModuleMock(const Configuration & config)212 explicit ModuleMock(const Configuration& config) : mConfig(config) {}
isScreenTurnedOn() const213 bool isScreenTurnedOn() const { return mIsScreenTurnedOn; }
getScreenRotation() const214 ScreenRotation getScreenRotation() const { return mScreenRotation; }
getPatches()215 std::vector<AudioPatch> getPatches() {
216 std::vector<AudioPatch> result;
217 getAudioPatches(&result);
218 return result;
219 }
getPortConfig(int32_t id)220 std::optional<AudioPortConfig> getPortConfig(int32_t id) {
221 auto iter = findById<AudioPortConfig>(mConfig.portConfigs, id);
222 if (iter != mConfig.portConfigs.end()) {
223 return *iter;
224 }
225 return std::nullopt;
226 }
227
228 private:
setModuleDebug(const::aidl::android::hardware::audio::core::ModuleDebug &)229 ndk::ScopedAStatus setModuleDebug(
230 const ::aidl::android::hardware::audio::core::ModuleDebug&) override {
231 return ndk::ScopedAStatus::ok();
232 }
getTelephony(std::shared_ptr<::aidl::android::hardware::audio::core::ITelephony> *)233 ndk::ScopedAStatus getTelephony(
234 std::shared_ptr<::aidl::android::hardware::audio::core::ITelephony>*) override {
235 return ndk::ScopedAStatus::ok();
236 }
getBluetooth(std::shared_ptr<::aidl::android::hardware::audio::core::IBluetooth> *)237 ndk::ScopedAStatus getBluetooth(
238 std::shared_ptr<::aidl::android::hardware::audio::core::IBluetooth>*) override {
239 return ndk::ScopedAStatus::ok();
240 }
getBluetoothA2dp(std::shared_ptr<::aidl::android::hardware::audio::core::IBluetoothA2dp> *)241 ndk::ScopedAStatus getBluetoothA2dp(
242 std::shared_ptr<::aidl::android::hardware::audio::core::IBluetoothA2dp>*) override {
243 return ndk::ScopedAStatus::ok();
244 }
getBluetoothLe(std::shared_ptr<::aidl::android::hardware::audio::core::IBluetoothLe> *)245 ndk::ScopedAStatus getBluetoothLe(
246 std::shared_ptr<::aidl::android::hardware::audio::core::IBluetoothLe>*) override {
247 return ndk::ScopedAStatus::ok();
248 }
connectExternalDevice(const::aidl::android::media::audio::common::AudioPort & portIdAndData,::aidl::android::media::audio::common::AudioPort * port)249 ndk::ScopedAStatus connectExternalDevice(
250 const ::aidl::android::media::audio::common::AudioPort& portIdAndData,
251 ::aidl::android::media::audio::common::AudioPort* port) override {
252 auto src = portIdAndData; // Make a copy to mimic RPC behavior.
253 auto iter = findById<AudioPort>(mConfig.ports, src.id);
254 if (iter == mConfig.ports.end()) {
255 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
256 }
257 *port = *iter;
258 port->ext = src.ext;
259 port->id = mConfig.nextPortId++;
260 ALOGD("%s: returning %s", __func__, port->toString().c_str());
261 mConfig.ports.push_back(*port);
262 std::vector<AudioRoute> newRoutes;
263 for (auto& r : mConfig.routes) {
264 if (r.sinkPortId == src.id) {
265 newRoutes.push_back(AudioRoute{.sourcePortIds = r.sourcePortIds,
266 .sinkPortId = port->id,
267 .isExclusive = r.isExclusive});
268 } else if (std::find(r.sourcePortIds.begin(), r.sourcePortIds.end(), src.id) !=
269 r.sourcePortIds.end()) {
270 r.sourcePortIds.push_back(port->id);
271 }
272 }
273 mConfig.routes.insert(mConfig.routes.end(), newRoutes.begin(), newRoutes.end());
274 return ndk::ScopedAStatus::ok();
275 }
disconnectExternalDevice(int32_t portId)276 ndk::ScopedAStatus disconnectExternalDevice(int32_t portId) override {
277 auto iter = findById<AudioPort>(mConfig.ports, portId);
278 if (iter == mConfig.ports.end()) {
279 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
280 }
281 mConfig.ports.erase(iter);
282 for (auto it = mConfig.routes.begin(); it != mConfig.routes.end();) {
283 if (it->sinkPortId == portId) {
284 it = mConfig.routes.erase(it);
285 } else {
286 if (auto srcIt =
287 std::find(it->sourcePortIds.begin(), it->sourcePortIds.end(), portId);
288 srcIt != it->sourcePortIds.end()) {
289 it->sourcePortIds.erase(srcIt);
290 }
291 ++it;
292 }
293 }
294 return ndk::ScopedAStatus::ok();
295 }
getAudioPatches(std::vector<::aidl::android::hardware::audio::core::AudioPatch> * patches)296 ndk::ScopedAStatus getAudioPatches(
297 std::vector<::aidl::android::hardware::audio::core::AudioPatch>* patches) override {
298 *patches = mConfig.patches;
299 return ndk::ScopedAStatus::ok();
300 }
getAudioPort(int32_t portId,::aidl::android::media::audio::common::AudioPort * port)301 ndk::ScopedAStatus getAudioPort(
302 int32_t portId, ::aidl::android::media::audio::common::AudioPort* port) override {
303 auto iter = findById<AudioPort>(mConfig.ports, portId);
304 if (iter == mConfig.ports.end()) {
305 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
306 }
307 *port = *iter;
308 return ndk::ScopedAStatus::ok();
309 }
getAudioPortConfigs(std::vector<::aidl::android::media::audio::common::AudioPortConfig> * configs)310 ndk::ScopedAStatus getAudioPortConfigs(
311 std::vector<::aidl::android::media::audio::common::AudioPortConfig>* configs) override {
312 *configs = mConfig.portConfigs;
313 return ndk::ScopedAStatus::ok();
314 }
getAudioPorts(std::vector<::aidl::android::media::audio::common::AudioPort> * ports)315 ndk::ScopedAStatus getAudioPorts(
316 std::vector<::aidl::android::media::audio::common::AudioPort>* ports) override {
317 *ports = mConfig.ports;
318 return ndk::ScopedAStatus::ok();
319 }
getAudioRoutes(std::vector<::aidl::android::hardware::audio::core::AudioRoute> * routes)320 ndk::ScopedAStatus getAudioRoutes(
321 std::vector<::aidl::android::hardware::audio::core::AudioRoute>* routes) override {
322 *routes = mConfig.routes;
323 return ndk::ScopedAStatus::ok();
324 }
getAudioRoutesForAudioPort(int32_t portId,std::vector<::aidl::android::hardware::audio::core::AudioRoute> * routes)325 ndk::ScopedAStatus getAudioRoutesForAudioPort(
326 int32_t portId,
327 std::vector<::aidl::android::hardware::audio::core::AudioRoute>* routes) override {
328 for (auto& r : mConfig.routes) {
329 const auto& srcs = r.sourcePortIds;
330 if (r.sinkPortId == portId ||
331 std::find(srcs.begin(), srcs.end(), portId) != srcs.end()) {
332 routes->push_back(r);
333 }
334 }
335 return ndk::ScopedAStatus::ok();
336 }
openInputStream(const OpenInputStreamArguments &,OpenInputStreamReturn *)337 ndk::ScopedAStatus openInputStream(const OpenInputStreamArguments&,
338 OpenInputStreamReturn*) override {
339 return ndk::ScopedAStatus::ok();
340 }
openOutputStream(const OpenOutputStreamArguments &,OpenOutputStreamReturn *)341 ndk::ScopedAStatus openOutputStream(const OpenOutputStreamArguments&,
342 OpenOutputStreamReturn*) override {
343 return ndk::ScopedAStatus::ok();
344 }
getSupportedPlaybackRateFactors(SupportedPlaybackRateFactors *)345 ndk::ScopedAStatus getSupportedPlaybackRateFactors(SupportedPlaybackRateFactors*) override {
346 return ndk::ScopedAStatus::ok();
347 }
setAudioPatch(const::aidl::android::hardware::audio::core::AudioPatch & requested,::aidl::android::hardware::audio::core::AudioPatch * patch)348 ndk::ScopedAStatus setAudioPatch(
349 const ::aidl::android::hardware::audio::core::AudioPatch& requested,
350 ::aidl::android::hardware::audio::core::AudioPatch* patch) override {
351 if (requested.id == 0) {
352 *patch = requested;
353 patch->id = mConfig.nextPatchId++;
354 mConfig.patches.push_back(*patch);
355 ALOGD("%s: returning %s", __func__, patch->toString().c_str());
356 } else {
357 auto iter = findById<AudioPatch>(mConfig.patches, requested.id);
358 if (iter == mConfig.patches.end()) {
359 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
360 }
361 *iter = *patch = requested;
362 ALOGD("%s: updated %s", __func__, patch->toString().c_str());
363 }
364 return ndk::ScopedAStatus::ok();
365 }
setAudioPortConfig(const::aidl::android::media::audio::common::AudioPortConfig & requested,::aidl::android::media::audio::common::AudioPortConfig * config,bool * applied)366 ndk::ScopedAStatus setAudioPortConfig(
367 const ::aidl::android::media::audio::common::AudioPortConfig& requested,
368 ::aidl::android::media::audio::common::AudioPortConfig* config,
369 bool* applied) override {
370 *applied = false;
371 auto src = requested; // Make a copy to mimic RPC behavior.
372 if (src.id == 0) {
373 *config = src;
374 if (config->ext.getTag() == AudioPortExt::unspecified) {
375 auto iter = findById<AudioPort>(mConfig.ports, src.portId);
376 if (iter == mConfig.ports.end()) {
377 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
378 }
379 config->ext = iter->ext;
380 }
381 config->id = mConfig.nextPortId++;
382 mConfig.portConfigs.push_back(*config);
383 ALOGD("%s: returning %s", __func__, config->toString().c_str());
384 } else {
385 auto iter = findById<AudioPortConfig>(mConfig.portConfigs, src.id);
386 if (iter == mConfig.portConfigs.end()) {
387 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
388 }
389 *iter = *config = src;
390 ALOGD("%s: updated %s", __func__, config->toString().c_str());
391 }
392 *applied = true;
393 return ndk::ScopedAStatus::ok();
394 }
resetAudioPatch(int32_t patchId)395 ndk::ScopedAStatus resetAudioPatch(int32_t patchId) override {
396 auto iter = findById<AudioPatch>(mConfig.patches, patchId);
397 if (iter == mConfig.patches.end()) {
398 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
399 }
400 mConfig.patches.erase(iter);
401 return ndk::ScopedAStatus::ok();
402 }
resetAudioPortConfig(int32_t portConfigId)403 ndk::ScopedAStatus resetAudioPortConfig(int32_t portConfigId) override {
404 auto iter = findById<AudioPortConfig>(mConfig.portConfigs, portConfigId);
405 if (iter == mConfig.portConfigs.end()) {
406 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
407 }
408 mConfig.portConfigs.erase(iter);
409 return ndk::ScopedAStatus::ok();
410 }
getMasterMute(bool *)411 ndk::ScopedAStatus getMasterMute(bool*) override { return ndk::ScopedAStatus::ok(); }
setMasterMute(bool)412 ndk::ScopedAStatus setMasterMute(bool) override { return ndk::ScopedAStatus::ok(); }
getMasterVolume(float *)413 ndk::ScopedAStatus getMasterVolume(float*) override { return ndk::ScopedAStatus::ok(); }
setMasterVolume(float)414 ndk::ScopedAStatus setMasterVolume(float) override { return ndk::ScopedAStatus::ok(); }
getMicMute(bool *)415 ndk::ScopedAStatus getMicMute(bool*) override { return ndk::ScopedAStatus::ok(); }
setMicMute(bool)416 ndk::ScopedAStatus setMicMute(bool) override { return ndk::ScopedAStatus::ok(); }
getMicrophones(std::vector<::aidl::android::media::audio::common::MicrophoneInfo> *)417 ndk::ScopedAStatus getMicrophones(
418 std::vector<::aidl::android::media::audio::common::MicrophoneInfo>*) override {
419 return ndk::ScopedAStatus::ok();
420 }
updateAudioMode(::aidl::android::media::audio::common::AudioMode)421 ndk::ScopedAStatus updateAudioMode(::aidl::android::media::audio::common::AudioMode) override {
422 return ndk::ScopedAStatus::ok();
423 }
updateScreenRotation(ScreenRotation in_rotation)424 ndk::ScopedAStatus updateScreenRotation(ScreenRotation in_rotation) override {
425 mScreenRotation = in_rotation;
426 return ndk::ScopedAStatus::ok();
427 }
updateScreenState(bool in_isTurnedOn)428 ndk::ScopedAStatus updateScreenState(bool in_isTurnedOn) override {
429 mIsScreenTurnedOn = in_isTurnedOn;
430 return ndk::ScopedAStatus::ok();
431 }
getSoundDose(std::shared_ptr<::aidl::android::hardware::audio::core::sounddose::ISoundDose> *)432 ndk::ScopedAStatus getSoundDose(
433 std::shared_ptr<::aidl::android::hardware::audio::core::sounddose::ISoundDose>*)
434 override {
435 return ndk::ScopedAStatus::ok();
436 }
generateHwAvSyncId(int32_t *)437 ndk::ScopedAStatus generateHwAvSyncId(int32_t*) override { return ndk::ScopedAStatus::ok(); }
getVendorParameters(const std::vector<std::string> & in_parameterIds,std::vector<VendorParameter> *)438 ndk::ScopedAStatus getVendorParameters(const std::vector<std::string>& in_parameterIds,
439 std::vector<VendorParameter>*) override {
440 return getVendorParametersImpl(in_parameterIds);
441 }
setVendorParameters(const std::vector<VendorParameter> & in_parameters,bool async)442 ndk::ScopedAStatus setVendorParameters(const std::vector<VendorParameter>& in_parameters,
443 bool async) override {
444 return setVendorParametersImpl(in_parameters, async);
445 }
addDeviceEffect(int32_t,const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect> &)446 ndk::ScopedAStatus addDeviceEffect(
447 int32_t,
448 const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>&) override {
449 return ndk::ScopedAStatus::ok();
450 }
removeDeviceEffect(int32_t,const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect> &)451 ndk::ScopedAStatus removeDeviceEffect(
452 int32_t,
453 const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>&) override {
454 return ndk::ScopedAStatus::ok();
455 }
getMmapPolicyInfos(::aidl::android::media::audio::common::AudioMMapPolicyType,std::vector<::aidl::android::media::audio::common::AudioMMapPolicyInfo> *)456 ndk::ScopedAStatus getMmapPolicyInfos(
457 ::aidl::android::media::audio::common::AudioMMapPolicyType,
458 std::vector<::aidl::android::media::audio::common::AudioMMapPolicyInfo>*) override {
459 return ndk::ScopedAStatus::ok();
460 }
supportsVariableLatency(bool *)461 ndk::ScopedAStatus supportsVariableLatency(bool*) override { return ndk::ScopedAStatus::ok(); }
getAAudioMixerBurstCount(int32_t *)462 ndk::ScopedAStatus getAAudioMixerBurstCount(int32_t*) override {
463 return ndk::ScopedAStatus::ok();
464 }
getAAudioHardwareBurstMinUsec(int32_t *)465 ndk::ScopedAStatus getAAudioHardwareBurstMinUsec(int32_t*) override {
466 return ndk::ScopedAStatus::ok();
467 }
prepareToDisconnectExternalDevice(int32_t)468 ndk::ScopedAStatus prepareToDisconnectExternalDevice(int32_t) override {
469 return ndk::ScopedAStatus::ok();
470 }
471
472 Configuration mConfig;
473 bool mIsScreenTurnedOn = false;
474 ScreenRotation mScreenRotation = ScreenRotation::DEG_0;
475 };
476
477 class StreamCommonMock : public ::aidl::android::hardware::audio::core::BnStreamCommon,
478 public VendorParameterMock {
close()479 ndk::ScopedAStatus close() override { return ndk::ScopedAStatus::ok(); }
prepareToClose()480 ndk::ScopedAStatus prepareToClose() override { return ndk::ScopedAStatus::ok(); }
updateHwAvSyncId(int32_t)481 ndk::ScopedAStatus updateHwAvSyncId(int32_t) override { return ndk::ScopedAStatus::ok(); }
getVendorParameters(const std::vector<std::string> & in_parameterIds,std::vector<VendorParameter> *)482 ndk::ScopedAStatus getVendorParameters(const std::vector<std::string>& in_parameterIds,
483 std::vector<VendorParameter>*) override {
484 return getVendorParametersImpl(in_parameterIds);
485 }
setVendorParameters(const std::vector<VendorParameter> & in_parameters,bool async)486 ndk::ScopedAStatus setVendorParameters(const std::vector<VendorParameter>& in_parameters,
487 bool async) override {
488 return setVendorParametersImpl(in_parameters, async);
489 }
addEffect(const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect> &)490 ndk::ScopedAStatus addEffect(
491 const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>&) override {
492 return ndk::ScopedAStatus::ok();
493 }
removeEffect(const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect> &)494 ndk::ScopedAStatus removeEffect(
495 const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>&) override {
496 return ndk::ScopedAStatus::ok();
497 }
498 };
499
makeVendorParameter(const std::string & id,int value)500 VendorParameter makeVendorParameter(const std::string& id, int value) {
501 VendorParameter result{.id = id};
502 // Note: in real life, a parcelable type defined by vendor must be used,
503 // here we use Int just for test purposes.
504 ::aidl::android::media::audio::common::Int vendorValue{.value = value};
505 result.ext.setParcelable(std::move(vendorValue));
506 return result;
507 }
508
parseVendorParameter(const VendorParameter & param,int * value)509 android::status_t parseVendorParameter(const VendorParameter& param, int* value) {
510 std::optional<::aidl::android::media::audio::common::Int> vendorValue;
511 RETURN_STATUS_IF_ERROR(param.ext.getParcelable(&vendorValue));
512 if (!vendorValue.has_value()) return android::BAD_VALUE;
513 *value = vendorValue.value().value;
514 return android::OK;
515 }
516
517 class TestHalAdapterVendorExtension
518 : public ::aidl::android::media::audio::BnHalAdapterVendorExtension {
519 public:
520 static const std::string kLegacyParameterKey;
521 static const std::string kLegacyAsyncParameterKey;
522 static const std::string kModuleVendorParameterId;
523 static const std::string kStreamVendorParameterId;
524
525 private:
parseVendorParameterIds(ParameterScope in_scope,const std::string & in_rawKeys,std::vector<std::string> * _aidl_return)526 ndk::ScopedAStatus parseVendorParameterIds(ParameterScope in_scope,
527 const std::string& in_rawKeys,
528 std::vector<std::string>* _aidl_return) override {
529 android::AudioParameter keys(android::String8(in_rawKeys.c_str()));
530 for (size_t i = 0; i < keys.size(); ++i) {
531 android::String8 key;
532 if (android::status_t status = keys.getAt(i, key); status != android::OK) {
533 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
534 }
535 switch (in_scope) {
536 case ParameterScope::MODULE:
537 if (key == android::String8(kLegacyParameterKey.c_str()) ||
538 key == android::String8(kLegacyAsyncParameterKey.c_str())) {
539 _aidl_return->push_back(kModuleVendorParameterId);
540 } else {
541 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
542 }
543 break;
544 case ParameterScope::STREAM:
545 if (key == android::String8(kLegacyParameterKey.c_str()) ||
546 key == android::String8(kLegacyAsyncParameterKey.c_str())) {
547 _aidl_return->push_back(kStreamVendorParameterId);
548 } else {
549 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
550 }
551 break;
552 }
553 }
554 return ndk::ScopedAStatus::ok();
555 }
parseVendorParameters(ParameterScope in_scope,const std::string & in_rawKeysAndValues,std::vector<VendorParameter> * out_syncParameters,std::vector<VendorParameter> * out_asyncParameters)556 ndk::ScopedAStatus parseVendorParameters(
557 ParameterScope in_scope, const std::string& in_rawKeysAndValues,
558 std::vector<VendorParameter>* out_syncParameters,
559 std::vector<VendorParameter>* out_asyncParameters) override {
560 android::AudioParameter legacy(android::String8(in_rawKeysAndValues.c_str()));
561 for (size_t i = 0; i < legacy.size(); ++i) {
562 android::String8 key;
563 if (android::status_t status = legacy.getAt(i, key); status != android::OK) {
564 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
565 }
566 int value;
567 if (android::status_t status = legacy.getInt(key, value); status != android::OK) {
568 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
569 }
570 std::string parameterId;
571 switch (in_scope) {
572 case ParameterScope::MODULE:
573 parameterId = kModuleVendorParameterId;
574 break;
575 case ParameterScope::STREAM:
576 parameterId = kStreamVendorParameterId;
577 break;
578 }
579 if (key == android::String8(kLegacyParameterKey.c_str())) {
580 out_syncParameters->push_back(makeVendorParameter(parameterId, value));
581 } else if (key == android::String8(kLegacyAsyncParameterKey.c_str())) {
582 out_asyncParameters->push_back(makeVendorParameter(parameterId, value));
583 } else {
584 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
585 }
586 }
587 return ndk::ScopedAStatus::ok();
588 }
parseBluetoothA2dpReconfigureOffload(const std::string &,std::vector<VendorParameter> *)589 ndk::ScopedAStatus parseBluetoothA2dpReconfigureOffload(
590 const std::string&, std::vector<VendorParameter>*) override {
591 return ndk::ScopedAStatus::ok();
592 }
parseBluetoothLeReconfigureOffload(const std::string &,std::vector<VendorParameter> *)593 ndk::ScopedAStatus parseBluetoothLeReconfigureOffload(const std::string&,
594 std::vector<VendorParameter>*) override {
595 return ndk::ScopedAStatus::ok();
596 }
processVendorParameters(ParameterScope in_scope,const std::vector<VendorParameter> & in_parameters,std::string * _aidl_return)597 ndk::ScopedAStatus processVendorParameters(ParameterScope in_scope,
598 const std::vector<VendorParameter>& in_parameters,
599 std::string* _aidl_return) override {
600 android::AudioParameter legacy;
601 for (const auto& vendorParam : in_parameters) {
602 if ((in_scope == ParameterScope::MODULE &&
603 vendorParam.id == kModuleVendorParameterId) ||
604 (in_scope == ParameterScope::STREAM &&
605 vendorParam.id == kStreamVendorParameterId)) {
606 int value;
607 if (android::status_t status = parseVendorParameter(vendorParam, &value);
608 status != android::OK) {
609 return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
610 }
611 legacy.addInt(android::String8(kLegacyParameterKey.c_str()), value);
612 }
613 }
614 *_aidl_return = legacy.toString().c_str();
615 return ndk::ScopedAStatus::ok();
616 }
617 };
618
619 const std::string TestHalAdapterVendorExtension::kLegacyParameterKey = "aosp_test_param";
620 const std::string TestHalAdapterVendorExtension::kLegacyAsyncParameterKey = "aosp_test_param_async";
621 // Note: in real life, there is no need to explicitly separate "module" and "stream"
622 // parameters, here it's done just for test purposes.
623 const std::string TestHalAdapterVendorExtension::kModuleVendorParameterId =
624 "aosp.test.module.parameter";
625 const std::string TestHalAdapterVendorExtension::kStreamVendorParameterId =
626 "aosp.test.stream.parameter";
627
createParameterString(const std::string & key,const std::string & value)628 android::String8 createParameterString(const std::string& key, const std::string& value) {
629 android::AudioParameter params;
630 params.add(android::String8(key.c_str()), android::String8(value.c_str()));
631 return params.toString();
632 }
633
createParameterString(const std::string & key,int value)634 android::String8 createParameterString(const std::string& key, int value) {
635 android::AudioParameter params;
636 params.addInt(android::String8(key.c_str()), value);
637 return params.toString();
638 }
639
640 template <typename>
641 struct mf_traits {};
642 template <class T, class U>
643 struct mf_traits<U T::*> {
644 using member_type = U;
645 };
646
647 } // namespace
648
649 // Provide value printers for types generated from AIDL
650 // They need to be in the same namespace as the types we intend to print
651 namespace aidl::android::hardware::audio::core {
652 template <typename P>
653 std::enable_if_t<std::is_function_v<typename mf_traits<decltype(&P::toString)>::member_type>,
654 std::ostream&>
operator <<(std::ostream & os,const P & p)655 operator<<(std::ostream& os, const P& p) {
656 return os << p.toString();
657 }
658 template <typename E>
operator <<(std::ostream & os,const E & e)659 std::enable_if_t<std::is_enum_v<E>, std::ostream&> operator<<(std::ostream& os, const E& e) {
660 return os << toString(e);
661 }
662 } // namespace aidl::android::hardware::audio::core
663
664 namespace aidl::android::media::audio::common {
665 template <typename P>
666 std::enable_if_t<std::is_function_v<typename mf_traits<decltype(&P::toString)>::member_type>,
667 std::ostream&>
operator <<(std::ostream & os,const P & p)668 operator<<(std::ostream& os, const P& p) {
669 return os << p.toString();
670 }
671 template <typename E>
operator <<(std::ostream & os,const E & e)672 std::enable_if_t<std::is_enum_v<E>, std::ostream&> operator<<(std::ostream& os, const E& e) {
673 return os << toString(e);
674 }
675 } // namespace aidl::android::media::audio::common
676
677 using namespace android;
678
679 namespace {
680
681 class StreamHalMock : public virtual StreamHalInterface {
682 public:
683 StreamHalMock() = default;
684 ~StreamHalMock() override = default;
getBufferSize(size_t *)685 status_t getBufferSize(size_t*) override { return OK; }
getAudioProperties(audio_config_base_t *)686 status_t getAudioProperties(audio_config_base_t*) override { return OK; }
setParameters(const String8 &)687 status_t setParameters(const String8&) override { return OK; }
getParameters(const String8 &,String8 *)688 status_t getParameters(const String8&, String8*) override { return OK; }
getFrameSize(size_t *)689 status_t getFrameSize(size_t*) override { return OK; }
addEffect(sp<EffectHalInterface>)690 status_t addEffect(sp<EffectHalInterface>) override { return OK; }
removeEffect(sp<EffectHalInterface>)691 status_t removeEffect(sp<EffectHalInterface>) override { return OK; }
standby()692 status_t standby() override { return OK; }
dump(int,const Vector<String16> &)693 status_t dump(int, const Vector<String16>&) override { return OK; }
start()694 status_t start() override { return OK; }
stop()695 status_t stop() override { return OK; }
createMmapBuffer(int32_t,struct audio_mmap_buffer_info *)696 status_t createMmapBuffer(int32_t, struct audio_mmap_buffer_info*) override { return OK; }
getMmapPosition(struct audio_mmap_position *)697 status_t getMmapPosition(struct audio_mmap_position*) override { return OK; }
setHalThreadPriority(int)698 status_t setHalThreadPriority(int) override { return OK; }
legacyCreateAudioPatch(const struct audio_port_config &,std::optional<audio_source_t>,audio_devices_t)699 status_t legacyCreateAudioPatch(const struct audio_port_config&, std::optional<audio_source_t>,
700 audio_devices_t) override {
701 return OK;
702 }
legacyReleaseAudioPatch()703 status_t legacyReleaseAudioPatch() override { return OK; }
704 };
705
706 } // namespace
707
708 class DeviceHalAidlTest : public testing::Test {
709 public:
SetUp()710 void SetUp() override {
711 mModule = ndk::SharedRefBase::make<ModuleMock>();
712 mDevice = sp<DeviceHalAidl>::make("test", mModule, nullptr /*vext*/);
713 }
TearDown()714 void TearDown() override {
715 mDevice.clear();
716 mModule.reset();
717 }
718
719 protected:
720 std::shared_ptr<ModuleMock> mModule;
721 sp<DeviceHalAidl> mDevice;
722 };
723
TEST_F(DeviceHalAidlTest,ScreenState)724 TEST_F(DeviceHalAidlTest, ScreenState) {
725 EXPECT_FALSE(mModule->isScreenTurnedOn());
726 EXPECT_EQ(OK, mDevice->setParameters(createParameterString(AudioParameter::keyScreenState,
727 AudioParameter::valueOn)));
728 EXPECT_TRUE(mModule->isScreenTurnedOn());
729 EXPECT_EQ(OK, mDevice->setParameters(createParameterString(AudioParameter::keyScreenState,
730 AudioParameter::valueOff)));
731 EXPECT_FALSE(mModule->isScreenTurnedOn());
732 // The adaptation layer only logs a warning.
733 EXPECT_EQ(OK, mDevice->setParameters(
734 createParameterString(AudioParameter::keyScreenState, "blah")));
735 EXPECT_FALSE(mModule->isScreenTurnedOn());
736 }
737
TEST_F(DeviceHalAidlTest,ScreenRotation)738 TEST_F(DeviceHalAidlTest, ScreenRotation) {
739 using ScreenRotation = ::aidl::android::hardware::audio::core::IModule::ScreenRotation;
740 EXPECT_EQ(ScreenRotation::DEG_0, mModule->getScreenRotation());
741 EXPECT_EQ(OK,
742 mDevice->setParameters(createParameterString(AudioParameter::keyScreenRotation, 90)));
743 EXPECT_EQ(ScreenRotation::DEG_90, mModule->getScreenRotation());
744 EXPECT_EQ(OK,
745 mDevice->setParameters(createParameterString(AudioParameter::keyScreenRotation, 0)));
746 EXPECT_EQ(ScreenRotation::DEG_0, mModule->getScreenRotation());
747 // The adaptation layer only logs a warning.
748 EXPECT_EQ(OK,
749 mDevice->setParameters(createParameterString(AudioParameter::keyScreenRotation, 42)));
750 EXPECT_EQ(ScreenRotation::DEG_0, mModule->getScreenRotation());
751 }
752
753 class DeviceHalAidlVendorParametersTest : public testing::Test {
754 public:
SetUp()755 void SetUp() override {
756 mModule = ndk::SharedRefBase::make<ModuleMock>();
757 mVendorExt = ndk::SharedRefBase::make<TestHalAdapterVendorExtension>();
758 mDevice = sp<DeviceHalAidl>::make("test", mModule, mVendorExt);
759 }
TearDown()760 void TearDown() override {
761 mDevice.clear();
762 mVendorExt.reset();
763 mModule.reset();
764 }
765
766 protected:
767 std::shared_ptr<ModuleMock> mModule;
768 std::shared_ptr<TestHalAdapterVendorExtension> mVendorExt;
769 sp<DeviceHalAidl> mDevice;
770 };
771
TEST_F(DeviceHalAidlVendorParametersTest,GetVendorParameter)772 TEST_F(DeviceHalAidlVendorParametersTest, GetVendorParameter) {
773 EXPECT_EQ(0UL, mModule->getRetrievedParameterIds().size());
774 String8 values;
775 EXPECT_EQ(OK, mDevice->getParameters(
776 String8(TestHalAdapterVendorExtension::kLegacyParameterKey.c_str()),
777 &values));
778 EXPECT_EQ(1UL, mModule->getRetrievedParameterIds().size());
779 if (mModule->getRetrievedParameterIds().size() >= 1) {
780 EXPECT_EQ(TestHalAdapterVendorExtension::kModuleVendorParameterId,
781 mModule->getRetrievedParameterIds()[0]);
782 }
783 }
784
TEST_F(DeviceHalAidlVendorParametersTest,SetVendorParameter)785 TEST_F(DeviceHalAidlVendorParametersTest, SetVendorParameter) {
786 EXPECT_EQ(0UL, mModule->getAsyncParameters().size());
787 EXPECT_EQ(0UL, mModule->getSyncParameters().size());
788 EXPECT_EQ(OK, mDevice->setParameters(createParameterString(
789 TestHalAdapterVendorExtension::kLegacyParameterKey, 42)));
790 EXPECT_EQ(0UL, mModule->getAsyncParameters().size());
791 EXPECT_EQ(1UL, mModule->getSyncParameters().size());
792 EXPECT_EQ(OK, mDevice->setParameters(createParameterString(
793 TestHalAdapterVendorExtension::kLegacyAsyncParameterKey, 43)));
794 EXPECT_EQ(1UL, mModule->getAsyncParameters().size());
795 EXPECT_EQ(1UL, mModule->getSyncParameters().size());
796 if (mModule->getSyncParameters().size() >= 1) {
797 EXPECT_EQ(TestHalAdapterVendorExtension::kModuleVendorParameterId,
798 mModule->getSyncParameters()[0].id);
799 int value{};
800 EXPECT_EQ(android::OK, parseVendorParameter(mModule->getSyncParameters()[0], &value));
801 EXPECT_EQ(42, value);
802 }
803 if (mModule->getAsyncParameters().size() >= 1) {
804 EXPECT_EQ(TestHalAdapterVendorExtension::kModuleVendorParameterId,
805 mModule->getAsyncParameters()[0].id);
806 int value{};
807 EXPECT_EQ(android::OK, parseVendorParameter(mModule->getAsyncParameters()[0], &value));
808 EXPECT_EQ(43, value);
809 }
810 }
811
TEST_F(DeviceHalAidlVendorParametersTest,SetInvalidVendorParameters)812 TEST_F(DeviceHalAidlVendorParametersTest, SetInvalidVendorParameters) {
813 android::AudioParameter legacy;
814 legacy.addInt(android::String8(TestHalAdapterVendorExtension::kLegacyParameterKey.c_str()), 42);
815 legacy.addInt(android::String8(TestHalAdapterVendorExtension::kLegacyAsyncParameterKey.c_str()),
816 43);
817 legacy.addInt(android::String8("random_name"), 44);
818 EXPECT_EQ(0UL, mModule->getAsyncParameters().size());
819 EXPECT_EQ(0UL, mModule->getSyncParameters().size());
820 // TestHalAdapterVendorExtension throws an error for unknown parameters.
821 EXPECT_EQ(android::BAD_VALUE, mDevice->setParameters(legacy.toString()));
822 EXPECT_EQ(0UL, mModule->getAsyncParameters().size());
823 EXPECT_EQ(0UL, mModule->getSyncParameters().size());
824 }
825
826 class StreamHalAidlVendorParametersTest : public testing::Test {
827 public:
SetUp()828 void SetUp() override {
829 mStreamCommon = ndk::SharedRefBase::make<StreamCommonMock>();
830 mVendorExt = ndk::SharedRefBase::make<TestHalAdapterVendorExtension>();
831 struct audio_config config = AUDIO_CONFIG_INITIALIZER;
832 ::aidl::android::hardware::audio::core::StreamDescriptor descriptor;
833 mStream = sp<StreamHalAidl>::make("test", false /*isInput*/, config, 0 /*nominalLatency*/,
834 StreamContextAidl(descriptor, false /*isAsynchronous*/),
835 mStreamCommon, mVendorExt);
836 }
TearDown()837 void TearDown() override {
838 mStream.clear();
839 mVendorExt.reset();
840 mStreamCommon.reset();
841 }
842
843 protected:
844 std::shared_ptr<StreamCommonMock> mStreamCommon;
845 std::shared_ptr<TestHalAdapterVendorExtension> mVendorExt;
846 sp<StreamHalAidl> mStream;
847 };
848
TEST_F(StreamHalAidlVendorParametersTest,GetVendorParameter)849 TEST_F(StreamHalAidlVendorParametersTest, GetVendorParameter) {
850 EXPECT_EQ(0UL, mStreamCommon->getRetrievedParameterIds().size());
851 String8 values;
852 EXPECT_EQ(OK, mStream->getParameters(
853 String8(TestHalAdapterVendorExtension::kLegacyParameterKey.c_str()),
854 &values));
855 EXPECT_EQ(1UL, mStreamCommon->getRetrievedParameterIds().size());
856 if (mStreamCommon->getRetrievedParameterIds().size() >= 1) {
857 EXPECT_EQ(TestHalAdapterVendorExtension::kStreamVendorParameterId,
858 mStreamCommon->getRetrievedParameterIds()[0]);
859 }
860 }
861
TEST_F(StreamHalAidlVendorParametersTest,SetVendorParameter)862 TEST_F(StreamHalAidlVendorParametersTest, SetVendorParameter) {
863 EXPECT_EQ(0UL, mStreamCommon->getAsyncParameters().size());
864 EXPECT_EQ(0UL, mStreamCommon->getSyncParameters().size());
865 EXPECT_EQ(OK, mStream->setParameters(createParameterString(
866 TestHalAdapterVendorExtension::kLegacyParameterKey, 42)));
867 EXPECT_EQ(0UL, mStreamCommon->getAsyncParameters().size());
868 EXPECT_EQ(1UL, mStreamCommon->getSyncParameters().size());
869 EXPECT_EQ(OK, mStream->setParameters(createParameterString(
870 TestHalAdapterVendorExtension::kLegacyAsyncParameterKey, 43)));
871 EXPECT_EQ(1UL, mStreamCommon->getAsyncParameters().size());
872 EXPECT_EQ(1UL, mStreamCommon->getSyncParameters().size());
873 if (mStreamCommon->getSyncParameters().size() >= 1) {
874 EXPECT_EQ(TestHalAdapterVendorExtension::kStreamVendorParameterId,
875 mStreamCommon->getSyncParameters()[0].id);
876 int value{};
877 EXPECT_EQ(android::OK, parseVendorParameter(mStreamCommon->getSyncParameters()[0], &value));
878 EXPECT_EQ(42, value);
879 }
880 if (mStreamCommon->getAsyncParameters().size() >= 1) {
881 EXPECT_EQ(TestHalAdapterVendorExtension::kStreamVendorParameterId,
882 mStreamCommon->getAsyncParameters()[0].id);
883 int value{};
884 EXPECT_EQ(android::OK,
885 parseVendorParameter(mStreamCommon->getAsyncParameters()[0], &value));
886 EXPECT_EQ(43, value);
887 }
888 }
889
TEST_F(StreamHalAidlVendorParametersTest,SetInvalidVendorParameters)890 TEST_F(StreamHalAidlVendorParametersTest, SetInvalidVendorParameters) {
891 android::AudioParameter legacy;
892 legacy.addInt(android::String8(TestHalAdapterVendorExtension::kLegacyParameterKey.c_str()), 42);
893 legacy.addInt(android::String8(TestHalAdapterVendorExtension::kLegacyAsyncParameterKey.c_str()),
894 43);
895 legacy.addInt(android::String8("random_name"), 44);
896 EXPECT_EQ(0UL, mStreamCommon->getAsyncParameters().size());
897 EXPECT_EQ(0UL, mStreamCommon->getSyncParameters().size());
898 // TestHalAdapterVendorExtension throws an error for unknown parameters.
899 EXPECT_EQ(android::BAD_VALUE, mStream->setParameters(legacy.toString()));
900 EXPECT_EQ(0UL, mStreamCommon->getAsyncParameters().size());
901 EXPECT_EQ(0UL, mStreamCommon->getSyncParameters().size());
902 }
903
904 class Hal2AidlMapperTest : public testing::Test {
905 public:
SetUp()906 void SetUp() override {
907 mModule = ndk::SharedRefBase::make<ModuleMock>(getTestConfiguration());
908 mMapper = std::make_unique<Hal2AidlMapper>("test", mModule);
909 ASSERT_EQ(OK, mMapper->initialize());
910
911 mConnectedPort.ext = createPortDeviceExt(AudioDeviceType::OUT_DEVICE, 0,
912 AudioDeviceDescription::CONNECTION_BT_A2DP);
913 mConnectedPort.ext.get<AudioPortExt::device>().device.address = "00:11:22:33:44:55";
914 ASSERT_EQ(OK, mMapper->setDevicePortConnectedState(mConnectedPort, true /*connected*/));
915
916 std::mutex mutex; // Only needed for cleanups.
917 auto mapperAccessor = std::make_unique<LockedAccessor<Hal2AidlMapper>>(*mMapper, mutex);
918 Hal2AidlMapper::Cleanups cleanups(*mapperAccessor);
919 AudioConfig config;
920 config.base.channelMask = AudioChannelLayout::make<AudioChannelLayout::layoutMask>(
921 AudioChannelLayout::LAYOUT_STEREO);
922 config.base.format =
923 AudioFormatDescription{.type = AudioFormatType::PCM, .pcm = PcmType::INT_16_BIT};
924 config.base.sampleRate = 48000;
925 ASSERT_EQ(OK,
926 mMapper->prepareToOpenStream(
927 42 /*ioHandle*/, mConnectedPort.ext.get<AudioPortExt::device>().device,
928 AudioIoFlags::make<AudioIoFlags::output>(0), AudioSource::DEFAULT,
929 &cleanups, &config, &mMixPortConfig, &mPatch));
930 cleanups.disarmAll();
931 ASSERT_NE(0, mPatch.id);
932 ASSERT_NE(0, mMixPortConfig.id);
933 mStream = sp<StreamHalMock>::make();
934 mMapper->addStream(mStream, mMixPortConfig.id, mPatch.id);
935
936 ASSERT_EQ(OK, mMapper->findPortConfig(mConnectedPort.ext.get<AudioPortExt::device>().device,
937 &mDevicePortConfig));
938 ASSERT_EQ(1UL, mPatch.sourcePortConfigIds.size());
939 ASSERT_EQ(mMixPortConfig.id, mPatch.sourcePortConfigIds[0]);
940 ASSERT_EQ(1UL, mPatch.sinkPortConfigIds.size());
941 ASSERT_EQ(mDevicePortConfig.id, mPatch.sinkPortConfigIds[0]);
942 }
943
TearDown()944 void TearDown() override {
945 mStream.clear();
946 mMapper.reset();
947 mModule.reset();
948 }
949
950 protected:
CloseDisconnectImpl()951 void CloseDisconnectImpl() {
952 mStream.clear();
953 ASSERT_NO_FATAL_FAILURE(DisconnectDevice());
954 }
955
ConnectAnotherDevice()956 void ConnectAnotherDevice() {
957 mConnectedPort.ext.get<AudioPortExt::device>().device.address = "00:11:22:33:44:66";
958 ASSERT_EQ(OK, mMapper->setDevicePortConnectedState(mConnectedPort, true /*connected*/));
959 }
960
CreateFwkPatch(int32_t * patchId)961 void CreateFwkPatch(int32_t* patchId) {
962 std::mutex mutex; // Only needed for cleanups.
963 auto mapperAccessor = std::make_unique<LockedAccessor<Hal2AidlMapper>>(*mMapper, mutex);
964 Hal2AidlMapper::Cleanups cleanups(*mapperAccessor);
965 ASSERT_EQ(OK, mMapper->createOrUpdatePatch({mMixPortConfig}, {mDevicePortConfig}, patchId,
966 &cleanups));
967 cleanups.disarmAll();
968 }
969
DisconnectDevice()970 void DisconnectDevice() {
971 ASSERT_EQ(OK, mMapper->prepareToDisconnectExternalDevice(mConnectedPort));
972 ASSERT_EQ(OK, mMapper->setDevicePortConnectedState(mConnectedPort, false /*connected*/));
973 }
974
ReleaseFwkOnlyPatch(int32_t patchId)975 void ReleaseFwkOnlyPatch(int32_t patchId) {
976 // The patch only exists for the framework.
977 EXPECT_EQ(patchId, mMapper->findFwkPatch(patchId));
978 ASSERT_EQ(BAD_VALUE, mMapper->releaseAudioPatch(patchId));
979 mMapper->eraseFwkPatch(patchId);
980 // The patch is now erased.
981 EXPECT_EQ(0, mMapper->findFwkPatch(patchId));
982 }
983
984 std::shared_ptr<ModuleMock> mModule;
985 std::unique_ptr<Hal2AidlMapper> mMapper;
986 AudioPort mConnectedPort;
987 AudioPortConfig mMixPortConfig;
988 AudioPortConfig mDevicePortConfig;
989 AudioPatch mPatch;
990 sp<StreamHalInterface> mStream;
991 };
992
993 /**
994 * External device connections and patches tests diagram.
995 *
996 * [Connect device] -> [Create Stream]
997 * |-> [ (1) Close Stream] -> [Disconnect Device]
998 * |-> [ (2) Disconnect Device]
999 * | |-> [ (3) Close Stream]
1000 * | \-> [ (4) Connect Another Device]
1001 * | |-> (1)
1002 * | |-> (2) -> (3)
1003 * | \-> (5) -> (7)
1004 * \-> [ (5) Create/Update Fwk Patch]
1005 * |-> [(6) Release Fwk Patch]
1006 * | |-> (1)
1007 * | \-> (2) (including reconnection)
1008 * \-> [(7) Disconnect Device]
1009 * |-> [Release Fwk Patch] -> [Close Stream]
1010 * \-> (4) -> (5) -> (6) -> (1)
1011 *
1012 * Note that the test (acting on behalf of DeviceHalAidl) is responsible
1013 * for calling `eraseFwkPatch` and `updateFwkPatch` when needed.
1014 */
1015
1016 // (1)
TEST_F(Hal2AidlMapperTest,CloseDisconnect)1017 TEST_F(Hal2AidlMapperTest, CloseDisconnect) {
1018 ASSERT_NO_FATAL_FAILURE(CloseDisconnectImpl());
1019 // The patch is owned by HAL, must not be listed under fwkPatches after disconnection.
1020 EXPECT_EQ(0, mMapper->findFwkPatch(mPatch.id));
1021 }
1022
1023 // (2) -> (3)
TEST_F(Hal2AidlMapperTest,DisconnectClose)1024 TEST_F(Hal2AidlMapperTest, DisconnectClose) {
1025 ASSERT_NO_FATAL_FAILURE(DisconnectDevice());
1026 // The patch is owned by HAL, must not be listed under fwkPatches after disconnection.
1027 EXPECT_EQ(0, mMapper->findFwkPatch(mPatch.id));
1028 mStream.clear();
1029 }
1030
1031 // (2) -> (4) -> (1)
TEST_F(Hal2AidlMapperTest,DisconnectConnectCloseDisconnect)1032 TEST_F(Hal2AidlMapperTest, DisconnectConnectCloseDisconnect) {
1033 ASSERT_NO_FATAL_FAILURE(DisconnectDevice());
1034 // The patch is owned by HAL, must not be listed under fwkPatches after disconnection.
1035 EXPECT_EQ(0, mMapper->findFwkPatch(mPatch.id));
1036 ASSERT_NO_FATAL_FAILURE(ConnectAnotherDevice());
1037 ASSERT_NO_FATAL_FAILURE(CloseDisconnectImpl());
1038 // The patch is owned by HAL, must not be listed under fwkPatches after disconnection.
1039 EXPECT_EQ(0, mMapper->findFwkPatch(mPatch.id));
1040 }
1041
1042 // (2) -> (4) -> (2) -> (3)
TEST_F(Hal2AidlMapperTest,DisconnectConnectDisconnectClose)1043 TEST_F(Hal2AidlMapperTest, DisconnectConnectDisconnectClose) {
1044 ASSERT_NO_FATAL_FAILURE(DisconnectDevice());
1045 // The patch is owned by HAL, must not be listed under fwkPatches after disconnection.
1046 EXPECT_EQ(0, mMapper->findFwkPatch(mPatch.id));
1047 ASSERT_NO_FATAL_FAILURE(ConnectAnotherDevice());
1048 ASSERT_NO_FATAL_FAILURE(DisconnectDevice());
1049 // The patch is owned by HAL, must not be listed under fwkPatches after disconnection.
1050 EXPECT_EQ(0, mMapper->findFwkPatch(mPatch.id));
1051 mStream.clear();
1052 }
1053
1054 // (5) -> (6) -> (1)
TEST_F(Hal2AidlMapperTest,CreateFwkPatchReleaseCloseDisconnect)1055 TEST_F(Hal2AidlMapperTest, CreateFwkPatchReleaseCloseDisconnect) {
1056 int32_t patchId;
1057 ASSERT_NO_FATAL_FAILURE(CreateFwkPatch(&patchId));
1058 // Must be the patch created during stream opening.
1059 ASSERT_EQ(mPatch.id, patchId);
1060 // The patch was not reset by HAL, must not be listed under fwkPatches.
1061 EXPECT_EQ(0, mMapper->findFwkPatch(mPatch.id));
1062
1063 ASSERT_EQ(OK, mMapper->releaseAudioPatch(patchId));
1064 // The patch does not exist both for the fwk and the HAL, must not be listed under fwkPatches.
1065 EXPECT_EQ(0, mMapper->findFwkPatch(patchId));
1066 ASSERT_NO_FATAL_FAILURE(CloseDisconnectImpl());
1067 // The patch does not exist both for the fwk and the HAL, must not be listed under fwkPatches.
1068 EXPECT_EQ(0, mMapper->findFwkPatch(patchId));
1069 }
1070
1071 // (5) -> (6) -> (2) -> (3)
TEST_F(Hal2AidlMapperTest,CreateFwkPatchReleaseDisconnectClose)1072 TEST_F(Hal2AidlMapperTest, CreateFwkPatchReleaseDisconnectClose) {
1073 int32_t patchId;
1074 ASSERT_NO_FATAL_FAILURE(CreateFwkPatch(&patchId));
1075 // Must be the patch created during stream opening.
1076 ASSERT_EQ(mPatch.id, patchId);
1077 // The patch was not reset by HAL, must not be listed under fwkPatches.
1078 EXPECT_EQ(0, mMapper->findFwkPatch(mPatch.id));
1079
1080 ASSERT_EQ(OK, mMapper->releaseAudioPatch(patchId));
1081 // The patch does not exist both for the fwk and the HAL, must not be listed under fwkPatches.
1082 EXPECT_EQ(0, mMapper->findFwkPatch(patchId));
1083 ASSERT_NO_FATAL_FAILURE(DisconnectDevice());
1084 // The patch does not exist both for the fwk and the HAL, must not be listed under fwkPatches.
1085 EXPECT_EQ(0, mMapper->findFwkPatch(mPatch.id));
1086 mStream.clear();
1087 }
1088
1089 // (5) -> (6) -> (2) -> (4) -> (2) -> (3)
TEST_F(Hal2AidlMapperTest,CreateFwkPatchReleaseDisconnectConnectDisconnectClose)1090 TEST_F(Hal2AidlMapperTest, CreateFwkPatchReleaseDisconnectConnectDisconnectClose) {
1091 int32_t patchId;
1092 ASSERT_NO_FATAL_FAILURE(CreateFwkPatch(&patchId));
1093 // Must be the patch created during stream opening.
1094 ASSERT_EQ(mPatch.id, patchId);
1095 // The patch was not reset by HAL, must not be listed under fwkPatches.
1096 EXPECT_EQ(0, mMapper->findFwkPatch(mPatch.id));
1097
1098 ASSERT_EQ(OK, mMapper->releaseAudioPatch(patchId));
1099 // The patch does not exist both for the fwk and the HAL, must not be listed under fwkPatches.
1100 EXPECT_EQ(0, mMapper->findFwkPatch(patchId));
1101 ASSERT_NO_FATAL_FAILURE(DisconnectDevice());
1102 // The patch does not exist both for the fwk and the HAL, must not be listed under fwkPatches.
1103 EXPECT_EQ(0, mMapper->findFwkPatch(mPatch.id));
1104
1105 ASSERT_NO_FATAL_FAILURE(ConnectAnotherDevice());
1106 ASSERT_NO_FATAL_FAILURE(DisconnectDevice());
1107 // The patch does not exist both for the fwk and the HAL, must not be listed under fwkPatches.
1108 EXPECT_EQ(0, mMapper->findFwkPatch(mPatch.id));
1109 mStream.clear();
1110 }
1111
1112 // (5) -> (7) -> Release -> Close
TEST_F(Hal2AidlMapperTest,CreateFwkPatchDisconnectReleaseClose)1113 TEST_F(Hal2AidlMapperTest, CreateFwkPatchDisconnectReleaseClose) {
1114 int32_t patchId;
1115 ASSERT_NO_FATAL_FAILURE(CreateFwkPatch(&patchId));
1116 // Must be the patch created during stream opening.
1117 ASSERT_EQ(mPatch.id, patchId);
1118 // The patch was not reset by HAL, must not be listed under fwkPatches.
1119 EXPECT_EQ(0, mMapper->findFwkPatch(mPatch.id));
1120
1121 ASSERT_NO_FATAL_FAILURE(DisconnectDevice());
1122 ASSERT_NO_FATAL_FAILURE(ReleaseFwkOnlyPatch(patchId));
1123
1124 mStream.clear();
1125 EXPECT_EQ(0, mMapper->findFwkPatch(patchId));
1126 }
1127
1128 // (5) -> (7) -> (4) -> (5) -> (6) -> (1)
TEST_F(Hal2AidlMapperTest,CreateFwkPatchDisconnectConnectUpdateReleaseCloseDisconnect)1129 TEST_F(Hal2AidlMapperTest, CreateFwkPatchDisconnectConnectUpdateReleaseCloseDisconnect) {
1130 int32_t patchId;
1131 ASSERT_NO_FATAL_FAILURE(CreateFwkPatch(&patchId));
1132 // Must be the patch created during stream opening.
1133 ASSERT_EQ(mPatch.id, patchId);
1134 // The patch was not reset by HAL, must not be listed under fwkPatches.
1135 EXPECT_EQ(0, mMapper->findFwkPatch(mPatch.id));
1136
1137 ASSERT_NO_FATAL_FAILURE(DisconnectDevice());
1138 // The patch now only exists for the framework.
1139 EXPECT_EQ(mPatch.id, mMapper->findFwkPatch(mPatch.id));
1140
1141 ASSERT_NO_FATAL_FAILURE(ConnectAnotherDevice());
1142 // Change the device address locally, for patch update.
1143 mDevicePortConfig.ext.get<AudioPortExt::device>().device.address =
1144 mConnectedPort.ext.get<AudioPortExt::device>().device.address;
1145 int32_t newPatchId = patchId;
1146 ASSERT_NO_FATAL_FAILURE(CreateFwkPatch(&newPatchId));
1147 EXPECT_NE(patchId, newPatchId);
1148 mMapper->updateFwkPatch(patchId, newPatchId);
1149 EXPECT_EQ(newPatchId, mMapper->findFwkPatch(patchId));
1150 // Just in case, check that HAL patch ID is not listed as a fwk patch.
1151 EXPECT_EQ(0, mMapper->findFwkPatch(newPatchId));
1152 // Verify that device port config was updated.
1153 ASSERT_EQ(OK, mMapper->findPortConfig(mConnectedPort.ext.get<AudioPortExt::device>().device,
1154 &mDevicePortConfig));
1155
1156 ASSERT_EQ(OK, mMapper->releaseAudioPatch(newPatchId));
1157 // The patch does not exist both for the fwk and the HAL, must not be listed under fwkPatches.
1158 EXPECT_EQ(0, mMapper->findFwkPatch(patchId));
1159 // Just in case, check that HAL patch ID is not listed.
1160 EXPECT_EQ(0, mMapper->findFwkPatch(newPatchId));
1161
1162 ASSERT_NO_FATAL_FAILURE(CloseDisconnectImpl());
1163 EXPECT_EQ(0, mMapper->findFwkPatch(mPatch.id));
1164 EXPECT_EQ(0, mMapper->findFwkPatch(patchId));
1165 EXPECT_EQ(0, mMapper->findFwkPatch(newPatchId));
1166 }
1167
1168 // (2) -> (4) -> (5) -> (7) -> Release -> Close
TEST_F(Hal2AidlMapperTest,DisconnectConnectCreateFwkPatchDisconnectReleaseClose)1169 TEST_F(Hal2AidlMapperTest, DisconnectConnectCreateFwkPatchDisconnectReleaseClose) {
1170 const int32_t patchId = mPatch.id;
1171 ASSERT_NO_FATAL_FAILURE(DisconnectDevice());
1172 // The patch is owned by HAL, must not be listed under fwkPatches after disconnection.
1173 EXPECT_EQ(0, mMapper->findFwkPatch(mPatch.id));
1174
1175 ASSERT_NO_FATAL_FAILURE(ConnectAnotherDevice());
1176 // Change the device address locally, for patch update.
1177 mDevicePortConfig.ext.get<AudioPortExt::device>().device.address =
1178 mConnectedPort.ext.get<AudioPortExt::device>().device.address;
1179 int32_t newPatchId = 0; // Use 0 since the fwk does not know about the HAL patch.
1180 EXPECT_EQ(0, mMapper->findFwkPatch(newPatchId));
1181 ASSERT_NO_FATAL_FAILURE(CreateFwkPatch(&newPatchId));
1182 EXPECT_NE(0, newPatchId);
1183 EXPECT_NE(patchId, newPatchId);
1184 // Just in case, check that HAL patch ID is not listed as a fwk patch.
1185 EXPECT_EQ(0, mMapper->findFwkPatch(newPatchId));
1186 // Verify that device port config was updated.
1187 ASSERT_EQ(OK, mMapper->findPortConfig(mConnectedPort.ext.get<AudioPortExt::device>().device,
1188 &mDevicePortConfig));
1189
1190 ASSERT_NO_FATAL_FAILURE(DisconnectDevice());
1191 ASSERT_NO_FATAL_FAILURE(ReleaseFwkOnlyPatch(newPatchId));
1192
1193 mStream.clear();
1194 EXPECT_EQ(0, mMapper->findFwkPatch(mPatch.id));
1195 EXPECT_EQ(0, mMapper->findFwkPatch(newPatchId));
1196 }
1197
TEST_F(Hal2AidlMapperTest,ChangeTransientPatchDevice)1198 TEST_F(Hal2AidlMapperTest, ChangeTransientPatchDevice) {
1199 std::mutex mutex; // Only needed for cleanups.
1200 auto mapperAccessor = std::make_unique<LockedAccessor<Hal2AidlMapper>>(*mMapper, mutex);
1201 Hal2AidlMapper::Cleanups cleanups(*mapperAccessor);
1202 AudioConfig config;
1203 config.base.channelMask = AudioChannelLayout::make<AudioChannelLayout::layoutMask>(
1204 AudioChannelLayout::LAYOUT_STEREO);
1205 config.base.format =
1206 AudioFormatDescription{.type = AudioFormatType::PCM, .pcm = PcmType::INT_16_BIT};
1207 config.base.sampleRate = 48000;
1208 AudioDevice defaultDevice;
1209 defaultDevice.type.type = AudioDeviceType::IN_DEFAULT;
1210 AudioPortConfig mixPortConfig;
1211 AudioPatch transientPatch;
1212 ASSERT_EQ(OK, mMapper->prepareToOpenStream(43 /*ioHandle*/, defaultDevice,
1213 AudioIoFlags::make<AudioIoFlags::input>(0),
1214 AudioSource::DEFAULT, &cleanups, &config,
1215 &mixPortConfig, &transientPatch));
1216 cleanups.disarmAll();
1217 ASSERT_NE(0, transientPatch.id);
1218 ASSERT_NE(0, mixPortConfig.id);
1219 sp<StreamHalInterface> stream = sp<StreamHalMock>::make();
1220 mMapper->addStream(stream, mixPortConfig.id, transientPatch.id);
1221
1222 AudioPatch patch{};
1223 int32_t patchId;
1224 AudioPortConfig backMicPortConfig;
1225 backMicPortConfig.channelMask = config.base.channelMask;
1226 backMicPortConfig.format = config.base.format;
1227 backMicPortConfig.sampleRate = aidl::android::media::audio::common::Int{config.base.sampleRate};
1228 backMicPortConfig.flags = AudioIoFlags::make<AudioIoFlags::input>(0);
1229 backMicPortConfig.ext = createPortDeviceExt(AudioDeviceType::IN_MICROPHONE_BACK, 0);
1230 ASSERT_EQ(OK, mMapper->createOrUpdatePatch({backMicPortConfig}, {mixPortConfig}, &patchId,
1231 &cleanups));
1232 cleanups.disarmAll();
1233 ASSERT_EQ(android::OK,
1234 mMapper->findPortConfig(backMicPortConfig.ext.get<AudioPortExt::device>().device,
1235 &backMicPortConfig));
1236 EXPECT_NE(0, backMicPortConfig.id);
1237
1238 EXPECT_EQ(transientPatch.id, patchId);
1239 auto patches = mModule->getPatches();
1240 auto patchIt = findById(patches, patchId);
1241 ASSERT_NE(patchIt, patches.end());
1242 EXPECT_EQ(std::vector<int32_t>{backMicPortConfig.id}, patchIt->sourcePortConfigIds);
1243 EXPECT_EQ(std::vector<int32_t>{mixPortConfig.id}, patchIt->sinkPortConfigIds);
1244 }
1245
TEST_F(Hal2AidlMapperTest,SetAudioPortConfigGainChangeExistingPortConfig)1246 TEST_F(Hal2AidlMapperTest, SetAudioPortConfigGainChangeExistingPortConfig) {
1247 // First set config, then update gain.
1248 AudioPortConfig speakerPortConfig;
1249 speakerPortConfig.ext = createPortDeviceExt(AudioDeviceType::OUT_SPEAKER, 0);
1250 speakerPortConfig.channelMask = AudioChannelLayout::make<AudioChannelLayout::layoutMask>(
1251 AudioChannelLayout::LAYOUT_STEREO);
1252 speakerPortConfig.format =
1253 AudioFormatDescription{.type = AudioFormatType::PCM, .pcm = PcmType::INT_16_BIT};
1254 speakerPortConfig.sampleRate = ::aidl::android::media::audio::common::Int(48000);
1255 AudioPortConfig resultingPortConfig;
1256 ASSERT_EQ(OK,
1257 mMapper->setPortConfig(speakerPortConfig, std::set<int32_t>(), &resultingPortConfig));
1258 EXPECT_NE(0, resultingPortConfig.id);
1259 EXPECT_NE(0, resultingPortConfig.portId);
1260
1261 AudioPortConfig gainUpdate;
1262 gainUpdate.ext = createPortDeviceExt(AudioDeviceType::OUT_SPEAKER, 0);
1263 AudioGainConfig gainConfig{.index = -1,
1264 .mode = 1 << static_cast<int>(AudioGainMode::JOINT),
1265 .channelMask = AudioChannelLayout{},
1266 .values = std::vector<int32_t>{-3200},
1267 .rampDurationMs = 0};
1268 gainUpdate.gain = gainConfig;
1269 AudioPortConfig resultingGainUpdate;
1270 ASSERT_EQ(OK, mMapper->setPortConfig(gainUpdate, std::set<int32_t>(), &resultingGainUpdate));
1271 EXPECT_EQ(resultingPortConfig.id, resultingGainUpdate.id);
1272 auto updatedPortConfig = mModule->getPortConfig(resultingGainUpdate.id);
1273 ASSERT_TRUE(updatedPortConfig.has_value());
1274 ASSERT_TRUE(updatedPortConfig->gain.has_value());
1275 EXPECT_EQ(gainConfig, updatedPortConfig->gain);
1276 }
1277
TEST_F(Hal2AidlMapperTest,SetAudioPortConfigGainChangeFromScratch)1278 TEST_F(Hal2AidlMapperTest, SetAudioPortConfigGainChangeFromScratch) {
1279 // Set gain as the first operation, the HAL should suggest the rest of the configuration.
1280 AudioPortConfig gainSet;
1281 gainSet.ext = createPortDeviceExt(AudioDeviceType::OUT_SPEAKER, 0);
1282 AudioGainConfig gainConfig{.index = -1,
1283 .mode = 1 << static_cast<int>(AudioGainMode::JOINT),
1284 .channelMask = AudioChannelLayout{},
1285 .values = std::vector<int32_t>{-3200},
1286 .rampDurationMs = 0};
1287 gainSet.gain = gainConfig;
1288 AudioPortConfig resultingPortConfig;
1289 ASSERT_EQ(OK, mMapper->setPortConfig(gainSet, std::set<int32_t>(), &resultingPortConfig));
1290 EXPECT_NE(0, resultingPortConfig.id);
1291 EXPECT_NE(0, resultingPortConfig.portId);
1292 auto portConfig = mModule->getPortConfig(resultingPortConfig.id);
1293 ASSERT_TRUE(portConfig.has_value());
1294 ASSERT_TRUE(portConfig->gain.has_value());
1295 EXPECT_EQ(gainConfig, portConfig->gain);
1296 }
1297