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