1 /*
2 * Copyright (c) 2024 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 "NoneMixEngine"
17 #endif
18
19 #include "audio_common_converter.h"
20 #include "audio_errors.h"
21 #include "audio_service_log.h"
22 #include "audio_utils.h"
23 #include "common/hdi_adapter_info.h"
24 #include "manager/hdi_adapter_manager.h"
25 #include "sink/i_audio_render_sink.h"
26 #include "none_mix_engine.h"
27 #include "audio_performance_monitor.h"
28 #include "audio_volume.h"
29 #include "format_converter.h"
30 #include "audio_service.h"
31
32 namespace OHOS {
33 namespace AudioStandard {
34 constexpr int32_t DELTA_TIME = 4000000; // 4ms
35 constexpr int32_t PERIOD_NS = 20000000; // 20ms
36 constexpr int32_t AUDIO_US_PER_MS = 1000;
37 constexpr int32_t AUDIO_DEFAULT_LATENCY_US = 160000;
38 constexpr int32_t AUDIO_FRAME_WORK_LATENCY_US = 40000;
39 constexpr int32_t FADING_MS = 20; // 20ms
40 constexpr int32_t MAX_ERROR_COUNT = 50;
41 constexpr int16_t STEREO_CHANNEL_COUNT = 2;
42 constexpr int16_t HDI_STEREO_CHANNEL_LAYOUT = 3;
43 constexpr int16_t HDI_MONO_CHANNEL_LAYOUT = 4;
44 constexpr int32_t DIRECT_STOP_TIMEOUT_IN_SEC = 8; // 8S
45 constexpr int32_t DIRECT_SINK_STANDBY_TIMES = 8; // 8
46 const std::string THREAD_NAME = "noneMixThread";
47 const std::string VOIP_SINK_NAME = "voip";
48 const std::string DIRECT_SINK_NAME = "direct";
49 const char *SINK_ADAPTER_NAME = "primary";
50
NoneMixEngine()51 NoneMixEngine::NoneMixEngine()
52 : isVoip_(false),
53 isStart_(false),
54 isInit_(false),
55 failedCount_(0),
56 writeCount_(0),
57 fwkSyncTime_(0),
58 latency_(0),
59 stream_(nullptr),
60 startFadein_(false),
61 startFadeout_(false),
62 uChannel_(0),
63 uFormat_(sizeof(int32_t)),
64 uSampleRate_(0),
65 firstSetVolume_(true)
66 {
67 AUDIO_INFO_LOG("Constructor");
68 }
69
~NoneMixEngine()70 NoneMixEngine::~NoneMixEngine()
71 {
72 writeCount_ = 0;
73 failedCount_ = 0;
74 fwkSyncTime_ = 0;
75 if (playbackThread_) {
76 playbackThread_->Stop();
77 playbackThread_ = nullptr;
78 }
79 std::shared_ptr<IAudioRenderSink> sink = HdiAdapterManager::GetInstance().GetRenderSink(renderId_);
80 if (sink && sink->IsInited()) {
81 sink->Stop();
82 sink->DeInit();
83 }
84 HdiAdapterManager::GetInstance().ReleaseId(renderId_);
85 isStart_ = false;
86 startFadein_ = false;
87 startFadeout_ = false;
88 }
89
Init(const AudioDeviceDescriptor & type,bool isVoip)90 int32_t NoneMixEngine::Init(const AudioDeviceDescriptor &type, bool isVoip)
91 {
92 if (!isInit_) {
93 isVoip_ = isVoip;
94 device_ = type;
95 return SUCCESS;
96 }
97 if (type.deviceType_ != device_.deviceType_ || isVoip_ != isVoip) {
98 isVoip_ = isVoip;
99 device_ = type;
100 std::shared_ptr<IAudioRenderSink> sink = HdiAdapterManager::GetInstance().GetRenderSink(renderId_);
101 if (sink && sink->IsInited()) {
102 sink->Stop();
103 sink->DeInit();
104 }
105 HdiAdapterManager::GetInstance().ReleaseId(renderId_);
106 }
107 return SUCCESS;
108 }
109
Start()110 int32_t NoneMixEngine::Start()
111 {
112 AUDIO_INFO_LOG("Enter in");
113 int32_t ret = SUCCESS;
114 std::shared_ptr<IAudioRenderSink> sink = HdiAdapterManager::GetInstance().GetRenderSink(renderId_);
115 CHECK_AND_RETURN_RET_LOG(sink != nullptr, ERR_INVALID_HANDLE, "null sink");
116 CHECK_AND_RETURN_RET_LOG(sink->IsInited(), ERR_NOT_STARTED, "sink Not Inited! Init the sink first");
117 fwkSyncTime_ = static_cast<uint64_t>(ClockTime::GetCurNano());
118 writeCount_ = 0;
119 failedCount_ = 0;
120 if (!playbackThread_) {
121 playbackThread_ = std::make_unique<AudioThreadTask>(THREAD_NAME);
122 playbackThread_->RegisterJob([this] { this->MixStreams(); });
123 }
124 latency_ = 0;
125 if (!isStart_) {
126 startFadeout_ = false;
127 startFadein_ = true;
128 ret = sink->Start();
129 isStart_ = true;
130 }
131 if (!playbackThread_->CheckThreadIsRunning()) {
132 playbackThread_->Start();
133 }
134 return ret;
135 }
136
Stop()137 int32_t NoneMixEngine::Stop()
138 {
139 AUDIO_INFO_LOG("Enter");
140 int32_t ret = SUCCESS;
141 if (!isStart_) {
142 AUDIO_INFO_LOG("already stopped");
143 return ret;
144 }
145 AudioXCollie audioXCollie(
146 "NoneMixEngine::Stop", DIRECT_STOP_TIMEOUT_IN_SEC,
147 [this](void *) { AUDIO_ERR_LOG("%{public}d stop timeout", isVoip_); }, nullptr,
148 AUDIO_XCOLLIE_FLAG_LOG | AUDIO_XCOLLIE_FLAG_RECOVERY);
149
150 writeCount_ = 0;
151 failedCount_ = 0;
152 if (playbackThread_) {
153 startFadein_ = false;
154 startFadeout_ = true;
155 // wait until fadeout complete
156 std::unique_lock fadingLock(fadingMutex_);
157 cvFading_.wait_for(
158 fadingLock, std::chrono::milliseconds(FADING_MS), [this] { return (!(startFadein_ || startFadeout_)); });
159 playbackThread_->Stop();
160 playbackThread_ = nullptr;
161 }
162 ClockTime::RelativeSleep(PERIOD_NS * DIRECT_SINK_STANDBY_TIMES);
163 ret = StopAudioSink();
164 isStart_ = false;
165 return ret;
166 }
167
PauseAsync()168 void NoneMixEngine::PauseAsync()
169 {
170 // stop thread when failed 5 times,do not add logic inside.
171 if (playbackThread_ && playbackThread_->CheckThreadIsRunning()) {
172 playbackThread_->PauseAsync();
173 }
174 int32_t ret = StopAudioSink();
175 if (ret != SUCCESS) {
176 AUDIO_ERR_LOG("sink stop failed.ret:%{public}d", ret);
177 }
178 isStart_ = false;
179 }
180
StopAudioSink()181 int32_t NoneMixEngine::StopAudioSink()
182 {
183 int32_t ret = SUCCESS;
184 std::shared_ptr<IAudioRenderSink> sink = HdiAdapterManager::GetInstance().GetRenderSink(renderId_);
185 if (sink && sink->IsInited()) {
186 ret = sink->Stop();
187 } else {
188 AUDIO_ERR_LOG("sink is null or not init");
189 }
190 return ret;
191 }
192
Pause()193 int32_t NoneMixEngine::Pause()
194 {
195 AUDIO_INFO_LOG("Enter");
196 if (!isStart_) {
197 AUDIO_INFO_LOG("already stopped");
198 return SUCCESS;
199 }
200 AudioXCollie audioXCollie(
201 "NoneMixEngine::Pause", DIRECT_STOP_TIMEOUT_IN_SEC,
202 [this](void *) { AUDIO_ERR_LOG("%{public}d stop timeout", isVoip_); }, nullptr,
203 AUDIO_XCOLLIE_FLAG_LOG | AUDIO_XCOLLIE_FLAG_RECOVERY);
204
205 writeCount_ = 0;
206 failedCount_ = 0;
207 if (playbackThread_) {
208 startFadein_ = false;
209 startFadeout_ = true;
210 // wait until fadeout complete
211 std::unique_lock fadingLock(fadingMutex_);
212 cvFading_.wait_for(
213 fadingLock, std::chrono::milliseconds(FADING_MS), [this] { return (!(startFadein_ || startFadeout_)); });
214 playbackThread_->Pause();
215 }
216 ClockTime::RelativeSleep(PERIOD_NS * DIRECT_SINK_STANDBY_TIMES);
217 int32_t ret = StopAudioSink();
218 isStart_ = false;
219 return ret;
220 }
221
Flush()222 int32_t NoneMixEngine::Flush()
223 {
224 AUDIO_INFO_LOG("Enter");
225 return SUCCESS;
226 }
227
228 template <typename T, typename = std::enable_if_t<std::is_integral<T>::value>>
DoFadeInOut(T * dest,size_t count,bool isFadeOut,uint32_t channel)229 static void DoFadeInOut(T *dest, size_t count, bool isFadeOut, uint32_t channel)
230 {
231 if (count <= 0) {
232 return;
233 }
234 float fadeStep = 1.0f / count;
235 for (size_t i = 0; i < count; i++) {
236 float fadeFactor;
237 if (isFadeOut) {
238 fadeFactor = 1.0f - ((i + 1) * fadeStep);
239 } else {
240 fadeFactor = (i + 1) * fadeStep;
241 }
242 for (uint32_t j = 0; j < channel; j++) {
243 dest[i * channel + j] *= fadeFactor;
244 }
245 }
246 }
247
DoFadeinOut(bool isFadeOut,char * pBuffer,size_t bufferSize)248 void NoneMixEngine::DoFadeinOut(bool isFadeOut, char *pBuffer, size_t bufferSize)
249 {
250 CHECK_AND_RETURN_LOG(pBuffer != nullptr && bufferSize > 0 && uChannel_ > 0, "buffer is null.");
251 size_t dataLength = bufferSize / (static_cast<uint32_t>(uFormat_) * uChannel_);
252 if (uFormat_ == sizeof(int16_t)) {
253 AUDIO_INFO_LOG("int16 fading frame length:%{public}zu", dataLength);
254 DoFadeInOut(reinterpret_cast<int16_t *>(pBuffer), dataLength, isFadeOut, uChannel_);
255 } else if (uFormat_ == sizeof(int32_t)) {
256 AUDIO_INFO_LOG("int32 fading frame length:%{public}zu", dataLength);
257 DoFadeInOut(reinterpret_cast<int32_t *>(pBuffer), dataLength, isFadeOut, uChannel_);
258 }
259 if (isFadeOut) {
260 startFadeout_.store(false);
261 } else {
262 startFadein_.store(false);
263 }
264 }
265
AdjustVoipVolume()266 void NoneMixEngine::AdjustVoipVolume()
267 {
268 if (isVoip_) {
269 uint32_t streamIndx = stream_->GetStreamIndex();
270 AudioProcessConfig config = stream_->GetAudioProcessConfig();
271 AudioVolumeType volumeType = VolumeUtils::GetVolumeTypeFromStreamType(config.streamType);
272 float volumeBg = AudioVolume::GetInstance()->GetHistoryVolume(streamIndx);
273 float volumeEd = AudioVolume::GetInstance()->GetVolume(streamIndx, volumeType, std::string(SINK_ADAPTER_NAME));
274 if ((!firstSetVolume_ && volumeBg != volumeEd) || firstSetVolume_) {
275 AUDIO_INFO_LOG("Adjust voip volume");
276 AudioVolume::GetInstance()->SetHistoryVolume(streamIndx, volumeEd);
277 AudioVolume::GetInstance()->Monitor(streamIndx, true);
278 std::shared_ptr<IAudioRenderSink> sink = HdiAdapterManager::GetInstance().GetRenderSink(renderId_);
279 CHECK_AND_RETURN(sink != nullptr);
280 sink->SetVolume(volumeEd, volumeEd);
281 firstSetVolume_ = false;
282 }
283 }
284 }
285
DoRenderFrame(std::vector<char> & audioBufferConverted,int32_t index,int32_t appUid)286 void NoneMixEngine::DoRenderFrame(std::vector<char> &audioBufferConverted, int32_t index, int32_t appUid)
287 {
288 uint64_t written = 0;
289 std::shared_ptr<IAudioRenderSink> sink = HdiAdapterManager::GetInstance().GetRenderSink(renderId_);
290 CHECK_AND_RETURN(sink != nullptr);
291 sink->RenderFrame(*audioBufferConverted.data(), audioBufferConverted.size(), written);
292 stream_->ReturnIndex(index);
293 sink->UpdateAppsUid({appUid});
294 }
295
MixStreams()296 void NoneMixEngine::MixStreams()
297 {
298 if (stream_ == nullptr) {
299 StandbySleep();
300 return;
301 }
302 if (failedCount_ >= MAX_ERROR_COUNT) {
303 AUDIO_WARNING_LOG("failed count is overflow.");
304 PauseAsync();
305 return;
306 }
307 std::vector<char> audioBuffer;
308 int32_t appUid = stream_->GetAudioProcessConfig().appInfo.appUid;
309 int32_t index = -1;
310 int32_t result = stream_->Peek(&audioBuffer, index);
311
312 uint32_t sessionId = stream_->GetStreamIndex();
313 writeCount_++;
314 if (index < 0) {
315 AUDIO_WARNING_LOG("peek buffer failed.result:%{public}d,buffer size:%{public}d", result, index);
316 AudioPerformanceMonitor::GetInstance().RecordSilenceState(sessionId, true, PIPE_TYPE_DIRECT_OUT);
317 stream_->ReturnIndex(index);
318 failedCount_++;
319 if (startFadeout_) {
320 startFadeout_.store(false);
321 cvFading_.notify_all();
322 return;
323 }
324 ClockTime::RelativeSleep(PERIOD_NS);
325 return;
326 }
327 AudioPerformanceMonitor::GetInstance().RecordSilenceState(sessionId, false, PIPE_TYPE_DIRECT_OUT);
328 AdjustVoipVolume();
329 failedCount_ = 0;
330 // fade in or fade out
331 if (startFadeout_ || startFadein_) {
332 if (startFadeout_) {
333 stream_->BlockStream();
334 }
335 DoFadeinOut(startFadeout_, audioBuffer.data(), audioBuffer.size());
336 cvFading_.notify_all();
337 }
338 DoRenderFrame(audioBuffer, index, appUid);
339 StandbySleep();
340 }
341
AddRenderer(const std::shared_ptr<IRendererStream> & stream)342 int32_t NoneMixEngine::AddRenderer(const std::shared_ptr<IRendererStream> &stream)
343 {
344 AUDIO_INFO_LOG("Enter add");
345 if (!stream_) {
346 AudioProcessConfig config = stream->GetAudioProcessConfig();
347 int32_t result = InitSink(config.streamInfo);
348 if (result == SUCCESS) {
349 stream_ = stream;
350 isInit_ = true;
351 }
352 return result;
353 } else if (stream->GetStreamIndex() != stream_->GetStreamIndex()) {
354 return ERROR_UNSUPPORTED;
355 }
356 return SUCCESS;
357 }
358
RemoveRenderer(const std::shared_ptr<IRendererStream> & stream)359 void NoneMixEngine::RemoveRenderer(const std::shared_ptr<IRendererStream> &stream)
360 {
361 AUDIO_INFO_LOG("step in remove");
362 if (stream_ == nullptr) {
363 AUDIO_INFO_LOG("stream already removed.");
364 return;
365 }
366 if (stream->GetStreamIndex() == stream_->GetStreamIndex()) {
367 Stop();
368 stream_ = nullptr;
369 }
370 }
371
IsPlaybackEngineRunning() const372 bool NoneMixEngine::IsPlaybackEngineRunning() const noexcept
373 {
374 return isStart_;
375 }
376
StandbySleep()377 void NoneMixEngine::StandbySleep()
378 {
379 int64_t writeTime = static_cast<int64_t>(fwkSyncTime_) + static_cast<int64_t>(writeCount_) * PERIOD_NS + DELTA_TIME;
380 ClockTime::AbsoluteSleep(writeTime);
381 }
382
GetDirectSampleRate(AudioSamplingRate sampleRate)383 AudioSamplingRate NoneMixEngine::GetDirectSampleRate(AudioSamplingRate sampleRate)
384 {
385 AudioSamplingRate result = sampleRate;
386 switch (sampleRate) {
387 case AudioSamplingRate::SAMPLE_RATE_44100:
388 result = AudioSamplingRate::SAMPLE_RATE_48000;
389 break;
390 case AudioSamplingRate::SAMPLE_RATE_88200:
391 result = AudioSamplingRate::SAMPLE_RATE_96000;
392 break;
393 case AudioSamplingRate::SAMPLE_RATE_176400:
394 result = AudioSamplingRate::SAMPLE_RATE_192000;
395 break;
396 default:
397 break;
398 }
399 AUDIO_INFO_LOG("GetDirectSampleRate: sampleRate: %{public}d, result: %{public}d", sampleRate, result);
400 return result;
401 }
402
GetDirectVoipSampleRate(AudioSamplingRate sampleRate)403 AudioSamplingRate NoneMixEngine::GetDirectVoipSampleRate(AudioSamplingRate sampleRate)
404 {
405 AudioSamplingRate result = sampleRate;
406 if (sampleRate <= AudioSamplingRate::SAMPLE_RATE_16000) {
407 result = AudioSamplingRate::SAMPLE_RATE_16000;
408 } else {
409 result = AudioSamplingRate::SAMPLE_RATE_48000;
410 }
411 AUDIO_INFO_LOG("GetDirectVoipSampleRate: sampleRate: %{public}d, result: %{public}d", sampleRate, result);
412 return result;
413 }
414
GetDirectDeviceFormat(AudioSampleFormat format)415 AudioSampleFormat NoneMixEngine::GetDirectDeviceFormat(AudioSampleFormat format)
416 {
417 switch (format) {
418 case AudioSampleFormat::SAMPLE_U8:
419 case AudioSampleFormat::SAMPLE_S16LE:
420 return AudioSampleFormat::SAMPLE_S16LE;
421 case AudioSampleFormat::SAMPLE_S24LE:
422 case AudioSampleFormat::SAMPLE_S32LE:
423 return AudioSampleFormat::SAMPLE_S32LE;
424 case AudioSampleFormat::SAMPLE_F32LE:
425 return AudioSampleFormat::SAMPLE_F32LE;
426 default:
427 return AudioSampleFormat::SAMPLE_S16LE;
428 }
429 }
430
431 // replaced by using xml configuration later
GetDirectVoipDeviceFormat(AudioSampleFormat format)432 AudioSampleFormat NoneMixEngine::GetDirectVoipDeviceFormat(AudioSampleFormat format)
433 {
434 switch (format) {
435 case AudioSampleFormat::SAMPLE_U8:
436 case AudioSampleFormat::SAMPLE_S16LE:
437 case AudioSampleFormat::SAMPLE_F32LE:
438 return AudioSampleFormat::SAMPLE_S16LE;
439 case AudioSampleFormat::SAMPLE_S24LE:
440 case AudioSampleFormat::SAMPLE_S32LE:
441 return AudioSampleFormat::SAMPLE_S32LE;
442 default:
443 return AudioSampleFormat::SAMPLE_S16LE;
444 }
445 }
446
GetDirectFormatByteSize(AudioSampleFormat format)447 int32_t NoneMixEngine::GetDirectFormatByteSize(AudioSampleFormat format)
448 {
449 switch (format) {
450 case AudioSampleFormat::SAMPLE_S16LE:
451 return sizeof(int16_t);
452 case AudioSampleFormat::SAMPLE_S32LE:
453 case AudioSampleFormat::SAMPLE_F32LE:
454 return sizeof(int32_t);
455 default:
456 return sizeof(int32_t);
457 }
458 }
459
GetTargetSinkStreamInfo(const AudioStreamInfo & clientStreamInfo,uint32_t & targetSampleRate,uint32_t & targetChannel,AudioSampleFormat & targetFormat,bool & isVoip)460 void NoneMixEngine::GetTargetSinkStreamInfo(const AudioStreamInfo &clientStreamInfo, uint32_t &targetSampleRate,
461 uint32_t &targetChannel, AudioSampleFormat &targetFormat, bool &isVoip)
462 {
463 targetChannel = clientStreamInfo.channels >= STEREO_CHANNEL_COUNT ? STEREO_CHANNEL_COUNT : 1;
464
465 if (isVoip) {
466 targetSampleRate = GetDirectVoipSampleRate(clientStreamInfo.samplingRate);
467 targetFormat = GetDirectVoipDeviceFormat(clientStreamInfo.format);
468 } else {
469 targetSampleRate = GetDirectSampleRate(clientStreamInfo.samplingRate);
470 targetFormat = GetDirectDeviceFormat(clientStreamInfo.format);
471 }
472 }
473
InitSink(const AudioStreamInfo & clientStreamInfo)474 int32_t NoneMixEngine::InitSink(const AudioStreamInfo &clientStreamInfo)
475 {
476 uint32_t targetSampleRate;
477 uint32_t targetChannel;
478 AudioSampleFormat targetFormat;
479 GetTargetSinkStreamInfo(clientStreamInfo, targetSampleRate, targetChannel, targetFormat, isVoip_);
480
481 std::shared_ptr<IAudioRenderSink> sink = HdiAdapterManager::GetInstance().GetRenderSink(renderId_);
482 if (isInit_ && sink) {
483 if (uChannel_ != targetChannel || uFormat_ != targetFormat || targetSampleRate != uSampleRate_) {
484 if (sink && sink->IsInited()) {
485 sink->Stop();
486 sink->DeInit();
487 }
488 } else {
489 return SUCCESS;
490 }
491 }
492 HdiAdapterManager::GetInstance().ReleaseId(renderId_);
493 return InitSink(targetChannel, targetFormat, targetSampleRate);
494 }
495
InitSink(uint32_t channel,AudioSampleFormat format,uint32_t rate)496 int32_t NoneMixEngine::InitSink(uint32_t channel, AudioSampleFormat format, uint32_t rate)
497 {
498 std::string sinkName = DIRECT_SINK_NAME;
499 if (isVoip_) {
500 sinkName = VOIP_SINK_NAME;
501 }
502 renderId_ = HdiAdapterManager::GetInstance().GetId(HDI_ID_BASE_RENDER, HDI_ID_TYPE_PRIMARY, sinkName, true);
503 std::shared_ptr<IAudioRenderSink> sink = HdiAdapterManager::GetInstance().GetRenderSink(renderId_, true);
504 if (sink == nullptr) {
505 AUDIO_ERR_LOG("get render fail, sinkName: %{public}s", sinkName.c_str());
506 HdiAdapterManager::GetInstance().ReleaseId(renderId_);
507 return ERR_INVALID_HANDLE;
508 }
509 IAudioSinkAttr attr = {};
510 bool isDefaultAdapterEnable = AudioService::GetInstance()->GetDefaultAdapterEnable();
511 attr.adapterName = isDefaultAdapterEnable ? "dp" : SINK_ADAPTER_NAME;
512 attr.sampleRate = rate;
513 attr.channel = channel;
514 attr.format = format;
515 attr.channelLayout = channel >= STEREO_CHANNEL_COUNT ? HDI_STEREO_CHANNEL_LAYOUT : HDI_MONO_CHANNEL_LAYOUT;
516 attr.deviceType = device_.deviceType_;
517 attr.volume = 1.0f;
518 attr.openMicSpeaker = 1;
519 AUDIO_INFO_LOG("sinkName:%{public}s,device:%{public}d,sample rate:%{public}d,format:%{public}d,channel:%{public}d",
520 sinkName.c_str(), attr.deviceType, attr.sampleRate, attr.format, attr.channel);
521 int32_t ret = sink->Init(attr);
522 if (ret != SUCCESS) {
523 return ret;
524 }
525 float volume = 1.0f;
526 ret = sink->SetVolume(volume, volume);
527 uChannel_ = attr.channel;
528 uSampleRate_ = attr.sampleRate;
529 uFormat_ = GetDirectFormatByteSize(attr.format);
530
531 return ret;
532 }
533
SwitchSink(const AudioStreamInfo & streamInfo,bool isVoip)534 int32_t NoneMixEngine::SwitchSink(const AudioStreamInfo &streamInfo, bool isVoip)
535 {
536 Stop();
537 std::shared_ptr<IAudioRenderSink> sink = HdiAdapterManager::GetInstance().GetRenderSink(renderId_);
538 if (sink != nullptr) {
539 sink->DeInit();
540 }
541 isVoip_ = isVoip;
542 return InitSink(streamInfo);
543 }
544
GetLatency()545 uint64_t NoneMixEngine::GetLatency() noexcept
546 {
547 if (!isStart_) {
548 return 0;
549 }
550 if (latency_ > 0) {
551 return latency_;
552 }
553 uint32_t latency = 0;
554 std::shared_ptr<IAudioRenderSink> sink = HdiAdapterManager::GetInstance().GetRenderSink(renderId_);
555 CHECK_AND_RETURN_RET(sink != nullptr, 0);
556 if (sink->GetLatency(latency) == 0) {
557 latency_ = latency * AUDIO_US_PER_MS + AUDIO_FRAME_WORK_LATENCY_US;
558 } else {
559 AUDIO_INFO_LOG("get latency failed,use default");
560 latency_ = AUDIO_DEFAULT_LATENCY_US;
561 }
562 AUDIO_INFO_LOG("latency value:%{public}" PRId64 " ns", latency_);
563 return latency_;
564 }
565 } // namespace AudioStandard
566 } // namespace OHOS
567