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(&params[0], &params[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