From 5470b973a020881f5075b98f2ffd9152e7625b03 Mon Sep 17 00:00:00 2001 From: kw Date: Mon, 8 Sep 2025 15:25:33 +0800 Subject: [PATCH] fix Signed-off-by: kw --- ...api_audio_renderer_write_data_callback.cpp | 59 ++++++++----------- .../napi_audio_renderer_write_data_callback.h | 10 ++-- .../audiorenderer/napi_audio_renderer.cpp | 11 +++- .../napi/audiorenderer/napi_audio_renderer.h | 4 +- .../native/audioutils/include/audio_utils.h | 3 + .../native/audioutils/src/audio_utils.cpp | 11 ++++ .../unittest/audio_utils_second_unit_test.cpp | 15 +++++ .../client/src/audio_process_in_client.cpp | 9 +-- .../client/src/renderer_in_client_public.cpp | 5 -- 9 files changed, 74 insertions(+), 53 deletions(-) diff --git a/frameworks/js/napi/audiorenderer/callback/napi_audio_renderer_write_data_callback.cpp b/frameworks/js/napi/audiorenderer/callback/napi_audio_renderer_write_data_callback.cpp index 0b67671f30..22bf2fab1e 100644 --- a/frameworks/js/napi/audiorenderer/callback/napi_audio_renderer_write_data_callback.cpp +++ b/frameworks/js/napi/audiorenderer/callback/napi_audio_renderer_write_data_callback.cpp @@ -28,8 +28,10 @@ static const int32_t WRITE_CALLBACK_TIMEOUT_IN_MS = 1000; // 1s #if defined(ANDROID_PLATFORM) || defined(IOS_PLATFORM) vector NapiRendererWriteDataCallback::activeRenderers_; #endif -NapiRendererWriteDataCallback::NapiRendererWriteDataCallback(napi_env env, NapiAudioRenderer *napiRenderer) - : env_(env), napiRenderer_(napiRenderer) +NapiRendererWriteDataCallback::NapiRendererWriteDataCallback(napi_env env, NapiAudioRenderer *napiRenderer, + size_t bufferSize) + : env_(env), napiRenderer_(napiRenderer), bufferSize_(bufferSize), + callbackBuffer_(std::make_unique(bufferSize)) { AUDIO_DEBUG_LOG("instance create"); #if defined(ANDROID_PLATFORM) || defined(IOS_PLATFORM) @@ -113,7 +115,7 @@ void NapiRendererWriteDataCallback::OnWriteData(size_t length) std::lock_guard lock(mutex_); CHECK_AND_RETURN_LOG(rendererWriteDataCallback_ != nullptr, "Cannot find the reference of writeData callback"); - std::unique_ptr cb = std::make_unique(); + sptr cb = sptr::MakeSptr(); cb->callback = rendererWriteDataCallback_; cb->callbackName = WRITE_DATA_CALLBACK_NAME; cb->bufDesc.buffer = nullptr; @@ -124,37 +126,28 @@ void NapiRendererWriteDataCallback::OnWriteData(size_t length) AUDIO_INFO_LOG("OnWriteData audioRenderer_ is null."); return; } - napiRenderer_->audioRenderer_->GetBufferDesc(cb->bufDesc); - if (cb->bufDesc.buffer == nullptr) { - return; - } - if (length > cb->bufDesc.bufLength) { - cb->bufDesc.dataLength = cb->bufDesc.bufLength; - } else { - cb->bufDesc.dataLength = length; - } + CHECK_AND_RETURN_LOG(bufferSize_ >= length, "buffersize: %{public}zu, lenth: %{public}zu", bufferSize_, length); + + cb->bufDesc.buffer = callbackBuffer_.get(); + cb->bufDesc.bufLength = length; + cb->bufDesc.dataLength = length; return OnJsRendererWriteDataCallback(cb); } -void NapiRendererWriteDataCallback::OnJsRendererWriteDataCallback(std::unique_ptr &jsCb) +void NapiRendererWriteDataCallback::OnJsRendererWriteDataCallback(sptr &jsCb) { - if (jsCb.get() == nullptr) { - AUDIO_ERR_LOG("OnJsRendererWriteDataCallback: jsCb.get() is null"); - return; - } - - RendererWriteDataJsCallback *event = jsCb.release(); + RendererWriteDataJsCallback *event = jsCb.GetRefPtr(); CHECK_AND_RETURN_LOG((event != nullptr) && (event->callback != nullptr), "event is nullptr."); auto obj = static_cast(napiRenderer_); NapiAudioRenderer *napiRenderer = ObjectRefMap::IncreaseRef(obj); if (napiRenderer == nullptr) { AUDIO_ERR_LOG("napiRenderer is null"); - delete event; return; } - + + event->IncStrongRef(nullptr); napi_acquire_threadsafe_function(arWriteDataTsfn_); napi_call_threadsafe_function(arWriteDataTsfn_, event, napi_tsfn_blocking); @@ -163,14 +156,15 @@ void NapiRendererWriteDataCallback::OnJsRendererWriteDataCallback(std::unique_pt } std::unique_lock writeCallbackLock(napiRenderer_->writeCallbackMutex_); bool ret = napiRenderer_->writeCallbackCv_.wait_for(writeCallbackLock, - std::chrono::milliseconds(WRITE_CALLBACK_TIMEOUT_IN_MS), [this] () { - return napiRenderer_->enqueued_; + std::chrono::milliseconds(WRITE_CALLBACK_TIMEOUT_IN_MS), [event] () { + return event->enqueued; }); - if (!ret) { - AUDIO_ERR_LOG("Client OnWriteData operation timed out"); - } - napiRenderer_->enqueued_ = false; + CHECK_AND_RETURN_LOG(ret, "Client OnWriteData operation timed out"); writeCallbackLock.unlock(); + +#if !defined(ANDROID_PLATFORM) && !defined(IOS_PLATFORM) + napiRenderer_->audioRenderer_->Enqueue(event->bufDesc); +#endif } void NapiRendererWriteDataCallback::CheckWriteDataCallbackResult(napi_env env, BufferDesc &bufDesc, napi_value result) @@ -193,15 +187,12 @@ void NapiRendererWriteDataCallback::SafeJsCallbackWriteDataWork( { RendererWriteDataJsCallback *event = reinterpret_cast(data); CHECK_AND_RETURN_LOG((event != nullptr) && (event->callback != nullptr), "event is nullptr."); - std::shared_ptr safeContext( - static_cast(data), - [](RendererWriteDataJsCallback *ptr) { - delete ptr; - }); + sptr safeContext(event); + event->DecStrongRef(nullptr); WorkCallbackRendererWriteDataInner(event); CHECK_AND_RETURN_LOG(event->rendererNapiObj != nullptr, "NapiAudioRenderer object is nullptr"); std::unique_lock writeCallbackLock(event->rendererNapiObj->writeCallbackMutex_); - event->rendererNapiObj->enqueued_ = true; + event->enqueued = true; event->rendererNapiObj->writeCallbackCv_.notify_all(); writeCallbackLock.unlock(); auto napiObj = static_cast(event->rendererNapiObj); @@ -250,8 +241,6 @@ void NapiRendererWriteDataCallback::WorkCallbackRendererWriteDataInner(RendererW } else { AUDIO_INFO_LOG("NapiRendererWriteDataCallback is finalize."); } -#else - event->rendererNapiObj->audioRenderer_->Enqueue(event->bufDesc); #endif } while (0); napi_close_handle_scope(env, scope); diff --git a/frameworks/js/napi/audiorenderer/callback/napi_audio_renderer_write_data_callback.h b/frameworks/js/napi/audiorenderer/callback/napi_audio_renderer_write_data_callback.h index 11d49314cf..c53bf904ef 100644 --- a/frameworks/js/napi/audiorenderer/callback/napi_audio_renderer_write_data_callback.h +++ b/frameworks/js/napi/audiorenderer/callback/napi_audio_renderer_write_data_callback.h @@ -25,7 +25,7 @@ namespace OHOS { namespace AudioStandard { class NapiRendererWriteDataCallback : public AudioRendererWriteCallback { public: - NapiRendererWriteDataCallback(napi_env env, NapiAudioRenderer *napiRenderer); + NapiRendererWriteDataCallback(napi_env env, NapiAudioRenderer *napiRenderer, size_t bufferSize); virtual ~NapiRendererWriteDataCallback(); void OnWriteData(size_t length) override; @@ -35,17 +35,18 @@ public: bool GetWriteDTsfnFlag(); private: - struct RendererWriteDataJsCallback { + struct RendererWriteDataJsCallback : public RefBase { std::shared_ptr callback = nullptr; std::string callbackName = "unknown"; BufferDesc bufDesc {}; NapiAudioRenderer *rendererNapiObj; + bool enqueued = false; }; static void WorkCallbackRendererWriteDataInner(RendererWriteDataJsCallback *event); static void SafeJsCallbackWriteDataWork(napi_env env, napi_value js_cb, void *context, void *data); static void WriteDataTsfnFinalize(napi_env env, void *data, void *hint); - void OnJsRendererWriteDataCallback(std::unique_ptr &jsCb); + void OnJsRendererWriteDataCallback(sptr &jsCb); static void CheckWriteDataCallbackResult(napi_env env, BufferDesc &bufDesc, napi_value result); std::mutex mutex_; @@ -54,7 +55,8 @@ private: NapiAudioRenderer *napiRenderer_; bool regArWriteDataTsfn_ = false; napi_threadsafe_function arWriteDataTsfn_ = nullptr; - + const size_t bufferSize_ = 0; + const std::unique_ptr callbackBuffer_ = nullptr; #if defined(ANDROID_PLATFORM) || defined(IOS_PLATFORM) static vector activeRenderers_; #endif diff --git a/frameworks/js/napi/audiorenderer/napi_audio_renderer.cpp b/frameworks/js/napi/audiorenderer/napi_audio_renderer.cpp index 6f69353376..00bff08465 100644 --- a/frameworks/js/napi/audiorenderer/napi_audio_renderer.cpp +++ b/frameworks/js/napi/audiorenderer/napi_audio_renderer.cpp @@ -24,6 +24,7 @@ #include "xpower_event_js.h" #endif #endif +#include "audio_utils.h" #include "napi_param_utils.h" #include "napi_audio_error.h" #include "napi_audio_enum.h" @@ -233,6 +234,7 @@ unique_ptr NapiAudioRenderer::CreateAudioRendererNativeObject rendererOptions.rendererInfo.isOffloadAllowed = false; } rendererOptions.rendererInfo.playerType = PLAYER_TYPE_ARKTS_AUDIO_RENDERER; + rendererNapi->rendererOptions_ = rendererOptions; #if !defined(ANDROID_PLATFORM) && !defined(IOS_PLATFORM) rendererNapi->audioRenderer_ = AudioRenderer::CreateRenderer(rendererOptions); #else @@ -2232,7 +2234,14 @@ void NapiAudioRenderer::RegisterRendererWriteDataCallback(napi_env env, napi_val AUDIO_WARNING_LOG("writeData already subscribed. The old writeData function will be overwritten."); } - napiRenderer->rendererWriteDataCallbackNapi_ = std::make_shared(env, napiRenderer); + CHECK_AND_RETURN_LOG(napiRenderer->rendererOptions_.has_value(), "rendererOptions_ has no value"); + const auto &streamInfo = napiRenderer->rendererOptions_->streamInfo; + uint32_t sampleRate = streamInfo.samplingRate; + uint32_t bytesPerSample = (streamInfo.channels * Util::GetSamplePerFrame(streamInfo.format)); + size_t bufferSize = Util::CalculatePcmSizeFromDurationCeiling( + std::chrono::microseconds(MAX_CBBUF_IN_USEC), sampleRate, bytesPerSample); + napiRenderer->rendererWriteDataCallbackNapi_ = std::make_shared( + env, napiRenderer, bufferSize); napiRenderer->audioRenderer_->SetRenderMode(RENDER_MODE_CALLBACK); CHECK_AND_RETURN_LOG(napiRenderer->rendererWriteDataCallbackNapi_ != nullptr, "writeDataCbNapi_ is nullpur"); int32_t ret = napiRenderer->audioRenderer_->SetRendererWriteCallback(napiRenderer->rendererWriteDataCallbackNapi_); diff --git a/frameworks/js/napi/audiorenderer/napi_audio_renderer.h b/frameworks/js/napi/audiorenderer/napi_audio_renderer.h index beed0e5ec7..6eb569a510 100644 --- a/frameworks/js/napi/audiorenderer/napi_audio_renderer.h +++ b/frameworks/js/napi/audiorenderer/napi_audio_renderer.h @@ -19,11 +19,13 @@ #include #include #include +#include #include "napi/native_api.h" #include "napi/native_node_api.h" #include "audio_stream_manager.h" #include "audio_renderer.h" +#include "audio_info.h" #include "napi_async_work.h" #include "napi_audio_renderer_device_change_callback.h" @@ -47,9 +49,9 @@ public: #else std::unique_ptr audioRenderer_; #endif + std::optional rendererOptions_ = std::nullopt; std::mutex writeCallbackMutex_; std::condition_variable writeCallbackCv_; - bool enqueued_ = false; std::list> audioRendererCallbacks_; private: diff --git a/frameworks/native/audioutils/include/audio_utils.h b/frameworks/native/audioutils/include/audio_utils.h index 21c3f0f12e..7868f5db8e 100644 --- a/frameworks/native/audioutils/include/audio_utils.h +++ b/frameworks/native/audioutils/include/audio_utils.h @@ -79,6 +79,9 @@ public: static uint32_t GetSamplePerFrame(const AudioSampleFormat &format); static bool IsBackgroundSourceType(const SourceType sourceType); + + static size_t CalculatePcmSizeFromDurationCeiling(std::chrono::nanoseconds duration, + uint32_t sampleRate, uint32_t bytesPerSample); }; class Trace { diff --git a/frameworks/native/audioutils/src/audio_utils.cpp b/frameworks/native/audioutils/src/audio_utils.cpp index eb00aac7a3..67a46f0562 100644 --- a/frameworks/native/audioutils/src/audio_utils.cpp +++ b/frameworks/native/audioutils/src/audio_utils.cpp @@ -45,6 +45,7 @@ #include "privacy_error.h" using OHOS::Security::AccessToken::AccessTokenKit; +using namespace std::chrono_literals; namespace OHOS { namespace AudioStandard { @@ -217,6 +218,16 @@ bool Util::IsRingerAudioScene(const AudioScene &audioScene) return audioScene == AUDIO_SCENE_RINGING || audioScene == AUDIO_SCENE_VOICE_RINGING; } +size_t Util::CalculatePcmSizeFromDurationCeiling(std::chrono::nanoseconds duration, + uint32_t sampleRate, uint32_t bytesPerSample) +{ + size_t sampleCount = duration * sampleRate / (1s); + if (((duration * sampleRate) % (1s)) > (0ns)) { + sampleCount++; + } + return sampleCount * bytesPerSample; +} + WatchTimeout::WatchTimeout(const std::string &funcName, int64_t timeoutNs) : funcName_(funcName), timeoutNs_(timeoutNs) { startTimeNs_ = ClockTime::GetCurNano(); diff --git a/frameworks/native/audioutils/test/unittest/audio_utils_second_unit_test.cpp b/frameworks/native/audioutils/test/unittest/audio_utils_second_unit_test.cpp index 4034d4f16b..89adcbc7ce 100644 --- a/frameworks/native/audioutils/test/unittest/audio_utils_second_unit_test.cpp +++ b/frameworks/native/audioutils/test/unittest/audio_utils_second_unit_test.cpp @@ -319,5 +319,20 @@ HWTEST(AudioUtilsUnitTest, XperfAdapterNeedNotifyXperf_004, TestSize.Level1) { EXPECT_EQ(XperfAdapter::GetInstance().NeedNotifyXperf(STREAM_USAGE_NOTIFICATION_RINGTONE), false); } + +/** + * @tc.name : Test CalculatePcmSizeFromDurationCeiling API + * @tc.type : FUNC + * @tc.number: CalculatePcmSizeFromDurationCeiling + * @tc.desc : Test CalculatePcmSizeFromDurationCeiling. + */ +HWTEST(AudioUtilsUnitTest, CalculatePcmSizeFromDurationCeiling, TestSize.Level1) +{ + EXPECT_EQ(Util::CalculatePcmSizeFromDurationCeiling(20ms, 48000, 4), 3840); + + EXPECT_EQ(Util::CalculatePcmSizeFromDurationCeiling(1ns, 48000, 4), 4); + + EXPECT_EQ(Util::CalculatePcmSizeFromDurationCeiling(20ms + 1ns, 48000, 4), 3844); +} } // namespace AudioStandard } // namespace OHOS \ No newline at end of file diff --git a/services/audio_service/client/src/audio_process_in_client.cpp b/services/audio_service/client/src/audio_process_in_client.cpp index 0e2d82fef7..b2729a36c7 100644 --- a/services/audio_service/client/src/audio_process_in_client.cpp +++ b/services/audio_service/client/src/audio_process_in_client.cpp @@ -1124,10 +1124,6 @@ int32_t AudioProcessInClientInner::Enqueue(const BufferDesc &bufDesc) bufDesc.dataLength <= bufDesc.bufLength, ERR_INVALID_PARAM, "bufDesc error, bufLen %{public}zu, dataLen %{public}zu, spanSize %{public}zu.", bufDesc.bufLength, bufDesc.dataLength, clientSpanSizeInByte_); - // check if this buffer is form us. - if (bufDesc.buffer != callbackBuffer_.get()) { - AUDIO_WARNING_LOG("the buffer is not created by client."); - } if (processConfig_.audioMode == AUDIO_MODE_RECORD) { if (memset_s(callbackBuffer_.get(), clientSpanSizeInByte_, 0, clientSpanSizeInByte_) != EOK) { @@ -1150,9 +1146,8 @@ int32_t AudioProcessInClientInner::Enqueue(const BufferDesc &bufDesc) int32_t ret = WriteDataChunk(bufDesc, clientRemainSizeInFrame); CHECK_AND_RETURN_RET_LOG(ret == SUCCESS, ret, "writedataChunk failed, err: %{public}d", ret); - if (memset_s(callbackBuffer_.get(), clientSpanSizeInByte_, 0, clientSpanSizeInByte_) != EOK) { - AUDIO_WARNING_LOG("reset callback buffer fail."); - } + JUDGE_AND_WARNING_LOG(memset_s(bufDesc.buffer, bufDesc.bufLength, 0, bufDesc.bufLength) != EOK, + "reset callback buffer fail."); return SUCCESS; } diff --git a/services/audio_service/client/src/renderer_in_client_public.cpp b/services/audio_service/client/src/renderer_in_client_public.cpp index 1ff02bee64..0088a75ef9 100644 --- a/services/audio_service/client/src/renderer_in_client_public.cpp +++ b/services/audio_service/client/src/renderer_in_client_public.cpp @@ -837,11 +837,6 @@ int32_t RendererInClientInner::Enqueue(const BufferDesc &bufDesc) CHECK_AND_RETURN_RET_LOG(curStreamParams_.encoding != ENCODING_AUDIOVIVID || converter_ != nullptr && converter_->CheckInputValid(bufDesc), ERR_INVALID_PARAM, "Invalid buffer desc"); - // allow opensles enqueue self buffer - if ((rendererInfo_.playerType != PLAYER_TYPE_OPENSL_ES) && !CheckBufferValid(bufDesc)) { - AUDIO_WARNING_LOG("Invalid bufLength:%{public}zu or dataLength:%{public}zu, should be %{public}zu", - bufDesc.bufLength, bufDesc.dataLength, cbBufferSize_); - } BufferDesc temp = bufDesc; -- Gitee