1 /*
2  * Copyright (C) 2020 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 #include <fuzzer/FuzzedDataProvider.h>
17 
18 #include "../g722_enc_dec.h"
19 
get_rate_from_fdp(FuzzedDataProvider * fdp)20 uint32_t get_rate_from_fdp(FuzzedDataProvider* fdp) {
21   uint32_t rate = fdp->ConsumeIntegralInRange<uint32_t>(
22       0, 3);  // Currently 3 different bit rates are available in G.722 codec
23   switch (rate) {
24     case 0:
25       return 48000;
26     case 1:
27       return 56000;
28     default:
29       return 64000;
30   }
31 }
32 
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)33 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
34   FuzzedDataProvider fdp(data, size);
35 
36   std::vector<uint8_t> buff;
37   for (size_t i = 0; i < size; i++) {
38     buff.push_back(data[i]);
39   }
40 
41   int num_samples =
42       buff.size() / (2 /*bytes_per_sample*/ * 2 /*number of channels*/);
43 
44   // The G.722 codec accept only even number of samples for encoding
45   if (num_samples % 2 != 0) {
46     num_samples--;
47   }
48 
49   // Making channel data from buffer
50   std::vector<uint16_t> channel_data;
51 
52   for (int i = 0; i < num_samples; i++) {
53     const uint8_t* sample = buff.data() + i * 2;
54     int16_t left = (int16_t)((*(sample + 1) << 8) + *sample) >> 1;
55 
56     sample += 2;
57     int16_t right = (int16_t)((*(sample + 1) << 8) + *sample) >> 1;
58 
59     uint16_t mono_data = (int16_t)(((uint32_t)left + (uint32_t)right) >> 1);
60     channel_data.push_back(mono_data);
61   }
62 
63   uint32_t rate = get_rate_from_fdp(&fdp);
64 
65   // Encoder Initialization
66   g722_encode_state_t* encoder_state = nullptr;
67   encoder_state = g722_encode_init(nullptr, rate, G722_PACKED);
68 
69   // Encode
70   std::vector<uint8_t> encoded_data;
71   // Magic number is used in api, It should basically fit the number generated
72   // by this formula : num_channels * sample_rate * data_interval_ms
73   // * (bit_rate / 8)) / 1000 as mentioned in hearing_aid.cc And if we fit all
74   // the values in the above formula, the max value we can get is 1920. And I
75   // used "size" of the input that libfuzzer generates as the initial
76   // parameter to resize
77   encoded_data.resize(size);
78   int encoded_size =
79       g722_encode(encoder_state, encoded_data.data(),
80                   (const int16_t*)channel_data.data(), channel_data.size());
81   encoded_data.resize(encoded_size);
82 
83   // Encoder release
84   if (encoder_state != nullptr) {
85     g722_encode_release(encoder_state);
86     encoder_state = nullptr;
87   }
88 
89   return 0;
90 }