1 /*
2 * Copyright (c) 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
16 #ifndef LOG_TAG
17 #define LOG_TAG "MultichannelAudioRenderSink"
18 #endif
19
20 #include "sink/multichannel_audio_render_sink.h"
21 #include <climits>
22 #include "parameters.h"
23 #include "audio_hdi_log.h"
24 #include "audio_errors.h"
25 #include "audio_dump_pcm.h"
26 #include "volume_tools.h"
27 #include "audio_performance_monitor.h"
28 #include "common/hdi_adapter_info.h"
29 #include "manager/hdi_adapter_manager.h"
30
31 namespace OHOS {
32 namespace AudioStandard {
MultichannelAudioRenderSink(const std::string & halName)33 MultichannelAudioRenderSink::MultichannelAudioRenderSink(const std::string &halName)
34 : halName_(halName)
35 {
36 AUDIO_INFO_LOG("construction");
37 }
38
~MultichannelAudioRenderSink()39 MultichannelAudioRenderSink::~MultichannelAudioRenderSink()
40 {
41 AUDIO_INFO_LOG("destruction");
42 AudioPerformanceMonitor::GetInstance().DeleteOvertimeMonitor(ADAPTER_TYPE_MULTICHANNEL);
43 }
44
Init(const IAudioSinkAttr & attr)45 int32_t MultichannelAudioRenderSink::Init(const IAudioSinkAttr &attr)
46 {
47 std::lock_guard<std::mutex> lock(sinkMutex_);
48 attr_ = attr;
49 adapterNameCase_ = attr_.adapterName;
50 openSpeaker_ = attr_.openMicSpeaker;
51 logMode_ = system::GetIntParameter("persist.multimedia.audiolog.switch", 0);
52
53 int32_t ret = InitRender();
54 CHECK_AND_RETURN_RET(ret == SUCCESS, ret);
55
56 HdiAdapterManager &manager = HdiAdapterManager::GetInstance();
57 std::shared_ptr<IDeviceManager> deviceManager = manager.GetDeviceManager(HDI_DEVICE_MANAGER_TYPE_LOCAL);
58 CHECK_AND_RETURN_RET(deviceManager != nullptr, ERR_INVALID_HANDLE);
59
60 sinkInited_ = true;
61 return SUCCESS;
62 }
63
DeInit(void)64 void MultichannelAudioRenderSink::DeInit(void)
65 {
66 std::lock_guard<std::mutex> lock(sinkMutex_);
67 sinkInited_ = false;
68 started_ = false;
69
70 AUDIO_INFO_LOG("destroy render, hdiRenderId: %{public}u", hdiRenderId_);
71 HdiAdapterManager &manager = HdiAdapterManager::GetInstance();
72 std::shared_ptr<IDeviceManager> deviceManager = manager.GetDeviceManager(HDI_DEVICE_MANAGER_TYPE_LOCAL);
73 CHECK_AND_RETURN(deviceManager != nullptr);
74 renderInited_ = false;
75 deviceManager->DestroyRender(adapterNameCase_, hdiRenderId_);
76 audioRender_ = nullptr;
77
78 DumpFileUtil::CloseDumpFile(&dumpFile_);
79 }
80
IsInited(void)81 bool MultichannelAudioRenderSink::IsInited(void)
82 {
83 return sinkInited_;
84 }
85
Start(void)86 int32_t MultichannelAudioRenderSink::Start(void)
87 {
88 std::lock_guard<std::mutex> lock(sinkMutex_);
89 Trace trace("MultichannelAudioRenderSink::Start");
90 #ifdef FEATURE_POWER_MANAGER
91 if (runningLock_ == nullptr) {
92 WatchTimeout guard("create AudioRunningLock start");
93 runningLock_ = std::make_shared<AudioRunningLock>(std::string(RUNNING_LOCK_NAME_BASE) + halName_);
94 guard.CheckCurrTimeout();
95 }
96 if (runningLock_ != nullptr) {
97 runningLock_->Lock(RUNNING_LOCK_TIMEOUTMS_LASTING);
98 } else {
99 AUDIO_ERR_LOG("running lock is null, playback can not work well");
100 }
101 #endif
102 dumpFileName_ = "multichannel_sink_" + GetTime() + "_" + std::to_string(attr_.sampleRate) + "_" +
103 std::to_string(attr_.channel) + "_" + std::to_string(attr_.format) + ".pcm";
104 DumpFileUtil::OpenDumpFile(DumpFileUtil::DUMP_SERVER_PARA, dumpFileName_, &dumpFile_);
105 if (started_) {
106 return SUCCESS;
107 }
108 CHECK_AND_RETURN_RET_LOG(audioRender_ != nullptr, ERR_INVALID_HANDLE, "render is nullptr");
109 int32_t ret = audioRender_->Start(audioRender_);
110 CHECK_AND_RETURN_RET_LOG(ret == SUCCESS, ERR_NOT_STARTED, "start fail");
111 UpdateSinkState(true);
112 started_ = true;
113
114 uint64_t frameSize = 0;
115 uint64_t frameCount = 0;
116 ret = audioRender_->GetFrameSize(audioRender_, &frameSize);
117 CHECK_AND_RETURN_RET_LOG(ret == SUCCESS, ERR_NOT_STARTED, "get frame size fail");
118 ret = audioRender_->GetFrameCount(audioRender_, &frameCount);
119 CHECK_AND_RETURN_RET_LOG(ret == SUCCESS, ERR_NOT_STARTED, "get frame count fail");
120 ret = audioRender_->SetVolume(audioRender_, 1);
121 CHECK_AND_RETURN_RET_LOG(ret == SUCCESS, ERR_NOT_STARTED, "set volume fail");
122 AUDIO_INFO_LOG("start success, frameSize: %{public}" PRIu64 ", frameCount: %{public}" PRIu64, frameSize,
123 frameCount);
124 AudioPerformanceMonitor::GetInstance().RecordTimeStamp(ADAPTER_TYPE_MULTICHANNEL, INIT_LASTWRITTEN_TIME);
125 return SUCCESS;
126 }
127
Stop(void)128 int32_t MultichannelAudioRenderSink::Stop(void)
129 {
130 std::lock_guard<std::mutex> lock(sinkMutex_);
131 Trace trace("MultichannelAudioRenderSink::Stop");
132 AUDIO_INFO_LOG("in");
133 #ifdef FEATURE_POWER_MANAGER
134 if (runningLock_ != nullptr) {
135 AUDIO_INFO_LOG("running lock unlock");
136 runningLock_->UnLock();
137 } else {
138 AUDIO_WARNING_LOG("running lock is null, playback can not work well");
139 }
140 #endif
141 if (!started_) {
142 return SUCCESS;
143 }
144 CHECK_AND_RETURN_RET_LOG(audioRender_ != nullptr, ERR_INVALID_HANDLE, "render is nullptr");
145 int32_t ret = audioRender_->Stop(audioRender_);
146 UpdateSinkState(false);
147 CHECK_AND_RETURN_RET_LOG(ret == SUCCESS, ERR_NOT_STARTED, "stop fail");
148 started_ = false;
149 return SUCCESS;
150 }
151
Resume(void)152 int32_t MultichannelAudioRenderSink::Resume(void)
153 {
154 std::lock_guard<std::mutex> lock(sinkMutex_);
155 CHECK_AND_RETURN_RET_LOG(audioRender_ != nullptr, ERR_INVALID_HANDLE, "render is nullptr");
156 CHECK_AND_RETURN_RET_LOG(started_, ERR_OPERATION_FAILED, "not start, invalid state");
157
158 if (!paused_) {
159 return SUCCESS;
160 }
161 int32_t ret = audioRender_->Resume(audioRender_);
162 CHECK_AND_RETURN_RET_LOG(ret == SUCCESS, ERR_OPERATION_FAILED, "resume fail");
163 paused_ = false;
164 AudioPerformanceMonitor::GetInstance().RecordTimeStamp(ADAPTER_TYPE_MULTICHANNEL, INIT_LASTWRITTEN_TIME);
165 return SUCCESS;
166 }
167
Pause(void)168 int32_t MultichannelAudioRenderSink::Pause(void)
169 {
170 std::lock_guard<std::mutex> lock(sinkMutex_);
171 Trace trace("MultichannelAudioRenderSink::Pause");
172 CHECK_AND_RETURN_RET_LOG(audioRender_ != nullptr, ERR_INVALID_HANDLE, "render is nullptr");
173 CHECK_AND_RETURN_RET_LOG(started_, ERR_OPERATION_FAILED, "not start, invalid state");
174
175 if (paused_) {
176 return SUCCESS;
177 }
178 int32_t ret = audioRender_->Pause(audioRender_);
179 CHECK_AND_RETURN_RET_LOG(ret == SUCCESS, ERR_OPERATION_FAILED, "pause fail");
180 paused_ = true;
181 return SUCCESS;
182 }
183
Flush(void)184 int32_t MultichannelAudioRenderSink::Flush(void)
185 {
186 Trace trace("MultichannelAudioRenderSink::Flush");
187 CHECK_AND_RETURN_RET_LOG(audioRender_ != nullptr, ERR_INVALID_HANDLE, "render is nullptr");
188 CHECK_AND_RETURN_RET_LOG(started_, ERR_OPERATION_FAILED, "not start, invalid state");
189
190 int32_t ret = audioRender_->Flush(audioRender_);
191 CHECK_AND_RETURN_RET_LOG(ret == SUCCESS, ERR_OPERATION_FAILED, "flush fail");
192 return SUCCESS;
193 }
194
Reset(void)195 int32_t MultichannelAudioRenderSink::Reset(void)
196 {
197 CHECK_AND_RETURN_RET_LOG(audioRender_ != nullptr, ERR_INVALID_HANDLE, "render is nullptr");
198 CHECK_AND_RETURN_RET_LOG(started_, ERR_OPERATION_FAILED, "not start, invalid state");
199
200 int32_t ret = audioRender_->Flush(audioRender_);
201 CHECK_AND_RETURN_RET_LOG(ret == SUCCESS, ERR_OPERATION_FAILED, "reset fail");
202 return SUCCESS;
203 }
204
RenderFrame(char & data,uint64_t len,uint64_t & writeLen)205 int32_t MultichannelAudioRenderSink::RenderFrame(char &data, uint64_t len, uint64_t &writeLen)
206 {
207 int64_t stamp = ClockTime::GetCurNano();
208 CHECK_AND_RETURN_RET_LOG(audioRender_ != nullptr, ERR_INVALID_HANDLE, "render is nullptr");
209 if (audioMonoState_) {
210 AdjustStereoToMono(&data, len);
211 }
212 if (audioBalanceState_) {
213 AdjustAudioBalance(&data, len);
214 }
215 CheckUpdateState(&data, len);
216 if (switchDeviceMute_) {
217 Trace trace("MultichannelAudioRenderSink::RenderFrame::switch");
218 writeLen = len;
219 return SUCCESS;
220 }
221 if (emptyFrameCount_ > 0) {
222 Trace trace("MultichannelAudioRenderSink::RenderFrame::renderEmpty");
223 if (memset_s(reinterpret_cast<void *>(&data), static_cast<size_t>(len), 0, static_cast<size_t>(len)) != EOK) {
224 AUDIO_WARNING_LOG("call memset_s fail");
225 }
226 --emptyFrameCount_;
227 if (emptyFrameCount_ == 0) {
228 switchDeviceCV_.notify_all();
229 }
230 }
231
232 BufferDesc buffer = { reinterpret_cast<uint8_t *>(&data), len, len };
233 AudioStreamInfo streamInfo(static_cast<AudioSamplingRate>(attr_.sampleRate), AudioEncodingType::ENCODING_PCM,
234 static_cast<AudioSampleFormat>(attr_.format), static_cast<AudioChannel>(attr_.channel));
235 VolumeTools::DfxOperation(buffer, streamInfo, logUtilsTag_, volumeDataCount_);
236 Trace trace("MultichannelAudioRenderSink::RenderFrame");
237 DumpFileUtil::WriteDumpFile(dumpFile_, static_cast<void *>(&data), len);
238 if (AudioDump::GetInstance().GetVersionType() == DumpFileUtil::BETA_VERSION) {
239 AudioCacheMgr::GetInstance().CacheData(dumpFileName_, static_cast<void *>(&data), len);
240 }
241 int32_t ret = audioRender_->RenderFrame(audioRender_, reinterpret_cast<int8_t *>(&data), static_cast<uint32_t>(len),
242 &writeLen);
243 CHECK_AND_RETURN_RET_LOG(ret == SUCCESS, ERR_WRITE_FAILED, "fail, ret: %{public}x", ret);
244 AudioPerformanceMonitor::GetInstance().RecordTimeStamp(ADAPTER_TYPE_MULTICHANNEL, ClockTime::GetCurNano());
245 stamp = (ClockTime::GetCurNano() - stamp) / AUDIO_US_PER_SECOND;
246 if (logMode_) {
247 AUDIO_DEBUG_LOG("len: [%{public}" PRIu64 "], cost: [%{public}" PRId64 "]ms", len, stamp);
248 }
249
250 return SUCCESS;
251 }
252
SuspendRenderSink(void)253 int32_t MultichannelAudioRenderSink::SuspendRenderSink(void)
254 {
255 return SUCCESS;
256 }
257
RestoreRenderSink(void)258 int32_t MultichannelAudioRenderSink::RestoreRenderSink(void)
259 {
260 return SUCCESS;
261 }
262
SetAudioParameter(const AudioParamKey key,const std::string & condition,const std::string & value)263 void MultichannelAudioRenderSink::SetAudioParameter(const AudioParamKey key, const std::string &condition,
264 const std::string &value)
265 {
266 }
267
GetAudioParameter(const AudioParamKey key,const std::string & condition)268 std::string MultichannelAudioRenderSink::GetAudioParameter(const AudioParamKey key, const std::string &condition)
269 {
270 if (condition == "get_usb_info") {
271 // init adapter to get parameter before load sink module (need fix)
272 adapterNameCase_ = "usb";
273 HdiAdapterManager &manager = HdiAdapterManager::GetInstance();
274 std::shared_ptr<IDeviceManager> deviceManager = manager.GetDeviceManager(HDI_DEVICE_MANAGER_TYPE_LOCAL);
275 return deviceManager->GetAudioParameter(adapterNameCase_, key, condition);
276 }
277 return "";
278 }
279
SetVolume(float left,float right)280 int32_t MultichannelAudioRenderSink::SetVolume(float left, float right)
281 {
282 CHECK_AND_RETURN_RET_LOG(audioRender_ != nullptr, ERR_INVALID_HANDLE, "render is nullptr");
283
284 leftVolume_ = left;
285 rightVolume_ = right;
286 float volume;
287 if ((leftVolume_ == 0) && (rightVolume_ != 0)) {
288 volume = rightVolume_;
289 } else if ((leftVolume_ != 0) && (rightVolume_ == 0)) {
290 volume = leftVolume_;
291 } else {
292 volume = (leftVolume_ + rightVolume_) / HALF_FACTOR;
293 }
294
295 int32_t ret = audioRender_->SetVolume(audioRender_, volume);
296 if (ret != SUCCESS) {
297 AUDIO_WARNING_LOG("set volume fail");
298 }
299
300 return ret;
301 }
302
GetVolume(float & left,float & right)303 int32_t MultichannelAudioRenderSink::GetVolume(float &left, float &right)
304 {
305 left = leftVolume_;
306 right = rightVolume_;
307 return SUCCESS;
308 }
309
GetLatency(uint32_t & latency)310 int32_t MultichannelAudioRenderSink::GetLatency(uint32_t &latency)
311 {
312 Trace trace("MultichannelAudioRenderSink::GetLatency");
313 CHECK_AND_RETURN_RET_LOG(audioRender_ != nullptr, ERR_INVALID_HANDLE, "render is nullptr");
314
315 uint32_t hdiLatency;
316 int32_t ret = audioRender_->GetLatency(audioRender_, &hdiLatency);
317 CHECK_AND_RETURN_RET_LOG(ret == SUCCESS, ERR_OPERATION_FAILED, "get latency fail");
318 latency = hdiLatency;
319 return SUCCESS;
320 }
321
GetTransactionId(uint64_t & transactionId)322 int32_t MultichannelAudioRenderSink::GetTransactionId(uint64_t &transactionId)
323 {
324 CHECK_AND_RETURN_RET_LOG(audioRender_ != nullptr, ERR_INVALID_HANDLE, "render is nullptr");
325 transactionId = reinterpret_cast<uint64_t>(audioRender_);
326 return SUCCESS;
327 }
328
GetPresentationPosition(uint64_t & frames,int64_t & timeSec,int64_t & timeNanoSec)329 int32_t MultichannelAudioRenderSink::GetPresentationPosition(uint64_t &frames, int64_t &timeSec, int64_t &timeNanoSec)
330 {
331 AUDIO_INFO_LOG("not support");
332 return ERR_NOT_SUPPORTED;
333 }
334
GetMaxAmplitude(void)335 float MultichannelAudioRenderSink::GetMaxAmplitude(void)
336 {
337 lastGetMaxAmplitudeTime_ = ClockTime::GetCurNano();
338 startUpdate_ = true;
339 return maxAmplitude_;
340 }
341
SetAudioMonoState(bool audioMono)342 void MultichannelAudioRenderSink::SetAudioMonoState(bool audioMono)
343 {
344 audioMonoState_ = audioMono;
345 }
346
SetAudioBalanceValue(float audioBalance)347 void MultichannelAudioRenderSink::SetAudioBalanceValue(float audioBalance)
348 {
349 // reset the balance coefficient value firstly
350 leftBalanceCoef_ = 1.0f;
351 rightBalanceCoef_ = 1.0f;
352
353 if (std::abs(audioBalance - 0.0f) <= std::numeric_limits<float>::epsilon()) {
354 // audioBalance is equal to 0.0f
355 audioBalanceState_ = false;
356 } else {
357 // audioBalance is not equal to 0.0f
358 audioBalanceState_ = true;
359 // calculate the balance coefficient
360 if (audioBalance > 0.0f) {
361 leftBalanceCoef_ -= audioBalance;
362 } else if (audioBalance < 0.0f) {
363 rightBalanceCoef_ += audioBalance;
364 }
365 }
366 }
367
SetAudioScene(AudioScene audioScene,std::vector<DeviceType> & activeDevices)368 int32_t MultichannelAudioRenderSink::SetAudioScene(AudioScene audioScene, std::vector<DeviceType> &activeDevices)
369 {
370 CHECK_AND_RETURN_RET_LOG(audioScene >= AUDIO_SCENE_DEFAULT && audioScene < AUDIO_SCENE_MAX, ERR_INVALID_PARAM,
371 "invalid scene");
372 CHECK_AND_RETURN_RET_LOG(!activeDevices.empty() && activeDevices.size() <= AUDIO_CONCURRENT_ACTIVE_DEVICES_LIMIT,
373 ERR_INVALID_PARAM, "invalid device");
374 AUDIO_INFO_LOG("scene: %{public}d, device: %{public}d", audioScene, activeDevices.front());
375 if (!openSpeaker_) {
376 return SUCCESS;
377 }
378
379 if (audioScene != currentAudioScene_) {
380 struct AudioSceneDescriptor sceneDesc;
381 InitSceneDesc(sceneDesc, audioScene);
382
383 CHECK_AND_RETURN_RET_LOG(audioRender_ != nullptr, ERR_INVALID_HANDLE, "render is nullptr");
384 int32_t ret = audioRender_->SelectScene(audioRender_, &sceneDesc);
385 CHECK_AND_RETURN_RET_LOG(ret >= 0, ERR_OPERATION_FAILED, "select scene fail, ret: %{public}d", ret);
386 currentAudioScene_ = audioScene;
387 }
388 int32_t ret = UpdateActiveDevice(activeDevices);
389 if (ret != SUCCESS) {
390 AUDIO_WARNING_LOG("update route fail, ret: %{public}d", ret);
391 }
392 return SUCCESS;
393 }
394
GetAudioScene(void)395 int32_t MultichannelAudioRenderSink::GetAudioScene(void)
396 {
397 return currentAudioScene_;
398 }
399
UpdateActiveDevice(std::vector<DeviceType> & outputDevices)400 int32_t MultichannelAudioRenderSink::UpdateActiveDevice(std::vector<DeviceType> &outputDevices)
401 {
402 CHECK_AND_RETURN_RET_LOG(!outputDevices.empty() && outputDevices.size() == 1, ERR_INVALID_PARAM, "invalid device");
403 if (currentActiveDevice_ == outputDevices[0]) {
404 AUDIO_INFO_LOG("output device not change, device: %{public}d", outputDevices[0]);
405 return SUCCESS;
406 }
407 currentActiveDevice_ = outputDevices[0];
408
409 emptyFrameCount_ = 5; // 5: frame count before update route
410 std::unique_lock<std::mutex> lock(switchDeviceMutex_);
411 switchDeviceCV_.wait_for(lock, std::chrono::milliseconds(SLEEP_TIME_FOR_EMPTY_FRAME), [this] {
412 if (emptyFrameCount_ == 0) {
413 AUDIO_INFO_LOG("wait for empty frame end");
414 return true;
415 }
416 AUDIO_DEBUG_LOG("emptyFrameCount: %{public}d", emptyFrameCount_.load());
417 return false;
418 });
419 int32_t ret = DoSetOutputRoute(outputDevices);
420 emptyFrameCount_ = 5; // 5: frame count after update route
421 return ret;
422 }
423
RegistCallback(uint32_t type,IAudioSinkCallback * callback)424 void MultichannelAudioRenderSink::RegistCallback(uint32_t type, IAudioSinkCallback *callback)
425 {
426 std::lock_guard<std::mutex> lock(sinkMutex_);
427 callback_.RegistCallback(type, callback);
428 AUDIO_INFO_LOG("regist succ");
429 }
430
ResetActiveDeviceForDisconnect(DeviceType device)431 void MultichannelAudioRenderSink::ResetActiveDeviceForDisconnect(DeviceType device)
432 {
433 if (currentActiveDevice_ == device) {
434 currentActiveDevice_ = DEVICE_TYPE_NONE;
435 }
436 }
437
SetPaPower(int32_t flag)438 int32_t MultichannelAudioRenderSink::SetPaPower(int32_t flag)
439 {
440 AUDIO_INFO_LOG("not support");
441 return ERR_NOT_SUPPORTED;
442 }
443
SetPriPaPower(void)444 int32_t MultichannelAudioRenderSink::SetPriPaPower(void)
445 {
446 AUDIO_INFO_LOG("not support");
447 return ERR_NOT_SUPPORTED;
448 }
449
UpdateAppsUid(const int32_t appsUid[MAX_MIX_CHANNELS],const size_t size)450 int32_t MultichannelAudioRenderSink::UpdateAppsUid(const int32_t appsUid[MAX_MIX_CHANNELS], const size_t size)
451 {
452 #ifdef FEATURE_POWER_MANAGER
453 CHECK_AND_RETURN_RET_LOG(runningLock_, ERR_INVALID_HANDLE, "running lock is nullptr");
454 runningLock_->UpdateAppsUid(appsUid, appsUid + size);
455 #endif
456 return SUCCESS;
457 }
458
UpdateAppsUid(const std::vector<int32_t> & appsUid)459 int32_t MultichannelAudioRenderSink::UpdateAppsUid(const std::vector<int32_t> &appsUid)
460 {
461 return SUCCESS;
462 }
463
DumpInfo(std::string & dumpString)464 void MultichannelAudioRenderSink::DumpInfo(std::string &dumpString)
465 {
466 dumpString += "type: MchSink\tstarted: " + std::string(started_ ? "true" : "false") + "\thalName: " + halName_ +
467 "\tcurrentActiveDevice: " + std::to_string(currentActiveDevice_) + "\n";
468 }
469
PcmFormatToBit(AudioSampleFormat format)470 uint32_t MultichannelAudioRenderSink::PcmFormatToBit(AudioSampleFormat format)
471 {
472 AudioFormat hdiFormat = ConvertToHdiFormat(format);
473 switch (hdiFormat) {
474 case AUDIO_FORMAT_TYPE_PCM_8_BIT:
475 return PCM_8_BIT;
476 case AUDIO_FORMAT_TYPE_PCM_16_BIT:
477 return PCM_16_BIT;
478 case AUDIO_FORMAT_TYPE_PCM_24_BIT:
479 return PCM_24_BIT;
480 case AUDIO_FORMAT_TYPE_PCM_32_BIT:
481 return PCM_32_BIT;
482 default:
483 AUDIO_DEBUG_LOG("unknown format type, set it to default");
484 return PCM_24_BIT;
485 }
486 }
487
ConvertToHdiFormat(AudioSampleFormat format)488 AudioFormat MultichannelAudioRenderSink::ConvertToHdiFormat(AudioSampleFormat format)
489 {
490 AudioFormat hdiFormat;
491 switch (format) {
492 case SAMPLE_U8:
493 hdiFormat = AUDIO_FORMAT_TYPE_PCM_8_BIT;
494 break;
495 case SAMPLE_S16LE:
496 hdiFormat = AUDIO_FORMAT_TYPE_PCM_16_BIT;
497 break;
498 case SAMPLE_S24LE:
499 hdiFormat = AUDIO_FORMAT_TYPE_PCM_24_BIT;
500 break;
501 case SAMPLE_S32LE:
502 hdiFormat = AUDIO_FORMAT_TYPE_PCM_32_BIT;
503 break;
504 default:
505 hdiFormat = AUDIO_FORMAT_TYPE_PCM_16_BIT;
506 break;
507 }
508 return hdiFormat;
509 }
510
ParseAudioFormat(const std::string & format)511 AudioSampleFormat MultichannelAudioRenderSink::ParseAudioFormat(const std::string &format)
512 {
513 if (format == "AUDIO_FORMAT_PCM_16_BIT") {
514 return SAMPLE_S16LE;
515 } else if (format == "AUDIO_FORMAT_PCM_24_BIT" || format == "AUDIO_FORMAT_PCM_24_BIT_PACKED") {
516 return SAMPLE_S24LE;
517 } else if (format == "AUDIO_FORMAT_PCM_32_BIT") {
518 return SAMPLE_S32LE;
519 } else {
520 return SAMPLE_S16LE;
521 }
522 }
523
GetAudioCategory(AudioScene audioScene)524 AudioCategory MultichannelAudioRenderSink::GetAudioCategory(AudioScene audioScene)
525 {
526 AudioCategory audioCategory;
527 switch (audioScene) {
528 case AUDIO_SCENE_DEFAULT:
529 audioCategory = AUDIO_IN_MEDIA;
530 break;
531 case AUDIO_SCENE_RINGING:
532 case AUDIO_SCENE_VOICE_RINGING:
533 audioCategory = AUDIO_IN_RINGTONE;
534 break;
535 case AUDIO_SCENE_PHONE_CALL:
536 audioCategory = AUDIO_IN_CALL;
537 break;
538 case AUDIO_SCENE_PHONE_CHAT:
539 audioCategory = AUDIO_IN_COMMUNICATION;
540 break;
541 default:
542 audioCategory = AUDIO_IN_MEDIA;
543 break;
544 }
545 AUDIO_DEBUG_LOG("audioCategory: %{public}d", audioCategory);
546
547 return audioCategory;
548 }
549
InitAudioSampleAttr(struct AudioSampleAttributes & param)550 void MultichannelAudioRenderSink::InitAudioSampleAttr(struct AudioSampleAttributes ¶m)
551 {
552 param.channelCount = CHANNEL_6;
553 param.sampleRate = AUDIO_SAMPLE_RATE_48K;
554 param.interleaved = true;
555 param.streamId = static_cast<int32_t>(GenerateUniqueID(AUDIO_HDI_RENDER_ID_BASE, HDI_RENDER_OFFSET_MULTICHANNEL));
556 param.type = AUDIO_MULTI_CHANNEL;
557 param.period = DEEP_BUFFER_RENDER_PERIOD_SIZE;
558 param.isBigEndian = false;
559 param.isSignedData = true;
560 param.stopThreshold = INT_MAX;
561 param.silenceThreshold = 0;
562
563 param.sampleRate = attr_.sampleRate;
564 param.channelCount = attr_.channel;
565 param.channelLayout = attr_.channelLayout;
566 param.format = ConvertToHdiFormat(attr_.format);
567 param.frameSize = PcmFormatToBit(attr_.format) * param.channelCount / PCM_8_BIT;
568 param.startThreshold = DEEP_BUFFER_RENDER_PERIOD_SIZE / (param.frameSize);
569 }
570
InitDeviceDesc(struct AudioDeviceDescriptor & deviceDesc)571 void MultichannelAudioRenderSink::InitDeviceDesc(struct AudioDeviceDescriptor &deviceDesc)
572 {
573 deviceDesc.desc = const_cast<char *>("");
574 deviceDesc.pins = PIN_OUT_SPEAKER;
575 if (halName_ == HDI_ID_INFO_USB) {
576 deviceDesc.pins = PIN_OUT_USB_HEADSET;
577 }
578 }
579
InitSceneDesc(struct AudioSceneDescriptor & sceneDesc,AudioScene audioScene)580 void MultichannelAudioRenderSink::InitSceneDesc(struct AudioSceneDescriptor &sceneDesc, AudioScene audioScene)
581 {
582 sceneDesc.scene.id = GetAudioCategory(audioScene);
583
584 AudioPortPin pin = PIN_OUT_SPEAKER;
585 if (halName_ == HDI_ID_INFO_USB) {
586 pin = PIN_OUT_USB_HEADSET;
587 }
588 AUDIO_DEBUG_LOG("pin is %{public}d", pin);
589 sceneDesc.desc.pins = pin;
590 sceneDesc.desc.desc = const_cast<char *>("");
591 }
592
CreateRender(void)593 int32_t MultichannelAudioRenderSink::CreateRender(void)
594 {
595 struct AudioSampleAttributes param;
596 struct AudioDeviceDescriptor deviceDesc;
597 InitAudioSampleAttr(param);
598 InitDeviceDesc(deviceDesc);
599
600 AUDIO_INFO_LOG("create render, halName: %{public}s, rate: %{public}u, channel: %{public}u, format: %{public}u",
601 halName_.c_str(), param.sampleRate, param.channelCount, param.format);
602 HdiAdapterManager &manager = HdiAdapterManager::GetInstance();
603 std::shared_ptr<IDeviceManager> deviceManager = manager.GetDeviceManager(HDI_DEVICE_MANAGER_TYPE_LOCAL);
604 CHECK_AND_RETURN_RET(deviceManager != nullptr, ERR_INVALID_HANDLE);
605 void *render = deviceManager->CreateRender(adapterNameCase_, ¶m, &deviceDesc, hdiRenderId_);
606 audioRender_ = static_cast<struct IAudioRender *>(render);
607 CHECK_AND_RETURN_RET(audioRender_ != nullptr, ERR_NOT_STARTED);
608
609 AUDIO_INFO_LOG("create render success, hdiRenderId_: %{public}u", hdiRenderId_);
610 return SUCCESS;
611 }
612
DoSetOutputRoute(std::vector<DeviceType> & outputDevices)613 int32_t MultichannelAudioRenderSink::DoSetOutputRoute(std::vector<DeviceType> &outputDevices)
614 {
615 HdiAdapterManager &manager = HdiAdapterManager::GetInstance();
616 std::shared_ptr<IDeviceManager> deviceManager = manager.GetDeviceManager(HDI_DEVICE_MANAGER_TYPE_LOCAL);
617 CHECK_AND_RETURN_RET(deviceManager != nullptr, ERR_INVALID_HANDLE);
618 int32_t ret = deviceManager->SetOutputRoute(adapterNameCase_, outputDevices,
619 GenerateUniqueID(AUDIO_HDI_RENDER_ID_BASE, HDI_RENDER_OFFSET_MULTICHANNEL));
620 return ret;
621 }
622
InitRender(void)623 int32_t MultichannelAudioRenderSink::InitRender(void)
624 {
625 AUDIO_INFO_LOG("in");
626 if (renderInited_) {
627 AUDIO_INFO_LOG("render already inited");
628 return SUCCESS;
629 }
630
631 int32_t ret = CreateRender();
632 CHECK_AND_RETURN_RET_LOG(ret == SUCCESS, ERR_NOT_STARTED, "create render fail");
633 renderInited_ = true;
634 return SUCCESS;
635 }
636
AdjustStereoToMono(char * data,uint64_t len)637 void MultichannelAudioRenderSink::AdjustStereoToMono(char *data, uint64_t len)
638 {
639 // only stereo is supported now (stereo channel count is 2)
640 CHECK_AND_RETURN_LOG(attr_.channel == STEREO_CHANNEL_COUNT, "unsupport, channel: %{public}d", attr_.channel);
641
642 switch (attr_.format) {
643 case SAMPLE_U8:
644 AdjustStereoToMonoForPCM8Bit(reinterpret_cast<int8_t *>(data), len);
645 break;
646 case SAMPLE_S16LE:
647 AdjustStereoToMonoForPCM16Bit(reinterpret_cast<int16_t *>(data), len);
648 break;
649 case SAMPLE_S24LE:
650 AdjustStereoToMonoForPCM24Bit(reinterpret_cast<uint8_t *>(data), len);
651 break;
652 case SAMPLE_S32LE:
653 AdjustStereoToMonoForPCM32Bit(reinterpret_cast<int32_t *>(data), len);
654 break;
655 default:
656 // if the audio format is unsupported, the audio data will not be changed
657 AUDIO_ERR_LOG("unsupport, format: %{public}d", attr_.format);
658 break;
659 }
660 }
661
AdjustAudioBalance(char * data,uint64_t len)662 void MultichannelAudioRenderSink::AdjustAudioBalance(char *data, uint64_t len)
663 {
664 // only stereo is supported now (stereo channel count is 2)
665 CHECK_AND_RETURN_LOG(attr_.channel == STEREO_CHANNEL_COUNT, "unsupport, channel: %{public}d", attr_.channel);
666
667 switch (attr_.format) {
668 case SAMPLE_U8:
669 // this function needs further tested for usability
670 AdjustAudioBalanceForPCM8Bit(reinterpret_cast<int8_t *>(data), len, leftBalanceCoef_, rightBalanceCoef_);
671 break;
672 case SAMPLE_S16LE:
673 AdjustAudioBalanceForPCM16Bit(reinterpret_cast<int16_t *>(data), len, leftBalanceCoef_, rightBalanceCoef_);
674 break;
675 case SAMPLE_S24LE:
676 // this function needs further tested for usability
677 AdjustAudioBalanceForPCM24Bit(reinterpret_cast<uint8_t *>(data), len, leftBalanceCoef_, rightBalanceCoef_);
678 break;
679 case SAMPLE_S32LE:
680 AdjustAudioBalanceForPCM32Bit(reinterpret_cast<int32_t *>(data), len, leftBalanceCoef_, rightBalanceCoef_);
681 break;
682 default:
683 // if the audio format is unsupported, the audio data will not be changed
684 AUDIO_ERR_LOG("unsupport, format: %{public}d", attr_.format);
685 break;
686 }
687 }
688
CheckUpdateState(char * data,uint64_t len)689 void MultichannelAudioRenderSink::CheckUpdateState(char *data, uint64_t len)
690 {
691 if (startUpdate_) {
692 if (renderFrameNum_ == 0) {
693 last10FrameStartTime_ = ClockTime::GetCurNano();
694 }
695 renderFrameNum_++;
696 maxAmplitude_ = UpdateMaxAmplitude(static_cast<ConvertHdiFormat>(attr_.format), data, len);
697 if (renderFrameNum_ == GET_MAX_AMPLITUDE_FRAMES_THRESHOLD) {
698 renderFrameNum_ = 0;
699 if (last10FrameStartTime_ > lastGetMaxAmplitudeTime_) {
700 startUpdate_ = false;
701 maxAmplitude_ = 0;
702 }
703 }
704 }
705 }
706
707 // must be called with sinkMutex_ held
UpdateSinkState(bool started)708 void MultichannelAudioRenderSink::UpdateSinkState(bool started)
709 {
710 callback_.OnRenderSinkStateChange(GenerateUniqueID(AUDIO_HDI_RENDER_ID_BASE, HDI_RENDER_OFFSET_MULTICHANNEL),
711 started);
712 }
713
714 } // namespace AudioStandard
715 } // namespace OHOS
716