1 /*
2 * Copyright 2021 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 #pragma once
18
19 #include <array>
20 #include <audio_utils/channels.h>
21 #include <audio_utils/primitives.h>
22 #include <climits>
23 #include <cstdlib>
24 #include <dlfcn.h>
25 #include <gtest/gtest.h>
26 #include <hardware/audio_effect.h>
27 #include <log/log.h>
28 #include <random>
29 #include <stdint.h>
30 #include <system/audio.h>
31 #include <vector>
32
33 extern audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM;
34 namespace android {
35
36 template <typename T>
computeSnr(const T * ref,const T * tst,size_t count)37 static float computeSnr(const T* ref, const T* tst, size_t count) {
38 double signal{};
39 double noise{};
40
41 for (size_t i = 0; i < count; ++i) {
42 const double value(ref[i]);
43 const double diff(tst[i] - value);
44 signal += value * value;
45 noise += diff * diff;
46 }
47 // Initialized to large value to handle
48 // cases where ref and tst match exactly
49 float snr = FLT_MAX;
50 if (signal > 0.0f && noise > 0.0f) {
51 snr = 10.f * log(signal / noise);
52 }
53 return snr;
54 }
55
56 template <typename T>
areNearlySame(const T * ref,const T * tst,size_t count)57 static float areNearlySame(const T* ref, const T* tst, size_t count) {
58 T delta;
59 if constexpr (std::is_floating_point_v<T>) {
60 delta = std::numeric_limits<T>::epsilon();
61 } else {
62 delta = 1;
63 }
64 for (size_t i = 0; i < count; ++i) {
65 const double diff(tst[i] - ref[i]);
66 if (abs(diff) > delta) {
67 return false;
68 }
69 }
70 return true;
71 }
72
73 class EffectTestHelper {
74 public:
EffectTestHelper(const effect_uuid_t * uuid,size_t inChMask,size_t outChMask,size_t sampleRate,size_t frameCount,size_t loopCount)75 EffectTestHelper(const effect_uuid_t* uuid, size_t inChMask, size_t outChMask,
76 size_t sampleRate, size_t frameCount, size_t loopCount)
77 : mUuid(uuid),
78 mInChMask(inChMask),
79 mInChannelCount(audio_channel_count_from_out_mask(mInChMask)),
80 mOutChMask(outChMask),
81 mOutChannelCount(audio_channel_count_from_out_mask(mOutChMask)),
82 mSampleRate(sampleRate),
83 mFrameCount(frameCount),
84 mLoopCount(loopCount) {}
85 void createEffect();
86 void releaseEffect();
87 void setConfig();
88
89 template <typename VALUE_DTYPE>
setParam(uint32_t type,VALUE_DTYPE const value)90 void setParam(uint32_t type, VALUE_DTYPE const value) {
91 int reply = 0;
92 uint32_t replySize = sizeof(reply);
93
94 uint8_t paramData[sizeof(effect_param_t) + sizeof(type) + sizeof(value)];
95 auto effectParam = (effect_param_t*)paramData;
96
97 memcpy(&effectParam->data[0], &type, sizeof(type));
98 memcpy(&effectParam->data[sizeof(type)], &value, sizeof(value));
99 effectParam->psize = sizeof(type);
100 effectParam->vsize = sizeof(value);
101 int status = (*mEffectHandle)
102 ->command(mEffectHandle, EFFECT_CMD_SET_PARAM,
103 sizeof(effect_param_t) + sizeof(type) + sizeof(value),
104 effectParam, &replySize, &reply);
105 ASSERT_EQ(status, 0) << "set_param returned an error " << status;
106 ASSERT_EQ(reply, 0) << "set_param reply non zero " << reply;
107 };
108
109 template <bool MULTI_VALUES, typename T>
getParam(uint32_t type,std::vector<T> & values)110 int32_t getParam(uint32_t type, std::vector<T>& values) {
111 const int kMaxEffectParamValues = 10;
112 uint32_t cmd[sizeof(effect_param_t) / sizeof(uint32_t) + 1];
113 uint32_t reply[sizeof(effect_param_t) / sizeof(uint32_t) + 1 + 1 + kMaxEffectParamValues];
114
115 effect_param_t* p = (effect_param_t*)cmd;
116 p->psize = sizeof(uint32_t);
117 if (MULTI_VALUES) {
118 p->vsize = (kMaxEffectParamValues + 1) * sizeof(T);
119 } else {
120 p->vsize = sizeof(T);
121 }
122 *(uint32_t*)p->data = type;
123 uint32_t replySize = sizeof(effect_param_t) + p->psize + p->vsize;
124
125 int32_t status = (*mEffectHandle)
126 ->command(mEffectHandle, EFFECT_CMD_GET_PARAM,
127 sizeof(effect_param_t) + sizeof(uint32_t), cmd,
128 &replySize, reply);
129 if (status) {
130 return status;
131 }
132 if (p->status) {
133 return p->status;
134 }
135 if (replySize <
136 sizeof(effect_param_t) + sizeof(uint32_t) + (MULTI_VALUES ? 2 : 1) * sizeof(T)) {
137 return -EINVAL;
138 }
139
140 T* params = (T*)((uint8_t*)reply + sizeof(effect_param_t) + sizeof(uint32_t));
141 int numParams = 1;
142 if (MULTI_VALUES) {
143 numParams = (int)*params++;
144 }
145 if (numParams > kMaxEffectParamValues) {
146 return -EINVAL;
147 }
148 values.clear();
149 std::copy(¶ms[0], ¶ms[numParams], back_inserter(values));
150 return 0;
151 }
152
153 template <typename T>
setParam(uint32_t type,const std::vector<T> & values)154 int setParam(uint32_t type, const std::vector<T>& values) {
155 int reply = 0;
156 uint32_t replySize = sizeof(reply);
157
158 uint32_t cmd[sizeof(effect_param_t) / sizeof(uint32_t) + 1 + values.size()];
159 effect_param_t* p = (effect_param_t*)cmd;
160 p->psize = sizeof(uint32_t);
161 p->vsize = sizeof(T) * values.size();
162 *(uint32_t*)p->data = type;
163 memcpy((uint32_t*)p->data + 1, values.data(), sizeof(T) * values.size());
164
165 int status = (*mEffectHandle)
166 ->command(mEffectHandle, EFFECT_CMD_SET_PARAM,
167 sizeof(effect_param_t) + p->psize + p->vsize, p, &replySize,
168 &reply);
169 if (status) {
170 return status;
171 }
172 if (reply) {
173 return reply;
174 }
175 return 0;
176 }
177
178 void process(float* input, float* output);
179
180 // Corresponds to SNR for 1 bit difference between two int16_t signals
181 static constexpr float kSNRThreshold = 90.308998;
182
183 static constexpr audio_channel_mask_t kChMasks[] = {
184 AUDIO_CHANNEL_OUT_MONO, AUDIO_CHANNEL_OUT_STEREO,
185 AUDIO_CHANNEL_OUT_2POINT1, AUDIO_CHANNEL_OUT_2POINT0POINT2,
186 AUDIO_CHANNEL_OUT_QUAD, AUDIO_CHANNEL_OUT_QUAD_BACK,
187 AUDIO_CHANNEL_OUT_QUAD_SIDE, AUDIO_CHANNEL_OUT_SURROUND,
188 AUDIO_CHANNEL_INDEX_MASK_4, AUDIO_CHANNEL_OUT_2POINT1POINT2,
189 AUDIO_CHANNEL_OUT_3POINT0POINT2, AUDIO_CHANNEL_OUT_PENTA,
190 AUDIO_CHANNEL_INDEX_MASK_5, AUDIO_CHANNEL_OUT_3POINT1POINT2,
191 AUDIO_CHANNEL_OUT_5POINT1, AUDIO_CHANNEL_OUT_5POINT1_BACK,
192 AUDIO_CHANNEL_OUT_5POINT1_SIDE, AUDIO_CHANNEL_INDEX_MASK_6,
193 AUDIO_CHANNEL_OUT_6POINT1, AUDIO_CHANNEL_INDEX_MASK_7,
194 AUDIO_CHANNEL_OUT_5POINT1POINT2, AUDIO_CHANNEL_OUT_7POINT1,
195 AUDIO_CHANNEL_INDEX_MASK_8, AUDIO_CHANNEL_INDEX_MASK_9,
196 AUDIO_CHANNEL_INDEX_MASK_10, AUDIO_CHANNEL_INDEX_MASK_11,
197 AUDIO_CHANNEL_INDEX_MASK_12, AUDIO_CHANNEL_INDEX_MASK_13,
198 AUDIO_CHANNEL_INDEX_MASK_14, AUDIO_CHANNEL_INDEX_MASK_15,
199 AUDIO_CHANNEL_INDEX_MASK_16, AUDIO_CHANNEL_INDEX_MASK_17,
200 AUDIO_CHANNEL_INDEX_MASK_18, AUDIO_CHANNEL_INDEX_MASK_19,
201 AUDIO_CHANNEL_INDEX_MASK_20, AUDIO_CHANNEL_INDEX_MASK_21,
202 AUDIO_CHANNEL_INDEX_MASK_22, AUDIO_CHANNEL_INDEX_MASK_23,
203 AUDIO_CHANNEL_INDEX_MASK_24,
204 };
205
206 static constexpr size_t kNumChMasks = std::size(kChMasks);
207
208 static constexpr size_t kSampleRates[] = {8000, 11025, 12000, 16000, 22050, 24000, 32000,
209 44100, 48000, 88200, 96000, 176400, 192000};
210
211 static constexpr size_t kNumSampleRates = std::size(kSampleRates);
212
213 static constexpr size_t kFrameCounts[] = {4, 2048};
214
215 static constexpr size_t kNumFrameCounts = std::size(kFrameCounts);
216
217 static constexpr size_t kLoopCounts[] = {1, 4};
218
219 static constexpr size_t kNumLoopCounts = std::size(kLoopCounts);
220
221 private:
222 const effect_uuid_t* mUuid;
223 const size_t mInChMask;
224 const size_t mInChannelCount;
225 const size_t mOutChMask;
226 const size_t mOutChannelCount;
227 const size_t mSampleRate;
228 const size_t mFrameCount;
229 const size_t mLoopCount;
230 effect_handle_t mEffectHandle{};
231 };
232 } // namespace android
233