From 4fdee254f80f6cfb3bc68a614d5413ee6e49b44f Mon Sep 17 00:00:00 2001 From: Vaidegi B Date: Thu, 30 Jun 2022 01:21:49 +0530 Subject: [PATCH] Fix Getlatency Signed-off-by: Vaidegi B --- bundle.json | 1 + .../include/audio_policy_manager.h | 2 + .../native/audiostream/include/audio_stream.h | 1 + .../pulseaudio/src/modules/hdi/BUILD.gn | 1 + .../pulseaudio/src/modules/hdi/hdi_sink.c | 52 +++++++-- .../src/modules/hdi/module_hdi_sink.c | 2 + .../include/audio_system_manager.h | 1 + .../inner_api/native/audiorenderer/BUILD.gn | 16 +++ .../audio_policy/client/audio_policy_base.h | 2 + .../client/audio_policy_manager_stub.h | 1 + .../audio_policy/client/audio_policy_proxy.h | 2 + .../audio_policy/common/audio_policy_types.h | 1 + .../audio_policy/server/audio_policy_server.h | 2 + .../server/service/audio_policy_service.h | 5 + .../server/service/common/audio_module_info.h | 2 + .../server/service/config/xml_parser.h | 1 + .../server/service/interface/iport_observer.h | 1 + .../client/audio_service_client.h | 4 + .../client/audio_policy_manager.cpp | 5 + .../client/audio_policy_proxy.cpp | 20 ++++ .../server/audio_policy_manager_stub.cpp | 10 ++ .../server/audio_policy_server.cpp | 5 + .../server/service/audio_policy_service.cpp | 11 ++ .../server/service/config/xml_parser.cpp | 15 +++ .../service/manager/audio_adapter_manager.cpp | 4 + .../client/audio_service_client.cpp | 107 ++++++++++++++---- .../src/audio_service/client/audio_stream.cpp | 10 +- .../client/audio_system_manager.cpp | 5 + services/test/audio_renderer_test.cpp | 38 +++++-- 29 files changed, 283 insertions(+), 44 deletions(-) diff --git a/bundle.json b/bundle.json index 33997fc2..5139f579 100644 --- a/bundle.json +++ b/bundle.json @@ -47,6 +47,7 @@ "//foundation/multimedia/audio_framework/interfaces/inner_api/native/audiocapturer:audio_capturer_test_packages", "//foundation/multimedia/audio_framework/interfaces/inner_api/native/audiomanager:audio_multichannel_test", "//foundation/multimedia/audio_framework/interfaces/inner_api/native/audiorenderer:audio_renderer_test", + "//foundation/multimedia/audio_framework/interfaces/inner_api/native/audiorenderer:audio_latency_accuracy_test", "//foundation/multimedia/audio_framework/interfaces/inner_api/native/audiorenderer:audio_render_mode_callback_test", "//foundation/multimedia/audio_framework/interfaces/inner_api/native/audiorenderer:audio_voip_test", "//foundation/multimedia/audio_framework/interfaces/inner_api/native/audiorenderer:audio_interrupt_test", diff --git a/frameworks/native/audiopolicy/include/audio_policy_manager.h b/frameworks/native/audiopolicy/include/audio_policy_manager.h index fc9a2e94..b58d25e9 100644 --- a/frameworks/native/audiopolicy/include/audio_policy_manager.h +++ b/frameworks/native/audiopolicy/include/audio_policy_manager.h @@ -120,6 +120,8 @@ public: int32_t GetAudioLatencyFromXml(); + uint32_t GetSinkLatencyFromXml(); + int32_t RegisterAudioRendererEventListener(const int32_t clientUID, const std::shared_ptr &callback); diff --git a/frameworks/native/audiostream/include/audio_stream.h b/frameworks/native/audiostream/include/audio_stream.h index 81c62749..4567c03a 100644 --- a/frameworks/native/audiostream/include/audio_stream.h +++ b/frameworks/native/audiostream/include/audio_stream.h @@ -105,6 +105,7 @@ private: static const std::map, AudioStreamType> streamTypeMap_; static std::map, AudioStreamType> CreateStreamMap(); bool isFirstRead_; + bool isFirstWrite_; }; } // namespace AudioStandard } // namespace OHOS diff --git a/frameworks/native/pulseaudio/src/modules/hdi/BUILD.gn b/frameworks/native/pulseaudio/src/modules/hdi/BUILD.gn index 685a8f3d..53bc24b8 100644 --- a/frameworks/native/pulseaudio/src/modules/hdi/BUILD.gn +++ b/frameworks/native/pulseaudio/src/modules/hdi/BUILD.gn @@ -51,6 +51,7 @@ ohos_shared_library("module-hdi-sink") { configs = [ ":hdi_config" ] cflags = [ "-DPA_MODULE_NAME=libmodule_hdi_sink_z_so" ] + cflags += [ "-DTEST_MODE" ] ldflags = [ "-Wl", diff --git a/frameworks/native/pulseaudio/src/modules/hdi/hdi_sink.c b/frameworks/native/pulseaudio/src/modules/hdi/hdi_sink.c index 7b4ec42d..6b47a3c9 100644 --- a/frameworks/native/pulseaudio/src/modules/hdi/hdi_sink.c +++ b/frameworks/native/pulseaudio/src/modules/hdi/hdi_sink.c @@ -59,6 +59,7 @@ struct Userdata { const char *adapterName; uint32_t buffer_size; uint32_t fixed_latency; + uint32_t sink_latency; uint32_t render_in_idle_state; uint32_t open_mic_speaker; size_t bytes_dropped; @@ -78,6 +79,10 @@ struct Userdata { struct RendererSinkAdapter *sinkAdapter; pa_asyncmsgq *dq; pa_atomic_t dflag; +#ifdef TEST_MODE + uint32_t writeCount; + uint32_t renderCount; +#endif // TEST_MODE }; static void UserdataFree(struct Userdata *u); @@ -96,6 +101,13 @@ static ssize_t RenderWrite(struct Userdata *u, pa_memchunk *pchunk) p = pa_memblock_acquire(pchunk->memblock); pa_assert(p); +#ifdef TEST_MODE + if (*((int*)p) > 0) { + AUDIO_DEBUG_LOG("RenderWrite Write: %{public}d", ++u->writeCount); + } + AUDIO_DEBUG_LOG("RenderWrite Write renderCount: %{public}d", ++u->renderCount); +#endif // TEST_MODE + while (true) { uint64_t writeLen = 0; @@ -263,25 +275,29 @@ static void SinkUpdateRequestedLatencyCb(pa_sink *s) static int SinkProcessMsg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { + AUDIO_INFO_LOG("SinkProcessMsg: code: %{public}d", code); struct Userdata *u = PA_SINK(o)->userdata; pa_assert(u); - AUDIO_INFO_LOG("SinkProcessMsg: code: %{public}d", code); switch (code) { case PA_SINK_MESSAGE_GET_LATENCY: { - uint64_t latency; - uint32_t hdiLatency; - - // Tries to fetch latency from HDI else will make an estimate based - // on samples to be rendered based on the timestamp and current time - if (u->sinkAdapter->RendererSinkGetLatency(&hdiLatency) == 0) { - latency = (PA_USEC_PER_MSEC * hdiLatency); + if (u->sink_latency) { + *((uint64_t *)data) = u->sink_latency * PA_USEC_PER_MSEC; } else { - pa_usec_t now = pa_rtclock_now(); - latency = (now - u->timestamp); - } + uint64_t latency; + uint32_t hdiLatency; - *((uint64_t *)data) = latency; + // Tries to fetch latency from HDI else will make an estimate based + // on samples to be rendered based on the timestamp and current time + if (u->sinkAdapter->RendererSinkGetLatency(&hdiLatency) == 0) { + latency = (PA_USEC_PER_MSEC * hdiLatency); + } else { + pa_usec_t now = pa_rtclock_now(); + latency = (now - u->timestamp); + } + + *((uint64_t *)data) = latency; + } return 0; } default: @@ -325,6 +341,10 @@ static int SinkSetStateInIoThreadCb(pa_sink *s, pa_sink_state_t newState, pa_core_exit(u->core, true, 0); } else { u->isHDISinkStarted = true; +#ifdef TEST_MODE + u->writeCount = 0; + u->renderCount = 0; +#endif // TEST_MODE AUDIO_INFO_LOG("Successfully restarted HDI renderer"); } } else if (PA_SINK_IS_OPENED(s->thread_info.state)) { @@ -485,6 +505,10 @@ pa_sink *PaHdiSinkNew(pa_module *m, pa_modargs *ma, const char *driver) } u->adapterName = pa_modargs_get_value(ma, "adapter_name", DEFAULT_DEVICE_CLASS); + u->sink_latency = 0; + if (pa_modargs_get_value_u32(ma, "sink_latency", &u->sink_latency) < 0) { + AUDIO_ERR_LOG("No sink_latency argument."); + } if (pa_modargs_get_value_u32(ma, "render_in_idle_state", &u->render_in_idle_state) < 0) { AUDIO_ERR_LOG("Failed to parse render_in_idle_state argument."); @@ -498,6 +522,10 @@ pa_sink *PaHdiSinkNew(pa_module *m, pa_modargs *ma, const char *driver) pa_atomic_store(&u->dflag, 0); u->dq = pa_asyncmsgq_new(0); +#ifdef TEST_MODE + u->writeCount = 0; + u->renderCount = 0; +#endif // TEST_MODE u->sink = PaHdiSinkInit(u, ma, driver); if (!u->sink) { diff --git a/frameworks/native/pulseaudio/src/modules/hdi/module_hdi_sink.c b/frameworks/native/pulseaudio/src/modules/hdi/module_hdi_sink.c index 7837e896..f6f5c62a 100644 --- a/frameworks/native/pulseaudio/src/modules/hdi/module_hdi_sink.c +++ b/frameworks/native/pulseaudio/src/modules/hdi/module_hdi_sink.c @@ -40,6 +40,7 @@ PA_MODULE_USAGE( "file_path=" "adapter_name=" "fixed_latency=" + "sink_latency=" "render_in_idle_state" "open_mic_speaker" ); @@ -56,6 +57,7 @@ static const char * const VALID_MODARGS[] = { "file_path", "adapter_name", "fixed_latency", + "sink_latency", "render_in_idle_state", "open_mic_speaker", NULL diff --git a/interfaces/inner_api/native/audiomanager/include/audio_system_manager.h b/interfaces/inner_api/native/audiomanager/include/audio_system_manager.h index 4faf911f..8660dc24 100644 --- a/interfaces/inner_api/native/audiomanager/include/audio_system_manager.h +++ b/interfaces/inner_api/native/audiomanager/include/audio_system_manager.h @@ -239,6 +239,7 @@ public: bool RequestIndependentInterrupt(FocusType focusType); bool AbandonIndependentInterrupt(FocusType focusType); int32_t GetAudioLatencyFromXml() const; + uint32_t GetSinkLatencyFromXml() const; private: AudioSystemManager(); diff --git a/interfaces/inner_api/native/audiorenderer/BUILD.gn b/interfaces/inner_api/native/audiorenderer/BUILD.gn index ff98b34c..5bf0b21b 100644 --- a/interfaces/inner_api/native/audiorenderer/BUILD.gn +++ b/interfaces/inner_api/native/audiorenderer/BUILD.gn @@ -76,6 +76,22 @@ ohos_executable("audio_renderer_test") { subsystem_name = "multimedia" } +ohos_executable("audio_latency_accuracy_test") { + install_enable = false + + sources = [ "//foundation/multimedia/audio_framework/services/test/audio_renderer_test.cpp" ] + + configs = [ ":audio_renderer_config" ] + cflags = [ "-DLATENCY_ACCURACY_TEST" ] + + deps = [ ":audio_renderer" ] + + external_deps = [ "hiviewdfx_hilog_native:libhilog" ] + + part_name = "multimedia_audio_framework" + subsystem_name = "multimedia" +} + ohos_executable("audio_render_mode_callback_test") { install_enable = false diff --git a/services/include/audio_policy/client/audio_policy_base.h b/services/include/audio_policy/client/audio_policy_base.h index ff8ac37c..dd16ff58 100644 --- a/services/include/audio_policy/client/audio_policy_base.h +++ b/services/include/audio_policy/client/audio_policy_base.h @@ -96,6 +96,8 @@ public: virtual int32_t GetAudioLatencyFromXml() = 0; + virtual uint32_t GetSinkLatencyFromXml() = 0; + virtual int32_t RegisterAudioRendererEventListener(int32_t clientUID, const sptr &object) = 0; virtual int32_t UnregisterAudioRendererEventListener(int32_t clientUID) = 0; diff --git a/services/include/audio_policy/client/audio_policy_manager_stub.h b/services/include/audio_policy/client/audio_policy_manager_stub.h index 7ee4c91c..f5384d76 100644 --- a/services/include/audio_policy/client/audio_policy_manager_stub.h +++ b/services/include/audio_policy/client/audio_policy_manager_stub.h @@ -62,6 +62,7 @@ private: void VerifyClientPermissionInternal(MessageParcel &data, MessageParcel &reply); void ReconfigureAudioChannelInternal(MessageParcel &data, MessageParcel &reply); void GetAudioLatencyFromXmlInternal(MessageParcel &data, MessageParcel &reply); + void GetSinkLatencyFromXmlInternal(MessageParcel &data, MessageParcel &reply); void ReadStreamChangeInfo(MessageParcel &data, const AudioMode &mode, AudioStreamChangeInfo &streamChangeInfo); void RegisterAudioRendererEventListenerInternal(MessageParcel &data, MessageParcel &reply); void UnregisterAudioRendererEventListenerInternal(MessageParcel &data, MessageParcel &reply); diff --git a/services/include/audio_policy/client/audio_policy_proxy.h b/services/include/audio_policy/client/audio_policy_proxy.h index 6c11a739..1920c58e 100644 --- a/services/include/audio_policy/client/audio_policy_proxy.h +++ b/services/include/audio_policy/client/audio_policy_proxy.h @@ -94,6 +94,8 @@ public: int32_t GetAudioLatencyFromXml() override; + uint32_t GetSinkLatencyFromXml() override; + int32_t RegisterAudioRendererEventListener(int32_t clientUID, const sptr &object) override; int32_t UnregisterAudioRendererEventListener(int32_t clientUID) override; diff --git a/services/include/audio_policy/common/audio_policy_types.h b/services/include/audio_policy/common/audio_policy_types.h index b672d4fd..6b44a519 100644 --- a/services/include/audio_policy/common/audio_policy_types.h +++ b/services/include/audio_policy/common/audio_policy_types.h @@ -54,6 +54,7 @@ enum AudioPolicyCommand { QUERY_PERMISSION, RECONFIGURE_CHANNEL, GET_AUDIO_LATENCY, + GET_SINK_LATENCY, REGISTER_PLAYBACK_EVENT, UNREGISTER_PLAYBACK_EVENT, REGISTER_RECORDING_EVENT, diff --git a/services/include/audio_policy/server/audio_policy_server.h b/services/include/audio_policy/server/audio_policy_server.h index c4db9bea..2a8aef58 100644 --- a/services/include/audio_policy/server/audio_policy_server.h +++ b/services/include/audio_policy/server/audio_policy_server.h @@ -121,6 +121,8 @@ public: int32_t GetAudioLatencyFromXml() override; + uint32_t GetSinkLatencyFromXml() override; + int32_t RegisterAudioRendererEventListener(int32_t clientUID, const sptr &object) override; int32_t UnregisterAudioRendererEventListener(int32_t clientUID) override; diff --git a/services/include/audio_policy/server/service/audio_policy_service.h b/services/include/audio_policy/server/service/audio_policy_service.h index 4e3c24d7..aa6b4741 100644 --- a/services/include/audio_policy/server/service/audio_policy_service.h +++ b/services/include/audio_policy/server/service/audio_policy_service.h @@ -80,6 +80,8 @@ public: int32_t GetAudioLatencyFromXml() const; + uint32_t GetSinkLatencyFromXml() const; + // Parser callbacks void OnXmlParsingCompleted(const std::unordered_map> &xmldata); @@ -104,6 +106,8 @@ public: int32_t ReconfigureAudioChannel(const uint32_t &count, DeviceType deviceType); void OnAudioLatencyParsed(uint64_t latency); + + void OnSinkLatencyParsed(uint32_t latency); private: AudioPolicyService() : mAudioPolicyManager(AudioPolicyManagerFactory::GetAudioPolicyManager()), @@ -145,6 +149,7 @@ private: bool interruptEnabled_ = true; bool isUpdateRouteSupported_ = true; uint64_t audioLatencyInMsec_ = 50; + uint32_t sinkLatencyInMsec_ {0}; std::bitset serviceFlag_; DeviceType mCurrentActiveDevice_ = DEVICE_TYPE_NONE; DeviceType mActiveInputDevice_ = DEVICE_TYPE_NONE; diff --git a/services/include/audio_policy/server/service/common/audio_module_info.h b/services/include/audio_policy/server/service/common/audio_module_info.h index 719a3a15..0a762489 100644 --- a/services/include/audio_policy/server/service/common/audio_module_info.h +++ b/services/include/audio_policy/server/service/common/audio_module_info.h @@ -52,6 +52,7 @@ enum NodeName { AUDIO_INTERRUPT_ENABLE, UPDATE_ROUTE_SUPPORT, AUDIO_LATENCY, + SINK_LATENCY, UNKNOWN }; @@ -79,6 +80,7 @@ public: std::string channels; std::string bufferSize; std::string fixedLatency; + std::string sinkLatency; std::string renderInIdleState; std::string OpenMicSpeaker; std::string fileName; diff --git a/services/include/audio_policy/server/service/config/xml_parser.h b/services/include/audio_policy/server/service/config/xml_parser.h index 45c7cd61..c467fe8f 100644 --- a/services/include/audio_policy/server/service/config/xml_parser.h +++ b/services/include/audio_policy/server/service/config/xml_parser.h @@ -56,6 +56,7 @@ private: void ParseAudioInterrupt(xmlNode &node); void ParseUpdateRouteSupport(xmlNode &node); void ParseAudioLatency(xmlNode &node); + void ParseSinkLatency(xmlNode &node); std::string ExtractPropertyValue(const std::string &propName, xmlNode &node); ClassType GetDeviceClassType(const std::string &deviceClass); diff --git a/services/include/audio_policy/server/service/interface/iport_observer.h b/services/include/audio_policy/server/service/interface/iport_observer.h index c5b448ef..e739c572 100644 --- a/services/include/audio_policy/server/service/interface/iport_observer.h +++ b/services/include/audio_policy/server/service/interface/iport_observer.h @@ -27,6 +27,7 @@ public: virtual void OnAudioInterruptEnable(bool enable) = 0; virtual void OnUpdateRouteSupport(bool isSupported) = 0; virtual void OnAudioLatencyParsed(uint64_t latency) = 0; + virtual void OnSinkLatencyParsed(uint32_t latency) = 0; }; } // namespace AudioStandard } // namespace OHOS diff --git a/services/include/audio_service/client/audio_service_client.h b/services/include/audio_service/client/audio_service_client.h index d3bf5cae..ed4cb3b3 100644 --- a/services/include/audio_service/client/audio_service_client.h +++ b/services/include/audio_service/client/audio_service_client.h @@ -230,6 +230,7 @@ public: * @return returns size of audio data written in bytes. */ size_t WriteStream(const StreamBuffer &stream, int32_t &pError); + int32_t RenderPrebuf(uint32_t writeLen); /** * Writes audio data of the stream created using CreateStream to active sink device @@ -527,6 +528,9 @@ private: bool isContextConnected; bool isStreamConnected; + std::unique_ptr preBuf_ {nullptr}; + uint32_t sinkLatencyInMsec_ {0}; + int32_t clientPid_ = 0; int32_t clientUid_ = 0; diff --git a/services/src/audio_policy/client/audio_policy_manager.cpp b/services/src/audio_policy/client/audio_policy_manager.cpp index 66fb2bf7..ffe1eb90 100644 --- a/services/src/audio_policy/client/audio_policy_manager.cpp +++ b/services/src/audio_policy/client/audio_policy_manager.cpp @@ -446,6 +446,11 @@ int32_t AudioPolicyManager::GetAudioLatencyFromXml() return g_sProxy->GetAudioLatencyFromXml(); } +uint32_t AudioPolicyManager::GetSinkLatencyFromXml() +{ + return g_sProxy->GetSinkLatencyFromXml(); +} + int32_t AudioPolicyManager::GetCurrentRendererChangeInfos( vector> &audioRendererChangeInfos) { diff --git a/services/src/audio_policy/client/audio_policy_proxy.cpp b/services/src/audio_policy/client/audio_policy_proxy.cpp index 904f0486..8ec04b87 100644 --- a/services/src/audio_policy/client/audio_policy_proxy.cpp +++ b/services/src/audio_policy/client/audio_policy_proxy.cpp @@ -814,6 +814,26 @@ int32_t AudioPolicyProxy::GetAudioLatencyFromXml() return reply.ReadInt32(); } +uint32_t AudioPolicyProxy::GetSinkLatencyFromXml() +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + if (!data.WriteInterfaceToken(GetDescriptor())) { + AUDIO_ERR_LOG("AudioPolicyProxy: GetSinkLatencyFromXml WriteInterfaceToken failed"); + return 0; + } + + int32_t error = Remote()->SendRequest(GET_SINK_LATENCY, data, reply, option); + if (error != ERR_NONE) { + AUDIO_ERR_LOG("GetSinkLatencyFromXml, error: %d", error); + return 0; + } + + return reply.ReadUint32(); +} + int32_t AudioPolicyProxy::RegisterAudioCapturerEventListener(const int32_t clientUID, const sptr &object) { MessageParcel data; diff --git a/services/src/audio_policy/server/audio_policy_manager_stub.cpp b/services/src/audio_policy/server/audio_policy_manager_stub.cpp index 4c82aaf0..5bdf4f7b 100644 --- a/services/src/audio_policy/server/audio_policy_manager_stub.cpp +++ b/services/src/audio_policy/server/audio_policy_manager_stub.cpp @@ -339,6 +339,12 @@ void AudioPolicyManagerStub::GetAudioLatencyFromXmlInternal(MessageParcel &data, reply.WriteInt32(ret); } +void AudioPolicyManagerStub::GetSinkLatencyFromXmlInternal(MessageParcel &data, MessageParcel &reply) +{ + uint32_t ret = GetSinkLatencyFromXml(); + reply.WriteUint32(ret); +} + void AudioPolicyManagerStub::ReconfigureAudioChannelInternal(MessageParcel &data, MessageParcel &reply) { uint32_t count = data.ReadUint32(); @@ -622,6 +628,10 @@ int AudioPolicyManagerStub::OnRemoteRequest( GetAudioLatencyFromXmlInternal(data, reply); break; + case GET_SINK_LATENCY: + GetSinkLatencyFromXmlInternal(data, reply); + break; + case REGISTER_PLAYBACK_EVENT: RegisterAudioRendererEventListenerInternal(data, reply); break; diff --git a/services/src/audio_policy/server/audio_policy_server.cpp b/services/src/audio_policy/server/audio_policy_server.cpp index 0abd6305..ece9a1b1 100644 --- a/services/src/audio_policy/server/audio_policy_server.cpp +++ b/services/src/audio_policy/server/audio_policy_server.cpp @@ -1118,6 +1118,11 @@ int32_t AudioPolicyServer::GetAudioLatencyFromXml() return mPolicyService.GetAudioLatencyFromXml(); } +uint32_t AudioPolicyServer::GetSinkLatencyFromXml() +{ + return mPolicyService.GetSinkLatencyFromXml(); +} + int32_t AudioPolicyServer::RegisterAudioRendererEventListener(int32_t clientUID, const sptr &object) { RegisterClientDeathRecipient(object, LISTENER_CLIENT); diff --git a/services/src/audio_policy/server/service/audio_policy_service.cpp b/services/src/audio_policy/server/service/audio_policy_service.cpp index dcea515b..48df01a4 100644 --- a/services/src/audio_policy/server/service/audio_policy_service.cpp +++ b/services/src/audio_policy/server/service/audio_policy_service.cpp @@ -677,6 +677,7 @@ void AudioPolicyService::OnServiceConnected(AudioServiceIndex serviceIndex) auto moduleInfoList = device.second; for (auto &moduleInfo : moduleInfoList) { AUDIO_INFO_LOG("[module_load]::Load module[%{public}s]", moduleInfo.name.c_str()); + moduleInfo.sinkLatency = sinkLatencyInMsec_ != 0 ? to_string(sinkLatencyInMsec_) : ""; AudioIOHandle ioHandle = mAudioPolicyManager.OpenAudioPort(moduleInfo); if (ioHandle == OPEN_PORT_FAILURE) { AUDIO_INFO_LOG("[module_load]::Open port failed"); @@ -928,6 +929,16 @@ int32_t AudioPolicyService::GetAudioLatencyFromXml() const return audioLatencyInMsec_; } +void AudioPolicyService::OnSinkLatencyParsed(uint32_t latency) +{ + sinkLatencyInMsec_ = latency; +} + +uint32_t AudioPolicyService::GetSinkLatencyFromXml() const +{ + return sinkLatencyInMsec_; +} + void AudioPolicyService::UpdateInputDeviceInfo(DeviceType deviceType) { AUDIO_DEBUG_LOG("Current input device is %{public}d", mActiveInputDevice_); diff --git a/services/src/audio_policy/server/service/config/xml_parser.cpp b/services/src/audio_policy/server/service/config/xml_parser.cpp index d615edd0..2e1d230d 100644 --- a/services/src/audio_policy/server/service/config/xml_parser.cpp +++ b/services/src/audio_policy/server/service/config/xml_parser.cpp @@ -70,6 +70,9 @@ bool XMLParser::ParseInternal(xmlNode &node) case AUDIO_LATENCY: ParseAudioLatency(*currNode); break; + case SINK_LATENCY: + ParseSinkLatency(*currNode); + break; default: ParseInternal(*(currNode->children)); break; @@ -215,6 +218,8 @@ NodeName XMLParser::GetNodeNameAsInt(xmlNode &node) return UPDATE_ROUTE_SUPPORT; } else if (!xmlStrcmp(node.name, reinterpret_cast("AudioLatency"))) { return AUDIO_LATENCY; + } else if (!xmlStrcmp(node.name, reinterpret_cast("SinkLatency"))) { + return SINK_LATENCY; } else { return UNKNOWN; } @@ -288,5 +293,15 @@ void XMLParser::ParseAudioLatency(xmlNode &node) xmlFree(audioLatency); } + +void XMLParser::ParseSinkLatency(xmlNode &node) +{ + xmlNode *child = node.children; + xmlChar *latency = xmlNodeGetContent(child); + std::string sLatency(reinterpret_cast(latency)); + mPortObserver.OnSinkLatencyParsed((uint64_t)std::stoi(sLatency)); + + xmlFree(latency); +} } // namespace AudioStandard } // namespace OHOS diff --git a/services/src/audio_policy/server/service/manager/audio_adapter_manager.cpp b/services/src/audio_policy/server/service/manager/audio_adapter_manager.cpp index 0f2c74b2..79f23709 100644 --- a/services/src/audio_policy/server/service/manager/audio_adapter_manager.cpp +++ b/services/src/audio_policy/server/service/manager/audio_adapter_manager.cpp @@ -302,6 +302,10 @@ std::string AudioAdapterManager::GetModuleArgs(const AudioModuleInfo &audioModul args.append(" file_path="); args.append(audioModuleInfo.fileName); } + if (!audioModuleInfo.sinkLatency.empty()) { + args.append(" sink_latency="); + args.append(audioModuleInfo.sinkLatency); + } } else if (audioModuleInfo.lib == HDI_SOURCE) { UpdateCommonArgs(audioModuleInfo, args); if (!audioModuleInfo.name.empty()) { diff --git a/services/src/audio_service/client/audio_service_client.cpp b/services/src/audio_service/client/audio_service_client.cpp index 869f3205..55aacb66 100644 --- a/services/src/audio_service/client/audio_service_client.cpp +++ b/services/src/audio_service/client/audio_service_client.cpp @@ -36,6 +36,9 @@ const uint32_t DOUBLE_VALUE = 2; const uint32_t MAX_LENGTH_FACTOR = 5; const uint32_t T_LENGTH_FACTOR = 4; const uint64_t MIN_BUF_DURATION_IN_USEC = 92880; +const uint32_t LATENCY_THRESHOLD = 35; +const int32_t NO_OF_PREBUF_TIMES = 6; + const string PATH_SEPARATOR = "/"; const string COOKIE_FILE_NAME = "cookie"; @@ -780,29 +783,42 @@ int32_t AudioServiceClient::ConnectStreamToPA() return AUDIO_CLIENT_ERR; } uint64_t latency_in_msec = AudioSystemManager::GetInstance()->GetAudioLatencyFromXml(); + sinkLatencyInMsec_ = AudioSystemManager::GetInstance()->GetSinkLatencyFromXml(); pa_threaded_mainloop_lock(mainLoop); pa_buffer_attr bufferAttr; bufferAttr.fragsize = static_cast(-1); + if (latency_in_msec <= LATENCY_THRESHOLD) { + bufferAttr.prebuf = AlignToAudioFrameSize(pa_usec_to_bytes(latency_in_msec * PA_USEC_PER_MSEC, &sampleSpec), + sampleSpec); + bufferAttr.maxlength = NO_OF_PREBUF_TIMES * bufferAttr.prebuf; + bufferAttr.tlength = static_cast(-1); + } else { + bufferAttr.prebuf = pa_usec_to_bytes(latency_in_msec * PA_USEC_PER_MSEC, &sampleSpec); + bufferAttr.maxlength = pa_usec_to_bytes(latency_in_msec * PA_USEC_PER_MSEC * MAX_LENGTH_FACTOR, &sampleSpec); + bufferAttr.tlength = pa_usec_to_bytes(latency_in_msec * PA_USEC_PER_MSEC * T_LENGTH_FACTOR, &sampleSpec); + } + bufferAttr.minreq = bufferAttr.prebuf; - bufferAttr.prebuf = pa_usec_to_bytes(latency_in_msec * PA_USEC_PER_MSEC, &sampleSpec); - bufferAttr.maxlength = pa_usec_to_bytes(latency_in_msec * PA_USEC_PER_MSEC * MAX_LENGTH_FACTOR, &sampleSpec); - bufferAttr.tlength = pa_usec_to_bytes(latency_in_msec * PA_USEC_PER_MSEC * T_LENGTH_FACTOR, &sampleSpec); - bufferAttr.minreq = pa_usec_to_bytes(latency_in_msec * PA_USEC_PER_MSEC, &sampleSpec); - - if (eAudioClientType == AUDIO_SERVICE_CLIENT_PLAYBACK) + if (eAudioClientType == AUDIO_SERVICE_CLIENT_PLAYBACK) { result = pa_stream_connect_playback(paStream, nullptr, &bufferAttr, (pa_stream_flags_t)(PA_STREAM_ADJUST_LATENCY | PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_START_CORKED | PA_STREAM_VARIABLE_RATE), nullptr, nullptr); - else + preBuf_ = make_unique(bufferAttr.maxlength); + if (preBuf_ == nullptr) { + AUDIO_ERR_LOG("Allocate memory for buffer failed."); + return AUDIO_CLIENT_INIT_ERR; + } + memset_s(preBuf_.get(), bufferAttr.maxlength, 0, bufferAttr.maxlength); + } else { result = pa_stream_connect_record(paStream, nullptr, nullptr, (pa_stream_flags_t)(PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_ADJUST_LATENCY | PA_STREAM_START_CORKED | PA_STREAM_AUTO_TIMING_UPDATE)); - + } if (result < 0) { error = pa_context_errno(context); AUDIO_ERR_LOG("connection to stream error: %{public}d", error); @@ -1447,6 +1463,52 @@ int32_t AudioServiceClient::UpdateReadBuffer(uint8_t *buffer, size_t &length, si return 0; } +int32_t AudioServiceClient::RenderPrebuf(uint32_t writeLen) +{ + const pa_buffer_attr *bufferAttr = pa_stream_get_buffer_attr(paStream); + if (bufferAttr == nullptr) { + AUDIO_ERR_LOG("pa_stream_get_buffer_attr returned nullptr"); + return AUDIO_CLIENT_ERR; + } + + size_t diff = bufferAttr->maxlength - writeLen; + if (diff <= 0) { + return AUDIO_CLIENT_SUCCESS; + } + + int32_t writeError; + StreamBuffer prebufStream; + prebufStream.buffer = preBuf_.get(); + uint32_t extra {0}; + if (writeLen == 0) { + return AUDIO_CLIENT_SUCCESS; + } else if (writeLen > diff) { + prebufStream.bufferLen = diff; + } else { + prebufStream.bufferLen = writeLen; + extra = diff % writeLen; + } + + size_t bytesWritten {0}; + while (true) { + bytesWritten += WriteStream(prebufStream, writeError); + if (writeError) { + AUDIO_ERR_LOG("RenderPrebuf failed: %{public}d", writeError); + return AUDIO_CLIENT_ERR; + } + + if ((diff - bytesWritten) <= 0) { + break; + } + + if ((diff - bytesWritten) == extra) { + prebufStream.bufferLen = extra; + } + } + + return AUDIO_CLIENT_SUCCESS; +} + void AudioServiceClient::OnTimeOut() { AUDIO_ERR_LOG("Inside read timeout callback"); @@ -1742,27 +1804,24 @@ int32_t AudioServiceClient::GetAudioLatency(uint64_t &latency) const return AUDIO_CLIENT_PA_ERR; } - pa_usec_t paLatency; - pa_usec_t cacheLatency; - int32_t retVal = AUDIO_CLIENT_SUCCESS; - int negative = 0; + pa_usec_t paLatency {0}; + pa_usec_t cacheLatency {0}; + int negative {0}; // Get PA latency pa_threaded_mainloop_lock(mainLoop); - - pa_operation *operation = pa_stream_update_timing_info(paStream, NULL, NULL); - if (operation != nullptr) { - pa_operation_unref(operation); - } else { - AUDIO_ERR_LOG("pa_stream_update_timing_info failed"); - } - while (true) { + pa_operation *operation = pa_stream_update_timing_info(paStream, NULL, NULL); + if (operation != nullptr) { + pa_operation_unref(operation); + } else { + AUDIO_ERR_LOG("pa_stream_update_timing_info failed"); + } if (pa_stream_get_latency(paStream, &paLatency, &negative) >= 0) { if (negative) { latency = 0; - retVal = AUDIO_CLIENT_ERR; - return retVal; + pa_threaded_mainloop_unlock(mainLoop); + return AUDIO_CLIENT_ERR; } break; } @@ -1776,7 +1835,7 @@ int32_t AudioServiceClient::GetAudioLatency(uint64_t &latency) const cacheLatency = pa_bytes_to_usec((acache.totalCacheSize - acache.writeIndex), &sampleSpec); // Total latency will be sum of audio write cache latency + PA latency - latency = paLatency + cacheLatency; + latency = paLatency + cacheLatency - (sinkLatencyInMsec_ * PA_USEC_PER_MSEC); AUDIO_INFO_LOG("total latency: %{public}" PRIu64 ", pa latency: %{public}" PRIu64 ", cache latency: %{public}" PRIu64, latency, paLatency, cacheLatency); } else if (eAudioClientType == AUDIO_SERVICE_CLIENT_RECORD) { @@ -1788,7 +1847,7 @@ int32_t AudioServiceClient::GetAudioLatency(uint64_t &latency) const AUDIO_INFO_LOG("total latency: %{public}" PRIu64 ", pa latency: %{public}" PRIu64, latency, paLatency); } - return retVal; + return AUDIO_CLIENT_SUCCESS; } void AudioServiceClient::RegisterAudioRendererCallbacks(const AudioRendererCallbacks &cb) diff --git a/services/src/audio_service/client/audio_stream.cpp b/services/src/audio_service/client/audio_stream.cpp index 09893dcf..7346f6e8 100644 --- a/services/src/audio_service/client/audio_stream.cpp +++ b/services/src/audio_service/client/audio_stream.cpp @@ -91,7 +91,8 @@ AudioStream::AudioStream(AudioStreamType eStreamType, AudioMode eMode, int32_t a captureMode_(CAPTURE_MODE_NORMAL), isReadyToWrite_(false), isReadyToRead_(false), - isFirstRead_(false) + isFirstRead_(false), + isFirstWrite_(false) { AUDIO_DEBUG_LOG("AudioStream ctor, appUID = %{public}d", appUid); audioStreamTracker_ = std::make_unique(eMode, appUid); @@ -366,6 +367,7 @@ bool AudioStream::StartAudioStream() } isFirstRead_ = true; + isFirstWrite_ = true; state_ = RUNNING; AUDIO_INFO_LOG("StartAudioStream SUCCESS"); @@ -431,6 +433,12 @@ size_t AudioStream::Write(uint8_t *buffer, size_t buffer_size) stream.buffer = buffer; stream.bufferLen = buffer_size; isWriteInProgress_ = true; + if (isFirstWrite_) { + if (RenderPrebuf(stream.bufferLen)) { + return ERR_WRITE_FAILED; + } + isFirstWrite_ = false; + } size_t bytesWritten = WriteStream(stream, writeError); isWriteInProgress_ = false; if (writeError != 0) { diff --git a/services/src/audio_service/client/audio_system_manager.cpp b/services/src/audio_service/client/audio_system_manager.cpp index ee29121a..3a653795 100644 --- a/services/src/audio_service/client/audio_system_manager.cpp +++ b/services/src/audio_service/client/audio_system_manager.cpp @@ -695,5 +695,10 @@ int32_t AudioSystemManager::GetAudioLatencyFromXml() const { return AudioPolicyManager::GetInstance().GetAudioLatencyFromXml(); } + +uint32_t AudioSystemManager::GetSinkLatencyFromXml() const +{ + return AudioPolicyManager::GetInstance().GetSinkLatencyFromXml(); +} } // namespace AudioStandard } // namespace OHOS diff --git a/services/test/audio_renderer_test.cpp b/services/test/audio_renderer_test.cpp index 4dae27cf..e9b74f4f 100644 --- a/services/test/audio_renderer_test.cpp +++ b/services/test/audio_renderer_test.cpp @@ -12,6 +12,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#ifdef LATENCY_ACCURACY_TEST +#include +#endif // LATENCY_ACCURACY_TEST #include #include "audio_renderer.h" @@ -29,11 +32,13 @@ namespace { constexpr int32_t ARGS_COUNT_THREE = 3; constexpr int32_t ARGS_COUNT_FOUR = 4; constexpr int32_t SUCCESS = 0; +#ifndef LATENCY_ACCURACY_TEST constexpr int32_t STOP_BUFFER_POSITION = 700000; constexpr int32_t PAUSE_BUFFER_POSITION = 1400000; constexpr int32_t PAUSE_RENDER_TIME_SECONDS = 1; constexpr int32_t STOP_RENDER_TIME_SECONDS = 1; constexpr float TRACK_VOLUME = 0.2f; +#endif // LATENCY_ACCURACY_TEST constexpr int32_t SAMPLE_FORMAT_U8 = 8; constexpr int32_t SAMPLE_FORMAT_S16LE = 16; @@ -135,14 +140,16 @@ public: return false; } AUDIO_INFO_LOG("AudioRendererTest: Playback started"); - +#ifndef LATENCY_ACCURACY_TEST if (audioRenderer->SetVolume(TRACK_VOLUME) == SUCCESS) { AUDIO_INFO_LOG("AudioRendererTest: volume set to: %{public}f", audioRenderer->GetVolume()); } +#endif // LATENCY_ACCURACY_TEST return true; } +#ifndef LATENCY_ACCURACY_TEST bool TestPauseStop(const unique_ptr &audioRenderer, bool &pauseTested, bool &stopTested, FILE &wavFile) const { @@ -176,6 +183,7 @@ public: return true; } +#endif // LATENCY_ACCURACY_TEST bool GetBufferLen(const unique_ptr &audioRenderer, size_t &bufferLen) const { @@ -210,23 +218,27 @@ public: size_t bytesWritten = 0; size_t minBytes = 4; uint64_t latency; +#ifndef LATENCY_ACCURACY_TEST bool stopTested = false; bool pauseTested = false; +#endif // LATENCY_ACCURACY_TEST +#ifdef LATENCY_ACCURACY_TEST + uint32_t writeCount {0}; +#endif // LATENCY_ACCURACY_TEST while (!feof(wavFile)) { bytesToWrite = fread(buffer.get(), 1, bufferLen, wavFile); bytesWritten = 0; AUDIO_INFO_LOG("AudioRendererTest: Bytes to write: %{public}zu", bytesToWrite); +#ifndef LATENCY_ACCURACY_TEST if (!TestPauseStop(audioRenderer, pauseTested, stopTested, *wavFile)) { break; } - - if (audioRenderer->GetLatency(latency)) { - AUDIO_ERR_LOG("AudioRendererTest: GetLatency failed"); - break; - } - +#endif // LATENCY_ACCURACY_TEST +#ifdef LATENCY_ACCURACY_TEST + AUDIO_DEBUG_LOG("start: %{public}d", ++writeCount); +#endif // LATENCY_ACCURACY_TEST while ((bytesWritten < bytesToWrite) && ((bytesToWrite - bytesWritten) > minBytes)) { bytesWritten += audioRenderer->Write(buffer.get() + bytesWritten, bytesToWrite - bytesWritten); @@ -235,6 +247,18 @@ public: break; } } +#ifdef LATENCY_ACCURACY_TEST + AUDIO_DEBUG_LOG("complete: %{public}d", writeCount); +#endif // LATENCY_ACCURACY_TEST + + if (audioRenderer->GetLatency(latency)) { + AUDIO_ERR_LOG("AudioRendererTest: GetLatency failed"); + break; +#if LATENCY_ACCURACY_TEST + } else { + AUDIO_DEBUG_LOG("GetLatency: %{public}" PRIu64, latency); +#endif // LATENCY_ACCURACY_TEST + } } if (!audioRenderer->Drain()) {