* Copyright (c) 2025 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 "AudioRender.h"
#include "SampleLog.h"
#include "CodecCallback.h"
#include "dfx/error/SampleError.h"
static int32_t OnRenderStreamEvent([[maybe_unused]]OH_AudioRenderer *renderer, [[maybe_unused]]void *userData,
[[maybe_unused]]OH_AudioStream_Event event)
{
return 0;
}
static int32_t OnRenderInterruptEvent(OH_AudioRenderer *renderer, [[maybe_unused]]void *userData,
OH_AudioInterrupt_ForceType type, OH_AudioInterrupt_Hint hint)
{
if ((type == AUDIOSTREAM_INTERRUPT_SHARE) && (hint == AUDIOSTREAM_INTERRUPT_HINT_RESUME)) {
OH_AudioRenderer_Start(renderer);
}
return 0;
}
static int32_t OnRenderError([[maybe_unused]]OH_AudioRenderer *renderer, [[maybe_unused]]void *userData,
[[maybe_unused]]OH_AudioStream_Result error)
{
SAMPLE_LOGE("OnRenderError");
return 0;
}
OH_AudioData_Callback_Result AudioRendererOnWriteData(
OH_AudioRenderer* renderer,
void* userData,
void* audioData,
int32_t audioDataSize)
{
CodecUserData *codecUserData = static_cast<CodecUserData *>(userData);
uint8_t *dest = (uint8_t *)audioData;
size_t index = 0;
std::unique_lock<std::mutex> lock(codecUserData->outputMutex);
while (!codecUserData->renderQueue.empty() && index < audioDataSize) {
dest[index++] = codecUserData->renderQueue.front();
codecUserData->renderQueue.pop();
}
SAMPLE_LOGD("render BufferLength:%{public}d Out buffer count: %{public}u, renderQueue.size: %{public}u "
"renderReadSize: %{public}u",
audioDataSize, codecUserData->outputFrameCount, (unsigned int)codecUserData->renderQueue.size(),
(unsigned int)index);
if (codecUserData->renderQueue.size() < audioDataSize) {
codecUserData->renderCond.notify_all();
}
return AUDIO_DATA_CALLBACK_RESULT_VALID;
}
AudioRender::~AudioRender()
{
}
int32_t AudioRender::CreateAudioRender(CodecUserData* userData, const AudioInfo &audioInfo)
{
OH_AudioStreamBuilder_Create(&builder_, AUDIOSTREAM_TYPE_RENDERER);
OH_AudioStreamBuilder_SetLatencyMode(builder_, AUDIOSTREAM_LATENCY_MODE_NORMAL);
OH_AudioStreamBuilder_SetSamplingRate(builder_, audioInfo.audioSampleRate);
OH_AudioStreamBuilder_SetChannelCount(builder_, audioInfo.audioChannelCount);
OH_AudioStreamBuilder_SetSampleFormat(builder_, AUDIOSTREAM_SAMPLE_S16LE);
OH_AudioStreamBuilder_SetEncodingType(builder_, AUDIOSTREAM_ENCODING_TYPE_RAW);
OH_AudioStreamBuilder_SetRendererInfo(builder_, AUDIOSTREAM_USAGE_MOVIE);
SAMPLE_LOGI("Init audioSampleRate: %{public}d, ChannelCount: %{public}d", audioInfo.audioSampleRate,
audioInfo.audioChannelCount);
OH_AudioRenderer_Callbacks callbacks;
callbacks.OH_AudioRenderer_OnWriteData = nullptr;
callbacks.OH_AudioRenderer_OnStreamEvent = OnRenderStreamEvent;
callbacks.OH_AudioRenderer_OnInterruptEvent = OnRenderInterruptEvent;
callbacks.OH_AudioRenderer_OnError = OnRenderError;
OH_AudioStreamBuilder_SetRendererCallback(builder_, callbacks, userData);
OH_AudioRenderer_OnWriteDataCallback writeDataCb = AudioRendererOnWriteData;
OH_AudioStreamBuilder_SetRendererWriteDataCallback(builder_, writeDataCb, userData);
OH_AudioStreamBuilder_GenerateRenderer(builder_, &audioRenderer_);
return SAMPLE_ERR_OK;
}
int32_t AudioRender::StartAudioRender()
{
if (audioRenderer_) {
OH_AudioRenderer_Start(audioRenderer_);
}
return SAMPLE_ERR_OK;
}
int32_t AudioRender::StopAudioRender()
{
if (audioRenderer_) {
OH_AudioRenderer_Stop(audioRenderer_);
}
return SAMPLE_ERR_OK;
}
int32_t AudioRender::ReleaseAudioRender()
{
OH_AudioStreamBuilder_Destroy(builder_);
if (audioRenderer_) {
OH_AudioRenderer_Release(audioRenderer_);
audioRenderer_ = nullptr;
}
builder_ = nullptr;
audioRenderer_ = nullptr;
return SAMPLE_ERR_OK;
}