/*
 * 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 "audio_log.h"
#include "audio_renderer_private.h"

namespace OHOS {
namespace AudioStandard {
std::mutex AudioRenderer::createRendererMutex_;

AudioRenderer::~AudioRenderer() = default;
AudioRendererPrivate::~AudioRendererPrivate()
{
    rendererImpl_ = nullptr;
}

int32_t AudioRenderer::CheckMaxRendererInstances()
{
    return SUCCESS;
}

std::unique_ptr<AudioRenderer> AudioRenderer::Create(AudioStreamType audioStreamType)
{
    AppInfo appInfo = {};
    return Create(audioStreamType, appInfo);
}

std::unique_ptr<AudioRenderer> AudioRenderer::Create(AudioStreamType audioStreamType, const AppInfo& appInfo)
{
    return nullptr;
}

std::unique_ptr<AudioRenderer> AudioRenderer::Create(const AudioRendererOptions& rendererOptions)
{
    AppInfo appInfo = {};
    return Create("", rendererOptions, appInfo);
}

std::unique_ptr<AudioRenderer> AudioRenderer::Create(
    const AudioRendererOptions& rendererOptions, const AppInfo& appInfo)
{
    return Create("", rendererOptions, appInfo);
}

std::unique_ptr<AudioRenderer> AudioRenderer::Create(
    const std::string cachePath, const AudioRendererOptions& rendererOptions)
{
    AppInfo appInfo = {};
    return Create(cachePath, rendererOptions, appInfo);
}

std::unique_ptr<AudioRenderer> AudioRenderer::Create(
    const std::string cachePath, const AudioRendererOptions& rendererOptions, const AppInfo& appInfo)
{
    std::lock_guard<std::mutex> lock(createRendererMutex_);

    auto audioRenderer = std::make_unique<AudioRendererPrivate>();
    if (audioRenderer->CheckParams(rendererOptions) != SUCCESS) {
        AUDIO_ERR_LOG("CheckParams failed in renderer");
        audioRenderer = nullptr;
    } else {
        int32_t ret = audioRenderer->CreateAudioTrack(rendererOptions);
        if (ret != SUCCESS) {
            audioRenderer = nullptr;
        }
    }
    return audioRenderer;
}

int32_t AudioRendererPrivate::CreateAudioTrack(const AudioRendererOptions& rendererOptions)
{
    rendererImpl_ = std::make_shared<AudioRendererImpl>();
    return rendererImpl_->CreateAudioTrack(rendererOptions);
}

int32_t AudioRendererPrivate::CheckParams(const AudioRendererOptions& rendererOptions)
{
    ContentType contentType = rendererOptions.rendererInfo.contentType;
    CHECK_AND_RETURN_RET_LOG(contentType >= CONTENT_TYPE_UNKNOWN && contentType <= CONTENT_TYPE_ULTRASONIC,
        ERR_NOT_SUPPORTED, "Invalid content type");

    StreamUsage streamUsage = rendererOptions.rendererInfo.streamUsage;
    CHECK_AND_RETURN_RET_LOG(
        streamUsage >= STREAM_USAGE_UNKNOWN && streamUsage <= STREAM_USAGE_VOICE_MODEM_COMMUNICATION, ERR_NOT_SUPPORTED,
        "Invalid stream usage");

    if (!IsFormatValid(rendererOptions.streamInfo.format) ||
        !IsSamplingRateValid(rendererOptions.streamInfo.samplingRate) ||
        !IsEncodingTypeValid(rendererOptions.streamInfo.encoding)) {
        AUDIO_ERR_LOG("Unsupported audio parameter");
        return ERR_NOT_SUPPORTED;
    }
    if (!IsPlaybackChannelRelatedInfoValid(
            rendererOptions.streamInfo.channels, rendererOptions.streamInfo.channelLayout)) {
        AUDIO_ERR_LOG("Unsupported channels or channelLayout");
        return ERR_NOT_SUPPORTED;
    }
    return SUCCESS;
}

int32_t AudioRendererPrivate::GetRendererInfo(AudioRendererInfo& rendererInfo) const
{
    CHECK_AND_RETURN_RET_LOG(rendererImpl_ != nullptr, ERROR, "rendererImpl_ == nullptr.");

    return rendererImpl_->GetRendererInfo(rendererInfo);
}

int32_t AudioRendererPrivate::GetStreamInfo(AudioStreamInfo& streamInfo) const
{
    CHECK_AND_RETURN_RET_LOG(rendererImpl_ != nullptr, ERROR, "rendererImpl_ == nullptr.");

    return rendererImpl_->GetStreamInfo(streamInfo);
}

bool AudioRendererPrivate::Start(StateChangeCmdType cmdType)
{
    CHECK_AND_RETURN_RET_LOG(rendererImpl_ != nullptr, false, "rendererImpl_ == nullptr.");

    return rendererImpl_->Start();
}

int32_t AudioRendererPrivate::Write(uint8_t* buffer, size_t bufferSize)
{
    CHECK_AND_RETURN_RET_LOG(rendererImpl_ != nullptr, 0, "rendererImpl_ == nullptr.");

    return rendererImpl_->Write(buffer, bufferSize);
}

int32_t AudioRendererPrivate::SetRenderMode(AudioRenderMode renderMode)
{
    CHECK_AND_RETURN_RET_LOG(rendererImpl_ != nullptr, ERROR, "rendererImpl_ == nullptr.");
    return rendererImpl_->SetRenderMode(renderMode);
}

int32_t AudioRendererPrivate::SetRendererWriteCallback(const std::shared_ptr<AudioRendererWriteCallback>& callback)
{
    CHECK_AND_RETURN_RET_LOG(callback != nullptr, ERR_INVALID_PARAM, "input param is invalid.");
    CHECK_AND_RETURN_RET_LOG(rendererImpl_ != nullptr, ERROR, "rendererImpl_ == nullptr.");

    return rendererImpl_->SetRendererWriteCallback(callback);
}

RendererState AudioRendererPrivate::GetStatus() const
{
    CHECK_AND_RETURN_RET_LOG(rendererImpl_ != nullptr, RENDERER_INVALID, "rendererImpl_ == nullptr.");

    return rendererImpl_->GetStatus();
}

bool AudioRendererPrivate::GetAudioTime(Timestamp& timestamp, Timestamp::Timestampbase base) const
{
    CHECK_AND_RETURN_RET_LOG(rendererImpl_ != nullptr, false, "rendererImpl_ == nullptr.");

    return rendererImpl_->GetAudioTime(timestamp, base);
}

bool AudioRendererPrivate::Flush() const
{
    CHECK_AND_RETURN_RET_LOG(rendererImpl_ != nullptr, false, "rendererImpl_ == nullptr.");

    return rendererImpl_->Flush();
}

bool AudioRendererPrivate::Pause(StateChangeCmdType cmdType)
{
    CHECK_AND_RETURN_RET_LOG(rendererImpl_ != nullptr, false, "rendererImpl_ == nullptr.");

    return rendererImpl_->Pause();
}

bool AudioRendererPrivate::Stop()
{
    CHECK_AND_RETURN_RET_LOG(rendererImpl_ != nullptr, false, "rendererImpl_ == nullptr.");

    return rendererImpl_->Stop();
}

bool AudioRendererPrivate::Release()
{
    CHECK_AND_RETURN_RET_LOG(rendererImpl_ != nullptr, false, "rendererImpl_ == nullptr.");

    return rendererImpl_->Release();
}

int32_t AudioRendererPrivate::GetBufferSize(size_t& bufferSize) const
{
    CHECK_AND_RETURN_RET_LOG(rendererImpl_ != nullptr, ERROR, "rendererImpl_ == nullptr.");

    return rendererImpl_->GetBufferSize(bufferSize);
}

int32_t AudioRendererPrivate::GetAudioStreamId(uint32_t& sessionID) const
{
    CHECK_AND_RETURN_RET_LOG(rendererImpl_ != nullptr, ERROR, "rendererImpl_ == nullptr.");

    return rendererImpl_->GetAudioStreamId(sessionID);
}

int32_t AudioRendererPrivate::SetVolume(float volume) const
{
    CHECK_AND_RETURN_RET_LOG(rendererImpl_ != nullptr, ERROR, "rendererImpl_ == nullptr.");

    return rendererImpl_->SetVolume(volume);
}

int32_t AudioRendererPrivate::SetChannelBlendMode(ChannelBlendMode blendMode)
{
    CHECK_AND_RETURN_RET_LOG(rendererImpl_ != nullptr, ERR_ILLEGAL_STATE, "rendererImpl_ == nullptr.");

    return rendererImpl_->SetChannelBlendMode(blendMode);
}

int32_t AudioRendererPrivate::GetBufferDesc(BufferDesc& bufDesc)
{
    CHECK_AND_RETURN_RET_LOG(rendererImpl_ != nullptr, ERROR, "rendererImpl_ == nullptr.");

    return rendererImpl_->GetBufferDesc(bufDesc);
}

int32_t AudioRendererPrivate::Enqueue(const BufferDesc& bufDesc)
{
    CHECK_AND_RETURN_RET_LOG(rendererImpl_ != nullptr, ERROR, "rendererImpl_ == nullptr.");

    return rendererImpl_->Enqueue(bufDesc);
}

float AudioRendererPrivate::GetMinStreamVolume() const
{
    CHECK_AND_RETURN_RET_LOG(rendererImpl_ != nullptr, 0.0f, "rendererImpl_ == nullptr.");

    return rendererImpl_->GetMinStreamVolume();
}

float AudioRendererPrivate::GetMaxStreamVolume() const
{
    CHECK_AND_RETURN_RET_LOG(rendererImpl_ != nullptr, 0.0f, "rendererImpl_ == nullptr.");

    return rendererImpl_->GetMaxStreamVolume();
}

int32_t AudioRendererPrivate::GetCurrentOutputDevices(AudioDeviceDescriptor& deviceInfo) const
{
    CHECK_AND_RETURN_RET_LOG(rendererImpl_ != nullptr, ERROR, "rendererImpl_ == nullptr.");

    return rendererImpl_->GetCurrentOutputDevices(deviceInfo);
}

uint32_t AudioRendererPrivate::GetUnderflowCount() const
{
    CHECK_AND_RETURN_RET_LOG(rendererImpl_ != nullptr, 0, "rendererImpl_ == nullptr.");

    return rendererImpl_->GetUnderflowCount();
}

int32_t AudioRendererPrivate::SetSpeed(float speed)
{
    CHECK_AND_RETURN_RET_LOG(rendererImpl_ != nullptr, ERROR, "rendererImpl_ == nullptr.");
    CHECK_AND_RETURN_RET_LOG((speed >= MIN_STREAM_SPEED_LEVEL) && (speed <= MAX_STREAM_SPEED_LEVEL), ERR_INVALID_PARAM,
        "invaild speed index");

    return rendererImpl_->SetSpeed(speed);
}

float AudioRendererPrivate::GetSpeed()
{
    CHECK_AND_RETURN_RET_LOG(rendererImpl_ != nullptr, 0.0f, "rendererImpl_ == nullptr.");

    return rendererImpl_->GetSpeed();
}

int32_t AudioRendererPrivate::SetRendererCallback(const std::shared_ptr<AudioRendererCallback>& callback)
{
    CHECK_AND_RETURN_RET_LOG(callback != nullptr, ERR_INVALID_PARAM, "input param is invalid");
    CHECK_AND_RETURN_RET_LOG(rendererImpl_ != nullptr, ERROR, "rendererImpl_ == nullptr.");

    return rendererImpl_->SetRendererCallback(callback);
}

int32_t AudioRendererPrivate::SetRendererPositionCallback(
    int64_t markPosition, const std::shared_ptr<RendererPositionCallback>& callback)
{
    CHECK_AND_RETURN_RET_LOG((callback != nullptr) && (markPosition > 0), ERR_INVALID_PARAM, "input param is invalid");
    CHECK_AND_RETURN_RET_LOG(rendererImpl_ != nullptr, ERROR, "rendererImpl_ == nullptr.");

    return rendererImpl_->SetRendererPositionCallback(markPosition, callback);
}

void AudioRendererPrivate::UnsetRendererPositionCallback()
{
    CHECK_AND_RETURN_LOG(rendererImpl_ != nullptr, "rendererImpl_ == nullptr.");

    rendererImpl_->UnsetRendererPositionCallback();
}

int32_t AudioRendererPrivate::SetRendererPeriodPositionCallback(
    int64_t frameNumber, const std::shared_ptr<RendererPeriodPositionCallback>& callback)
{
    CHECK_AND_RETURN_RET_LOG((callback != nullptr) && (frameNumber > 0), ERR_INVALID_PARAM, "input param is invalid");
    CHECK_AND_RETURN_RET_LOG(rendererImpl_ != nullptr, ERROR, "rendererImpl_ == nullptr.");

    return rendererImpl_->SetRendererPeriodPositionCallback(frameNumber, callback);
}

void AudioRendererPrivate::UnsetRendererPeriodPositionCallback()
{
    CHECK_AND_RETURN_LOG(rendererImpl_ != nullptr, "rendererImpl_ == nullptr.");

    rendererImpl_->UnsetRendererPeriodPositionCallback();
}

int32_t AudioRendererPrivate::RegisterOutputDeviceChangeWithInfoCallback(
        const std::shared_ptr<AudioRendererOutputDeviceChangeCallback> &callback)
{
    CHECK_AND_RETURN_RET_LOG(callback != nullptr, ERR_INVALID_PARAM, "callback is null");
    CHECK_AND_RETURN_RET_LOG(rendererImpl_ != nullptr, ERROR, "rendererImpl_ == nullptr.");
    return rendererImpl_->RegisterRendererDeviceChangeListener(callback);
}
    
int32_t AudioRendererPrivate::UnregisterOutputDeviceChangeWithInfoCallback()
{
    CHECK_AND_RETURN_RET_LOG(rendererImpl_ != nullptr, ERROR, "rendererImpl_ == nullptr.");
    return rendererImpl_->UnregisterRendererDeviceChangeListener();
}

int32_t AudioRendererPrivate::UnregisterOutputDeviceChangeWithInfoCallback(
    const std::shared_ptr<AudioRendererOutputDeviceChangeCallback> &callback)
{
    CHECK_AND_RETURN_RET_LOG(rendererImpl_ != nullptr, ERROR, "rendererImpl_ == nullptr.");
    return rendererImpl_->UnregisterRendererDeviceChangeListener();
}

bool AudioRendererPrivate::IsFormatValid(uint8_t format)
{
    bool isValidFormat =
        (find(AUDIO_SUPPORTED_FORMATS.begin(), AUDIO_SUPPORTED_FORMATS.end(), format) != AUDIO_SUPPORTED_FORMATS.end());
    AUDIO_DEBUG_LOG("AudioRendererPrivate: IsFormatValid: %{public}s", isValidFormat ? "true" : "false");
    return isValidFormat;
}

bool AudioRendererPrivate::IsRendererChannelValid(uint8_t channel)
{
    bool isValidChannel = (find(RENDERER_SUPPORTED_CHANNELS.begin(), RENDERER_SUPPORTED_CHANNELS.end(), channel) !=
                           RENDERER_SUPPORTED_CHANNELS.end());
    AUDIO_DEBUG_LOG("AudioRendererPrivate: IsChannelValid: %{public}s", isValidChannel ? "true" : "false");
    return isValidChannel;
}

bool AudioRendererPrivate::IsEncodingTypeValid(uint8_t encodingType)
{
    bool isValidEncodingType = (find(AUDIO_SUPPORTED_ENCODING_TYPES.begin(), AUDIO_SUPPORTED_ENCODING_TYPES.end(),
                                    encodingType) != AUDIO_SUPPORTED_ENCODING_TYPES.end());
    AUDIO_DEBUG_LOG("AudioRendererPrivate: IsEncodingTypeValid: %{public}s", isValidEncodingType ? "true" : "false");
    return isValidEncodingType;
}

bool AudioRendererPrivate::IsSamplingRateValid(uint32_t samplingRate)
{
    bool isValidSamplingRate = (find(AUDIO_SUPPORTED_SAMPLING_RATES.begin(), AUDIO_SUPPORTED_SAMPLING_RATES.end(),
                                    samplingRate) != AUDIO_SUPPORTED_SAMPLING_RATES.end());
    AUDIO_DEBUG_LOG("AudioRendererPrivate: IsSamplingRateValid: %{public}s", isValidSamplingRate ? "true" : "false");
    return isValidSamplingRate;
}

bool AudioRendererPrivate::IsRendererChannelLayoutValid(uint64_t channelLayout)
{
    bool isValidRendererChannelLayout =
        (find(RENDERER_SUPPORTED_CHANNELLAYOUTS.begin(), RENDERER_SUPPORTED_CHANNELLAYOUTS.end(), channelLayout) !=
            RENDERER_SUPPORTED_CHANNELLAYOUTS.end());
    AUDIO_DEBUG_LOG("AudioRendererPrivate: isValidRendererChannelLayout: %{public}s",
        isValidRendererChannelLayout ? "true" : "false");
    return isValidRendererChannelLayout;
}

bool AudioRendererPrivate::IsPlaybackChannelRelatedInfoValid(uint8_t channels, uint64_t channelLayout)
{
    if (!IsRendererChannelValid(channels)) {
        AUDIO_ERR_LOG("AudioRendererPrivate: Invalid sink channel %{public}d", channels);
        return false;
    }
    if (!IsRendererChannelLayoutValid(channelLayout)) {
        AUDIO_ERR_LOG("AudioRendererPrivate: Invalid sink channel layout");
        return false;
    }
    return true;
}

int32_t AudioRendererPrivate::GetAudioTimestampInfo(Timestamp &timestamp, Timestamp::Timestampbase base) const
{
    return ERR_NOT_SUPPORTED;
}

int32_t AudioRendererPrivate::SetLoopTimes(int64_t bufferLoopTimes)
{
    return ERR_NOT_SUPPORTED;
}

void AudioRendererPrivate::SetFastStatusChangeCallback(
    const std::shared_ptr<AudioRendererFastStatusChangeCallback>& callback)
{
    (void)callback;
}

int32_t AudioRendererPrivate::GetLatencyWithFlag(uint64_t &latency, LatencyFlag flag) const
{
    return ERR_NOT_SUPPORTED;
}

int32_t AudioRendererPrivate::StartWithError(StateChangeCmdType cmdType)
{
    return Start(cmdType) ? SUCCESS : ERROR;
}

int32_t AudioRendererPrivate::StopWithError()
{
    return Stop() ? SUCCESS : ERROR;
}

int32_t AudioRendererPrivate::FlushWithError() const
{
    return Flush() ? SUCCESS : ERROR;
}

int32_t AudioRendererPrivate::ReleaseWithError()
{
    return Release() ? SUCCESS : ERROR;
}

int32_t AudioRendererPrivate::PauseWithError(StateChangeCmdType cmdType)
{
    return Pause(cmdType) ? SUCCESS : ERROR;
}

int32_t AudioRendererPrivate::DrainWithError() const
{
    return Drain() ? SUCCESS : ERROR;
}

int32_t AudioRendererPrivate::StartImpl(StateChangeCmdType cmdType)
{
    return ERR_NOT_SUPPORTED;
}

int32_t AudioRendererPrivate::StopImpl()
{
    return ERR_NOT_SUPPORTED;
}

int32_t AudioRendererPrivate::FlushImpl() const
{
    return ERR_NOT_SUPPORTED;
}

int32_t AudioRendererPrivate::ReleaseImpl()
{
    return ERR_NOT_SUPPORTED;
}

int32_t AudioRendererPrivate::PauseImpl(StateChangeCmdType cmdType)
{
    return ERR_NOT_SUPPORTED;
}

int32_t AudioRendererPrivate::DrainImpl() const
{
    return ERR_NOT_SUPPORTED;
}
} // namespace AudioStandard
} // namespace OHOS