Fix Getlatency

Signed-off-by: Vaidegi B <vaidegi.b1@huawei.com>
This commit is contained in:
Vaidegi B
2022-06-30 01:21:49 +05:30
parent 25956cc120
commit 4fdee254f8
29 changed files with 283 additions and 44 deletions
+1
View File
@@ -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",
@@ -120,6 +120,8 @@ public:
int32_t GetAudioLatencyFromXml();
uint32_t GetSinkLatencyFromXml();
int32_t RegisterAudioRendererEventListener(const int32_t clientUID,
const std::shared_ptr<AudioRendererStateChangeCallback> &callback);
@@ -105,6 +105,7 @@ private:
static const std::map<std::pair<ContentType, StreamUsage>, AudioStreamType> streamTypeMap_;
static std::map<std::pair<ContentType, StreamUsage>, AudioStreamType> CreateStreamMap();
bool isFirstRead_;
bool isFirstWrite_;
};
} // namespace AudioStandard
} // namespace OHOS
@@ -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",
@@ -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) {
@@ -40,6 +40,7 @@ PA_MODULE_USAGE(
"file_path=<file path for data writing>"
"adapter_name=<primary>"
"fixed_latency=<latency measure>"
"sink_latency=<hdi latency>"
"render_in_idle_state<renderer state>"
"open_mic_speaker<open mic and 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
@@ -239,6 +239,7 @@ public:
bool RequestIndependentInterrupt(FocusType focusType);
bool AbandonIndependentInterrupt(FocusType focusType);
int32_t GetAudioLatencyFromXml() const;
uint32_t GetSinkLatencyFromXml() const;
private:
AudioSystemManager();
@@ -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
@@ -96,6 +96,8 @@ public:
virtual int32_t GetAudioLatencyFromXml() = 0;
virtual uint32_t GetSinkLatencyFromXml() = 0;
virtual int32_t RegisterAudioRendererEventListener(int32_t clientUID, const sptr<IRemoteObject> &object) = 0;
virtual int32_t UnregisterAudioRendererEventListener(int32_t clientUID) = 0;
@@ -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);
@@ -94,6 +94,8 @@ public:
int32_t GetAudioLatencyFromXml() override;
uint32_t GetSinkLatencyFromXml() override;
int32_t RegisterAudioRendererEventListener(int32_t clientUID, const sptr<IRemoteObject> &object) override;
int32_t UnregisterAudioRendererEventListener(int32_t clientUID) override;
@@ -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,
@@ -121,6 +121,8 @@ public:
int32_t GetAudioLatencyFromXml() override;
uint32_t GetSinkLatencyFromXml() override;
int32_t RegisterAudioRendererEventListener(int32_t clientUID, const sptr<IRemoteObject> &object) override;
int32_t UnregisterAudioRendererEventListener(int32_t clientUID) override;
@@ -80,6 +80,8 @@ public:
int32_t GetAudioLatencyFromXml() const;
uint32_t GetSinkLatencyFromXml() const;
// Parser callbacks
void OnXmlParsingCompleted(const std::unordered_map<ClassType, std::list<AudioModuleInfo>> &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<MIN_SERVICE_COUNT> serviceFlag_;
DeviceType mCurrentActiveDevice_ = DEVICE_TYPE_NONE;
DeviceType mActiveInputDevice_ = DEVICE_TYPE_NONE;
@@ -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;
@@ -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);
@@ -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
@@ -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<uint8_t[]> preBuf_ {nullptr};
uint32_t sinkLatencyInMsec_ {0};
int32_t clientPid_ = 0;
int32_t clientUid_ = 0;
@@ -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<unique_ptr<AudioRendererChangeInfo>> &audioRendererChangeInfos)
{
@@ -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<IRemoteObject> &object)
{
MessageParcel data;
@@ -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;
@@ -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<IRemoteObject> &object)
{
RegisterClientDeathRecipient(object, LISTENER_CLIENT);
@@ -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_);
@@ -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<const xmlChar*>("AudioLatency"))) {
return AUDIO_LATENCY;
} else if (!xmlStrcmp(node.name, reinterpret_cast<const xmlChar*>("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<char *>(latency));
mPortObserver.OnSinkLatencyParsed((uint64_t)std::stoi(sLatency));
xmlFree(latency);
}
} // namespace AudioStandard
} // namespace OHOS
@@ -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()) {
@@ -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<uint32_t>(-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<uint32_t>(-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<uint8_t[]>(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)
@@ -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<AudioStreamTracker>(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) {
@@ -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
+31 -7
View File
@@ -12,6 +12,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifdef LATENCY_ACCURACY_TEST
#include <cinttypes>
#endif // LATENCY_ACCURACY_TEST
#include <vector>
#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> &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> &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()) {