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_DEFAULT_LATENCY_US = 160000;
37 constexpr int32_t AUDIO_FRAME_WORK_LATENCY_US = 40000;
38 constexpr int32_t FADING_MS = 20; // 20ms
39 constexpr int32_t MAX_ERROR_COUNT = 50;
40 constexpr int16_t STEREO_CHANNEL_COUNT = 2;
41 constexpr int16_t HDI_STEREO_CHANNEL_LAYOUT = 3;
42 constexpr int16_t HDI_MONO_CHANNEL_LAYOUT = 4;
43 constexpr int32_t DIRECT_STOP_TIMEOUT_IN_SEC = 8; // 8S
44 constexpr int32_t DIRECT_SINK_STANDBY_TIMES = 8; // 8
45 const std::string THREAD_NAME = "noneMixThread";
46 const std::string VOIP_SINK_NAME = "voip";
47 const std::string DIRECT_SINK_NAME = "direct";
48 const char *SINK_ADAPTER_NAME = "primary";
49
NoneMixEngine()50 NoneMixEngine::NoneMixEngine()
51 : isVoip_(false),
52 isStart_(false),
53 isInit_(false),
54 failedCount_(0),
55 writeCount_(0),
56 fwkSyncTime_(0),
57 latency_(0),
58 stream_(nullptr),
59 startFadein_(false),
60 startFadeout_(false),
61 uChannel_(0),
62 uFormat_(sizeof(int32_t)),
63 uSampleRate_(0),
64 firstSetVolume_(true)
65 {
66 AUDIO_INFO_LOG("Constructor");
67 }
68
~NoneMixEngine()69 NoneMixEngine::~NoneMixEngine()
70 {
71 writeCount_ = 0;
72 failedCount_ = 0;
73 fwkSyncTime_ = 0;
74 if (playbackThread_) {
75 playbackThread_->Stop();
76 playbackThread_ = nullptr;
77 }
78 std::shared_ptr<IAudioRenderSink> sink = HdiAdapterManager::GetInstance().GetRenderSink(renderId_);
79 if (sink && sink->IsInited()) {
80 sink->Stop();
81 sink->DeInit();
82 }
83 HdiAdapterManager::GetInstance().ReleaseId(renderId_);
84 isStart_ = false;
85 startFadein_ = false;
86 startFadeout_ = false;
87 }
88
Init(const AudioDeviceDescriptor & type,bool isVoip)89 int32_t NoneMixEngine::Init(const AudioDeviceDescriptor &type, bool isVoip)
90 {
91 if (!isInit_) {
92 isVoip_ = isVoip;
93 device_ = type;
94 return SUCCESS;
95 }
96 if (type.deviceType_ != device_.deviceType_ || isVoip_ != isVoip) {
97 isVoip_ = isVoip;
98 device_ = type;
99 std::shared_ptr<IAudioRenderSink> sink = HdiAdapterManager::GetInstance().GetRenderSink(renderId_);
100 if (sink && sink->IsInited()) {
101 sink->Stop();
102 sink->DeInit();
103 }
104 HdiAdapterManager::GetInstance().ReleaseId(renderId_);
105 }
106 return SUCCESS;
107 }
108
Start()109 int32_t NoneMixEngine::Start()
110 {
111 AUDIO_INFO_LOG("Enter in");
112 int32_t ret = SUCCESS;
113 std::shared_ptr<IAudioRenderSink> sink = HdiAdapterManager::GetInstance().GetRenderSink(renderId_);
114 CHECK_AND_RETURN_RET_LOG(sink != nullptr, ERR_INVALID_HANDLE, "null sink!");
115 CHECK_AND_RETURN_RET_LOG(sink->IsInited(), ERR_NOT_STARTED, "sink Not Inited! Init the sink first!");
116 fwkSyncTime_ = static_cast<uint64_t>(ClockTime::GetCurNano());
117 writeCount_ = 0;
118 failedCount_ = 0;
119 if (!playbackThread_) {
120 playbackThread_ = std::make_unique<AudioThreadTask>(THREAD_NAME);
121 playbackThread_->RegisterJob([this] { this->MixStreams(); });
122 }
123 latency_ = 0;
124 if (!isStart_) {
125 startFadeout_ = false;
126 startFadein_ = true;
127 ret = sink->Start();
128 isStart_ = true;
129 }
130 if (!playbackThread_->CheckThreadIsRunning()) {
131 playbackThread_->Start();
132 }
133 return ret;
134 }
135
Stop()136 int32_t NoneMixEngine::Stop()
137 {
138 AUDIO_INFO_LOG("Enter");
139 int32_t ret = SUCCESS;
140 if (!isStart_) {
141 AUDIO_INFO_LOG("already stopped");
142 return ret;
143 }
144 AudioXCollie audioXCollie(
145 "NoneMixEngine::Stop", DIRECT_STOP_TIMEOUT_IN_SEC,
146 [this](void *) { AUDIO_ERR_LOG("%{public}d stop timeout", isVoip_); }, nullptr,
147 AUDIO_XCOLLIE_FLAG_LOG | AUDIO_XCOLLIE_FLAG_RECOVERY);
148
149 writeCount_ = 0;
150 failedCount_ = 0;
151 if (playbackThread_) {
152 startFadein_ = false;
153 startFadeout_ = true;
154 // wait until fadeout complete
155 std::unique_lock fadingLock(fadingMutex_);
156 cvFading_.wait_for(
157 fadingLock, std::chrono::milliseconds(FADING_MS), [this] { return (!(startFadein_ || startFadeout_)); });
158 playbackThread_->Stop();
159 playbackThread_ = nullptr;
160 }
161 ClockTime::RelativeSleep(PERIOD_NS * DIRECT_SINK_STANDBY_TIMES);
162 ret = StopAudioSink();
163 isStart_ = false;
164 return ret;
165 }
166
PauseAsync()167 void NoneMixEngine::PauseAsync()
168 {
169 // stop thread when failed 5 times,do not add logic inside.
170 if (playbackThread_ && playbackThread_->CheckThreadIsRunning()) {
171 playbackThread_->PauseAsync();
172 }
173 int32_t ret = StopAudioSink();
174 if (ret != SUCCESS) {
175 AUDIO_ERR_LOG("sink stop failed.ret:%{public}d", ret);
176 }
177 isStart_ = false;
178 }
179
StopAudioSink()180 int32_t NoneMixEngine::StopAudioSink()
181 {
182 int32_t ret = SUCCESS;
183 std::shared_ptr<IAudioRenderSink> sink = HdiAdapterManager::GetInstance().GetRenderSink(renderId_);
184 if (sink && sink->IsInited()) {
185 ret = sink->Stop();
186 } else {
187 AUDIO_ERR_LOG("sink is null or not init!");
188 }
189 return ret;
190 }
191
Pause()192 int32_t NoneMixEngine::Pause()
193 {
194 AUDIO_INFO_LOG("Enter");
195 if (!isStart_) {
196 AUDIO_INFO_LOG("already stopped");
197 return SUCCESS;
198 }
199 AudioXCollie audioXCollie(
200 "NoneMixEngine::Pause", DIRECT_STOP_TIMEOUT_IN_SEC,
201 [this](void *) { AUDIO_ERR_LOG("%{public}d stop timeout", isVoip_); }, nullptr,
202 AUDIO_XCOLLIE_FLAG_LOG | AUDIO_XCOLLIE_FLAG_RECOVERY);
203
204 writeCount_ = 0;
205 failedCount_ = 0;
206 if (playbackThread_) {
207 startFadein_ = false;
208 startFadeout_ = true;
209 // wait until fadeout complete
210 std::unique_lock fadingLock(fadingMutex_);
211 cvFading_.wait_for(
212 fadingLock, std::chrono::milliseconds(FADING_MS), [this] { return (!(startFadein_ || startFadeout_)); });
213 playbackThread_->Pause();
214 }
215 ClockTime::RelativeSleep(PERIOD_NS * DIRECT_SINK_STANDBY_TIMES);
216 int32_t ret = StopAudioSink();
217 isStart_ = false;
218 return ret;
219 }
220
Flush()221 int32_t NoneMixEngine::Flush()
222 {
223 AUDIO_INFO_LOG("Enter");
224 return SUCCESS;
225 }
226
227 template <typename T, typename = std::enable_if_t<std::is_integral<T>::value>>
DoFadeInOut(T * dest,size_t count,bool isFadeOut,uint32_t channel)228 static void DoFadeInOut(T *dest, size_t count, bool isFadeOut, uint32_t channel)
229 {
230 if (count <= 0) {
231 return;
232 }
233 float fadeStep = 1.0f / count;
234 for (size_t i = 0; i < count; i++) {
235 float fadeFactor;
236 if (isFadeOut) {
237 fadeFactor = 1.0f - ((i + 1) * fadeStep);
238 } else {
239 fadeFactor = (i + 1) * fadeStep;
240 }
241 for (uint32_t j = 0; j < channel; j++) {
242 dest[i * channel + j] *= fadeFactor;
243 }
244 }
245 }
246
DoFadeinOut(bool isFadeOut,char * pBuffer,size_t bufferSize)247 void NoneMixEngine::DoFadeinOut(bool isFadeOut, char *pBuffer, size_t bufferSize)
248 {
249 CHECK_AND_RETURN_LOG(pBuffer != nullptr && bufferSize > 0 && uChannel_ > 0, "buffer is null.");
250 size_t dataLength = bufferSize / (static_cast<uint32_t>(uFormat_) * uChannel_);
251 if (uFormat_ == sizeof(int16_t)) {
252 AUDIO_INFO_LOG("int16 fading frame length:%{public}zu", dataLength);
253 DoFadeInOut(reinterpret_cast<int16_t *>(pBuffer), dataLength, isFadeOut, uChannel_);
254 } else if (uFormat_ == sizeof(int32_t)) {
255 AUDIO_INFO_LOG("int32 fading frame length:%{public}zu", dataLength);
256 DoFadeInOut(reinterpret_cast<int32_t *>(pBuffer), dataLength, isFadeOut, uChannel_);
257 }
258 if (isFadeOut) {
259 startFadeout_.store(false);
260 } else {
261 startFadein_.store(false);
262 }
263 }
264
AdjustVoipVolume()265 void NoneMixEngine::AdjustVoipVolume()
266 {
267 if (isVoip_) {
268 uint32_t streamIndx = stream_->GetStreamIndex();
269 AudioProcessConfig config = stream_->GetAudioProcessConfig();
270 struct VolumeValues volumes = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f};
271 float volumeEd = AudioVolume::GetInstance()->GetVolume(streamIndx, config.streamType,
272 std::string(SINK_ADAPTER_NAME), &volumes);
273 float volumeBg = volumes.volumeHistory;
274 if ((!firstSetVolume_ && abs(volumeBg - volumeEd) > FLOAT_EPS) || 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, appUid);
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, appUid);
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