* Copyright (c) 2026 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 "AudioRenderWrapper.h"
#include "AudioVividPlaybackManager.h"
#include <cstring>
AudioRenderWrapper::~AudioRenderWrapper()
{
Release();
}
int32_t AudioRenderWrapper::Create(int32_t sampleRate, int32_t channelCount, int64_t channelLayout)
{
sampleRate_ = sampleRate;
channelCount_ = channelCount;
channelLayout_ = channelLayout;
int32_t ret = OH_AudioStreamBuilder_Create(&builder_, AUDIOSTREAM_TYPE_RENDERER);
if (ret != 0 || builder_ == nullptr) {
AVCODEC_SAMPLE_LOGE("Create AudioStreamBuilder failed");
return -1;
}
OH_AudioStreamBuilder_SetLatencyMode(builder_, AUDIOSTREAM_LATENCY_MODE_NORMAL);
OH_AudioStreamBuilder_SetSamplingRate(builder_, sampleRate_);
OH_AudioStreamBuilder_SetChannelCount(builder_, channelCount_);
OH_AudioStreamBuilder_SetSampleFormat(builder_, AUDIOSTREAM_SAMPLE_S24LE);
OH_AudioStreamBuilder_SetRendererInfo(builder_, AUDIOSTREAM_USAGE_MUSIC);
OH_AudioStreamBuilder_SetChannelLayout(builder_, static_cast<OH_AudioChannelLayout>(channelLayout_));
OH_AudioStreamBuilder_SetEncodingType(builder_, AUDIOSTREAM_ENCODING_TYPE_AUDIOVIVID);
ret = SetupCallbacks();
if (ret != 0) {
AVCODEC_SAMPLE_LOGE("SetupCallbacks failed");
return ret;
}
ret = OH_AudioStreamBuilder_GenerateRenderer(builder_, &renderer_);
if (ret != 0 || renderer_ == nullptr) {
AVCODEC_SAMPLE_LOGE("GenerateRenderer failed");
return -1;
}
return 0;
}
int32_t AudioRenderWrapper::SetupCallbacks()
{
OH_AudioRenderer_Callbacks callbacks;
callbacks.OH_AudioRenderer_OnWriteData = nullptr;
callbacks.OH_AudioRenderer_OnStreamEvent = OnRenderStreamEventCallback;
callbacks.OH_AudioRenderer_OnInterruptEvent = OnRenderInterruptEventCallback;
callbacks.OH_AudioRenderer_OnError = OnRenderErrorCallback;
int32_t ret = OH_AudioStreamBuilder_SetRendererCallback(builder_, callbacks, this);
if (ret != 0) {
AVCODEC_SAMPLE_LOGE("SetRendererCallback failed");
return -1;
}
OH_AudioRenderer_WriteDataWithMetadataCallback metadataCallback = OnWriteDataWithMetadataCallback;
ret = OH_AudioStreamBuilder_SetWriteDataWithMetadataCallback(builder_, metadataCallback, this);
if (ret != 0) {
AVCODEC_SAMPLE_LOGE("SetWriteDataWithMetadataCallback failed");
return -1;
}
return 0;
}
int32_t AudioRenderWrapper::Start()
{
if (renderer_ == nullptr) {
AVCODEC_SAMPLE_LOGE("Renderer is null");
return -1;
}
int32_t ret = OH_AudioRenderer_Start(renderer_);
if (ret != 0) {
AVCODEC_SAMPLE_LOGE("Start renderer failed, ret: %{public}d", ret);
return -1;
}
context_.isStarted.store(true);
context_.eos = false;
AVCODEC_SAMPLE_LOGI("AudioRenderWrapper started");
return 0;
}
int32_t AudioRenderWrapper::Stop()
{
if (renderer_ == nullptr) {
return -1;
}
context_.eos = true;
context_.isStarted.store(false);
int32_t ret = OH_AudioRenderer_Stop(renderer_);
if (ret != 0) {
AVCODEC_SAMPLE_LOGE("Stop renderer failed, ret: %{public}d", ret);
return -1;
}
AVCODEC_SAMPLE_LOGI("AudioRenderWrapper stopped");
return 0;
}
int32_t AudioRenderWrapper::Release()
{
if (renderer_ != nullptr) {
OH_AudioRenderer_Release(renderer_);
renderer_ = nullptr;
}
if (builder_ != nullptr) {
OH_AudioStreamBuilder_Destroy(builder_);
builder_ = nullptr;
}
context_.eos = false;
context_.errorCode = 0;
context_.isStarted.store(false);
return 0;
}
void AudioRenderWrapper::SetPlaybackManager(AudioVividPlaybackManager *playbackManager)
{
playbackManager_ = playbackManager;
}
int32_t AudioRenderWrapper::OnWriteDataWithMetadataCallback(OH_AudioRenderer *renderer, void *userData, void *audioData,
int32_t audioDataSize, void *metadata, int32_t metadataSize)
{
(void)renderer;
AudioRenderWrapper *wrapper = static_cast<AudioRenderWrapper *>(userData);
if (wrapper->playbackManager_ == nullptr) {
AVCODEC_SAMPLE_LOGE("PlaybackManager not set, cannot pull data");
memset(audioData, 0, audioDataSize);
if (metadata && metadataSize > 0) {
memset(metadata, 0, metadataSize);
}
return 0;
}
uint8_t *pcmData = nullptr;
int32_t pcmSize = 0;
uint8_t *metadataData = nullptr;
int32_t metadataSizeOut = 0;
int32_t ret =
wrapper->playbackManager_->GetDecodedDataToRender(&pcmData, &pcmSize, &metadataData, &metadataSizeOut);
if (ret == 0 && pcmData != nullptr) {
memcpy(audioData, pcmData, pcmSize);
if (pcmSize < audioDataSize) {
memset((uint8_t *)audioData + pcmSize, 0, audioDataSize - pcmSize);
}
if (metadata && metadataSize > 0 && metadataData != nullptr) {
memcpy(metadata, metadataData, metadataSizeOut);
if (metadataSizeOut < metadataSize) {
memset((uint8_t *)metadata + metadataSizeOut, 0, metadataSize - metadataSizeOut);
}
}
if (pcmData) {
delete[] pcmData;
pcmData = nullptr;
}
if (metadataData) {
delete[] metadataData;
metadataData = nullptr;
}
} else {
memset(audioData, 0, audioDataSize);
if (metadata && metadataSize > 0) {
memset(metadata, 0, metadataSize);
}
}
return 0;
}
int32_t AudioRenderWrapper::OnRenderStreamEventCallback(
OH_AudioRenderer *renderer, void *userData, OH_AudioStream_Event event)
{
(void)renderer;
(void)userData;
(void)event;
return 0;
}
int32_t AudioRenderWrapper::OnRenderInterruptEventCallback(
OH_AudioRenderer *renderer, void *userData, OH_AudioInterrupt_ForceType type, OH_AudioInterrupt_Hint hint)
{
(void)renderer;
(void)userData;
(void)type;
(void)hint;
return 0;
}
int32_t AudioRenderWrapper::OnRenderErrorCallback(
OH_AudioRenderer *renderer, void *userData, OH_AudioStream_Result error)
{
(void)renderer;
(void)userData;
(void)error;
return 0;
}