/*
 * Copyright 2018 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.
 */

//#define LOG_NDEBUG 0
#define LOG_TAG "audio_utils_format_tests"
#include <log/log.h>

#include <audio_utils/format.h>
#include <gtest/gtest.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;
}

// Initialize PCM 16 bit ramp for basic data validation (generated from PCM 8 bit data).
// TODO: consider creating fillPseudoRandomValue().
template<size_t size>
static void fillRamp(int16_t(&buffer)[size])
{
    // Create PCM 16 bit data based on PCM 8 bit format because PCM 8 bit is convertible
    // to all other audio formats without loss; hence, round trip conversion preserves equality.
    uint8_t bytes[size];
    for (size_t i = 0; i < size; ++i) {
        bytes[i] = i;
    }
    // convert to PCM 16 bit
    memcpy_by_audio_format(
            buffer, AUDIO_FORMAT_PCM_16_BIT,
            bytes, AUDIO_FORMAT_PCM_8_BIT, size);

    uint8_t check[size];
    memcpy_by_audio_format(
            check, AUDIO_FORMAT_PCM_8_BIT,
            buffer, AUDIO_FORMAT_PCM_16_BIT, size);
    EXPECT_EQ(0, memcmp(check, bytes, size));
}

class FormatTest : public testing::TestWithParam<std::tuple<audio_format_t, audio_format_t>>
{
};

TEST_P(FormatTest, memcpy_by_audio_format)
{
    // fetch parameters
    const auto param = GetParam();
    const audio_format_t src_encoding = std::get<0>(param);
    const audio_format_t dst_encoding = std::get<1>(param);

    // 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)) {
        printf("skip conversion src:%#x  dst:%#x\n", src_encoding, dst_encoding);
        return;
    }

    constexpr size_t SAMPLES = UINT8_MAX;
    constexpr audio_format_t orig_encoding = AUDIO_FORMAT_PCM_16_BIT;
    int16_t orig_data[SAMPLES];

    fillRamp(orig_data);

    // data buffer for in-place conversion (uint32_t is maximum sample size of 4 bytes)
    uint32_t data[SAMPLES];
    // check buffer is used to compare out-of-place vs in-place conversion.
    uint32_t check[SAMPLES];

    printf("trying conversion src:%#x  dst:%#x\n", src_encoding, dst_encoding);
    fflush(stdout);
    // Copy original data to data buffer at src_encoding.
    memcpy_by_audio_format(
            data, src_encoding,
            orig_data, orig_encoding, SAMPLES);

    // Convert from src encoding to dst encoding.
    memcpy_by_audio_format(
            check, dst_encoding,
            data, src_encoding, SAMPLES);

    // Check in-place is same as out-of-place conversion.
    memcpy_by_audio_format(
            data, dst_encoding,
            data, src_encoding, SAMPLES);
    EXPECT_EQ(0, memcmp(check, data, SAMPLES * audio_bytes_per_sample(dst_encoding)));

    // Go back to the original data encoding for comparison.
    memcpy_by_audio_format(
            data, orig_encoding,
            data, dst_encoding, SAMPLES);

    // Raw byte compare at the original encoding must succeed - our conversions
    // must be lossless for PCM 8 bit representation which orig_data was constructed from.
    EXPECT_EQ(0,
            memcmp(data, orig_data, SAMPLES * audio_bytes_per_sample(orig_encoding)));
}

INSTANTIATE_TEST_CASE_P(FormatVariations, FormatTest, ::testing::Combine(
    ::testing::Values(
        AUDIO_FORMAT_PCM_8_BIT,
        AUDIO_FORMAT_PCM_16_BIT,
        AUDIO_FORMAT_PCM_FLOAT,
        AUDIO_FORMAT_PCM_24_BIT_PACKED,
        AUDIO_FORMAT_PCM_32_BIT,
        AUDIO_FORMAT_PCM_8_24_BIT
    ),
    ::testing::Values(
        AUDIO_FORMAT_PCM_8_BIT,
        AUDIO_FORMAT_PCM_16_BIT,
        AUDIO_FORMAT_PCM_FLOAT,
        AUDIO_FORMAT_PCM_24_BIT_PACKED,
        AUDIO_FORMAT_PCM_32_BIT,
        AUDIO_FORMAT_PCM_8_24_BIT
    )));

class FormatTest1p : public testing::TestWithParam<audio_format_t>
{
};


TEST_P(FormatTest1p, accumulate_by_audio_format)
{
    const audio_format_t src_encoding = GetParam();

    constexpr size_t SAMPLES = UINT8_MAX;
    constexpr audio_format_t orig_encoding = AUDIO_FORMAT_PCM_16_BIT;
    int16_t orig_data[SAMPLES];
    fillRamp(orig_data);

    // Copy original data to data buffer at src_encoding.
    uint32_t src[SAMPLES];
    memcpy_by_audio_format(
            src, src_encoding,
            orig_data, orig_encoding, SAMPLES);

    // Just do a basic test that accumulating on a silent buffer keeps original values.
    // Accumulation primitives are already tested by primitives_tests.
    printf("trying accumulation for format: %#x\n", src_encoding);
    fflush(stdout);

    uint32_t acc[SAMPLES];
    if (src_encoding == AUDIO_FORMAT_PCM_8_BIT) {
        memset(acc, 0x80, SAMPLES * sizeof(uint32_t));
    } else {
        memset(acc, 0, SAMPLES * sizeof(uint32_t));
    }

    accumulate_by_audio_format(acc, src, src_encoding, SAMPLES);
    EXPECT_EQ(0, memcmp(src, acc, SAMPLES * audio_bytes_per_sample(src_encoding)));
}

INSTANTIATE_TEST_CASE_P(FormatVariation, FormatTest1p, ::testing::Values(
        AUDIO_FORMAT_PCM_8_BIT,
        AUDIO_FORMAT_PCM_16_BIT,
        AUDIO_FORMAT_PCM_FLOAT,
        AUDIO_FORMAT_PCM_24_BIT_PACKED,
        AUDIO_FORMAT_PCM_32_BIT,
        AUDIO_FORMAT_PCM_8_24_BIT
    ));
