| // Copyright 2019 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <stdint.h> |
| #include <stddef.h> |
| #include "ldacBT.h" |
| |
| #include <fuzzer/FuzzedDataProvider.h> |
| #include <vector> |
| |
| constexpr LDACBT_SMPL_FMT_T kFormat[] = { |
| LDACBT_SMPL_FMT_S16, LDACBT_SMPL_FMT_S24, LDACBT_SMPL_FMT_S32, |
| LDACBT_SMPL_FMT_F32}; |
| constexpr int32_t kEqmidValue[] = {LDACBT_EQMID_HQ, LDACBT_EQMID_SQ, |
| LDACBT_EQMID_MQ}; |
| constexpr int32_t kChannel[] = {LDACBT_CHANNEL_MODE_STEREO, |
| LDACBT_CHANNEL_MODE_DUAL_CHANNEL, |
| LDACBT_CHANNEL_MODE_MONO}; |
| constexpr int32_t kSamplingFrequency[] = {44100, 48000, 2 * 44100, 2 * 48000}; |
| constexpr int32_t kLdacBtRequiredMtu = 679; |
| constexpr int32_t kMaxWlValue = 4; |
| constexpr int32_t kMinChValue = 1; |
| constexpr int32_t kMaxChValue = 2; |
| constexpr int32_t kOutputSize = 1024; |
| |
| class Codec { |
| public: |
| Codec(const uint8_t *data, size_t size) : mFdp(data, size){}; |
| ~Codec() { deInitEncoder(); } |
| bool initEncoder(); |
| void deInitEncoder(); |
| void encodeFrames(const uint8_t *data, size_t size); |
| void getSamplingFrequeny(); |
| void getBitrate(); |
| void getVersion(); |
| FuzzedDataProvider mFdp; |
| |
| private: |
| int32_t mChannel; |
| LDACBT_SMPL_FMT_T mFormat; |
| HANDLE_LDAC_BT mHandleLdacBt; |
| }; |
| |
| bool Codec::initEncoder() { |
| mHandleLdacBt = ldacBT_get_handle(); |
| |
| mChannel = mFdp.PickValueInArray(kChannel); |
| mFormat = mFdp.PickValueInArray(kFormat); |
| int32_t status = ldacBT_init_handle_encode( |
| mHandleLdacBt, kLdacBtRequiredMtu, mFdp.PickValueInArray(kEqmidValue), |
| mChannel, mFormat, mFdp.PickValueInArray(kSamplingFrequency)); |
| if (!status) { |
| return true; |
| } |
| return false; |
| } |
| |
| void Codec::encodeFrames(const uint8_t *data, size_t size) { |
| int32_t pcmUsed, streamSize, frameNum; |
| unsigned char pStream[kOutputSize]; |
| int32_t ch, wl, frameSize; |
| ch = (mChannel == LDAC_CCI_MONO) ? kMinChValue : kMaxChValue; |
| wl = mFormat > kMaxWlValue ? kMaxWlValue : mFormat; |
| frameSize = LDACBT_ENC_LSU * ch * wl; |
| std::vector<uint8_t> tmpData(frameSize); |
| uint8_t *readPointer = const_cast<uint8_t *>(data); |
| while (size > 0) { |
| if (size < frameSize) { |
| memcpy(tmpData.data(), data, size); |
| size = frameSize; |
| readPointer = tmpData.data(); |
| } |
| ldacBT_encode(mHandleLdacBt, readPointer, &pcmUsed, pStream, &streamSize, |
| &frameNum); |
| readPointer += frameSize; |
| size -= frameSize; |
| } |
| } |
| |
| void Codec::getSamplingFrequeny() { ldacBT_get_sampling_freq(mHandleLdacBt); } |
| |
| void Codec::getBitrate() { ldacBT_get_bitrate(mHandleLdacBt); } |
| |
| void Codec::getVersion() { ldacBT_get_version(); } |
| |
| void Codec::deInitEncoder() { |
| ldacBT_close_handle(mHandleLdacBt); |
| ldacBT_free_handle(mHandleLdacBt); |
| } |
| |
| extern "C" int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t size) { |
| Codec codec(buf, size); |
| /* initEncoder() initializes mHandleLdacBt and is supposed to be called before |
| encoding begins. Hence initEncoder() is not included in the lambda |
| construct. */ |
| if (codec.initEncoder()) { |
| while (codec.mFdp.remaining_bytes() > 0) { |
| auto executeFunction = |
| codec.mFdp.PickValueInArray<const std::function<void()>>({ |
| [&]() { codec.encodeFrames(buf, size); }, |
| [&]() { codec.getSamplingFrequeny(); }, |
| [&]() { codec.getBitrate(); }, |
| [&]() { codec.getVersion(); }, |
| }); |
| executeFunction(); |
| } |
| } |
| return 0; |
| } |