• 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 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 &param)
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_, &param, &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