Harish Mahendrakar | 88de9c4 | 2021-03-03 12:39:09 -0800 | [diff] [blame] | 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 <gtest/gtest.h> |
| 25 | #include <hardware/audio_effect.h> |
| 26 | #include <log/log.h> |
| 27 | #include <random> |
| 28 | #include <stdint.h> |
| 29 | #include <system/audio.h> |
| 30 | #include <vector> |
| 31 | |
| 32 | namespace android { |
| 33 | template <typename T> |
| 34 | static float computeSnr(const T* ref, const T* tst, size_t count) { |
| 35 | double signal{}; |
| 36 | double noise{}; |
| 37 | |
| 38 | for (size_t i = 0; i < count; ++i) { |
| 39 | const double value(ref[i]); |
| 40 | const double diff(tst[i] - value); |
| 41 | signal += value * value; |
| 42 | noise += diff * diff; |
| 43 | } |
| 44 | // Initialized to large value to handle |
| 45 | // cases where ref and tst match exactly |
| 46 | float snr = FLT_MAX; |
| 47 | if (signal > 0.0f && noise > 0.0f) { |
| 48 | snr = 10.f * log(signal / noise); |
| 49 | } |
| 50 | return snr; |
| 51 | } |
| 52 | |
Harish Mahendrakar | f2abe3b | 2021-09-03 13:40:36 -0700 | [diff] [blame] | 53 | template <typename T> |
| 54 | static float areNearlySame(const T* ref, const T* tst, size_t count) { |
| 55 | T delta; |
| 56 | if constexpr (std::is_floating_point_v<T>) { |
| 57 | delta = std::numeric_limits<T>::epsilon(); |
| 58 | } else { |
| 59 | delta = 1; |
| 60 | } |
| 61 | for (size_t i = 0; i < count; ++i) { |
| 62 | const double diff(tst[i] - ref[i]); |
| 63 | if (abs(diff) > delta) { |
| 64 | return false; |
| 65 | } |
| 66 | } |
| 67 | return true; |
| 68 | } |
| 69 | |
Harish Mahendrakar | 88de9c4 | 2021-03-03 12:39:09 -0800 | [diff] [blame] | 70 | class EffectTestHelper { |
| 71 | public: |
| 72 | EffectTestHelper(const effect_uuid_t* uuid, size_t inChMask, size_t outChMask, |
| 73 | size_t sampleRate, size_t frameCount, size_t loopCount) |
| 74 | : mUuid(uuid), |
| 75 | mInChMask(inChMask), |
| 76 | mInChannelCount(audio_channel_count_from_out_mask(mInChMask)), |
| 77 | mOutChMask(outChMask), |
| 78 | mOutChannelCount(audio_channel_count_from_out_mask(mOutChMask)), |
| 79 | mSampleRate(sampleRate), |
| 80 | mFrameCount(frameCount), |
| 81 | mLoopCount(loopCount) {} |
| 82 | void createEffect(); |
| 83 | void releaseEffect(); |
| 84 | void setConfig(); |
Harish Mahendrakar | f2abe3b | 2021-09-03 13:40:36 -0700 | [diff] [blame] | 85 | template <typename VALUE_DTYPE> |
| 86 | void setParam(uint32_t type, VALUE_DTYPE const value) { |
| 87 | int reply = 0; |
| 88 | uint32_t replySize = sizeof(reply); |
| 89 | |
| 90 | uint8_t paramData[sizeof(effect_param_t) + sizeof(type) + sizeof(value)]; |
| 91 | auto effectParam = (effect_param_t*)paramData; |
| 92 | |
| 93 | memcpy(&effectParam->data[0], &type, sizeof(type)); |
| 94 | memcpy(&effectParam->data[sizeof(type)], &value, sizeof(value)); |
| 95 | effectParam->psize = sizeof(type); |
| 96 | effectParam->vsize = sizeof(value); |
| 97 | int status = (*mEffectHandle) |
| 98 | ->command(mEffectHandle, EFFECT_CMD_SET_PARAM, |
| 99 | sizeof(effect_param_t) + sizeof(type) + sizeof(value), |
| 100 | effectParam, &replySize, &reply); |
| 101 | ASSERT_EQ(status, 0) << "set_param returned an error " << status; |
| 102 | ASSERT_EQ(reply, 0) << "set_param reply non zero " << reply; |
| 103 | }; |
Harish Mahendrakar | 88de9c4 | 2021-03-03 12:39:09 -0800 | [diff] [blame] | 104 | void process(float* input, float* output); |
| 105 | |
| 106 | // Corresponds to SNR for 1 bit difference between two int16_t signals |
| 107 | static constexpr float kSNRThreshold = 90.308998; |
| 108 | |
| 109 | static constexpr audio_channel_mask_t kChMasks[] = { |
| 110 | AUDIO_CHANNEL_OUT_MONO, AUDIO_CHANNEL_OUT_STEREO, |
| 111 | AUDIO_CHANNEL_OUT_2POINT1, AUDIO_CHANNEL_OUT_2POINT0POINT2, |
| 112 | AUDIO_CHANNEL_OUT_QUAD, AUDIO_CHANNEL_OUT_QUAD_BACK, |
| 113 | AUDIO_CHANNEL_OUT_QUAD_SIDE, AUDIO_CHANNEL_OUT_SURROUND, |
| 114 | AUDIO_CHANNEL_INDEX_MASK_4, AUDIO_CHANNEL_OUT_2POINT1POINT2, |
| 115 | AUDIO_CHANNEL_OUT_3POINT0POINT2, AUDIO_CHANNEL_OUT_PENTA, |
| 116 | AUDIO_CHANNEL_INDEX_MASK_5, AUDIO_CHANNEL_OUT_3POINT1POINT2, |
| 117 | AUDIO_CHANNEL_OUT_5POINT1, AUDIO_CHANNEL_OUT_5POINT1_BACK, |
| 118 | AUDIO_CHANNEL_OUT_5POINT1_SIDE, AUDIO_CHANNEL_INDEX_MASK_6, |
| 119 | AUDIO_CHANNEL_OUT_6POINT1, AUDIO_CHANNEL_INDEX_MASK_7, |
| 120 | AUDIO_CHANNEL_OUT_5POINT1POINT2, AUDIO_CHANNEL_OUT_7POINT1, |
| 121 | AUDIO_CHANNEL_INDEX_MASK_8, AUDIO_CHANNEL_INDEX_MASK_9, |
| 122 | AUDIO_CHANNEL_INDEX_MASK_10, AUDIO_CHANNEL_INDEX_MASK_11, |
| 123 | AUDIO_CHANNEL_INDEX_MASK_12, AUDIO_CHANNEL_INDEX_MASK_13, |
| 124 | AUDIO_CHANNEL_INDEX_MASK_14, AUDIO_CHANNEL_INDEX_MASK_15, |
| 125 | AUDIO_CHANNEL_INDEX_MASK_16, AUDIO_CHANNEL_INDEX_MASK_17, |
| 126 | AUDIO_CHANNEL_INDEX_MASK_18, AUDIO_CHANNEL_INDEX_MASK_19, |
| 127 | AUDIO_CHANNEL_INDEX_MASK_20, AUDIO_CHANNEL_INDEX_MASK_21, |
| 128 | AUDIO_CHANNEL_INDEX_MASK_22, AUDIO_CHANNEL_INDEX_MASK_23, |
| 129 | AUDIO_CHANNEL_INDEX_MASK_24, |
| 130 | }; |
| 131 | |
| 132 | static constexpr size_t kNumChMasks = std::size(kChMasks); |
| 133 | |
| 134 | static constexpr size_t kSampleRates[] = {8000, 11025, 12000, 16000, 22050, 24000, 32000, |
| 135 | 44100, 48000, 88200, 96000, 176400, 192000}; |
| 136 | |
| 137 | static constexpr size_t kNumSampleRates = std::size(kSampleRates); |
| 138 | |
| 139 | static constexpr size_t kFrameCounts[] = {4, 2048}; |
| 140 | |
| 141 | static constexpr size_t kNumFrameCounts = std::size(kFrameCounts); |
| 142 | |
| 143 | static constexpr size_t kLoopCounts[] = {1, 4}; |
| 144 | |
| 145 | static constexpr size_t kNumLoopCounts = std::size(kLoopCounts); |
| 146 | |
| 147 | private: |
| 148 | const effect_uuid_t* mUuid; |
| 149 | const size_t mInChMask; |
| 150 | const size_t mInChannelCount; |
| 151 | const size_t mOutChMask; |
| 152 | const size_t mOutChannelCount; |
| 153 | const size_t mSampleRate; |
| 154 | const size_t mFrameCount; |
| 155 | const size_t mLoopCount; |
| 156 | effect_handle_t mEffectHandle{}; |
| 157 | }; |
| 158 | } // namespace android |