1 /*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #ifndef LOG_TAG
16 #define LOG_TAG "PaRendererStreamImpl"
17 #endif
18
19 #ifdef FEATURE_POWER_MANAGER
20 #include "power_mgr_client.h"
21 #endif
22
23 #include "pa_renderer_stream_impl.h"
24
25 #include <chrono>
26
27 #include "safe_map.h"
28 #include "pa_adapter_tools.h"
29 #include "audio_effect_chain_manager.h"
30 #include "audio_errors.h"
31 #include "audio_service_log.h"
32 #include "audio_utils.h"
33 #include "i_audio_renderer_sink.h"
34 #include "policy_handler.h"
35
36 namespace OHOS {
37 namespace AudioStandard {
38 static SafeMap<void *, std::weak_ptr<PaRendererStreamImpl>> rendererStreamInstanceMap_;
39 static const int32_t PA_STREAM_IMPL_TIMEOUT = 5; // 5s
40 const uint32_t DOUBLE_VALUE = 2;
41 const uint32_t MAX_LENGTH_OFFLOAD = 500;
42 const int32_t OFFLOAD_HDI_CACHE1 = 200; // ms, should equal with val in hdi_sink.c
43 const int32_t OFFLOAD_HDI_CACHE2 = 7000; // ms, should equal with val in hdi_sink.c
44 const uint32_t OFFLOAD_BUFFER = 50;
45 const uint64_t AUDIO_US_PER_MS = 1000;
46 const uint64_t AUDIO_NS_PER_US = 1000;
47 const uint64_t AUDIO_MS_PER_S = 1000;
48 const uint64_t AUDIO_US_PER_S = 1000000;
49 const uint64_t AUDIO_NS_PER_S = 1000000000;
50 const uint64_t AUDIO_CYCLE_TIME_US = 20000;
51 const float MIN_VOLUME = 0.0;
52 const float MAX_VOLUME = 1.0;
53
CheckReturnIfStreamInvalid(pa_stream * paStream,const int32_t retVal)54 static int32_t CheckReturnIfStreamInvalid(pa_stream *paStream, const int32_t retVal)
55 {
56 do {
57 if (!(paStream && PA_STREAM_IS_GOOD(pa_stream_get_state(paStream)))) {
58 return retVal;
59 }
60 } while (false);
61 return SUCCESS;
62 }
63
PaRendererStreamImpl(pa_stream * paStream,AudioProcessConfig processConfig,pa_threaded_mainloop * mainloop)64 PaRendererStreamImpl::PaRendererStreamImpl(pa_stream *paStream, AudioProcessConfig processConfig,
65 pa_threaded_mainloop *mainloop)
66 {
67 mainloop_ = mainloop;
68 paStream_ = paStream;
69 processConfig_ = processConfig;
70 }
71
~PaRendererStreamImpl()72 PaRendererStreamImpl::~PaRendererStreamImpl()
73 {
74 AUDIO_DEBUG_LOG("~PaRendererStreamImpl");
75
76 PaLockGuard lock(mainloop_);
77 rendererStreamInstanceMap_.Erase(this);
78 if (paStream_) {
79 if (!releasedFlag_) {
80 pa_stream_set_state_callback(paStream_, nullptr, nullptr);
81 pa_stream_set_write_callback(paStream_, nullptr, nullptr);
82 pa_stream_set_latency_update_callback(paStream_, nullptr, nullptr);
83 pa_stream_set_underflow_callback(paStream_, nullptr, nullptr);
84 pa_stream_set_moved_callback(paStream_, nullptr, nullptr);
85 pa_stream_set_started_callback(paStream_, nullptr, nullptr);
86
87 pa_stream_disconnect(paStream_);
88 }
89 pa_stream_unref(paStream_);
90 paStream_ = nullptr;
91 }
92 }
93
InitParams()94 int32_t PaRendererStreamImpl::InitParams()
95 {
96 PaLockGuard lock(mainloop_);
97 rendererStreamInstanceMap_.Insert(this, weak_from_this());
98 if (CheckReturnIfStreamInvalid(paStream_, ERR_ILLEGAL_STATE) < 0) {
99 return ERR_ILLEGAL_STATE;
100 }
101
102 sinkInputIndex_ = pa_stream_get_index(paStream_);
103 pa_stream_set_moved_callback(paStream_, PAStreamMovedCb,
104 reinterpret_cast<void *>(this)); // used to notify sink/source moved
105 pa_stream_set_write_callback(paStream_, PAStreamWriteCb, reinterpret_cast<void *>(this));
106 pa_stream_set_underflow_callback(paStream_, PAStreamUnderFlowCb, reinterpret_cast<void *>(this));
107 pa_stream_set_started_callback(paStream_, PAStreamSetStartedCb, reinterpret_cast<void *>(this));
108 pa_stream_set_underflow_ohos_callback(paStream_, PAStreamUnderFlowCountAddCb, reinterpret_cast<void *>(this));
109
110 // Get byte size per frame
111 const pa_sample_spec *sampleSpec = pa_stream_get_sample_spec(paStream_);
112 CHECK_AND_RETURN_RET_LOG(sampleSpec != nullptr, ERR_OPERATION_FAILED, "pa_sample_spec sampleSpec is nullptr");
113 AUDIO_INFO_LOG("sampleSpec: channels: %{public}u, formats: %{public}d, rate: %{public}d", sampleSpec->channels,
114 sampleSpec->format, sampleSpec->rate);
115
116 if (sampleSpec->channels != processConfig_.streamInfo.channels) {
117 AUDIO_WARNING_LOG("Unequal channels, in server: %{public}d, in client: %{public}d", sampleSpec->channels,
118 processConfig_.streamInfo.channels);
119 }
120 if (static_cast<uint8_t>(sampleSpec->format) != processConfig_.streamInfo.format) { // In plan
121 AUDIO_WARNING_LOG("Unequal format, in server: %{public}d, in client: %{public}d", sampleSpec->format,
122 processConfig_.streamInfo.format);
123 }
124 byteSizePerFrame_ = pa_frame_size(sampleSpec);
125
126 // Get min buffer size in frame
127 const pa_buffer_attr *bufferAttr = pa_stream_get_buffer_attr(paStream_);
128 if (bufferAttr == nullptr) {
129 int32_t count = ++bufferNullCount_;
130 AUDIO_ERR_LOG("pa_stream_get_buffer_attr returned nullptr count is %{public}d", count);
131 if (count >= 5) { // bufferAttr is nullptr 5 times, reboot audioserver
132 sleep(3); // sleep 3 seconds to dump stacktrace
133 AudioXCollie audioXCollie("AudioServer::Kill", 1, nullptr, nullptr, 2); // 2 means RECOVERY
134 sleep(2); // sleep 2 seconds to dump stacktrace
135 }
136 return ERR_OPERATION_FAILED;
137 }
138 bufferNullCount_ = 0;
139 minBufferSize_ = (size_t)bufferAttr->minreq;
140 if (byteSizePerFrame_ == 0) {
141 AUDIO_ERR_LOG("byteSizePerFrame_ should not be zero.");
142 return ERR_INVALID_PARAM;
143 }
144 spanSizeInFrame_ = minBufferSize_ / byteSizePerFrame_;
145
146 lock.Unlock();
147 // In plan: Get data from xml
148 effectSceneName_ = processConfig_.rendererInfo.sceneType;
149
150 clientVolume_ = 1.0f;
151 ResetOffload();
152
153 return SUCCESS;
154 }
155
Start()156 int32_t PaRendererStreamImpl::Start()
157 {
158 AUDIO_INFO_LOG("Enter");
159 PaLockGuard lock(mainloop_);
160 if (CheckReturnIfStreamInvalid(paStream_, ERR_ILLEGAL_STATE) < 0) {
161 return ERR_ILLEGAL_STATE;
162 }
163 pa_operation *operation = nullptr;
164
165 pa_stream_state_t state = pa_stream_get_state(paStream_);
166 if (state != PA_STREAM_READY) {
167 return ERR_OPERATION_FAILED;
168 }
169
170 streamCmdStatus_ = 0;
171 operation = pa_stream_cork(paStream_, 0, PAStreamStartSuccessCb, reinterpret_cast<void *>(this));
172 CHECK_AND_RETURN_RET_LOG(operation != nullptr, ERR_OPERATION_FAILED, "pa_stream_cork operation is null");
173 pa_operation_unref(operation);
174
175 std::shared_ptr<AudioEffectVolume> audioEffectVolume = AudioEffectVolume::GetInstance();
176 if (audioEffectVolume != nullptr) {
177 std::string sessionIDTemp = std::to_string(streamIndex_);
178 audioEffectVolume->SetStreamVolume(sessionIDTemp, clientVolume_);
179 }
180
181 return SUCCESS;
182 }
183
Pause(bool isStandby)184 int32_t PaRendererStreamImpl::Pause(bool isStandby)
185 {
186 AUDIO_INFO_LOG("Enter");
187 PaLockGuard palock(mainloop_, 1);
188 if (CheckReturnIfStreamInvalid(paStream_, ERR_ILLEGAL_STATE) < 0) {
189 return ERR_ILLEGAL_STATE;
190 }
191 pa_operation *operation = nullptr;
192 pa_stream_state_t state = pa_stream_get_state(paStream_);
193 if (state != PA_STREAM_READY) {
194 AUDIO_ERR_LOG("Stream Stop Failed");
195 return ERR_OPERATION_FAILED;
196 }
197 pa_proplist *propList = pa_proplist_new();
198 if (propList != nullptr) {
199 pa_proplist_sets(propList, "fadeoutPause", "1");
200 pa_operation *updatePropOperation = pa_stream_proplist_update(paStream_, PA_UPDATE_REPLACE, propList,
201 nullptr, nullptr);
202 pa_proplist_free(propList);
203 CHECK_AND_RETURN_RET_LOG(updatePropOperation != nullptr, ERR_OPERATION_FAILED, "updatePropOp is nullptr");
204 pa_operation_unref(updatePropOperation);
205 AUDIO_INFO_LOG("pa_stream_proplist_update done");
206 if (!offloadEnable_) {
207 palock.Unlock();
208 {
209 std::unique_lock<std::mutex> lock(fadingMutex_);
210 const int32_t WAIT_TIME_MS = 40;
211 fadingCondition_.wait_for(lock, std::chrono::milliseconds(WAIT_TIME_MS));
212 }
213 palock.Relock();
214 }
215 }
216 isStandbyPause_ = isStandby;
217 operation = pa_stream_cork(paStream_, 1, PAStreamPauseSuccessCb, reinterpret_cast<void *>(this));
218 pa_operation_unref(operation);
219 CHECK_AND_RETURN_RET_LOG(operation != nullptr, ERR_OPERATION_FAILED, "pa_stream_cork operation is null");
220 palock.Unlock();
221
222 std::shared_ptr<AudioEffectVolume> audioEffectVolume = AudioEffectVolume::GetInstance();
223 if (audioEffectVolume != nullptr) {
224 std::string sessionIDTemp = std::to_string(streamIndex_);
225 audioEffectVolume->StreamVolumeDelete(sessionIDTemp);
226 }
227
228 return SUCCESS;
229 }
230
Flush()231 int32_t PaRendererStreamImpl::Flush()
232 {
233 AUDIO_PRERELEASE_LOGI("Enter");
234 PaLockGuard lock(mainloop_);
235 if (CheckReturnIfStreamInvalid(paStream_, ERR_ILLEGAL_STATE) < 0) {
236 return ERR_ILLEGAL_STATE;
237 }
238
239 pa_operation *operation = nullptr;
240 pa_stream_state_t state = pa_stream_get_state(paStream_);
241 if (state != PA_STREAM_READY) {
242 AUDIO_ERR_LOG("Stream Flush Failed");
243 return ERR_OPERATION_FAILED;
244 }
245
246 streamFlushStatus_ = 0;
247 operation = pa_stream_flush(paStream_, PAStreamFlushSuccessCb, reinterpret_cast<void *>(this));
248 if (operation == nullptr) {
249 AUDIO_ERR_LOG("Stream Flush Operation Failed");
250 return ERR_OPERATION_FAILED;
251 }
252 Trace trace("PaRendererStreamImpl::InitAudioEffectChainDynamic");
253 if (effectMode_ == EFFECT_DEFAULT) {
254 AudioEffectChainManager::GetInstance()->InitAudioEffectChainDynamic(effectSceneName_);
255 }
256 pa_operation_unref(operation);
257 return SUCCESS;
258 }
259
Drain()260 int32_t PaRendererStreamImpl::Drain()
261 {
262 AUDIO_INFO_LOG("Enter");
263 PaLockGuard lock(mainloop_);
264 if (CheckReturnIfStreamInvalid(paStream_, ERR_ILLEGAL_STATE) < 0) {
265 return ERR_ILLEGAL_STATE;
266 }
267 isDrain_ = true;
268
269 pa_operation *operation = nullptr;
270 pa_stream_state_t state = pa_stream_get_state(paStream_);
271 if (state != PA_STREAM_READY) {
272 AUDIO_ERR_LOG("Stream drain failed, state is not ready");
273 return ERR_OPERATION_FAILED;
274 }
275 streamDrainStatus_ = 0;
276 operation = pa_stream_drain(paStream_, PAStreamDrainSuccessCb, reinterpret_cast<void *>(this));
277 pa_operation_unref(operation);
278 return SUCCESS;
279 }
280
Stop()281 int32_t PaRendererStreamImpl::Stop()
282 {
283 AUDIO_INFO_LOG("Enter");
284 state_ = STOPPING;
285 PaLockGuard palock(mainloop_);
286
287 if (CheckReturnIfStreamInvalid(paStream_, ERR_ILLEGAL_STATE) < 0) {
288 return ERR_ILLEGAL_STATE;
289 }
290
291 pa_proplist *propList = pa_proplist_new();
292 if (propList != nullptr) {
293 pa_proplist_sets(propList, "fadeoutPause", "1");
294 pa_operation *updatePropOperation = pa_stream_proplist_update(paStream_, PA_UPDATE_REPLACE, propList,
295 nullptr, nullptr);
296 pa_proplist_free(propList);
297 CHECK_AND_RETURN_RET_LOG(updatePropOperation != nullptr, ERR_OPERATION_FAILED, "updatePropOp is nullptr");
298 pa_operation_unref(updatePropOperation);
299 AUDIO_INFO_LOG("pa_stream_proplist_update done");
300 if (!offloadEnable_) {
301 palock.Unlock();
302 {
303 std::unique_lock<std::mutex> lock(fadingMutex_);
304 const int32_t WAIT_TIME_MS = 20;
305 fadingCondition_.wait_for(lock, std::chrono::milliseconds(WAIT_TIME_MS));
306 }
307 palock.Relock();
308 }
309 }
310
311 pa_operation *operation = pa_stream_cork(paStream_, 1, PaRendererStreamImpl::PAStreamAsyncStopSuccessCb,
312 reinterpret_cast<void *>(this));
313 CHECK_AND_RETURN_RET_LOG(operation != nullptr, ERR_OPERATION_FAILED, "pa_stream_cork operation is null");
314 pa_operation_unref(operation);
315
316 std::shared_ptr<AudioEffectVolume> audioEffectVolume = AudioEffectVolume::GetInstance();
317 if (audioEffectVolume != nullptr) {
318 std::string sessionIDTemp = std::to_string(streamIndex_);
319 audioEffectVolume->StreamVolumeDelete(sessionIDTemp);
320 }
321
322 return SUCCESS;
323 }
324
Release()325 int32_t PaRendererStreamImpl::Release()
326 {
327 AUDIO_INFO_LOG("Enter");
328
329 if (state_ == RUNNING) {
330 PaLockGuard lock(mainloop_);
331 if (CheckReturnIfStreamInvalid(paStream_, ERR_ILLEGAL_STATE) < 0) {
332 return ERR_ILLEGAL_STATE;
333 }
334 pa_operation *operation = pa_stream_cork(paStream_, 1, nullptr, nullptr);
335 CHECK_AND_RETURN_RET_LOG(operation != nullptr, ERR_OPERATION_FAILED, "pa_stream_cork operation is null");
336 pa_operation_unref(operation);
337 }
338
339 std::shared_ptr<IStatusCallback> statusCallback = statusCallback_.lock();
340 if (statusCallback != nullptr) {
341 statusCallback->OnStatusUpdate(OPERATION_RELEASED);
342 }
343 state_ = RELEASED;
344
345 std::shared_ptr<AudioEffectVolume> audioEffectVolume = AudioEffectVolume::GetInstance();
346 if (audioEffectVolume != nullptr) {
347 std::string sessionIDTemp = std::to_string(streamIndex_);
348 audioEffectVolume->StreamVolumeDelete(sessionIDTemp);
349 }
350
351 PaLockGuard lock(mainloop_);
352 if (paStream_) {
353 pa_stream_set_state_callback(paStream_, nullptr, nullptr);
354 pa_stream_set_write_callback(paStream_, nullptr, nullptr);
355 pa_stream_set_latency_update_callback(paStream_, nullptr, nullptr);
356 pa_stream_set_underflow_callback(paStream_, nullptr, nullptr);
357 pa_stream_set_moved_callback(paStream_, nullptr, nullptr);
358 pa_stream_set_started_callback(paStream_, nullptr, nullptr);
359
360 pa_stream_disconnect(paStream_);
361 releasedFlag_ = true;
362 }
363
364 return SUCCESS;
365 }
366
GetStreamFramesWritten(uint64_t & framesWritten)367 int32_t PaRendererStreamImpl::GetStreamFramesWritten(uint64_t &framesWritten)
368 {
369 CHECK_AND_RETURN_RET_LOG(byteSizePerFrame_ != 0, ERR_ILLEGAL_STATE, "Error frame size");
370 framesWritten = totalBytesWritten_ / byteSizePerFrame_;
371 return SUCCESS;
372 }
373
GetCurrentTimeStamp(uint64_t & timestamp)374 int32_t PaRendererStreamImpl::GetCurrentTimeStamp(uint64_t ×tamp)
375 {
376 PaLockGuard lock(mainloop_);
377 if (CheckReturnIfStreamInvalid(paStream_, ERR_ILLEGAL_STATE) < 0) {
378 return ERR_ILLEGAL_STATE;
379 }
380 int32_t XcollieFlag = (1 | 2); // flag 1 generate log file, flag 2 die when timeout, restart server
381 AudioXCollie audioXCollie("PaRendererStreamImpl::GetCurrentTimeStamp", PA_STREAM_IMPL_TIMEOUT,
382 [](void *) {
383 AUDIO_ERR_LOG("pulseAudio timeout");
384 }, nullptr, XcollieFlag);
385
386 UpdatePaTimingInfo();
387
388 const pa_timing_info *info = pa_stream_get_timing_info(paStream_);
389 if (info == nullptr) {
390 AUDIO_ERR_LOG("pa_stream_get_timing_info failed");
391 return ERR_OPERATION_FAILED;
392 }
393
394 const pa_sample_spec *sampleSpec = pa_stream_get_sample_spec(paStream_);
395 timestamp = pa_bytes_to_usec(info->write_index, sampleSpec);
396 return SUCCESS;
397 }
398
GetCurrentPosition(uint64_t & framePosition,uint64_t & timestamp,uint64_t & latency)399 int32_t PaRendererStreamImpl::GetCurrentPosition(uint64_t &framePosition, uint64_t ×tamp, uint64_t &latency)
400 {
401 Trace trace("PaRendererStreamImpl::GetCurrentPosition");
402 PaLockGuard lock(mainloop_);
403 if (CheckReturnIfStreamInvalid(paStream_, ERR_ILLEGAL_STATE) < 0) {
404 return ERR_ILLEGAL_STATE;
405 }
406 int32_t XcollieFlag = (1 | 2); // flag 1 generate log file, flag 2 die when timeout, restart server
407 AudioXCollie audioXCollie("PaRendererStreamImpl::GetCurrentPosition", PA_STREAM_IMPL_TIMEOUT,
408 [](void *) { AUDIO_ERR_LOG("pulseAudio timeout"); }, nullptr, XcollieFlag);
409
410 pa_usec_t curTimeGetLatency = pa_rtclock_now();
411 if (curTimeGetLatency - preTimeGetPaLatency_ > AUDIO_CYCLE_TIME_US || firstGetPaLatency_) { // 20000 cycle time
412 UpdatePaTimingInfo();
413 firstGetPaLatency_ = false;
414 preTimeGetPaLatency_ = curTimeGetLatency;
415 }
416
417 const pa_timing_info *info = pa_stream_get_timing_info(paStream_);
418 CHECK_AND_RETURN_RET_LOG(info != nullptr, ERR_OPERATION_FAILED, "pa_stream_get_timing_info failed");
419 const pa_sample_spec *sampleSpec = pa_stream_get_sample_spec(paStream_);
420 uint64_t readIndex = pa_bytes_to_usec(info->read_index, sampleSpec);
421 framePosition = readIndex * sampleSpec->rate / AUDIO_US_PER_S;
422 latency = info->sink_usec * sampleSpec->rate / AUDIO_US_PER_S;
423 lock.Unlock();
424
425 // Processing data for algorithmic time delays
426 uint32_t algorithmLatency = GetEffectChainLatency();
427 if (!offloadEnable_) {
428 latency += algorithmLatency * sampleSpec->rate / AUDIO_MS_PER_S;
429 }
430 // Processing data for a2dpoffload time delays
431 uint32_t a2dpOffloadLatency = GetA2dpOffloadLatency();
432 latency += a2dpOffloadLatency * sampleSpec->rate / AUDIO_MS_PER_S;
433
434 timespec tm {};
435 clock_gettime(CLOCK_MONOTONIC, &tm);
436 timestamp = static_cast<uint64_t>(tm.tv_sec) * AUDIO_NS_PER_S + static_cast<uint64_t>(tm.tv_nsec);
437
438 AUDIO_DEBUG_LOG("Latency info: framePosition: %{public}" PRIu64 ",readIndex %{public}" PRIu64
439 ",timestamp %{public}" PRIu64 ", effect latency: %{public}u ms, a2dp offload latency: %{public}u ms",
440 framePosition, readIndex, timestamp, algorithmLatency, a2dpOffloadLatency);
441 return SUCCESS;
442 }
443
PAStreamUpdateTimingInfoSuccessCb(pa_stream * stream,int32_t success,void * userdata)444 void PaRendererStreamImpl::PAStreamUpdateTimingInfoSuccessCb(pa_stream *stream, int32_t success, void *userdata)
445 {
446 PaRendererStreamImpl *rendererStreamImpl = (PaRendererStreamImpl *)userdata;
447 pa_threaded_mainloop *mainLoop = (pa_threaded_mainloop *)rendererStreamImpl->mainloop_;
448 pa_threaded_mainloop_signal(mainLoop, 0);
449 }
450
GetLatency(uint64_t & latency)451 int32_t PaRendererStreamImpl::GetLatency(uint64_t &latency)
452 {
453 Trace trace("PaRendererStreamImpl::GetLatency");
454 int32_t XcollieFlag = (1 | 2); // flag 1 generate log file, flag 2 die when timeout, restart server
455 AudioXCollie audioXCollie("PaRendererStreamImpl::GetLatency", PA_STREAM_IMPL_TIMEOUT,
456 [](void *) {
457 AUDIO_ERR_LOG("pulseAudio timeout");
458 }, nullptr, XcollieFlag);
459 pa_usec_t curTimeGetLatency = pa_rtclock_now();
460 if (curTimeGetLatency - preTimeGetLatency_ < AUDIO_CYCLE_TIME_US && !firstGetLatency_) { // 20000 cycle time
461 latency = preLatency_;
462 return SUCCESS;
463 }
464 PaLockGuard lock(mainloop_);
465 if (CheckReturnIfStreamInvalid(paStream_, ERR_ILLEGAL_STATE) < 0) {
466 return ERR_ILLEGAL_STATE;
467 }
468 pa_usec_t paLatency {0};
469
470 UpdatePaTimingInfo();
471 const pa_timing_info *info = pa_stream_get_timing_info(paStream_);
472 CHECK_AND_RETURN_RET_LOG(info != nullptr, ERR_OPERATION_FAILED, "pa_stream_get_timing_info failed");
473 const pa_sample_spec *sampleSpec = pa_stream_get_sample_spec(paStream_);
474 uint64_t readIndex = pa_bytes_to_usec(info->read_index < 0 ? 0 : info->read_index, sampleSpec);
475 uint64_t writeIndex = pa_bytes_to_usec(info->write_index < 0 ? 0 : info->write_index, sampleSpec);
476 pa_usec_t usec = readIndex >= info->sink_usec ? readIndex - info->sink_usec : 0;
477 paLatency = writeIndex >= usec ? writeIndex - usec : 0;
478 lock.Unlock();
479
480 latency = paLatency;
481 uint32_t algorithmLatency = GetEffectChainLatency();
482 latency += offloadEnable_ ? 0 : algorithmLatency * AUDIO_US_PER_MS;
483 uint32_t a2dpOffloadLatency = GetA2dpOffloadLatency();
484 latency += a2dpOffloadLatency * AUDIO_US_PER_MS;
485 AUDIO_DEBUG_LOG("total latency: %{public}" PRIu64 ", pa latency: %{public}" PRIu64 ", algo latency: %{public}u ms"
486 ", a2dp offload latency: %{public}u ms, write: %{public}" PRIu64 ", read: %{public}" PRIu64 ", sink:%{public}"
487 PRIu64, latency, paLatency, algorithmLatency, a2dpOffloadLatency, writeIndex, readIndex, info->sink_usec);
488
489 preLatency_ = latency;
490 preTimeGetLatency_ = curTimeGetLatency;
491 firstGetLatency_ = false;
492 return SUCCESS;
493 }
494
GetEffectChainLatency()495 uint32_t PaRendererStreamImpl::GetEffectChainLatency()
496 {
497 AudioEffectChainManager *audioEffectChainManager = AudioEffectChainManager::GetInstance();
498 uint32_t algorithmLatency = 0;
499 if (audioEffectChainManager != nullptr) {
500 algorithmLatency = audioEffectChainManager->GetLatency(std::to_string(streamIndex_));
501 }
502 return algorithmLatency;
503 }
504
GetA2dpOffloadLatency()505 uint32_t PaRendererStreamImpl::GetA2dpOffloadLatency()
506 {
507 Trace trace("PaRendererStreamImpl::GetA2dpOffloadLatency");
508 uint32_t a2dpOffloadLatency = 0;
509 uint64_t a2dpOffloadSendDataSize = 0;
510 uint32_t a2dpOffloadTimestamp = 0;
511 auto& handle = PolicyHandler::GetInstance();
512 int32_t ret = handle.OffloadGetRenderPosition(a2dpOffloadLatency, a2dpOffloadSendDataSize, a2dpOffloadTimestamp);
513 if (ret != SUCCESS) {
514 AUDIO_ERR_LOG("OffloadGetRenderPosition failed");
515 }
516 return a2dpOffloadLatency;
517 }
518
SetRate(int32_t rate)519 int32_t PaRendererStreamImpl::SetRate(int32_t rate)
520 {
521 AUDIO_INFO_LOG("SetRate in");
522 PaLockGuard lock(mainloop_);
523 if (CheckReturnIfStreamInvalid(paStream_, ERR_ILLEGAL_STATE) < 0) {
524 return ERR_ILLEGAL_STATE;
525 }
526 uint32_t currentRate = processConfig_.streamInfo.samplingRate;
527 switch (rate) {
528 case RENDER_RATE_NORMAL:
529 break;
530 case RENDER_RATE_DOUBLE:
531 currentRate *= DOUBLE_VALUE;
532 break;
533 case RENDER_RATE_HALF:
534 currentRate /= DOUBLE_VALUE;
535 break;
536 default:
537 return ERR_INVALID_PARAM;
538 }
539 renderRate_ = rate;
540
541 pa_operation *operation = pa_stream_update_sample_rate(paStream_, currentRate, nullptr, nullptr);
542 if (operation != nullptr) {
543 pa_operation_unref(operation);
544 } else {
545 AUDIO_ERR_LOG("SetRate: operation is nullptr");
546 }
547 return SUCCESS;
548 }
549
SetLowPowerVolume(float powerVolume)550 int32_t PaRendererStreamImpl::SetLowPowerVolume(float powerVolume)
551 {
552 AUDIO_INFO_LOG("SetLowPowerVolume: %{public}f", powerVolume);
553 PaLockGuard lock(mainloop_);
554 if (CheckReturnIfStreamInvalid(paStream_, ERR_ILLEGAL_STATE) < 0) {
555 return ERR_ILLEGAL_STATE;
556 }
557
558 /* Validate and return INVALID_PARAMS error */
559 if ((powerVolume < MIN_STREAM_VOLUME_LEVEL) || (powerVolume > MAX_STREAM_VOLUME_LEVEL)) {
560 AUDIO_ERR_LOG("Invalid Power Volume Set!");
561 return -1;
562 }
563
564 powerVolumeFactor_ = powerVolume;
565 pa_proplist *propList = pa_proplist_new();
566 if (propList == nullptr) {
567 AUDIO_ERR_LOG("pa_proplist_new failed");
568 return ERR_OPERATION_FAILED;
569 }
570
571 pa_proplist_sets(propList, "stream.powerVolumeFactor", std::to_string(powerVolumeFactor_).c_str());
572 pa_operation *updatePropOperation = pa_stream_proplist_update(paStream_, PA_UPDATE_REPLACE, propList,
573 nullptr, nullptr);
574 pa_proplist_free(propList);
575 CHECK_AND_RETURN_RET_LOG(updatePropOperation != nullptr, ERR_OPERATION_FAILED, "updatePropOperation is nullptr");
576 pa_operation_unref(updatePropOperation);
577
578 // In plan: Call reset volume
579
580 return SUCCESS;
581 }
582
GetLowPowerVolume(float & powerVolume)583 int32_t PaRendererStreamImpl::GetLowPowerVolume(float &powerVolume)
584 {
585 powerVolume = powerVolumeFactor_;
586 return SUCCESS;
587 }
588
SetAudioEffectMode(int32_t effectMode)589 int32_t PaRendererStreamImpl::SetAudioEffectMode(int32_t effectMode)
590 {
591 AUDIO_INFO_LOG("SetAudioEffectMode: %{public}d", effectMode);
592 PaLockGuard lock(mainloop_);
593 if (CheckReturnIfStreamInvalid(paStream_, ERR_ILLEGAL_STATE) < 0) {
594 return ERR_ILLEGAL_STATE;
595 }
596
597 effectMode_ = effectMode;
598 const std::string effectModeName = GetEffectModeName(effectMode_);
599
600 pa_proplist *propList = pa_proplist_new();
601 if (propList == nullptr) {
602 AUDIO_ERR_LOG("pa_proplist_new failed");
603 return ERR_OPERATION_FAILED;
604 }
605
606 pa_proplist_sets(propList, "scene.mode", effectModeName.c_str());
607 pa_operation *updatePropOperation = pa_stream_proplist_update(paStream_, PA_UPDATE_REPLACE, propList,
608 nullptr, nullptr);
609 pa_proplist_free(propList);
610 CHECK_AND_RETURN_RET_LOG(updatePropOperation != nullptr, ERR_OPERATION_FAILED, "updatePropOperation is nullptr");
611 pa_operation_unref(updatePropOperation);
612
613 return SUCCESS;
614 }
615
GetEffectModeName(int32_t effectMode)616 const std::string PaRendererStreamImpl::GetEffectModeName(int32_t effectMode)
617 {
618 std::string name;
619 switch (effectMode) {
620 case 0: // AudioEffectMode::EFFECT_NONE
621 name = "EFFECT_NONE";
622 break;
623 default:
624 name = "EFFECT_DEFAULT";
625 }
626
627 const std::string modeName = name;
628 return modeName;
629 }
630
GetAudioEffectMode(int32_t & effectMode)631 int32_t PaRendererStreamImpl::GetAudioEffectMode(int32_t &effectMode)
632 {
633 effectMode = effectMode_;
634 return SUCCESS;
635 }
636
SetPrivacyType(int32_t privacyType)637 int32_t PaRendererStreamImpl::SetPrivacyType(int32_t privacyType)
638 {
639 AUDIO_DEBUG_LOG("SetInnerCapturerState: %{public}d", privacyType);
640 privacyType_ = privacyType;
641 return SUCCESS;
642 }
643
GetPrivacyType(int32_t & privacyType)644 int32_t PaRendererStreamImpl::GetPrivacyType(int32_t &privacyType)
645 {
646 privacyType_ = privacyType;
647 return SUCCESS;
648 }
649
650
RegisterStatusCallback(const std::weak_ptr<IStatusCallback> & callback)651 void PaRendererStreamImpl::RegisterStatusCallback(const std::weak_ptr<IStatusCallback> &callback)
652 {
653 AUDIO_DEBUG_LOG("RegisterStatusCallback in");
654 statusCallback_ = callback;
655 }
656
RegisterWriteCallback(const std::weak_ptr<IWriteCallback> & callback)657 void PaRendererStreamImpl::RegisterWriteCallback(const std::weak_ptr<IWriteCallback> &callback)
658 {
659 AUDIO_DEBUG_LOG("RegisterWriteCallback in");
660 writeCallback_ = callback;
661 }
662
DequeueBuffer(size_t length)663 BufferDesc PaRendererStreamImpl::DequeueBuffer(size_t length)
664 {
665 BufferDesc bufferDesc;
666 bufferDesc.bufLength = length;
667 // DequeueBuffer is called in PAStreamWriteCb which is running in mainloop, so don't need lock mainloop.
668 pa_stream_begin_write(paStream_, reinterpret_cast<void **>(&bufferDesc.buffer), &bufferDesc.bufLength);
669 return bufferDesc;
670 }
671
EnqueueBuffer(const BufferDesc & bufferDesc)672 int32_t PaRendererStreamImpl::EnqueueBuffer(const BufferDesc &bufferDesc)
673 {
674 Trace trace("PaRendererStreamImpl::EnqueueBuffer " + std::to_string(bufferDesc.bufLength) + " totalBytesWritten" +
675 std::to_string(totalBytesWritten_));
676 int32_t error = 0;
677 if (offloadEnable_) {
678 error = OffloadUpdatePolicyInWrite();
679 CHECK_AND_RETURN_RET_LOG(error == SUCCESS, error, "OffloadUpdatePolicyInWrite failed");
680 }
681
682 // EnqueueBuffer is called in mainloop in most cases and don't need lock.
683 PaLockGuard palock(mainloop_, 1);
684
685 if (paStream_ == nullptr) {
686 AUDIO_ERR_LOG("paStream is nullptr");
687 return ERR_ILLEGAL_STATE;
688 }
689
690 error = pa_stream_write(paStream_, static_cast<void*>(bufferDesc.buffer), bufferDesc.bufLength, nullptr,
691 0LL, PA_SEEK_RELATIVE);
692 if (error < 0) {
693 AUDIO_ERR_LOG("Write stream failed");
694 pa_stream_cancel_write(paStream_);
695 }
696 totalBytesWritten_ += bufferDesc.bufLength;
697 return SUCCESS;
698 }
699
PAStreamWriteCb(pa_stream * stream,size_t length,void * userdata)700 void PaRendererStreamImpl::PAStreamWriteCb(pa_stream *stream, size_t length, void *userdata)
701 {
702 CHECK_AND_RETURN_LOG(userdata, "PAStreamWriteCb: userdata is null");
703
704 std::weak_ptr<PaRendererStreamImpl> paRendererStreamWeakPtr;
705 if (rendererStreamInstanceMap_.Find(userdata, paRendererStreamWeakPtr) == false) {
706 AUDIO_ERR_LOG("streamImpl is nullptr");
707 return;
708 }
709 auto streamImpl = paRendererStreamWeakPtr.lock();
710 CHECK_AND_RETURN_LOG(streamImpl, "PAStreamWriteCb: userdata is null");
711
712 Trace trace("PaRendererStreamImpl::PAStreamWriteCb sink-input:" + std::to_string(streamImpl->sinkInputIndex_) +
713 " length:" + std::to_string(length));
714 std::shared_ptr<IWriteCallback> writeCallback = streamImpl->writeCallback_.lock();
715 if (writeCallback != nullptr) {
716 writeCallback->OnWriteData(length);
717 } else {
718 AUDIO_ERR_LOG("Write callback is nullptr");
719 }
720 }
721
PAStreamMovedCb(pa_stream * stream,void * userdata)722 void PaRendererStreamImpl::PAStreamMovedCb(pa_stream *stream, void *userdata)
723 {
724 CHECK_AND_RETURN_LOG(userdata, "PAStreamMovedCb: userdata is null");
725
726 // get stream informations.
727 uint32_t deviceIndex = pa_stream_get_device_index(stream); // pa_context_get_sink_info_by_index
728 uint32_t streamIndex = pa_stream_get_index(stream); // get pa_stream index
729
730 // Return 1 if the sink or source this stream is connected to has been suspended.
731 // This will return 0 if not, and a negative value on error.
732 int res = pa_stream_is_suspended(stream);
733 AUDIO_WARNING_LOG("PAstream:[%{public}d] moved to index:[%{public}d] suspended:[%{public}d]",
734 streamIndex, deviceIndex, res);
735 }
736
PAStreamUnderFlowCb(pa_stream * stream,void * userdata)737 void PaRendererStreamImpl::PAStreamUnderFlowCb(pa_stream *stream, void *userdata)
738 {
739 Trace trace("PaRendererStreamImpl::PAStreamUnderFlowCb");
740 CHECK_AND_RETURN_LOG(userdata, "userdata is null");
741
742 std::weak_ptr<PaRendererStreamImpl> paRendererStreamWeakPtr;
743 if (rendererStreamInstanceMap_.Find(userdata, paRendererStreamWeakPtr) == false) {
744 AUDIO_ERR_LOG("streamImpl is nullptr");
745 return;
746 }
747 auto streamImpl = paRendererStreamWeakPtr.lock();
748 CHECK_AND_RETURN_LOG(streamImpl, "PAStreamWriteCb: userdata is null");
749
750 streamImpl->underFlowCount_++;
751 std::shared_ptr<IStatusCallback> statusCallback = streamImpl->statusCallback_.lock();
752 if (statusCallback != nullptr) {
753 statusCallback->OnStatusUpdate(OPERATION_UNDERRUN);
754 }
755 AUDIO_WARNING_LOG("PaRendererStreamImpl underrun: %{public}d!", streamImpl->underFlowCount_);
756 }
757
PAStreamUnderFlowCountAddCb(pa_stream * stream,void * userdata)758 void PaRendererStreamImpl::PAStreamUnderFlowCountAddCb(pa_stream *stream, void *userdata)
759 {
760 Trace trace("PaRendererStreamImpl::PAStreamUnderFlowCountAddCb");
761 CHECK_AND_RETURN_LOG(userdata, "userdata is null");
762
763 std::weak_ptr<PaRendererStreamImpl> paRendererStreamWeakPtr;
764 if (rendererStreamInstanceMap_.Find(userdata, paRendererStreamWeakPtr) == false) {
765 AUDIO_ERR_LOG("streamImpl is nullptr");
766 return;
767 }
768 auto streamImpl = paRendererStreamWeakPtr.lock();
769 CHECK_AND_RETURN_LOG(streamImpl, "PAStreamWriteCb: userdata is null");
770
771 std::shared_ptr<IStatusCallback> statusCallback = streamImpl->statusCallback_.lock();
772 if (statusCallback != nullptr) {
773 statusCallback->OnStatusUpdate(OPERATION_UNDERFLOW);
774 }
775 }
776
PAStreamSetStartedCb(pa_stream * stream,void * userdata)777 void PaRendererStreamImpl::PAStreamSetStartedCb(pa_stream *stream, void *userdata)
778 {
779 CHECK_AND_RETURN_LOG(userdata, "PAStreamSetStartedCb: userdata is null");
780 AUDIO_PRERELEASE_LOGI("PAStreamSetStartedCb");
781 Trace trace("PaRendererStreamImpl::PAStreamSetStartedCb");
782 }
783
PAStreamStartSuccessCb(pa_stream * stream,int32_t success,void * userdata)784 void PaRendererStreamImpl::PAStreamStartSuccessCb(pa_stream *stream, int32_t success, void *userdata)
785 {
786 AUDIO_INFO_LOG("PAStreamStartSuccessCb in");
787 CHECK_AND_RETURN_LOG(userdata, "PAStreamStartSuccessCb: userdata is null");
788
789 std::weak_ptr<PaRendererStreamImpl> paRendererStreamWeakPtr;
790 if (rendererStreamInstanceMap_.Find(userdata, paRendererStreamWeakPtr) == false) {
791 AUDIO_ERR_LOG("streamImpl is nullptr");
792 return;
793 }
794 auto streamImpl = paRendererStreamWeakPtr.lock();
795 CHECK_AND_RETURN_LOG(streamImpl, "PAStreamWriteCb: userdata is null");
796
797 streamImpl->state_ = RUNNING;
798 streamImpl->offloadTsLast_ = 0;
799 std::shared_ptr<IStatusCallback> statusCallback = streamImpl->statusCallback_.lock();
800 if (statusCallback != nullptr) {
801 statusCallback->OnStatusUpdate(OPERATION_STARTED);
802 }
803 streamImpl->streamCmdStatus_ = success;
804 }
805
PAStreamPauseSuccessCb(pa_stream * stream,int32_t success,void * userdata)806 void PaRendererStreamImpl::PAStreamPauseSuccessCb(pa_stream *stream, int32_t success, void *userdata)
807 {
808 CHECK_AND_RETURN_LOG(userdata, "PAStreamPauseSuccessCb: userdata is null");
809
810 std::weak_ptr<PaRendererStreamImpl> paRendererStreamWeakPtr;
811 if (rendererStreamInstanceMap_.Find(userdata, paRendererStreamWeakPtr) == false) {
812 AUDIO_ERR_LOG("streamImpl is nullptr");
813 return;
814 }
815 auto streamImpl = paRendererStreamWeakPtr.lock();
816 CHECK_AND_RETURN_LOG(streamImpl, "PAStreamWriteCb: userdata is null");
817
818 streamImpl->state_ = PAUSED;
819 if (streamImpl->offloadEnable_ && !streamImpl->isStandbyPause_) {
820 streamImpl->offloadTsLast_ = 0;
821 streamImpl->ResetOffload();
822 }
823 std::shared_ptr<IStatusCallback> statusCallback = streamImpl->statusCallback_.lock();
824 if (statusCallback != nullptr) {
825 statusCallback->OnStatusUpdate(OPERATION_PAUSED);
826 }
827 streamImpl->streamCmdStatus_ = success;
828 }
829
PAStreamFlushSuccessCb(pa_stream * stream,int32_t success,void * userdata)830 void PaRendererStreamImpl::PAStreamFlushSuccessCb(pa_stream *stream, int32_t success, void *userdata)
831 {
832 CHECK_AND_RETURN_LOG(userdata, "PAStreamFlushSuccessCb: userdata is null");
833 std::weak_ptr<PaRendererStreamImpl> paRendererStreamWeakPtr;
834 if (rendererStreamInstanceMap_.Find(userdata, paRendererStreamWeakPtr) == false) {
835 AUDIO_ERR_LOG("streamImpl is nullptr");
836 return;
837 }
838 auto streamImpl = paRendererStreamWeakPtr.lock();
839 CHECK_AND_RETURN_LOG(streamImpl, "Userdata is null");
840
841 std::shared_ptr<IStatusCallback> statusCallback = streamImpl->statusCallback_.lock();
842 if (statusCallback != nullptr) {
843 statusCallback->OnStatusUpdate(OPERATION_FLUSHED);
844 }
845 streamImpl->streamFlushStatus_ = success;
846 }
847
PAStreamDrainSuccessCb(pa_stream * stream,int32_t success,void * userdata)848 void PaRendererStreamImpl::PAStreamDrainSuccessCb(pa_stream *stream, int32_t success, void *userdata)
849 {
850 CHECK_AND_RETURN_LOG(userdata, "PAStreamDrainSuccessCb: userdata is null");
851
852 std::weak_ptr<PaRendererStreamImpl> paRendererStreamWeakPtr;
853 if (rendererStreamInstanceMap_.Find(userdata, paRendererStreamWeakPtr) == false) {
854 AUDIO_ERR_LOG("streamImpl is nullptr");
855 return;
856 }
857 auto streamImpl = paRendererStreamWeakPtr.lock();
858 CHECK_AND_RETURN_LOG(streamImpl, "PAStreamWriteCb: userdata is null");
859
860 std::shared_ptr<IStatusCallback> statusCallback = streamImpl->statusCallback_.lock();
861 if (statusCallback != nullptr) {
862 statusCallback->OnStatusUpdate(OPERATION_DRAINED);
863 }
864 streamImpl->streamDrainStatus_ = success;
865 streamImpl->isDrain_ = false;
866 }
867
PAStreamDrainInStopCb(pa_stream * stream,int32_t success,void * userdata)868 void PaRendererStreamImpl::PAStreamDrainInStopCb(pa_stream *stream, int32_t success, void *userdata)
869 {
870 CHECK_AND_RETURN_LOG(userdata, "PAStreamDrainInStopCb: userdata is null");
871
872 PaRendererStreamImpl *streamImpl = static_cast<PaRendererStreamImpl *>(userdata);
873 pa_operation *operation = pa_stream_cork(streamImpl->paStream_, 1,
874 PaRendererStreamImpl::PAStreamAsyncStopSuccessCb, userdata);
875
876 CHECK_AND_RETURN_LOG(operation != nullptr, "pa_stream_cork operation is null");
877
878 pa_operation_unref(operation);
879 streamImpl->streamDrainStatus_ = success;
880 }
881
PAStreamAsyncStopSuccessCb(pa_stream * stream,int32_t success,void * userdata)882 void PaRendererStreamImpl::PAStreamAsyncStopSuccessCb(pa_stream *stream, int32_t success, void *userdata)
883 {
884 AUDIO_DEBUG_LOG("PAStreamAsyncStopSuccessCb in");
885 CHECK_AND_RETURN_LOG(userdata, "PAStreamAsyncStopSuccessCb: userdata is null");
886 std::weak_ptr<PaRendererStreamImpl> paRendererStreamWeakPtr;
887 if (rendererStreamInstanceMap_.Find(userdata, paRendererStreamWeakPtr) == false) {
888 AUDIO_ERR_LOG("streamImpl is nullptr");
889 return;
890 }
891 auto streamImpl = paRendererStreamWeakPtr.lock();
892 CHECK_AND_RETURN_LOG(streamImpl, "PAStreamWriteCb: userdata is null");
893
894 streamImpl->state_ = STOPPED;
895 std::shared_ptr<IStatusCallback> statusCallback = streamImpl->statusCallback_.lock();
896
897 if (statusCallback != nullptr) {
898 statusCallback->OnStatusUpdate(OPERATION_STOPPED);
899 }
900 }
901
GetMinimumBufferSize(size_t & minBufferSize) const902 int32_t PaRendererStreamImpl::GetMinimumBufferSize(size_t &minBufferSize) const
903 {
904 minBufferSize = minBufferSize_;
905 return SUCCESS;
906 }
907
GetByteSizePerFrame(size_t & byteSizePerFrame) const908 void PaRendererStreamImpl::GetByteSizePerFrame(size_t &byteSizePerFrame) const
909 {
910 byteSizePerFrame = byteSizePerFrame_;
911 }
912
GetSpanSizePerFrame(size_t & spanSizeInFrame) const913 void PaRendererStreamImpl::GetSpanSizePerFrame(size_t &spanSizeInFrame) const
914 {
915 spanSizeInFrame = spanSizeInFrame_;
916 }
917
SetStreamIndex(uint32_t index)918 void PaRendererStreamImpl::SetStreamIndex(uint32_t index)
919 {
920 AUDIO_INFO_LOG("Using index/sessionId %{public}d", index);
921 streamIndex_ = index;
922 }
923
GetStreamIndex()924 uint32_t PaRendererStreamImpl::GetStreamIndex()
925 {
926 return streamIndex_;
927 }
928
AbortCallback(int32_t abortTimes)929 void PaRendererStreamImpl::AbortCallback(int32_t abortTimes)
930 {
931 abortFlag_ += abortTimes;
932 }
933
934 // offload
935
GetWritableSize()936 size_t PaRendererStreamImpl::GetWritableSize()
937 {
938 PaLockGuard lock(mainloop_, 1);
939 if (paStream_ == nullptr) {
940 return 0;
941 }
942 return pa_stream_writable_size(paStream_);
943 }
944
OffloadSetVolume(float volume)945 int32_t PaRendererStreamImpl::OffloadSetVolume(float volume)
946 {
947 if (!offloadEnable_) {
948 return ERR_OPERATION_FAILED;
949 }
950 IAudioRendererSink *audioRendererSinkInstance = IAudioRendererSink::GetInstance("offload", "");
951
952 if (audioRendererSinkInstance == nullptr) {
953 AUDIO_ERR_LOG("Renderer is null.");
954 return ERROR;
955 }
956 return audioRendererSinkInstance->SetVolume(volume, volume);
957 }
958
UpdateSpatializationState(bool spatializationEnabled,bool headTrackingEnabled)959 int32_t PaRendererStreamImpl::UpdateSpatializationState(bool spatializationEnabled, bool headTrackingEnabled)
960 {
961 PaLockGuard lock(mainloop_);
962 if (CheckReturnIfStreamInvalid(paStream_, ERR_ILLEGAL_STATE) < 0) {
963 return ERR_ILLEGAL_STATE;
964 }
965
966 pa_proplist *propList = pa_proplist_new();
967 if (propList == nullptr) {
968 AUDIO_ERR_LOG("pa_proplist_new failed");
969 return ERR_OPERATION_FAILED;
970 }
971
972 pa_proplist_sets(propList, "spatialization.enabled", std::to_string(spatializationEnabled).c_str());
973 pa_proplist_sets(propList, "headtracking.enabled", std::to_string(headTrackingEnabled).c_str());
974 pa_operation *updatePropOperation = pa_stream_proplist_update(paStream_, PA_UPDATE_REPLACE, propList,
975 nullptr, nullptr);
976 pa_proplist_free(propList);
977 CHECK_AND_RETURN_RET_LOG(updatePropOperation != nullptr, ERR_OPERATION_FAILED, "updatePropOperation is nullptr");
978 pa_operation_unref(updatePropOperation);
979
980 return SUCCESS;
981 }
982
OffloadGetPresentationPosition(uint64_t & frames,int64_t & timeSec,int64_t & timeNanoSec)983 int32_t PaRendererStreamImpl::OffloadGetPresentationPosition(uint64_t& frames, int64_t& timeSec, int64_t& timeNanoSec)
984 {
985 auto *audioRendererSinkInstance = static_cast<IOffloadAudioRendererSink*> (IAudioRendererSink::GetInstance(
986 "offload", ""));
987
988 CHECK_AND_RETURN_RET_LOG(audioRendererSinkInstance != nullptr, ERROR, "Renderer is null.");
989 return audioRendererSinkInstance->GetPresentationPosition(frames, timeSec, timeNanoSec);
990 }
991
OffloadSetBufferSize(uint32_t sizeMs)992 int32_t PaRendererStreamImpl::OffloadSetBufferSize(uint32_t sizeMs)
993 {
994 auto *audioRendererSinkInstance = static_cast<IOffloadAudioRendererSink*> (IAudioRendererSink::GetInstance(
995 "offload", ""));
996
997 CHECK_AND_RETURN_RET_LOG(audioRendererSinkInstance != nullptr, ERROR, "Renderer is null.");
998 return audioRendererSinkInstance->SetBufferSize(sizeMs);
999 }
1000
GetOffloadApproximatelyCacheTime(uint64_t & timestamp,uint64_t & paWriteIndex,uint64_t & cacheTimeDsp,uint64_t & cacheTimePa)1001 int32_t PaRendererStreamImpl::GetOffloadApproximatelyCacheTime(uint64_t ×tamp, uint64_t &paWriteIndex,
1002 uint64_t &cacheTimeDsp, uint64_t &cacheTimePa)
1003 {
1004 if (!offloadEnable_) {
1005 return ERR_OPERATION_FAILED;
1006 }
1007 PaLockGuard lock(mainloop_);
1008 if (CheckReturnIfStreamInvalid(paStream_, ERR_ILLEGAL_STATE) < 0) {
1009 return ERR_ILLEGAL_STATE;
1010 }
1011
1012 pa_operation *operation = pa_stream_update_timing_info(paStream_, NULL, NULL);
1013 if (operation != nullptr) {
1014 pa_operation_unref(operation);
1015 } else {
1016 AUDIO_ERR_LOG("pa_stream_update_timing_info failed");
1017 }
1018
1019 const pa_timing_info *info = pa_stream_get_timing_info(paStream_);
1020 if (info == nullptr) {
1021 AUDIO_WARNING_LOG("pa_stream_get_timing_info failed");
1022 return SUCCESS;
1023 }
1024
1025 const pa_sample_spec *sampleSpec = pa_stream_get_sample_spec(paStream_);
1026 uint64_t readIndex = pa_bytes_to_usec(info->read_index, sampleSpec);
1027 uint64_t writeIndex = pa_bytes_to_usec(info->write_index, sampleSpec);
1028 timestamp = info->timestamp.tv_sec * AUDIO_US_PER_SECOND + info->timestamp.tv_usec;
1029 lock.Unlock();
1030
1031 uint64_t cacheTimeInPulse = writeIndex > readIndex ? writeIndex - readIndex : 0;
1032 cacheTimePa = cacheTimeInPulse;
1033 paWriteIndex = writeIndex;
1034
1035 bool first = offloadTsLast_ == 0;
1036 offloadTsLast_ = readIndex;
1037
1038 uint64_t frames = 0;
1039 int64_t timeSec = 0;
1040 int64_t timeNanoSec = 0;
1041 OffloadGetPresentationPosition(frames, timeSec, timeNanoSec);
1042 int64_t timeDelta = static_cast<int64_t>(timestamp) -
1043 static_cast<int64_t>(timeSec * AUDIO_US_PER_SECOND + timeNanoSec / AUDIO_NS_PER_US);
1044 int64_t framesInt = static_cast<int64_t>(frames) + timeDelta;
1045 framesInt = framesInt > 0 ? framesInt : 0;
1046 int64_t readIndexInt = static_cast<int64_t>(readIndex);
1047 if (framesInt + offloadTsOffset_ < readIndexInt - static_cast<int64_t>(
1048 (OFFLOAD_HDI_CACHE2 + MAX_LENGTH_OFFLOAD + OFFLOAD_BUFFER) * AUDIO_US_PER_MS) ||
1049 framesInt + offloadTsOffset_ > readIndexInt || first) {
1050 offloadTsOffset_ = readIndexInt - framesInt;
1051 }
1052 cacheTimeDsp = static_cast<uint64_t>(readIndexInt - (framesInt + offloadTsOffset_));
1053 return SUCCESS;
1054 }
1055
OffloadUpdatePolicyInWrite()1056 int32_t PaRendererStreamImpl::OffloadUpdatePolicyInWrite()
1057 {
1058 int error = 0;
1059 if ((lastOffloadUpdateFinishTime_ != 0) &&
1060 (std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()) > lastOffloadUpdateFinishTime_)) {
1061 AUDIO_INFO_LOG("PaWriteStream switching curTime %{public}" PRIu64 ", switchTime %{public}" PRIu64,
1062 std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()), lastOffloadUpdateFinishTime_);
1063 error = OffloadUpdatePolicy(offloadNextStateTargetPolicy_, true);
1064 }
1065 return error;
1066 }
1067
SyncOffloadMode()1068 void PaRendererStreamImpl::SyncOffloadMode()
1069 {
1070 std::shared_ptr<IStatusCallback> statusCallback = statusCallback_.lock();
1071 if (statusCallback != nullptr) {
1072 if (offloadEnable_) {
1073 statusCallback->OnStatusUpdate(OPERATION_SET_OFFLOAD_ENABLE);
1074 } else {
1075 statusCallback->OnStatusUpdate(OPERATION_UNSET_OFFLOAD_ENABLE);
1076 }
1077 }
1078 }
1079
ResetOffload()1080 void PaRendererStreamImpl::ResetOffload()
1081 {
1082 offloadEnable_ = false;
1083 SyncOffloadMode();
1084 offloadTsOffset_ = 0;
1085 offloadTsLast_ = 0;
1086 OffloadUpdatePolicy(OFFLOAD_DEFAULT, true);
1087 }
1088
OffloadUpdatePolicy(AudioOffloadType statePolicy,bool force)1089 int32_t PaRendererStreamImpl::OffloadUpdatePolicy(AudioOffloadType statePolicy, bool force)
1090 {
1091 // if possible turn on the buffer immediately(long buffer -> short buffer), turn it at once.
1092 if (statePolicy < offloadStatePolicy_ || offloadStatePolicy_ == OFFLOAD_DEFAULT || force) {
1093 AUDIO_DEBUG_LOG("Update statePolicy immediately: %{public}d -> %{public}d, force(%d)",
1094 offloadStatePolicy_, statePolicy, force);
1095 lastOffloadUpdateFinishTime_ = 0;
1096 PaLockGuard lock(mainloop_, 1);
1097 if (CheckReturnIfStreamInvalid(paStream_, ERR_ILLEGAL_STATE) < 0) {
1098 AUDIO_ERR_LOG("Set offload mode: invalid stream state, quit SetStreamOffloadMode due err");
1099 return ERR_ILLEGAL_STATE;
1100 }
1101 pa_proplist *propList = pa_proplist_new();
1102 CHECK_AND_RETURN_RET_LOG(propList != nullptr, ERR_OPERATION_FAILED, "pa_proplist_new failed");
1103 if (offloadEnable_) {
1104 pa_proplist_sets(propList, "stream.offload.enable", "1");
1105 } else {
1106 pa_proplist_sets(propList, "stream.offload.enable", "0");
1107 }
1108 pa_proplist_sets(propList, "stream.offload.statePolicy", std::to_string(statePolicy).c_str());
1109
1110 pa_operation *updatePropOperation =
1111 pa_stream_proplist_update(paStream_, PA_UPDATE_REPLACE, propList, nullptr, nullptr);
1112 if (updatePropOperation == nullptr) {
1113 AUDIO_ERR_LOG("pa_stream_proplist_update failed!");
1114 pa_proplist_free(propList);
1115 return ERR_OPERATION_FAILED;
1116 }
1117 pa_proplist_free(propList);
1118 pa_operation_unref(updatePropOperation);
1119
1120 if ((statePolicy != OFFLOAD_DEFAULT && offloadStatePolicy_ != OFFLOAD_DEFAULT) ||
1121 offloadStatePolicy_ == OFFLOAD_INACTIVE_BACKGROUND) {
1122 const uint32_t bufLenMs = statePolicy > 1 ? OFFLOAD_HDI_CACHE2 : OFFLOAD_HDI_CACHE1;
1123 OffloadSetBufferSize(bufLenMs);
1124 }
1125
1126 offloadStatePolicy_ = statePolicy;
1127 offloadNextStateTargetPolicy_ = statePolicy; // Fix here if sometimes can't cut into state 3
1128 } else {
1129 // Otherwise, hdi_sink.c's times detects the stateTarget change and switches later
1130 // this time is checked the PaWriteStream to check if the switch has been made
1131 AUDIO_DEBUG_LOG("Update statePolicy in 3 seconds: %{public}d -> %{public}d", offloadStatePolicy_, statePolicy);
1132 lastOffloadUpdateFinishTime_ = std::chrono::system_clock::to_time_t(
1133 std::chrono::system_clock::now() + std::chrono::seconds(3)); // add 3s latency to change offload state
1134 offloadNextStateTargetPolicy_ = statePolicy;
1135 }
1136
1137 return SUCCESS;
1138 }
1139
SetOffloadMode(int32_t state,bool isAppBack)1140 int32_t PaRendererStreamImpl::SetOffloadMode(int32_t state, bool isAppBack)
1141 {
1142 #ifdef FEATURE_POWER_MANAGER
1143 static const std::set<PowerMgr::PowerState> screenOffTable = {
1144 PowerMgr::PowerState::INACTIVE, PowerMgr::PowerState::STAND_BY,
1145 PowerMgr::PowerState::DOZE, PowerMgr::PowerState::SLEEP,
1146 PowerMgr::PowerState::HIBERNATE,
1147 };
1148 AudioOffloadType statePolicy = OFFLOAD_DEFAULT;
1149 auto powerState = static_cast<PowerMgr::PowerState>(state);
1150 if (screenOffTable.count(powerState)) {
1151 statePolicy = OFFLOAD_INACTIVE_BACKGROUND;
1152 } else {
1153 statePolicy = OFFLOAD_ACTIVE_FOREGROUND;
1154 }
1155
1156 if (statePolicy == OFFLOAD_DEFAULT) {
1157 AUDIO_ERR_LOG("impossible INPUT branch error");
1158 return ERR_OPERATION_FAILED;
1159 }
1160
1161 AUDIO_INFO_LOG("calling set stream offloadMode PowerState: %{public}d, isAppBack: %{public}d", state, isAppBack);
1162
1163 if (offloadNextStateTargetPolicy_ == statePolicy) {
1164 return SUCCESS;
1165 }
1166
1167 if ((offloadStatePolicy_ == offloadNextStateTargetPolicy_) && (offloadStatePolicy_ == statePolicy)) {
1168 return SUCCESS;
1169 }
1170
1171 offloadEnable_ = true;
1172 SyncOffloadMode();
1173 if (OffloadUpdatePolicy(statePolicy, false) != SUCCESS) {
1174 return ERR_OPERATION_FAILED;
1175 }
1176 #else
1177 AUDIO_INFO_LOG("SetStreamOffloadMode not available, FEATURE_POWER_MANAGER no define");
1178 #endif
1179 return SUCCESS;
1180 }
1181
UnsetOffloadMode()1182 int32_t PaRendererStreamImpl::UnsetOffloadMode()
1183 {
1184 offloadEnable_ = false;
1185 SyncOffloadMode();
1186 return OffloadUpdatePolicy(OFFLOAD_DEFAULT, true);
1187 }
1188
UpdateMaxLength(uint32_t maxLength)1189 int32_t PaRendererStreamImpl::UpdateMaxLength(uint32_t maxLength)
1190 {
1191 uint32_t tlength = 4; // 4 is tlength of dup playback
1192 uint32_t prebuf = 2; // 2 is prebuf of dup playback
1193 uint32_t maxlength = maxLength;
1194 AUDIO_INFO_LOG("dup playback stream tlength: %{public}u, maxlength: %{public}u prebuf: %{public}u", tlength,
1195 maxlength, prebuf);
1196
1197 PaLockGuard lock(mainloop_);
1198 const pa_sample_spec *sampleSpec = pa_stream_get_sample_spec(paStream_);
1199 pa_buffer_attr bufferAttr;
1200 bufferAttr.fragsize = static_cast<uint32_t>(-1);
1201 bufferAttr.prebuf = pa_usec_to_bytes(20 * PA_USEC_PER_MSEC * prebuf, sampleSpec); // 20 buf len in ms
1202 bufferAttr.maxlength = pa_usec_to_bytes(20 * PA_USEC_PER_MSEC * maxlength, sampleSpec); // 20 buf len in ms
1203 bufferAttr.tlength = pa_usec_to_bytes(20 * PA_USEC_PER_MSEC * tlength, sampleSpec); // 20 buf len in ms
1204 bufferAttr.minreq = pa_usec_to_bytes(20 * PA_USEC_PER_MSEC, sampleSpec); // 20 buf len in ms
1205
1206 pa_operation *operation = pa_stream_set_buffer_attr(paStream_, &bufferAttr, nullptr, nullptr);
1207 if (operation != nullptr) {
1208 pa_operation_unref(operation);
1209 }
1210 return SUCCESS;
1211 }
1212
GetAudioProcessConfig() const1213 AudioProcessConfig PaRendererStreamImpl::GetAudioProcessConfig() const noexcept
1214 {
1215 return processConfig_;
1216 }
1217
Peek(std::vector<char> * audioBuffer,int32_t & index)1218 int32_t PaRendererStreamImpl::Peek(std::vector<char> *audioBuffer, int32_t &index)
1219 {
1220 return SUCCESS;
1221 }
1222
ReturnIndex(int32_t index)1223 int32_t PaRendererStreamImpl::ReturnIndex(int32_t index)
1224 {
1225 return SUCCESS;
1226 }
1227 // offload end
1228
SetClientVolume(float clientVolume)1229 int32_t PaRendererStreamImpl::SetClientVolume(float clientVolume)
1230 {
1231 PaLockGuard lock(mainloop_);
1232 if (clientVolume < MIN_VOLUME || clientVolume > MAX_VOLUME) {
1233 AUDIO_ERR_LOG("SetClientVolume with invalid clientVolume %{public}f", clientVolume);
1234 return ERR_INVALID_PARAM;
1235 }
1236
1237 pa_proplist *propList = pa_proplist_new();
1238 if (propList == nullptr) {
1239 AUDIO_ERR_LOG("pa_proplist_new failed");
1240 return ERR_OPERATION_FAILED;
1241 }
1242
1243 AudioEffectChainManager *audioEffectChainManager = AudioEffectChainManager::GetInstance();
1244 audioEffectChainManager->StreamVolumeUpdate(std::to_string(streamIndex_), clientVolume);
1245
1246 pa_operation *updatePropOperation = pa_stream_proplist_update(paStream_, PA_UPDATE_REPLACE, propList,
1247 nullptr, nullptr);
1248 pa_proplist_free(propList);
1249 CHECK_AND_RETURN_RET_LOG(updatePropOperation != nullptr, ERR_OPERATION_FAILED, "updatePropOperation is nullptr");
1250 pa_operation_unref(updatePropOperation);
1251 AUDIO_PRERELEASE_LOGI("set client volume success");
1252
1253 return SUCCESS;
1254 }
1255
UpdatePaTimingInfo()1256 void PaRendererStreamImpl::UpdatePaTimingInfo()
1257 {
1258 pa_operation *operation = pa_stream_update_timing_info(paStream_, PAStreamUpdateTimingInfoSuccessCb, (void *)this);
1259 if (operation != nullptr) {
1260 auto start_time = std::chrono::steady_clock::now();
1261 while (pa_operation_get_state(operation) == PA_OPERATION_RUNNING) {
1262 if ((std::chrono::steady_clock::now() - start_time) > std::chrono::seconds(PA_STREAM_IMPL_TIMEOUT + 1)) {
1263 AUDIO_ERR_LOG("pa_stream_update_timing_info timeout");
1264 break;
1265 }
1266 pa_threaded_mainloop_wait(mainloop_);
1267 }
1268 pa_operation_unref(operation);
1269 } else {
1270 AUDIO_ERR_LOG("pa_stream_update_timing_info failed");
1271 }
1272 }
1273 } // namespace AudioStandard
1274 } // namespace OHOS
1275