1 /*
2 * Copyright (c) 2025 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <iostream>
17 #include <cstddef>
18 #include <cstdint>
19 #include <cstring>
20 #include "audio_info.h"
21 #include "audio_device_info.h"
22 #include "audio_utils.h"
23 #include "audio_channel_blend.h"
24 #include "volume_ramp.h"
25 #include <algorithm>
26 #include <cinttypes>
27 #include "down_mixer.h"
28 #include "audio_engine_log.h"
29
30 namespace OHOS {
31 namespace AudioStandard {
32 using namespace std;
33 using namespace HPAE;
34
35 static const uint8_t* RAW_DATA = nullptr;
36 static size_t g_dataSize = 0;
37 static size_t g_pos;
38 static std::string g_rootCapturerPath = "/data/source_file_io_48000_2_s16le.pcm";
39 const char* DEFAULT_TEST_DEVICE_CLASS = "file_io";
40 const char* DEFAULT_TEST_DEVICE_NETWORKID = "LocalDevice";
41 constexpr size_t THRESHOLD = 10;
42 constexpr uint8_t TESTSIZE = 4;
43
44 // need full audio channel layouts to cover all cases during setting up downmix table -- first part
45 constexpr static AudioChannelLayout FIRST_PART_CH_LAYOUTS = static_cast<AudioChannelLayout> (
46 FRONT_LEFT | FRONT_RIGHT | FRONT_CENTER | LOW_FREQUENCY |
47 BACK_LEFT | BACK_RIGHT |
48 FRONT_LEFT_OF_CENTER | FRONT_RIGHT_OF_CENTER |
49 BACK_CENTER | SIDE_LEFT | SIDE_RIGHT |
50 TOP_CENTER | TOP_FRONT_LEFT | TOP_FRONT_CENTER | TOP_FRONT_RIGHT | TOP_BACK_LEFT
51 );
52
53 // need full audio channel layouts to cover all cases during setting up downmix table -- second part
54 constexpr static AudioChannelLayout SECOND_PART_CH_LAYOUTS = static_cast<AudioChannelLayout> (
55 TOP_CENTER | TOP_BACK_LEFT | TOP_BACK_CENTER | TOP_BACK_RIGHT |
56 STEREO_LEFT | STEREO_RIGHT |
57 WIDE_LEFT | WIDE_RIGHT |
58 SURROUND_DIRECT_LEFT | SURROUND_DIRECT_RIGHT | LOW_FREQUENCY_2 |
59 TOP_SIDE_LEFT | TOP_SIDE_RIGHT |
60 BOTTOM_FRONT_CENTER | BOTTOM_FRONT_LEFT | BOTTOM_FRONT_RIGHT
61 );
62 // for test predefined downmix rules
63 const static std::set<AudioChannelLayout> OUTPUT_CH_LAYOUT_SET = {
64 CH_LAYOUT_STEREO,
65 CH_LAYOUT_5POINT1,
66 CH_LAYOUT_5POINT1POINT2,
67 CH_LAYOUT_5POINT1POINT4,
68 CH_LAYOUT_7POINT1,
69 CH_LAYOUT_7POINT1POINT2,
70 CH_LAYOUT_7POINT1POINT4
71 };
72
73 const static std::set<AudioChannelLayout> GENERAL_OUTPUT_CH_LAYOUT_SET = {
74 CH_LAYOUT_SURROUND,
75 CH_LAYOUT_3POINT1,
76 CH_LAYOUT_4POINT0,
77 CH_LAYOUT_QUAD_SIDE,
78 CH_LAYOUT_QUAD,
79 CH_LAYOUT_4POINT1,
80 CH_LAYOUT_5POINT0,
81 CH_LAYOUT_5POINT0_BACK,
82 CH_LAYOUT_2POINT1POINT2,
83 CH_LAYOUT_3POINT0POINT2,
84 CH_LAYOUT_5POINT1_BACK,
85 CH_LAYOUT_6POINT0,
86 CH_LAYOUT_HEXAGONAL,
87 CH_LAYOUT_3POINT1POINT2,
88 CH_LAYOUT_6POINT0_FRONT,
89 CH_LAYOUT_6POINT1,
90 CH_LAYOUT_6POINT1_BACK,
91 CH_LAYOUT_7POINT0,
92 CH_LAYOUT_OCTAGONAL,
93 CH_LAYOUT_7POINT1_WIDE_BACK,
94 CH_LAYOUT_7POINT1_WIDE,
95 CH_LAYOUT_10POINT2,
96 CH_LAYOUT_9POINT1POINT4,
97 };
98
99 // define channelLayout set to cover all channels as input
100 const static std::set<AudioChannelLayout> FULL_CH_LAYOUT_SET = {
101 FIRST_PART_CH_LAYOUTS,
102 SECOND_PART_CH_LAYOUTS
103 };
104
105 const static std::map<AudioChannel, AudioChannelLayout> DOWNMIX_CHANNEL_COUNT_MAP = {
106 {MONO, CH_LAYOUT_MONO},
107 {STEREO, CH_LAYOUT_STEREO},
108 {CHANNEL_3, CH_LAYOUT_SURROUND},
109 {CHANNEL_4, CH_LAYOUT_3POINT1},
110 {CHANNEL_5, CH_LAYOUT_4POINT1},
111 {CHANNEL_6, CH_LAYOUT_5POINT1},
112 {CHANNEL_7, CH_LAYOUT_6POINT1},
113 {CHANNEL_8, CH_LAYOUT_5POINT1POINT2},
114 {CHANNEL_9, CH_LAYOUT_HOA_ORDER2_ACN_N3D},
115 {CHANNEL_10, CH_LAYOUT_7POINT1POINT2},
116 {CHANNEL_12, CH_LAYOUT_7POINT1POINT4},
117 {CHANNEL_13, CH_LAYOUT_UNKNOWN},
118 {CHANNEL_14, CH_LAYOUT_9POINT1POINT4},
119 {CHANNEL_16, CH_LAYOUT_9POINT1POINT6}
120 };
121
122 constexpr uint32_t TEST_FORMAT_SIZE = 4;
123 constexpr uint32_t TEST_FRAME_LEN = 100;
124 constexpr uint32_t TEST_BUFFER_LEN = 10;
125 constexpr bool MIX_FLE = true;
126
BitCounts(uint64_t bits)127 static uint32_t BitCounts(uint64_t bits)
128 {
129 uint32_t num = 0;
130 for (; bits != 0; bits &= bits - 1) {
131 num++;
132 }
133 return num;
134 }
135
136 template<class T>
GetData()137 T GetData()
138 {
139 T object {};
140 size_t objectSize = sizeof(object);
141 if (RAW_DATA == nullptr || objectSize > g_dataSize - g_pos) {
142 return object;
143 }
144 errno_t ret = memcpy_s(&object, objectSize, RAW_DATA + g_pos, objectSize);
145 if (ret != EOK) {
146 return {};
147 }
148 g_pos += objectSize;
149 return object;
150 }
151
152 template<class T>
GetArrLength(T & arr)153 uint32_t GetArrLength(T& arr)
154 {
155 if (arr == nullptr) {
156 AUDIO_INFO_LOG("%{public}s: The array length is equal to 0", __func__);
157 return 0;
158 }
159 return sizeof(arr) / sizeof(arr[0]);
160 }
161
SetParamFuzzTest()162 void SetParamFuzzTest()
163 {
164 // invalid input Param
165 DownMixer downMixer;
166 AudioChannelInfo inChannelInfo;
167 AudioChannelInfo outChannelInfo;
168 inChannelInfo.numChannels = MAX_CHANNELS + 1;
169 inChannelInfo.channelLayout = CH_LAYOUT_UNKNOWN;
170 outChannelInfo.numChannels = MAX_CHANNELS + 1;
171 outChannelInfo.channelLayout = CH_LAYOUT_UNKNOWN;
172 downMixer.SetParam(inChannelInfo, outChannelInfo, TEST_FORMAT_SIZE, MIX_FLE);
173
174 // valid param, predefined downmix rules
175 for (AudioChannelLayout outLayout: OUTPUT_CH_LAYOUT_SET) {
176 outChannelInfo.numChannels = BitCounts(outLayout);
177 outChannelInfo.channelLayout = outLayout;
178 for (AudioChannelLayout inLayout: FULL_CH_LAYOUT_SET) {
179 inChannelInfo.channelLayout = inLayout;
180 inChannelInfo.numChannels = MAX_CHANNELS;
181 downMixer.SetParam(inChannelInfo, outChannelInfo, TEST_FORMAT_SIZE, MIX_FLE);
182 }
183 }
184
185 // valid param, general downmix table rule
186 for (AudioChannelLayout outLayout: GENERAL_OUTPUT_CH_LAYOUT_SET) {
187 outChannelInfo.numChannels = BitCounts(outLayout);
188 outChannelInfo.channelLayout = outLayout;
189 for (AudioChannelLayout inLayout: FULL_CH_LAYOUT_SET) {
190 inChannelInfo.channelLayout = inLayout;
191 inChannelInfo.numChannels = MAX_CHANNELS;
192 downMixer.SetParam(inChannelInfo, outChannelInfo, TEST_FORMAT_SIZE, MIX_FLE);
193 }
194 }
195 }
196
SetDefaultChannelLayoutFuzzTest()197 void SetDefaultChannelLayoutFuzzTest()
198 {
199 DownMixer downMixer;
200 for (auto pair : DOWNMIX_CHANNEL_COUNT_MAP) {
201 downMixer.SetDefaultChannelLayout(pair.first);
202 }
203 downMixer.CheckIsHOA(CH_LAYOUT_HOA_ORDER2_ACN_SN3D);
204 downMixer.CheckIsHOA(CH_LAYOUT_UNKNOWN);
205 }
206
ProcesFuzzTest1()207 void ProcesFuzzTest1()
208 {
209 AudioChannelInfo inChannelInfo;
210 AudioChannelInfo outChannelInfo;
211 inChannelInfo.channelLayout = CH_LAYOUT_5POINT1;
212 inChannelInfo.numChannels = CHANNEL_6;
213 outChannelInfo.channelLayout = CH_LAYOUT_STEREO;
214 outChannelInfo.numChannels = STEREO;
215
216 // test uninitialized
217 DownMixer downMixer;
218 std::vector<float> in(TEST_BUFFER_LEN * CHANNEL_6, 0.0f);
219 std::vector<float> out(TEST_BUFFER_LEN * STEREO, 0.0f);
220 uint32_t testInBufferSize = in.size() * TEST_FORMAT_SIZE;
221 uint32_t testOutBufferSize = out.size() * TEST_FORMAT_SIZE;
222 downMixer.Process(TEST_BUFFER_LEN, in.data(), testInBufferSize, out.data(), testOutBufferSize);
223
224 // test input and output buffer length smaller than expected
225 downMixer.SetParam(inChannelInfo, outChannelInfo, TEST_FORMAT_SIZE, MIX_FLE);
226 downMixer.Process(TEST_FRAME_LEN, in.data(), testInBufferSize, out.data(), testOutBufferSize);
227
228 // test process usual channel layout
229 downMixer.Process(TEST_BUFFER_LEN, in.data(), testInBufferSize, out.data(), testOutBufferSize);
230
231 // test process HOA
232 inChannelInfo.channelLayout = CH_LAYOUT_HOA_ORDER2_ACN_SN3D;
233 inChannelInfo.numChannels = CHANNEL_9;
234 in.resize(CHANNEL_9 * TEST_BUFFER_LEN, 0.0f);
235 testInBufferSize = in.size() * TEST_FORMAT_SIZE;
236 downMixer.SetParam(inChannelInfo, outChannelInfo, TEST_FORMAT_SIZE, MIX_FLE);
237 downMixer.Process(TEST_BUFFER_LEN, in.data(), testInBufferSize, out.data(), testOutBufferSize);
238 }
239
ProcesFuzzTest2()240 void ProcesFuzzTest2()
241 {
242 AudioChannelInfo inChannelInfo;
243 AudioChannelInfo outChannelInfo;
244 inChannelInfo.channelLayout = CH_LAYOUT_5POINT1;
245 inChannelInfo.numChannels = CHANNEL_6;
246 outChannelInfo.channelLayout = CH_LAYOUT_STEREO;
247 outChannelInfo.numChannels = STEREO;
248
249 // test uninitialized
250 DownMixer downMixer;
251 std::vector<float> in(TEST_BUFFER_LEN * CHANNEL_6, 0.0f);
252 std::vector<float> out(TEST_BUFFER_LEN * STEREO, 0.0f);
253 for (size_t i = 0; i < TEST_BUFFER_LEN * CHANNEL_6; i++) {
254 in[i] = GetData<float>();
255 }
256 uint32_t testInBufferSize = in.size() * TEST_FORMAT_SIZE;
257 uint32_t testOutBufferSize = out.size() * TEST_FORMAT_SIZE;
258 downMixer.Process(TEST_BUFFER_LEN, in.data(), testInBufferSize, out.data(), testOutBufferSize);
259
260 // test input and output buffer length smaller than expected
261 downMixer.SetParam(inChannelInfo, outChannelInfo, TEST_FORMAT_SIZE, MIX_FLE);
262 downMixer.Process(TEST_FRAME_LEN, in.data(), testInBufferSize, out.data(), testOutBufferSize);
263
264 // test process usual channel layout
265 downMixer.Process(TEST_BUFFER_LEN, in.data(), testInBufferSize, out.data(), testOutBufferSize);
266
267 // test process HOA
268 inChannelInfo.channelLayout = CH_LAYOUT_HOA_ORDER2_ACN_SN3D;
269 inChannelInfo.numChannels = CHANNEL_9;
270 in.resize(CHANNEL_9 * TEST_BUFFER_LEN, 0.0f);
271 testInBufferSize = in.size() * TEST_FORMAT_SIZE;
272 downMixer.SetParam(inChannelInfo, outChannelInfo, TEST_FORMAT_SIZE, MIX_FLE);
273 downMixer.Process(TEST_BUFFER_LEN, in.data(), testInBufferSize, out.data(), testOutBufferSize);
274 }
275
276 typedef void (*TestFuncs)();
277 TestFuncs g_testFuncs[TESTSIZE] = {
278 SetParamFuzzTest,
279 SetDefaultChannelLayoutFuzzTest,
280 ProcesFuzzTest1,
281 ProcesFuzzTest2,
282 };
283
FuzzTest(const uint8_t * rawData,size_t size)284 bool FuzzTest(const uint8_t* rawData, size_t size)
285 {
286 if (rawData == nullptr) {
287 return false;
288 }
289
290 // initialize data
291 RAW_DATA = rawData;
292 g_dataSize = size;
293 g_pos = 0;
294
295 uint32_t code = GetData<uint32_t>();
296 uint32_t len = GetArrLength(g_testFuncs);
297 if (len > 0) {
298 g_testFuncs[code % len]();
299 } else {
300 AUDIO_INFO_LOG("%{public}s: The len length is equal to 0", __func__);
301 }
302
303 return true;
304 }
305 } // namespace AudioStandard
306 } // namesapce OHOS
307
308 /* Fuzzer entry point */
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)309 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
310 {
311 if (size < OHOS::AudioStandard::THRESHOLD) {
312 return 0;
313 }
314
315 OHOS::AudioStandard::FuzzTest(data, size);
316 return 0;
317 }
318