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