/*
 * Copyright (C) 2012 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 <stdint.h>
#include <math.h>
#include <utils/StrongPointer.h>
#include "audio/Buffer.h"
#include "BuiltinProcessing.h"
#include "Log.h"
#include "task/TaskCase.h"

// Buffer, Value, Value
static const bool RMS_MVA_INPUT_TYPE[] = {true, false, false};
// Value
static const bool RMS_MVA_OUTPUT_TYPE[] = {false};

BuiltinProcessing::BuiltinInfo BuiltinProcessing::BUINTIN_FN_TABLE[N_BUILTIN_FNS] =
{
    {
        "rms_mva", &BuiltinProcessing::rms_mva,
        sizeof(RMS_MVA_INPUT_TYPE)/sizeof(bool), RMS_MVA_INPUT_TYPE,
        sizeof(RMS_MVA_OUTPUT_TYPE)/sizeof(bool), RMS_MVA_OUTPUT_TYPE,
    }
};

BuiltinProcessing::BuiltinProcessing()
    : mRMSPasses(0)
{

}

// pass for 5 consecutive passes
TaskGeneric::ExecutionResult BuiltinProcessing::rms_mva(void** inputs, void** outputs)
{
    LOGD("BuiltinProcessing::rms_mva in %x %x %x out %x",
            inputs[0], inputs[1], inputs[2], outputs[0]);
    android::sp<Buffer>& data(*reinterpret_cast<android::sp<Buffer>*>(inputs[0]));

    int64_t passMin = (reinterpret_cast<TaskCase::Value*>(inputs[1]))->getInt64();
    int64_t passMax = (reinterpret_cast<TaskCase::Value*>(inputs[2]))->getInt64();

    int64_t rms = 0;
    size_t samples = data->getSize()/2;
    int16_t* rawData = reinterpret_cast<int16_t*>(data->getData());
    double energy = 0.0f;
    for (size_t i = 0; i < samples; i++) {
        energy += (rawData[i] * rawData[i]);
    }
    rms = (int64_t)sqrt(energy/samples);

    TaskGeneric::ExecutionResult result = TaskGeneric::EResultOK;
    if (rms < passMin) {
        LOGW("Volume %lld low compared to min %lld max %lld", rms, passMin, passMax);
        mRMSPasses = 0;
    } else if (rms <= passMax) {
        LOGW("Volume %lld OK compared to min %lld max %lld", rms, passMin, passMax);
        mRMSPasses++;
        if (mRMSPasses >= RMS_CONTINUOUS_PASSES) {
            //mRMSPasses = 0;
            result = TaskGeneric::EResultPass;
        }
    } else {
        LOGW("Volume %lld high compared to min %lld max %lld", rms, passMin, passMax);
        mRMSPasses = 0;
    }
    TaskCase::Value* rmsVal = reinterpret_cast<TaskCase::Value*>(outputs[0]);
    rmsVal->setInt64(rms);

    return result;
}