• 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 #ifdef RECORDER_SUPPORT
17 
18 #define HST_LOG_TAG "AudioCaptureFilter"
19 
20 #include "pipeline/filters/source/audio_capture/audio_capture_filter.h"
21 #include "foundation/cpp_ext/algorithm_ext.h"
22 #include "foundation/log.h"
23 #include "pipeline/factory/filter_factory.h"
24 #include "pipeline/filters/common/buffer_calibration/audio_buffer_calibration.h"
25 #include "pipeline/filters/common/plugin_utils.h"
26 #include "plugin/common/plugin_attr_desc.h"
27 
28 namespace OHOS {
29 namespace Media {
30 namespace Pipeline {
31 using namespace Plugin;
32 
33 static AutoRegisterFilter<AudioCaptureFilter> g_registerFilterHelper("builtin.recorder.audiocapture");
34 
AudioCaptureFilter(const std::string & name)35 AudioCaptureFilter::AudioCaptureFilter(const std::string& name)
36     : FilterBase(name),
37       taskPtr_(nullptr),
38       plugin_(nullptr),
39       pluginAllocator_(nullptr),
40       pluginInfo_(nullptr),
41       bufferCalibration_(new AudioBufferCalibration)
42 {
43     filterType_ = FilterType::CAPTURE_SOURCE;
44     MEDIA_LOG_D("ctor called");
45 }
46 
~AudioCaptureFilter()47 AudioCaptureFilter::~AudioCaptureFilter()
48 {
49     MEDIA_LOG_D("dtor called");
50     if (taskPtr_) {
51         taskPtr_->Stop();
52     }
53     if (plugin_) {
54         plugin_->Deinit();
55     }
56 }
57 
GetWorkModes()58 std::vector<WorkMode> AudioCaptureFilter::GetWorkModes()
59 {
60     return {WorkMode::PUSH};
61 }
62 
InitAndConfigWithMeta(const std::shared_ptr<Plugin::Meta> & audioMeta)63 ErrorCode AudioCaptureFilter::InitAndConfigWithMeta(const std::shared_ptr<Plugin::Meta>& audioMeta)
64 {
65     MEDIA_LOG_D("IN");
66     if (appTokenIdSpecified_) {
67         NOK_LOG(plugin_->SetParameter(Tag::APP_TOKEN_ID, appTokenId_));
68     }
69     if (appFullTokenIdSpecified_) {
70         NOK_LOG(plugin_->SetParameter(Tag::APP_FULL_TOKEN_ID, appFullTokenId_));
71     }
72     if (appUidSpecified_) {
73         NOK_LOG(plugin_->SetParameter(Tag::APP_UID, appUid_));
74     }
75     if (appPidSpecified_) {
76         NOK_LOG(plugin_->SetParameter(Tag::APP_PID, appPid_));
77     }
78     ErrorCode err = TranslatePluginStatus(plugin_->Init());
79     if (err != ErrorCode::SUCCESS) {
80         return err;
81     }
82     plugin_->SetCallback(this);
83     pluginAllocator_ = plugin_->GetAllocator();
84     uint32_t tmp = 0;
85     if (audioMeta->Get<Tag::AUDIO_SAMPLE_RATE>(tmp)) {
86         MEDIA_LOG_I("configure plugin with sample rate " PUBLIC_LOG_U32, tmp);
87         bufferCalibration_->SetParam(Tag::AUDIO_SAMPLE_RATE, tmp);
88         err = TranslatePluginStatus(plugin_->SetParameter(Tag::AUDIO_SAMPLE_RATE, tmp));
89         if (err != ErrorCode::SUCCESS) {
90             return err;
91         }
92     }
93     if (audioMeta->Get<Tag::AUDIO_CHANNELS>(tmp)) {
94         MEDIA_LOG_I("configure plugin with channel " PUBLIC_LOG_U32, tmp);
95         bufferCalibration_->SetParam(Tag::AUDIO_CHANNELS, tmp);
96         err = TranslatePluginStatus(plugin_->SetParameter(Tag::AUDIO_CHANNELS, channelNum_));
97         if (err != ErrorCode::SUCCESS) {
98             return err;
99         }
100     }
101     int64_t bitRate = 0;
102     if (audioMeta->Get<Tag::MEDIA_BITRATE>(bitRate)) {
103         MEDIA_LOG_I("configure plugin with bitrate " PUBLIC_LOG_D64, bitRate);
104         err = TranslatePluginStatus(plugin_->SetParameter(Tag::MEDIA_BITRATE, bitRate));
105         if (err != ErrorCode::SUCCESS) {
106             return err;
107         }
108     }
109     Plugin::AudioSampleFormat sampleFormat = Plugin::AudioSampleFormat::S16;
110     if (audioMeta->Get<Tag::AUDIO_SAMPLE_FORMAT>(sampleFormat)) {
111         bufferCalibration_->SetParam(Tag::AUDIO_SAMPLE_FORMAT, sampleFormat);
112         MEDIA_LOG_I("configure plugin with sampleFormat " PUBLIC_LOG_S, Plugin::GetAudSampleFmtNameStr(sampleFormat));
113         return TranslatePluginStatus(plugin_->SetParameter(Tag::AUDIO_SAMPLE_FORMAT, sampleFormat));
114     }
115     return ErrorCode::SUCCESS;
116 }
117 
SetParameter(int32_t key,const Plugin::Any & value)118 ErrorCode AudioCaptureFilter::SetParameter(int32_t key, const Plugin::Any& value)
119 {
120     auto tag = static_cast<OHOS::Media::Plugin::Tag>(key);
121     switch (tag) {
122         case Tag::SRC_INPUT_TYPE:
123             inputTypeSpecified_ = AssignParameterIfMatch(tag, inputType_, value);
124             break;
125         case Tag::AUDIO_SAMPLE_RATE:
126             sampleRateSpecified_ = AssignParameterIfMatch(tag, sampleRate_, value);
127             break;
128         case Tag::AUDIO_CHANNELS:
129             channelNumSpecified_ = AssignParameterIfMatch(tag, channelNum_, value);
130             break;
131         case Tag::MEDIA_BITRATE:
132             bitRateSpecified_ = AssignParameterIfMatch(tag, bitRate_, value);
133             break;
134         case Tag::AUDIO_SAMPLE_FORMAT:
135             sampleFormatSpecified_ = AssignParameterIfMatch(tag, sampleFormat_, value);
136             break;
137         case Tag::AUDIO_CHANNEL_LAYOUT:
138             channelLayoutSpecified_ = AssignParameterIfMatch(tag, channelLayout_, value);
139             break;
140         case Tag::APP_TOKEN_ID:
141             appTokenIdSpecified_ = AssignParameterIfMatch(tag, appTokenId_, value);
142             break;
143         case Tag::APP_FULL_TOKEN_ID:
144             appFullTokenIdSpecified_ = AssignParameterIfMatch(tag, appFullTokenId_, value);
145             break;
146         case Tag::APP_UID:
147             appUidSpecified_ = AssignParameterIfMatch(tag, appUid_, value);
148             break;
149         case Tag::APP_PID:
150             appPidSpecified_ = AssignParameterIfMatch(tag, appPid_, value);
151             break;
152         default:
153             MEDIA_LOG_W("SetParameter: unknown key " PUBLIC_LOG_S "(" PUBLIC_LOG_D32 ")", GetTagStrName(tag), key);
154             break;
155     }
156     return ErrorCode::SUCCESS;
157 }
158 
GetParameter(int32_t key,Plugin::Any & value)159 ErrorCode AudioCaptureFilter::GetParameter(int32_t key, Plugin::Any& value)
160 {
161     Tag tag = static_cast<Plugin::Tag>(key);
162     switch (tag) {
163         case Tag::SRC_INPUT_TYPE: {
164             value = inputType_;
165             break;
166         }
167         case Tag::AUDIO_SAMPLE_RATE: {
168             value = sampleRate_;
169             break;
170         }
171         case Tag::AUDIO_CHANNELS: {
172             value = channelNum_;
173             break;
174         }
175         case Tag::MEDIA_BITRATE: {
176             value = bitRate_;
177             break;
178         }
179         case Tag::AUDIO_SAMPLE_FORMAT: {
180             value = sampleFormat_;
181             break;
182         }
183         default:
184             MEDIA_LOG_W("Unknown key " PUBLIC_LOG_S, GetTagStrName(tag));
185             break;
186     }
187     return ErrorCode::SUCCESS;
188 }
189 
PickPreferSampleFmt(const std::shared_ptr<Plugin::Meta> & meta,const Plugin::ValueType & val)190 void AudioCaptureFilter::PickPreferSampleFmt(const std::shared_ptr<Plugin::Meta>& meta, const Plugin::ValueType& val)
191 {
192     static constexpr AudioSampleFormat preferFmt = AudioSampleFormat::S16;
193     bool pickPreferFmt = false;
194     if (val.SameTypeWith(typeid(FixedCapability<AudioSampleFormat>)) &&
195         preferFmt == Plugin::AnyCast<FixedCapability<AudioSampleFormat>>(val)) {
196         pickPreferFmt = true;
197     } else if (val.SameTypeWith(typeid(DiscreteCapability<AudioSampleFormat>))) {
198         const auto* fmts = Plugin::AnyCast<DiscreteCapability<AudioSampleFormat>>(&val);
199         pickPreferFmt = CppExt::AnyOf(fmts->begin(), fmts->end(), [&](AudioSampleFormat tmp) -> bool {
200             return preferFmt == tmp;
201         });
202     }
203     if (pickPreferFmt) {
204         FALSE_LOG(meta->Set<Tag::AUDIO_SAMPLE_FORMAT>(preferFmt));
205     }
206 }
207 
PickPreferParameters()208 std::shared_ptr<Plugin::Meta> AudioCaptureFilter::PickPreferParameters()
209 {
210     auto preferMeta = std::make_shared<Plugin::Meta>();
211     if (capNegWithDownstream_.keys.count(Capability::Key::AUDIO_SAMPLE_FORMAT)) {
212         PickPreferSampleFmt(preferMeta, capNegWithDownstream_.keys.at(Capability::Key::AUDIO_SAMPLE_FORMAT));
213     }
214     return preferMeta;
215 }
216 
DoConfigure()217 ErrorCode AudioCaptureFilter::DoConfigure()
218 {
219     auto preferMeta = PickPreferParameters();
220     auto audioMeta = std::make_shared<Plugin::Meta>();
221     if (!MergeMetaWithCapability(*preferMeta, capNegWithDownstream_, *audioMeta)) {
222         MEDIA_LOG_E("cannot find available capability of plugin " PUBLIC_LOG_S, pluginInfo_->name.c_str());
223         return ErrorCode::ERROR_UNKNOWN;
224     }
225     Plugin::Meta upstreamParams;
226     Plugin::Meta downstreamParams;
227     if (!outPorts_[0]->Configure(audioMeta, upstreamParams, downstreamParams)) {
228         MEDIA_LOG_E("Configure downstream fail with " PUBLIC_LOG_S, Meta2String(*audioMeta).c_str());
229         return ErrorCode::ERROR_UNKNOWN;
230     }
231     return InitAndConfigWithMeta(audioMeta);
232 }
233 
Prepare()234 ErrorCode AudioCaptureFilter::Prepare()
235 {
236     MEDIA_LOG_I("Prepare entered.");
237     if (!taskPtr_) {
238         taskPtr_ = std::make_shared<OSAL::Task>("DataReader");
239         taskPtr_->RegisterHandler([this] { ReadLoop(); });
240     }
241     ErrorCode err = FindPlugin();
242     if (err != ErrorCode::SUCCESS || !plugin_) {
243         MEDIA_LOG_E("Find plugin fail");
244         return err;
245     }
246     err = DoConfigure();
247     if (err != ErrorCode::SUCCESS) {
248         MEDIA_LOG_E("DoConfigure fail");
249         return err;
250     }
251     err = TranslatePluginStatus(plugin_->Prepare());
252     if (err == ErrorCode::SUCCESS) {
253         MEDIA_LOG_D("media source send EVENT_READY");
254         OnEvent(Event{name_, EventType::EVENT_READY, {}});
255     }
256     return err;
257 }
258 
Start()259 ErrorCode AudioCaptureFilter::Start()
260 {
261     MEDIA_LOG_I("Start entered.");
262     eos_ = false;
263     auto res = ErrorCode::SUCCESS;
264     bufferCalibration_->Enable();
265     // start plugin firstly
266     if (plugin_) {
267         res = TranslatePluginStatus(plugin_->Start());
268     } else {
269         res = ErrorCode::ERROR_INVALID_OPERATION;
270     }
271     FALSE_RETURN_V_MSG_E(res == ErrorCode::SUCCESS, res, "start plugin failed");
272     // start task secondly
273     if (taskPtr_) {
274         taskPtr_->Start();
275     }
276     return res;
277 }
278 
Stop()279 ErrorCode AudioCaptureFilter::Stop()
280 {
281     MEDIA_LOG_I("Stop entered.");
282     FilterBase::Stop();
283     // stop task firstly
284     if (taskPtr_) {
285         taskPtr_->Stop();
286     }
287     bufferCalibration_->Reset();
288     latestBufferTime_ = HST_TIME_NONE;
289     latestPausedTime_ = HST_TIME_NONE;
290     totalPausedTime_ = 0;
291     refreshTotalPauseTime_ = false;
292     // stop plugin secondly
293     ErrorCode ret = ErrorCode::SUCCESS;
294     if (plugin_) {
295         ret = TranslatePluginStatus(plugin_->Stop());
296     }
297     return ret;
298 }
299 
Pause()300 ErrorCode AudioCaptureFilter::Pause()
301 {
302     MEDIA_LOG_I("Pause entered.");
303     FilterBase::Pause();
304     if (taskPtr_) {
305         taskPtr_->Pause();
306     }
307     latestPausedTime_ = latestBufferTime_;
308     ErrorCode ret = ErrorCode::SUCCESS;
309     if (plugin_) {
310         ret = TranslatePluginStatus(plugin_->Stop());
311     }
312     return ret;
313 }
314 
Resume()315 ErrorCode AudioCaptureFilter::Resume()
316 {
317     MEDIA_LOG_I("Resume entered.");
318     if (state_ == FilterState::PAUSED) {
319         refreshTotalPauseTime_ = true;
320     }
321     state_ = FilterState::RUNNING;
322     if (taskPtr_) {
323         taskPtr_->Start();
324     }
325     return plugin_ ? TranslatePluginStatus(plugin_->Start()) : ErrorCode::ERROR_INVALID_OPERATION;
326 }
327 
SendEos()328 ErrorCode AudioCaptureFilter::SendEos()
329 {
330     MEDIA_LOG_I("SendEos entered.");
331     auto buf = std::make_shared<AVBuffer>();
332     buf->flag |= BUFFER_FLAG_EOS;
333     SendBuffer(buf);
334     eos_ = true;
335     return ErrorCode::SUCCESS;
336 }
337 
InitPorts()338 void AudioCaptureFilter::InitPorts()
339 {
340     MEDIA_LOG_D("IN");
341     auto outPort = std::make_shared<OutPort>(this);
342     outPorts_.push_back(outPort);
343 }
344 
ReadLoop()345 void AudioCaptureFilter::ReadLoop()
346 {
347     if (eos_.load()) {
348         return;
349     }
350     uint64_t bufferSize = 0;
351     auto ret = plugin_->GetSize(bufferSize);
352     if (ret != Status::OK || bufferSize <= 0) {
353         MEDIA_LOG_E("Get plugin buffer size fail");
354         return;
355     }
356     AVBufferPtr bufferPtr = std::make_shared<AVBuffer>(BufferMetaType::AUDIO);
357     ret = plugin_->Read(bufferPtr, bufferSize);
358     if (ret == Status::ERROR_AGAIN) {
359         MEDIA_LOG_D("plugin read return again");
360         return;
361     }
362     if (ret != Status::OK) {
363         SendEos();
364         return;
365     }
366     latestBufferTime_ = bufferPtr->pts;
367     if (refreshTotalPauseTime_) {
368         if (latestPausedTime_ != HST_TIME_NONE && latestBufferTime_ > latestPausedTime_) {
369             totalPausedTime_ += latestBufferTime_ - latestPausedTime_;
370         }
371         refreshTotalPauseTime_ = false;
372     }
373     bufferPtr->pts -= totalPausedTime_;
374     SendBuffer(bufferPtr);
375 }
376 
CreatePlugin(const std::shared_ptr<PluginInfo> & info,const std::string & name,PluginManager & manager)377 ErrorCode AudioCaptureFilter::CreatePlugin(const std::shared_ptr<PluginInfo>& info, const std::string& name,
378                                            PluginManager& manager)
379 {
380     if ((plugin_ != nullptr) && (pluginInfo_ != nullptr)) {
381         if (info->name == pluginInfo_->name && TranslatePluginStatus(plugin_->Reset()) == ErrorCode::SUCCESS) {
382             MEDIA_LOG_I("Reuse last plugin: " PUBLIC_LOG_S, name.c_str());
383             return ErrorCode::SUCCESS;
384         }
385         if (TranslatePluginStatus(plugin_->Deinit()) != ErrorCode::SUCCESS) {
386             MEDIA_LOG_E("Deinit last plugin: " PUBLIC_LOG_S " error", pluginInfo_->name.c_str());
387         }
388     }
389     plugin_ = manager.CreateSourcePlugin(name);
390     if (plugin_ == nullptr) {
391         MEDIA_LOG_E("PluginManager CreatePlugin " PUBLIC_LOG_S " fail", name.c_str());
392         return ErrorCode::ERROR_UNKNOWN;
393     }
394     pluginInfo_ = info;
395     MEDIA_LOG_I("Create new plugin: " PUBLIC_LOG_S " success", pluginInfo_->name.c_str());
396     return ErrorCode::SUCCESS;
397 }
398 
CheckSampleRate(const Plugin::Capability & cap)399 bool AudioCaptureFilter::CheckSampleRate(const Plugin::Capability& cap)
400 {
401     if (!sampleRateSpecified_) {
402         return true;
403     }
404     for (const auto& pairKey : cap.keys) {
405         if (pairKey.first != Capability::Key::AUDIO_SAMPLE_RATE ||
406             !pairKey.second.SameTypeWith(typeid(DiscreteCapability<uint32_t>))) {
407             continue;
408         }
409         auto supportedSampleRateList = Plugin::AnyCast<DiscreteCapability<uint32_t>>(pairKey.second);
410         for (const auto& rate : supportedSampleRateList) {
411             if (rate == sampleRate_) {
412                 return true;
413             }
414         }
415     }
416     return false;
417 }
418 
CheckChannels(const Plugin::Capability & cap)419 bool AudioCaptureFilter::CheckChannels(const Plugin::Capability& cap)
420 {
421     if (!channelNumSpecified_) {
422         return true;
423     }
424     for (const auto& pairKey : cap.keys) {
425         if (pairKey.first != Capability::Key::AUDIO_CHANNELS ||
426             !pairKey.second.SameTypeWith(typeid(DiscreteCapability<uint32_t>))) {
427             continue;
428         }
429         auto supportedChannelsList = Plugin::AnyCast<DiscreteCapability<uint32_t>>(pairKey.second);
430         for (const auto& channel : supportedChannelsList) {
431             if (channel == channelNum_) {
432                 return true;
433             }
434         }
435     }
436     return false;
437 }
438 
CheckSampleFormat(const Plugin::Capability & cap)439 bool AudioCaptureFilter::CheckSampleFormat(const Plugin::Capability& cap)
440 {
441     if (!channelNumSpecified_) {
442         return true;
443     }
444     for (const auto& pairKey : cap.keys) {
445         if (pairKey.first != Capability::Key::AUDIO_SAMPLE_FORMAT ||
446             !pairKey.second.SameTypeWith(typeid(DiscreteCapability<Plugin::AudioSampleFormat>))) {
447             continue;
448         }
449         auto supportedSampleFormatList =
450             Plugin::AnyCast<DiscreteCapability<Plugin::AudioSampleFormat>>(pairKey.second);
451         for (const auto& fmt : supportedSampleFormatList) {
452             if (fmt == sampleFormat_) {
453                 return true;
454             }
455         }
456     }
457     return false;
458 }
459 
DoNegotiate(const CapabilitySet & outCaps)460 bool AudioCaptureFilter::DoNegotiate(const CapabilitySet &outCaps)
461 {
462     if (outCaps.empty()) {
463         MEDIA_LOG_E("audio capture plugin must have out caps");
464         return false;
465     }
466     for (const auto& outCap : outCaps) {
467         if (!CheckSampleRate(outCap) || !CheckChannels(outCap) || !CheckSampleFormat(outCap)) {
468             continue;
469         }
470         auto thisOut = std::make_shared<Plugin::Capability>();
471         *thisOut = outCap;
472         if (sampleFormatSpecified_) {
473             thisOut->keys[Capability::Key::AUDIO_SAMPLE_FORMAT] = sampleFormat_;
474         }
475         if (sampleRateSpecified_) {
476             thisOut->keys[Capability::Key::AUDIO_SAMPLE_RATE] = sampleRate_;
477         }
478         if (channelNumSpecified_) {
479             thisOut->keys[Capability::Key::AUDIO_CHANNELS] = channelNum_;
480         }
481         if (channelNum_ == 1) {
482             thisOut->keys[Capability::Key::AUDIO_CHANNEL_LAYOUT] = AudioChannelLayout::MONO;
483         } else if (channelNum_ == 2) { // 2 stereo
484             thisOut->keys[Capability::Key::AUDIO_CHANNEL_LAYOUT] = AudioChannelLayout::STEREO;
485         } else if (channelLayoutSpecified_) {
486             thisOut->keys[Capability::Key::AUDIO_CHANNEL_LAYOUT] = channelLayout_;
487         } else {
488             MEDIA_LOG_W("audio channel layout is unknown");
489         }
490         if (bitRateSpecified_) {
491             thisOut->keys[Capability::Key::MEDIA_BITRATE] = bitRate_;
492         }
493         Plugin::Meta upstreamParams;
494         Plugin::Meta downstreamParams;
495         if (outPorts_[0]->Negotiate(thisOut, capNegWithDownstream_, upstreamParams, downstreamParams)) {
496             MEDIA_LOG_I("Negotiate success");
497             return true;
498         }
499     }
500     return false;
501 }
502 
FindPlugin()503 ErrorCode AudioCaptureFilter::FindPlugin()
504 {
505     if (!inputTypeSpecified_) {
506         MEDIA_LOG_E("Must set input type first");
507         return ErrorCode::ERROR_INVALID_OPERATION;
508     }
509     PluginManager& pluginManager = PluginManager::Instance();
510     auto nameList = pluginManager.ListPlugins(PluginType::SOURCE);
511     for (const std::string& name : nameList) {
512         std::shared_ptr<PluginInfo> info = pluginManager.GetPluginInfo(PluginType::SOURCE, name);
513         MEDIA_LOG_I("name: " PUBLIC_LOG_S ", info->name: " PUBLIC_LOG_S, name.c_str(), info->name.c_str());
514         auto val = info->extra[PLUGIN_INFO_EXTRA_INPUT_TYPE];
515         if (val.SameTypeWith(typeid(Plugin::SrcInputType))) {
516             auto supportInputType = OHOS::Media::Plugin::AnyCast<Plugin::SrcInputType>(val);
517             if (inputType_ == supportInputType && DoNegotiate(info->outCaps) &&
518                 CreatePlugin(info, name, pluginManager) == ErrorCode::SUCCESS) {
519                 MEDIA_LOG_I("CreatePlugin " PUBLIC_LOG_S " success", name_.c_str());
520                 return ErrorCode::SUCCESS;
521             }
522         }
523     }
524     MEDIA_LOG_I("Cannot find any plugin");
525     return ErrorCode::ERROR_UNSUPPORTED_FORMAT;
526 }
527 
SendBuffer(const std::shared_ptr<AVBuffer> & buffer)528 void AudioCaptureFilter::SendBuffer(const std::shared_ptr<AVBuffer>& buffer)
529 {
530     OSAL::ScopedLock lock(pushDataMutex_);
531     if (!eos_) {
532         bufferCalibration_->CorrectBuffer(buffer);
533         outPorts_[0]->PushData(buffer, -1);
534     }
535 }
536 } // namespace Pipeline
537 } // namespace Media
538 } // namespace OHOS
539 #endif // RECORDER_SUPPORT