| /* |
| * Copyright (C) 2019 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include <stddef.h> |
| #include <stdint.h> |
| #include <stdlib.h> |
| #include <audio_utils/format.h> |
| #include <system/audio.h> |
| |
| /** returns true if the format is a common source or destination format. |
| memcpy_by_audio_format() allows interchange between any PCM format and the |
| "common" PCM 16 bit and PCM float formats. */ |
| static bool is_common_src_format(audio_format_t format) { |
| return format == AUDIO_FORMAT_PCM_16_BIT || format == AUDIO_FORMAT_PCM_FLOAT; |
| } |
| |
| static bool is_common_dst_format(audio_format_t format) { |
| return format == AUDIO_FORMAT_PCM_8_BIT // Allowed for HAL to AudioRecord conversion. |
| || format == AUDIO_FORMAT_PCM_16_BIT |
| || format == AUDIO_FORMAT_PCM_FLOAT; |
| } |
| |
| const static audio_format_t formats[] = {AUDIO_FORMAT_PCM_16_BIT, AUDIO_FORMAT_PCM_FLOAT, |
| AUDIO_FORMAT_PCM_8_BIT, AUDIO_FORMAT_PCM_24_BIT_PACKED, AUDIO_FORMAT_PCM_32_BIT, |
| AUDIO_FORMAT_PCM_8_24_BIT}; |
| |
| // Initialize PCM 16 bit ramp for basic data validation (generated from PCM 8 bit data). |
| template<size_t size> |
| static void fillBuffer(const uint8_t bytes[], int16_t(&buffer)[size], size_t input_size) |
| { |
| if (size < input_size) { |
| input_size = size; |
| } |
| |
| // convert to PCM 16 bit |
| memcpy_by_audio_format( |
| buffer, AUDIO_FORMAT_PCM_16_BIT, |
| bytes, AUDIO_FORMAT_PCM_8_BIT, input_size); |
| |
| uint8_t check[size]; |
| memcpy_by_audio_format( |
| check, AUDIO_FORMAT_PCM_8_BIT, |
| buffer, AUDIO_FORMAT_PCM_16_BIT, input_size); |
| } |
| |
| extern "C" int LLVMFuzzerTestOneInput(const uint8_t *bytes, size_t size) { |
| if (size < 4 || size > UINT8_MAX) { |
| return 0; |
| } |
| size_t formats_len = sizeof(formats)/sizeof(audio_format_t); |
| int src = size % formats_len; |
| int dst = formats_len - 1 - src; |
| |
| // fetch parameters |
| const audio_format_t src_encoding = formats[src]; |
| const audio_format_t dst_encoding = formats[dst]; |
| |
| // either source or destination (or both) need to be a common format |
| if (!is_common_src_format(src_encoding) && !is_common_dst_format(dst_encoding)) { |
| return 0; |
| } |
| |
| constexpr size_t SAMPLES = UINT8_MAX; |
| constexpr audio_format_t orig_encoding = AUDIO_FORMAT_PCM_16_BIT; |
| int16_t data[SAMPLES]; |
| fillBuffer(bytes, data, size); |
| |
| // data buffer for in-place conversion (uint32_t is maximum sample size of 4 bytes) |
| uint32_t databuff[size]; |
| // check buffer is used to compare out-of-place vs in-place conversion. |
| uint32_t check[size]; |
| |
| // Copy original data to data buffer at src_encoding. |
| memcpy_by_audio_format( |
| databuff, src_encoding, |
| data, orig_encoding, size); |
| |
| // Convert from src encoding to dst encoding. |
| memcpy_by_audio_format( |
| check, dst_encoding, |
| databuff, src_encoding, size); |
| |
| // Check in-place is same as out-of-place conversion. |
| memcpy_by_audio_format( |
| databuff, dst_encoding, |
| databuff, src_encoding, size); |
| |
| // Go back to the original data encoding for comparison. |
| memcpy_by_audio_format( |
| databuff, orig_encoding, |
| databuff, dst_encoding, size); |
| |
| return 0; |
| } |