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