/*

 * Copyright (c) 2024 Huawei Device Co., Ltd.

 * 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 "alsa_snd_render.h"

#include "common.h"



#define HDF_LOG_TAG HDF_AUDIO_HAL_RENDER



typedef struct RenderData {

    struct AlsaMixerCtlElement ctrlLeftVolume;

    struct AlsaMixerCtlElement ctrlRightVolume;

    long tempVolume;

} RenderData;



static int32_t RenderInitImpl(struct AlsaRender *renderIns)

{

    CHECK_NULL_PTR_RETURN_DEFAULT(renderIns);

    if (renderIns->priData != NULL) {

        return HDF_SUCCESS;

    }



    RenderData *priData = (RenderData *)OsalMemCalloc(sizeof(RenderData));

    if (priData == NULL) {

        AUDIO_FUNC_LOGE("Failed to allocate memory!");

        return HDF_FAILURE;

    }



    SndElementItemInit(&priData->ctrlLeftVolume);

    SndElementItemInit(&priData->ctrlRightVolume);

    priData->ctrlLeftVolume.numid = SND_NUMID_DACL_PLAYBACK_VOL;

    priData->ctrlLeftVolume.name = SND_ELEM_DACL_PLAYBACK_VOL;

    priData->ctrlRightVolume.numid = SND_NUMID_DACR_PLAYBACK_VOL;

    priData->ctrlRightVolume.name = SND_ELEM_DACR_PLAYBACK_VOL;

    RenderSetPriData(renderIns, (RenderPriData)priData);



    return HDF_SUCCESS;

}



static int32_t RenderSelectSceneImpl(struct AlsaRender *renderIns, enum AudioPortPin descPins,

    const struct PathDeviceInfo *deviceInfo)

{

    CHECK_NULL_PTR_RETURN_DEFAULT(renderIns);

    renderIns->descPins = descPins;

    return HDF_SUCCESS;

}



static int32_t RenderGetVolThresholdImpl(struct AlsaRender *renderIns, long *volMin, long *volMax)

{

    CHECK_NULL_PTR_RETURN_DEFAULT(renderIns);

    CHECK_NULL_PTR_RETURN_DEFAULT(volMin);

    CHECK_NULL_PTR_RETURN_DEFAULT(volMax);

    int32_t ret = HDF_SUCCESS;

    long volMinTmp = 0;

    long volMaxTmp = 0;

    struct AlsaSoundCard *cardIns = (struct AlsaSoundCard *)renderIns;

    RenderData *priData = RenderGetPriData(renderIns);

    CHECK_NULL_PTR_RETURN_DEFAULT(cardIns);

    CHECK_NULL_PTR_RETURN_DEFAULT(priData);



    ret = SndElementReadRange(cardIns, &priData->ctrlLeftVolume, &volMinTmp, &volMaxTmp);

    if (ret != HDF_SUCCESS) {

        AUDIO_FUNC_LOGE("SndElementReadRange fail!");

        return HDF_FAILURE;

    }

    *volMin = volMinTmp;

    *volMax = volMaxTmp;

    

    return HDF_SUCCESS;

}



static int32_t RenderGetVolumeImpl(struct AlsaRender *renderIns, long *volume)

{

    CHECK_NULL_PTR_RETURN_DEFAULT(renderIns);

    CHECK_NULL_PTR_RETURN_DEFAULT(volume);

    int32_t ret = HDF_SUCCESS;

    long volLeft = 0;

    long volRight = 0;

    struct AlsaSoundCard *cardIns = (struct AlsaSoundCard *)renderIns;

    RenderData *priData = RenderGetPriData(renderIns);

    CHECK_NULL_PTR_RETURN_DEFAULT(cardIns);

    CHECK_NULL_PTR_RETURN_DEFAULT(priData);



    ret = SndElementReadInt(cardIns, &priData->ctrlLeftVolume, &volLeft);

    if (ret != HDF_SUCCESS) {

        AUDIO_FUNC_LOGE("Read left volume fail!");

        return HDF_FAILURE;

    }

    ret = SndElementReadInt(cardIns, &priData->ctrlRightVolume, &volRight);

    if (ret != HDF_SUCCESS) {

        AUDIO_FUNC_LOGE("Read right volume fail!");

        return HDF_FAILURE;

    }

    *volume = (volLeft + volRight) >> 1;



    return HDF_SUCCESS;

}



static int32_t RenderSetVolumeImpl(struct AlsaRender *renderIns, long volume)

{

    CHECK_NULL_PTR_RETURN_DEFAULT(renderIns);

    int32_t ret = HDF_SUCCESS;

    struct AlsaSoundCard *cardIns = (struct AlsaSoundCard *)renderIns;

    RenderData *priData = RenderGetPriData(renderIns);

    CHECK_NULL_PTR_RETURN_DEFAULT(cardIns);

    CHECK_NULL_PTR_RETURN_DEFAULT(priData);



    ret = SndElementWriteInt(cardIns, &priData->ctrlLeftVolume, volume);

    if (ret != HDF_SUCCESS) {

        AUDIO_FUNC_LOGE("Write left volume fail!");

        return HDF_FAILURE;

    }

    ret = SndElementWriteInt(cardIns, &priData->ctrlRightVolume, volume);

    if (ret != HDF_SUCCESS) {

        AUDIO_FUNC_LOGE("Write right volume fail!");

        return HDF_FAILURE;

    }

    

    return HDF_SUCCESS;

}



static bool RenderGetMuteImpl(struct AlsaRender *renderIns)

{

    CHECK_NULL_PTR_RETURN_DEFAULT(renderIns);

    return renderIns->muteState;

}



static int32_t RenderSetMuteImpl(struct AlsaRender *renderIns, bool muteFlag)

{

    CHECK_NULL_PTR_RETURN_DEFAULT(renderIns);

    int32_t ret = HDF_SUCCESS;

    long vol = 0;

    long setVol = 0;

    RenderData *priData = RenderGetPriData(renderIns);

    CHECK_NULL_PTR_RETURN_DEFAULT(renderIns);

    CHECK_NULL_PTR_RETURN_DEFAULT(priData);



    ret = renderIns->GetVolume(renderIns, &vol);

    if (ret != HDF_SUCCESS) {

        AUDIO_FUNC_LOGE("GetVolume failed!");

        return HDF_FAILURE;

    }

    

    if (muteFlag) {

        priData->tempVolume = vol;

        setVol = 0;

    } else {

        setVol = priData->tempVolume;

    }

    

    renderIns->SetVolume(renderIns, setVol);

    if (ret != HDF_SUCCESS) {

        AUDIO_FUNC_LOGE("SetVolume failed!");

        return HDF_FAILURE;

    }

    renderIns->muteState = muteFlag;

    

    return HDF_SUCCESS;

}



static int32_t RenderStartImpl(struct AlsaRender *renderIns)

{

    return HDF_SUCCESS;

}



static int32_t RenderStopImpl(struct AlsaRender *renderIns)

{

    CHECK_NULL_PTR_RETURN_DEFAULT(renderIns);

    snd_pcm_drain(renderIns->soundCard.pcmHandle);

    return HDF_SUCCESS;

}



static int32_t RenderGetGainThresholdImpl(struct AlsaRender *renderIns, float *gainMin, float *gainMax)

{

    AUDIO_FUNC_LOGI("emulator not support gain operation");

    return HDF_SUCCESS;

}



static int32_t RenderGetGainImpl(struct AlsaRender *renderIns, float *volume)

{

    AUDIO_FUNC_LOGI("emulator not support gain operation");

    return HDF_SUCCESS;

}



static int32_t RenderSetGainImpl(struct AlsaRender *renderIns, float volume)

{

    AUDIO_FUNC_LOGI("emulator not support gain operation");

    return HDF_SUCCESS;

}



static int32_t RenderGetChannelModeImpl(struct AlsaRender *renderIns, enum AudioChannelMode *mode)

{

    return HDF_SUCCESS;

}



static int32_t RenderSetChannelModeImpl(struct AlsaRender *renderIns, enum AudioChannelMode mode)

{

    return HDF_SUCCESS;

}



static int32_t RenderSetPauseStateImpl(struct AlsaRender *renderIns, bool pauseFlag)

{

    (void)pauseFlag;

    if (renderIns == NULL) {

        AUDIO_FUNC_LOGE("Parameter error!");

        return HDF_FAILURE;

    }

    return HDF_SUCCESS;

}



int32_t RenderOverrideFunc(struct AlsaRender *renderIns)

{

    CHECK_NULL_PTR_RETURN_DEFAULT(renderIns);

    struct AlsaSoundCard *cardIns = (struct AlsaSoundCard *)renderIns;



    if (cardIns->cardType == SND_CARD_PRIMARY) {

        renderIns->Init = RenderInitImpl;

        renderIns->SelectScene = RenderSelectSceneImpl;

        renderIns->Start = RenderStartImpl;

        renderIns->Stop = RenderStopImpl;

        renderIns->GetVolThreshold = RenderGetVolThresholdImpl;

        renderIns->GetVolume = RenderGetVolumeImpl;

        renderIns->SetVolume = RenderSetVolumeImpl;

        renderIns->GetGainThreshold = RenderGetGainThresholdImpl;

        renderIns->GetGain = RenderGetGainImpl;

        renderIns->SetGain = RenderSetGainImpl;

        renderIns->GetMute = RenderGetMuteImpl;

        renderIns->SetMute = RenderSetMuteImpl;

        renderIns->GetChannelMode = RenderGetChannelModeImpl;

        renderIns->SetChannelMode = RenderSetChannelModeImpl;

        renderIns->SetPauseState = RenderSetPauseStateImpl;

    }



    return HDF_SUCCESS;

}