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