• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2021 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 #define HST_LOG_TAG "HdiSinkPlugin"
17 
18 #include "hos_au_sink.h"
19 #include <memory>
20 #include "audio_adapter.h"
21 #include "audio_manager.h"
22 #include "foundation/log.h"
23 #include "foundation/osal/thread/scoped_lock.h"
24 #include "foundation/osal/utils/util.h"
25 #include "plugin/common/plugin_audio_tags.h"
26 #include "plugins/hdi_adapter/utils/hdi_au_utils.h"
27 #include "securec.h"
28 #include "utils/constants.h"
29 #include "utils/utils.h"
30 
31 namespace {
32 using namespace OHOS::Media::Plugin;
33 using PluginSampleFmt = OHOS::Media::Plugin::AudioSampleFormat;
34 constexpr int32_t MAX_RETRY_CNT = 3;
35 constexpr int32_t RETRY_INTERVAL = 100; // 100ms
36 constexpr int32_t HI_ERR_VI_BUF_FULL = 0xA016800F;
37 constexpr int32_t RANK100 = 100;
38 constexpr int32_t PCM_CHAN_CNT = 2;
39 static std::map<std::string, std::pair<uint32_t, bool>> g_sinkInfos;
40 
LoadAndInitAdapter(AudioManager * audioManager,AudioAdapterDescriptor * descriptor,AudioAdapter ** adapter)41 Status LoadAndInitAdapter(AudioManager* audioManager, AudioAdapterDescriptor* descriptor, AudioAdapter** adapter)
42 {
43     if (audioManager == nullptr) {
44         MEDIA_LOG_E("no audio manager when load adapter");
45         return Status::ERROR_UNKNOWN;
46     }
47     if (adapter == nullptr) {
48         MEDIA_LOG_E("**adapter null ptr");
49         return Status::ERROR_INVALID_PARAMETER;
50     }
51     if (audioManager->LoadAdapter(audioManager, descriptor, adapter) < 0) {
52         *adapter = nullptr;
53         MEDIA_LOG_W("failed to load adapter %" PUBLIC_LOG "s", descriptor->adapterName);
54         return Status::ERROR_UNSUPPORTED_FORMAT;
55     }
56     if (*adapter == nullptr) {
57         MEDIA_LOG_E("no available adapter after load adapter");
58         return Status::ERROR_UNKNOWN;
59     }
60 
61     int32_t retryCnt = 0;
62     do {
63         if ((*adapter)->InitAllPorts(*adapter) != 0) {
64             OHOS::Media::OSAL::SleepFor(RETRY_INTERVAL);
65         } else {
66             break;
67         }
68         MEDIA_LOG_I("retry init port on adapter %" PUBLIC_LOG "s", descriptor->adapterName);
69     } while (++retryCnt < MAX_RETRY_CNT);
70     if (retryCnt >= MAX_RETRY_CNT) {
71         MEDIA_LOG_W("cannot init port on adapter %" PUBLIC_LOG "s after retry %" PUBLIC_LOG "d times",
72                     descriptor->adapterName, retryCnt);
73         audioManager->UnloadAdapter(audioManager, *adapter);
74         *adapter = nullptr;
75         return Status::ERROR_UNKNOWN;
76     }
77     return Status::OK;
78 }
79 
UpdatePluginCapWithPortCap(const AudioPortCapability & portCap,Capability & pluginCap)80 void UpdatePluginCapWithPortCap(const AudioPortCapability& portCap, Capability& pluginCap)
81 {
82     std::vector<PluginSampleFmt> sampleFormats;
83     for (size_t cnt = 0; cnt < portCap.supportSampleFormatNum; cnt++) {
84         PluginSampleFmt tmp;
85         if (OHOS::Media::HosLitePlugin::HdiAuFormat2PluginFormat(portCap.supportSampleFormats[cnt], tmp)) {
86             sampleFormats.emplace_back(tmp);
87         }
88     }
89     if (!sampleFormats.empty()) {
90         if (sampleFormats.size() == 1) {
91             pluginCap.AppendFixedKey<PluginSampleFmt>(Capability::Key::AUDIO_SAMPLE_FORMAT, sampleFormats[0]);
92         } else {
93             pluginCap.AppendDiscreteKeys<PluginSampleFmt>(Capability::Key::AUDIO_SAMPLE_FORMAT, sampleFormats);
94         }
95     }
96     auto pluginSampleRates = OHOS::Media::HosLitePlugin::HdiSampleRatesMask2PluginRates(portCap.sampleRateMasks);
97     if (!pluginSampleRates.empty()) {
98         if (pluginSampleRates.size() == 1) {
99             pluginCap.AppendFixedKey<uint32_t>(Capability::Key::AUDIO_SAMPLE_RATE, pluginSampleRates[0]);
100         } else {
101             pluginCap.AppendDiscreteKeys<uint32_t>(Capability::Key::AUDIO_SAMPLE_RATE, pluginSampleRates);
102         }
103     }
104     AudioChannelLayout pluginLayout;
105     if (OHOS::Media::HosLitePlugin::HdiMask2PluginChannelLayout(portCap.channelMasks, pluginLayout)) {
106         pluginCap.AppendFixedKey(Capability::Key::AUDIO_CHANNEL_LAYOUT, pluginLayout);
107     }
108     if (portCap.channelCount > 0) {
109         pluginCap.AppendIntervalKey<uint32_t>(Capability::Key::AUDIO_CHANNELS, 1, portCap.channelCount);
110     }
111 }
112 
AudioSinkPluginCreator(const std::string & name)113 std::shared_ptr<AudioSinkPlugin> AudioSinkPluginCreator(const std::string& name)
114 {
115     return std::make_shared<OHOS::Media::HosLitePlugin::HdiSink>(name);
116 }
117 
RegisterOutportOnAdapter(const std::shared_ptr<Register> & reg,const AudioAdapterDescriptor & desc,AudioAdapter * adapter)118 void RegisterOutportOnAdapter(const std::shared_ptr<Register>& reg, const AudioAdapterDescriptor& desc,
119                               AudioAdapter* adapter)
120 {
121     CapabilitySet adapterCapabilities;
122     bool usingDefaultCaps = false;
123     uint32_t pIndex = 0;
124     for (uint32_t portIndex = 0; portIndex < desc.portNum; portIndex++) {
125         if (desc.ports[portIndex].dir != PORT_OUT) {
126             continue;
127         }
128         Capability capability(OHOS::Media::MEDIA_MIME_AUDIO_RAW);
129         AudioPortCapability portCap{0};
130         if (adapter->GetPortCapability != nullptr &&
131             adapter->GetPortCapability(adapter, &desc.ports[portIndex], &portCap) == 0) {
132             UpdatePluginCapWithPortCap(portCap, capability);
133             usingDefaultCaps = false;
134         } else {
135             MEDIA_LOG_W("query port capability failed when registering plugin, set audio sample format as S16/S16P");
136             capability.AppendDiscreteKeys<PluginSampleFmt>(Capability::Key::AUDIO_SAMPLE_FORMAT,
137                                                            {PluginSampleFmt::S16, PluginSampleFmt::S16P});
138             usingDefaultCaps = true;
139         }
140         adapterCapabilities.emplace_back(capability);
141         pIndex = portIndex;
142         break; // only take the first out port
143     }
144     if (adapterCapabilities.empty()) {
145         return;
146     }
147     AudioSinkPluginDef sinkPluginDef;
148     sinkPluginDef.creator = AudioSinkPluginCreator;
149     sinkPluginDef.name = desc.adapterName;
150     sinkPluginDef.inCaps = adapterCapabilities;
151     sinkPluginDef.rank = RANK100;
152     if (reg->AddPlugin(sinkPluginDef) == Status::OK) {
153         g_sinkInfos[sinkPluginDef.name] = std::make_pair(pIndex, usingDefaultCaps);
154         MEDIA_LOG_D("register plugin %" PUBLIC_LOG "s succ.", desc.adapterName);
155     } else {
156         MEDIA_LOG_W("register plugin %" PUBLIC_LOG "s failed", desc.adapterName);
157     }
158 }
159 
RegisterHdiSinkPlugins(const std::shared_ptr<Register> & reg)160 Status RegisterHdiSinkPlugins(const std::shared_ptr<Register>& reg)
161 {
162     auto audioManager = GetAudioManagerFuncs();
163     if (audioManager == nullptr) {
164         MEDIA_LOG_E("cannot find audio manager funcs");
165         return Status::ERROR_UNKNOWN;
166     }
167     int32_t adapterSize = 0;
168     AudioAdapterDescriptor* descriptors = nullptr;
169     int32_t ret = audioManager->GetAllAdapters(audioManager, &descriptors, &adapterSize);
170     if (ret != 0 || adapterSize == 0) {
171         MEDIA_LOG_E("cannot find available audio adapter");
172         return Status::OK;
173     }
174     for (int32_t index = 0; index < adapterSize; index++) {
175         AudioAdapter* adapter = nullptr;
176         const auto& desc = descriptors[index];
177         if (LoadAndInitAdapter(audioManager, &descriptors[index], &adapter) != Status::OK) {
178             continue;
179         }
180         RegisterOutportOnAdapter(reg, desc, adapter);
181         audioManager->UnloadAdapter(audioManager, adapter);
182     }
183     return Status::OK;
184 }
185 
UnRegisterAudioDecoderPlugin()186 void UnRegisterAudioDecoderPlugin()
187 {
188     g_sinkInfos.clear();
189 }
190 
191 template <typename T>
AssignIfCastSuccess(T & lvalue,const Any & anyValue,const char * tagName)192 inline Status AssignIfCastSuccess(T& lvalue, const Any& anyValue, const char* tagName)
193 {
194     if (anyValue.SameTypeWith(typeid(T))) {
195         lvalue = AnyCast<const T&>(anyValue);
196         MEDIA_LOG_I("AssignIfCastSuccess found %" PUBLIC_LOG "s", tagName);
197         return Status::OK;
198     } else {
199         MEDIA_LOG_W("tag:%" PUBLIC_LOG "s value type mismatch", tagName);
200         return Status::ERROR_MISMATCHED_TYPE;
201     }
202 }
203 
CalculateBufferSize(const AudioSampleAttributes & attributes)204 int32_t CalculateBufferSize(const AudioSampleAttributes& attributes)
205 {
206     return attributes.frameSize * attributes.period;
207 }
208 
209 PLUGIN_DEFINITION(HdiAuSink, LicenseType::APACHE_V2, RegisterHdiSinkPlugins, UnRegisterAudioDecoderPlugin);
210 } // namespace
211 namespace OHOS {
212 namespace Media {
213 namespace HosLitePlugin {
214 using namespace OHOS::Media::Plugin;
215 
HdiSink(std::string name)216 HdiSink::HdiSink(std::string name)
217     : Plugin::AudioSinkPlugin(std::move(name)), audioManager_(nullptr), cacheData_(), processing_(false), renderCond_()
218 {
219     // default is media
220     sampleAttributes_.type = AUDIO_IN_MEDIA;
221     if (g_sinkInfos.count(pluginName_) != 0) {
222         usingDefaultInCaps_ = g_sinkInfos[pluginName_].second;
223     }
224 }
225 
Init()226 Status HdiSink::Init()
227 {
228     MEDIA_LOG_I("Init entered.");
229     audioManager_ = GetAudioManagerFuncs();
230     if (audioManager_ == nullptr) {
231         MEDIA_LOG_E("Init error due to audioManager nullptr");
232         return Status::ERROR_UNKNOWN;
233     }
234     int32_t adapterSize = 0;
235     AudioAdapterDescriptor* descriptors = nullptr;
236     int32_t ret = audioManager_->GetAllAdapters(audioManager_, &descriptors, &adapterSize);
237     if (ret != 0 || adapterSize == 0) {
238         MEDIA_LOG_E("cannot find available audio adapter");
239         return Status::ERROR_UNKNOWN;
240     }
241     for (int32_t index = 0; index < adapterSize; index++) {
242         const auto& desc = descriptors[index];
243         if (pluginName_ != desc.adapterName) {
244             continue;
245         }
246         if (LoadAndInitAdapter(audioManager_, &descriptors[index], &audioAdapter_) != Status::OK) {
247             continue;
248         }
249         adapterDescriptor_ = descriptors[index];
250         break;
251     }
252     if (audioAdapter_ == nullptr) {
253         MEDIA_LOG_E("cannot find adapter with name %" PUBLIC_LOG "s", pluginName_.c_str());
254         return Status::ERROR_UNKNOWN;
255     }
256     return Status::OK;
257 }
258 
ReleaseRender()259 Media::Plugin::Status HdiSink::ReleaseRender()
260 {
261     {
262         OHOS::Media::OSAL::ScopedLock lock(renderMutex_);
263         if (audioAdapter_ != nullptr && audioRender_ != nullptr) {
264             audioAdapter_->DestroyRender(audioAdapter_, audioRender_);
265             audioRender_ = nullptr;
266         }
267     }
268     return Status::OK;
269 }
270 
Deinit()271 Status HdiSink::Deinit()
272 {
273     MEDIA_LOG_I("Deinit entered.");
274     Stop();
275     // release all resources
276     ReleaseRender();
277     if (audioManager_ != nullptr) {
278         if (audioAdapter_ != nullptr) {
279             audioManager_->UnloadAdapter(audioManager_, audioAdapter_);
280             audioAdapter_ = nullptr;
281         }
282         audioManager_ = nullptr;
283     }
284     return Status::OK;
285 }
286 
ProcessInputSampleFormat(const ValueType & value)287 Status HdiSink::ProcessInputSampleFormat(const ValueType& value)
288 {
289     AudioSampleFormat format;
290     auto ret = AssignIfCastSuccess<AudioSampleFormat>(format, value, "audioSampleFormat");
291     if (ret != Status::OK) {
292         return ret;
293     }
294     if (PluginAuFormat2HdiAttrs(format, sampleAttributes_)) {
295         // if using default in caps e.g. S16/S16P always pass non-interleaved pcm data to hdi
296         // otherwise using the specified format
297         if (usingDefaultInCaps_) {
298             if (sampleAttributes_.interleaved) {
299                 isInputInterleaved_ = true;
300                 sampleAttributes_.interleaved = false;
301             } else {
302                 isInputInterleaved_ = false;
303             }
304         }
305         return Status::OK;
306     } else {
307         MEDIA_LOG_E("audioSampleFormat mismatch");
308         return Status::ERROR_MISMATCHED_TYPE;
309     }
310 }
311 
SetParameter(Tag tag,const ValueType & value)312 Status HdiSink::SetParameter(Tag tag, const ValueType& value)
313 {
314     switch (tag) {
315         case Tag::AUDIO_CHANNELS:
316             return AssignIfCastSuccess<uint32_t>(sampleAttributes_.channelCount, value, "channel");
317         case Tag::AUDIO_SAMPLE_RATE:
318             return AssignIfCastSuccess<uint32_t>(sampleAttributes_.sampleRate, value, "sampleRate");
319         case Tag::AUDIO_SAMPLE_FORMAT:
320             return ProcessInputSampleFormat(value);
321         case Tag::AUDIO_SAMPLE_PER_FRAME:
322             return AssignIfCastSuccess<uint32_t>(sampleAttributes_.period, value, "samples per frame");
323         case Tag::AUDIO_CHANNEL_LAYOUT: {
324             AudioChannelLayout layout;
325             auto ret = AssignIfCastSuccess<AudioChannelLayout>(layout, value, "audioChannelLayout");
326             if (ret != Status::OK) {
327                 return ret;
328             }
329             if (PluginChannelLayout2HdiMask(layout, channelMask_)) {
330                 return Status::OK;
331             } else {
332                 MEDIA_LOG_E("audioChannelLayout mismatch");
333                 return Status::ERROR_MISMATCHED_TYPE;
334             }
335         }
336         default:
337             MEDIA_LOG_I("receive one parameter with unconcern tag, ignore it");
338     }
339     return Status::OK;
340 }
341 
GetParameter(Tag tag,ValueType & value)342 Status HdiSink::GetParameter(Tag tag, ValueType& value)
343 {
344     UNUSED_VARIABLE(tag);
345     UNUSED_VARIABLE(value);
346     return Status::ERROR_UNIMPLEMENTED;
347 }
348 
Prepare()349 Status HdiSink::Prepare()
350 {
351     MEDIA_LOG_I("Prepare entered.");
352     sampleAttributes_.frameSize = GetPcmBytes(sampleAttributes_.format) * sampleAttributes_.channelCount;
353     sampleAttributes_.startThreshold = sampleAttributes_.period * sampleAttributes_.frameSize;
354     sampleAttributes_.stopThreshold = INT32_MAX;
355     sampleAttributes_.silenceThreshold = 0;
356     if (g_sinkInfos.count(pluginName_) == 0) {
357         MEDIA_LOG_E("cannot find out port");
358         return Status::ERROR_UNKNOWN;
359     }
360     deviceDescriptor_.portId = g_sinkInfos[pluginName_].first;
361     deviceDescriptor_.pins = PIN_OUT_SPEAKER;
362     deviceDescriptor_.desc = nullptr;
363 
364     MEDIA_LOG_I("create render: %" PUBLIC_LOG "s, port: %" PUBLIC_LOG "d:\ncategory %" PUBLIC_LOG
365                 "s,\nchannels %" PUBLIC_LOG "d, sampleRate %" PUBLIC_LOG "d,\n"
366                 " audioChannelMask %" PUBLIC_LOG "x, format %" PUBLIC_LOG "d,\nisSignedData %" PUBLIC_LOG
367                 "d, interleaved %" PUBLIC_LOG "d,\nperiod %" PUBLIC_LOG "u, frameSize %" PUBLIC_LOG "u",
368                 adapterDescriptor_.adapterName, deviceDescriptor_.portId,
369                 (sampleAttributes_.type == AUDIO_IN_MEDIA) ? "media" : "communication", sampleAttributes_.channelCount,
370                 sampleAttributes_.sampleRate, channelMask_, sampleAttributes_.format, sampleAttributes_.isSignedData,
371                 sampleAttributes_.interleaved, sampleAttributes_.period, sampleAttributes_.frameSize);
372     {
373         OHOS::Media::OSAL::ScopedLock lock(renderMutex_);
374         auto ret = audioAdapter_->CreateRender(audioAdapter_, &deviceDescriptor_, &sampleAttributes_, &audioRender_);
375         if (ret != 0) {
376             MEDIA_LOG_E("cannot create render with error code %" PUBLIC_LOG PRIu64 "x",
377                         static_cast<uint64_t>(ret));
378             audioRender_ = nullptr;
379             return Status::ERROR_UNKNOWN;
380         }
381     }
382     MEDIA_LOG_I("create audio render successfully");
383     if (sampleAttributes_.channelCount == PCM_CHAN_CNT && usingDefaultInCaps_ && isInputInterleaved_) {
384         cacheData_.resize(CalculateBufferSize(sampleAttributes_));
385     }
386     return Status::OK;
387 }
388 
Reset()389 Status HdiSink::Reset()
390 {
391     MEDIA_LOG_I("Reset entered.");
392     ReleaseRender();
393     (void)memset_s(&sampleAttributes_, sizeof(sampleAttributes_), 0, sizeof(sampleAttributes_));
394     (void)memset_s(&deviceDescriptor_, sizeof(deviceDescriptor_), 0, sizeof(deviceDescriptor_));
395     isInputInterleaved_ = false;
396     processing_ = false;
397     channelMask_ = AUDIO_CHANNEL_MONO;
398 
399     return Status::OK;
400 }
401 
Start()402 Status HdiSink::Start()
403 {
404     MEDIA_LOG_I("Start entered.");
405     OHOS::Media::OSAL::ScopedLock lock(renderMutex_);
406     if (audioRender_ == nullptr) {
407         MEDIA_LOG_E("no available render");
408         return Status::ERROR_UNKNOWN;
409     }
410 
411     if (audioRender_->control.Start(audioRender_) != 0) {
412         MEDIA_LOG_E("audio render start error");
413         return Status::ERROR_UNKNOWN;
414     }
415     processing_ = true;
416     return Status::OK;
417 }
418 
Stop()419 Status HdiSink::Stop()
420 {
421     MEDIA_LOG_I("Stop Entered");
422     OHOS::Media::OSAL::ScopedLock lock(renderMutex_);
423     processing_ = false;
424     renderCond_.NotifyOne();
425     if (audioRender_ == nullptr) {
426         MEDIA_LOG_E("no available render");
427         return Status::OK;
428     }
429     if (audioRender_->control.Stop(audioRender_) != 0) {
430         MEDIA_LOG_E("audio render stop error");
431         return Status::ERROR_UNKNOWN;
432     }
433     MEDIA_LOG_D("Stop Exited");
434     return Status::OK;
435 }
436 
IsParameterSupported(Tag tag)437 bool HdiSink::IsParameterSupported(Tag tag)
438 {
439     UNUSED_VARIABLE(tag);
440     return false;
441 }
442 
GetAllocator()443 std::shared_ptr<Allocator> HdiSink::GetAllocator()
444 {
445     return nullptr;
446 }
447 
SetCallback(Callback * cb)448 Status HdiSink::SetCallback(Callback* cb)
449 {
450     eventCallback_ = cb;
451     return Status::OK;
452 }
453 
GetMute(bool & mute)454 Status HdiSink::GetMute(bool& mute)
455 {
456     OHOS::Media::OSAL::ScopedLock lock(renderMutex_);
457     if (audioRender_ == nullptr) {
458         MEDIA_LOG_W("no render available, get mute must be called after prepared");
459         return Status::ERROR_WRONG_STATE;
460     }
461     if (audioRender_->volume.GetMute(audioRender_, &mute) != 0) {
462         MEDIA_LOG_E("get mute failed");
463         return Status::ERROR_UNKNOWN;
464     }
465     return Status::OK;
466 }
467 
SetMute(bool mute)468 Status HdiSink::SetMute(bool mute)
469 {
470     // todo when to set mute
471     OHOS::Media::OSAL::ScopedLock lock(renderMutex_);
472     if (audioRender_ == nullptr) {
473         MEDIA_LOG_W("no render available, set mute must be called after prepare");
474         return Status::ERROR_WRONG_STATE;
475     }
476     if (audioRender_->volume.SetMute(audioRender_, mute) != 0) {
477         MEDIA_LOG_E("set mute failed");
478         return Status::ERROR_UNKNOWN;
479     }
480     return Status::OK;
481 }
482 
GetVolume(float & volume)483 Status HdiSink::GetVolume(float& volume)
484 {
485     OHOS::Media::OSAL::ScopedLock lock(renderMutex_);
486     if (audioRender_ == nullptr) {
487         MEDIA_LOG_W("no render available, get volume must be called after prepare");
488         return Status::ERROR_WRONG_STATE;
489     }
490     if (audioRender_->volume.GetVolume(audioRender_, &volume) != 0) {
491         MEDIA_LOG_E("get volume failed");
492         return Status::ERROR_UNKNOWN;
493     }
494     return Status::OK;
495 }
496 
SetVolume(float volume)497 Status HdiSink::SetVolume(float volume)
498 {
499     OHOS::Media::OSAL::ScopedLock lock(renderMutex_);
500     if (audioRender_ == nullptr) {
501         MEDIA_LOG_W("no render available, set volume must be called after prepare");
502         return Status::ERROR_WRONG_STATE;
503     }
504     constexpr float maxVolume = 100.0f;
505     auto relVolume = volume * maxVolume;
506     if (audioRender_->volume.SetVolume(audioRender_, relVolume) != 0) {
507         MEDIA_LOG_E("set volume failed");
508         return Status::ERROR_UNKNOWN;
509     }
510     MEDIA_LOG_W("set volume to %" PUBLIC_LOG ".3f", relVolume);
511     return Status::OK;
512 }
513 
GetSpeed(float & speed)514 Status HdiSink::GetSpeed(float& speed)
515 {
516     OHOS::Media::OSAL::ScopedLock lock(renderMutex_);
517     if (audioRender_ == nullptr) {
518         MEDIA_LOG_W("no render available, get speed must be called after prepare");
519         return Status::ERROR_WRONG_STATE;
520     }
521     if (audioRender_->GetRenderSpeed(audioRender_, &speed) != 0) {
522         MEDIA_LOG_E("get speed failed");
523         return Status::ERROR_UNKNOWN;
524     }
525     return Status::OK;
526 }
527 
SetSpeed(float speed)528 Status HdiSink::SetSpeed(float speed)
529 {
530     OHOS::Media::OSAL::ScopedLock lock(renderMutex_);
531     if (audioRender_ == nullptr) {
532         MEDIA_LOG_W("no render available, set speed must be called after prepare");
533         return Status::ERROR_WRONG_STATE;
534     }
535     if (audioRender_->SetRenderSpeed(audioRender_, speed) != 0) {
536         MEDIA_LOG_E("set speed failed");
537         return Status::ERROR_UNKNOWN;
538     }
539     return Status::OK;
540 }
541 
Pause()542 Status HdiSink::Pause()
543 {
544     MEDIA_LOG_I("Pause Entered");
545     OHOS::Media::OSAL::ScopedLock lock(renderMutex_);
546     processing_ = false;
547     renderCond_.NotifyOne();
548     if (audioRender_ != nullptr && audioRender_->control.Pause(audioRender_) != 0) {
549         MEDIA_LOG_E("pause failed");
550         return Status::ERROR_UNKNOWN;
551     }
552     return Status::OK;
553 }
554 
Resume()555 Status HdiSink::Resume()
556 {
557     MEDIA_LOG_I("Resume Entered");
558     OHOS::Media::OSAL::ScopedLock lock(renderMutex_);
559     processing_ = true;
560     if (audioRender_ != nullptr && audioRender_->control.Resume(audioRender_) != 0) {
561         MEDIA_LOG_E("resume failed");
562         return Status::ERROR_UNKNOWN;
563     }
564     return Status::OK;
565 }
566 
GetLatency(uint64_t & ms)567 Status HdiSink::GetLatency(uint64_t& ms)
568 {
569     OHOS::Media::OSAL::ScopedLock lock(renderMutex_);
570     if (audioRender_ == nullptr) {
571         MEDIA_LOG_W("no render available, get latency must be called after prepare");
572         return Status::ERROR_WRONG_STATE;
573     }
574     uint32_t tmp;
575     if (audioRender_->GetLatency(audioRender_, &tmp) != 0) {
576         MEDIA_LOG_E("get latency failed");
577         return Status::ERROR_UNKNOWN;
578     }
579     ms = tmp;
580     return Status::OK;
581 }
582 
GetFrameSize(size_t & size)583 Status HdiSink::GetFrameSize(size_t& size)
584 {
585     UNUSED_VARIABLE(size);
586     return Status::ERROR_UNIMPLEMENTED;
587 }
588 
GetFrameCount(uint32_t & count)589 Status HdiSink::GetFrameCount(uint32_t& count)
590 {
591     UNUSED_VARIABLE(count);
592     return Status::ERROR_UNIMPLEMENTED;
593 }
594 
Write(const std::shared_ptr<Buffer> & input)595 Status HdiSink::Write(const std::shared_ptr<Buffer>& input)
596 {
597     MEDIA_LOG_D("Write begin.");
598     if (!input) {
599         MEDIA_LOG_E("Write failed due to nullptr.");
600         return Status::ERROR_INVALID_PARAMETER;
601     }
602     if (!input->IsEmpty()) {
603         RenderFrame(input);
604         MEDIA_LOG_D("Write finished.");
605         return Status::OK;
606     }
607     Status status = Status::OK;
608     if ((input->flag & BUFFER_FLAG_EOS) != 0) {
609         // TODO: call DrainBuffer, but now this function is invalid.
610     } else {
611         status = Status::ERROR_INVALID_PARAMETER;
612     }
613     return status;
614 }
615 
Flush()616 Status HdiSink::Flush()
617 {
618     MEDIA_LOG_I("Flush Entered");
619     OHOS::Media::OSAL::ScopedLock lock(renderMutex_);
620     if (audioRender_ == nullptr) {
621         MEDIA_LOG_E("no render available, flush must be called after prepare");
622         return Status::ERROR_WRONG_STATE;
623     }
624     if (audioRender_->control.Flush(audioRender_) != 0) {
625         MEDIA_LOG_E("audio render flush error");
626         return Status::ERROR_UNKNOWN;
627     }
628     MEDIA_LOG_I("Flush Exited.");
629     return Status::OK;
630 }
631 
632 template <typename T>
Deinterleave(T inData,T outData,int32_t frameCnt)633 static void Deinterleave(T inData, T outData, int32_t frameCnt)
634 {
635     int32_t frameSize = frameCnt / PCM_CHAN_CNT;
636     for (int i = 0; i < PCM_CHAN_CNT; i++) {
637         for (int j = 0; j < frameSize; j++) {
638             outData[i * frameSize + j] = inData[j * PCM_CHAN_CNT + i];
639         }
640     }
641 }
642 
Deinterleave16(uint8_t * inData,uint8_t * outData,int32_t frameCnt)643 void HdiSink::Deinterleave16(uint8_t* inData, uint8_t* outData, int32_t frameCnt)
644 {
645     if (sampleAttributes_.isSignedData == true) {
646         Deinterleave(reinterpret_cast<int16_t*>(inData), reinterpret_cast<int16_t*>(outData), frameCnt);
647     } else {
648         Deinterleave(reinterpret_cast<uint16_t*>(inData), reinterpret_cast<uint16_t*>(outData), frameCnt);
649     }
650 }
651 
Deinterleave8(uint8_t * inData,uint8_t * outData,int32_t frameCnt)652 void HdiSink::Deinterleave8(uint8_t* inData, uint8_t* outData, int32_t frameCnt)
653 {
654     if (sampleAttributes_.isSignedData == true) {
655         Deinterleave(reinterpret_cast<int8_t*>(inData), reinterpret_cast<int8_t*>(outData), frameCnt);
656     } else {
657         Deinterleave(inData, outData, frameCnt);
658     }
659 }
660 
Deinterleave32(uint8_t * inData,uint8_t * outData,int32_t frameCnt)661 void HdiSink::Deinterleave32(uint8_t* inData, uint8_t* outData, int32_t frameCnt)
662 {
663     if (sampleAttributes_.isSignedData == true) {
664         Deinterleave(reinterpret_cast<int32_t*>(inData), reinterpret_cast<int32_t*>(outData), frameCnt);
665     } else {
666         Deinterleave(reinterpret_cast<uint32_t*>(inData), reinterpret_cast<uint32_t*>(outData), frameCnt);
667     }
668 }
669 
HandleInterleaveData(uint8_t * origData,int32_t frameCnt)670 bool HdiSink::HandleInterleaveData(uint8_t* origData, int32_t frameCnt)
671 {
672     if (sampleAttributes_.channelCount != PCM_CHAN_CNT || !usingDefaultInCaps_ || !isInputInterleaved_) {
673         return false;
674     }
675     bool isHandled = true;
676     switch (sampleAttributes_.format) {
677         case AUDIO_FORMAT_PCM_16_BIT:
678             Deinterleave16(origData, cacheData_.data(), frameCnt);
679             break;
680         default:
681             isHandled = false;
682             break;
683     }
684     return isHandled;
685 }
686 
RenderFrame(const std::shared_ptr<Buffer> & input)687 void HdiSink::RenderFrame(const std::shared_ptr<Buffer>& input)
688 {
689     MEDIA_LOG_D("RenderFrame started");
690     auto mem = input->GetMemory();
691     auto frame = const_cast<uint8_t*>(mem->GetReadOnlyData());
692     bool dataInterleaved = false;
693     for (size_t remainingBytes = mem->GetSize(); processing_.load() && remainingBytes > 0;) {
694         int32_t ret = 0;
695         uint64_t renderSize = 0;
696         {
697             OHOS::Media::OSAL::ScopedLock lock(renderMutex_);
698             if (audioRender_ == nullptr) {
699                 break;
700             }
701             if (!dataInterleaved && HandleInterleaveData(frame, remainingBytes / PCM_CHAN_CNT)) {
702                 frame = cacheData_.data();
703                 dataInterleaved = true;
704             }
705             ret = audioRender_->RenderFrame(audioRender_, frame, remainingBytes, &renderSize);
706         }
707         if (ret != 0) {
708             if (ret == HI_ERR_VI_BUF_FULL) {
709                 MEDIA_LOG_D("renderFrame buffer full"); // do not log this info
710                 constexpr int timeoutMs = 5;
711                 OSAL::ScopedLock lock(renderMutex_);
712                 renderCond_.WaitFor(lock, timeoutMs, [this] { return processing_.load() == false; });
713             } else {
714                 MEDIA_LOG_E("renderFrame buffer error %" PUBLIC_LOG "d", ret);
715                 break;
716             }
717         }
718         frame += renderSize;
719         remainingBytes -= renderSize;
720     }
721 }
722 } // namespace HosLitePlugin
723 } // namespace Media
724 } // namespace OHOS
725