• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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