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