1 /*
2 * Copyright (c) 2024 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 #include "dmic_dev.h"
17
18 #include <condition_variable>
19 #include <mutex>
20 #include <string>
21 #include <thread>
22
23 #include "daudio_constants.h"
24 #include "daudio_errorcode.h"
25 #include "daudio_hidumper.h"
26 #include "daudio_hisysevent.h"
27 #include "daudio_hitrace.h"
28 #include "daudio_log.h"
29 #include "daudio_radar.h"
30 #include "daudio_source_manager.h"
31 #include "daudio_util.h"
32
33 #undef DH_LOG_TAG
34 #define DH_LOG_TAG "DMicDev"
35
36 namespace OHOS {
37 namespace DistributedHardware {
38 static constexpr size_t DATA_QUEUE_EXT_SIZE = 20;
OnEngineTransEvent(const AVTransEvent & event)39 void DMicDev::OnEngineTransEvent(const AVTransEvent &event)
40 {
41 if (event.type == EventType::EVENT_START_SUCCESS) {
42 OnStateChange(DATA_OPENED);
43 } else if ((event.type == EventType::EVENT_STOP_SUCCESS) ||
44 (event.type == EventType::EVENT_CHANNEL_CLOSED) ||
45 (event.type == EventType::EVENT_START_FAIL)) {
46 OnStateChange(DATA_CLOSED);
47 }
48 }
49
OnEngineTransMessage(const std::shared_ptr<AVTransMessage> & message)50 void DMicDev::OnEngineTransMessage(const std::shared_ptr<AVTransMessage> &message)
51 {
52 CHECK_NULL_VOID(message);
53 DHLOGI("On Engine message, type : %{public}s.", GetEventNameByType(message->type_).c_str());
54 DAudioSourceManager::GetInstance().HandleDAudioNotify(message->dstDevId_, message->dstDevId_,
55 message->type_, message->content_);
56 }
57
OnEngineTransDataAvailable(const std::shared_ptr<AudioData> & audioData)58 void DMicDev::OnEngineTransDataAvailable(const std::shared_ptr<AudioData> &audioData)
59 {
60 std::lock_guard<std::mutex> lock(ringbufferMutex_);
61 CHECK_NULL_VOID(ringBuffer_);
62 CHECK_AND_RETURN_LOG(ringBuffer_->RingBufferInsert(audioData->Data(),
63 static_cast<int32_t>(audioData->Capacity())) != DH_SUCCESS, "RingBufferInsert failed.");
64 DHLOGD("ringbuffer insert one");
65 }
66
ReadFromRingbuffer()67 void DMicDev::ReadFromRingbuffer()
68 {
69 std::shared_ptr<AudioData> sendData = std::make_shared<AudioData>(frameSize_);
70 bool canRead = false;
71 while (isRingbufferOn_.load()) {
72 CHECK_NULL_VOID(ringBuffer_);
73 canRead = false;
74 {
75 std::lock_guard<std::mutex> lock(ringbufferMutex_);
76 if (ringBuffer_->CanBufferReadLen(frameSize_)) {
77 canRead = true;
78 }
79 }
80 if (!canRead) {
81 DHLOGD("Can not read from ringbuffer.");
82 std::this_thread::sleep_for(std::chrono::milliseconds(RINGBUFFER_WAIT_SECONDS));
83 continue;
84 }
85 {
86 std::lock_guard<std::mutex> lock(ringbufferMutex_);
87 if (ringBuffer_->RingBufferGetData(sendData->Data(), sendData->Capacity()) != DH_SUCCESS) {
88 DHLOGE("Read ringbuffer failed.");
89 continue;
90 }
91 }
92 SendToProcess(sendData);
93 }
94 }
95
SendToProcess(const std::shared_ptr<AudioData> & audioData)96 void DMicDev::SendToProcess(const std::shared_ptr<AudioData> &audioData)
97 {
98 DHLOGD("On Engine Data available");
99 if (echoCannelOn_) {
100 #ifdef ECHO_CANNEL_ENABLE
101 CHECK_NULL_VOID(echoManager_);
102 echoManager_->OnMicDataReceived(audioData);
103 #endif
104 } else {
105 OnDecodeTransDataDone(audioData);
106 }
107 }
108
InitReceiverEngine(IAVEngineProvider * providerPtr)109 int32_t DMicDev::InitReceiverEngine(IAVEngineProvider *providerPtr)
110 {
111 DHLOGI("InitReceiverEngine enter.");
112 if (micTrans_ == nullptr) {
113 micTrans_ = std::make_shared<AVTransReceiverTransport>(devId_, shared_from_this());
114 }
115 int32_t ret = micTrans_->InitEngine(providerPtr);
116 if (ret != DH_SUCCESS) {
117 DHLOGE("Mic dev initialize av receiver adapter failed.");
118 return ret;
119 }
120 return DH_SUCCESS;
121 }
122
InitSenderEngine(IAVEngineProvider * providerPtr)123 int32_t DMicDev::InitSenderEngine(IAVEngineProvider *providerPtr)
124 {
125 DHLOGI("InitReceiverEngine enter.");
126 return DH_SUCCESS;
127 }
128
InitCtrlTrans()129 int32_t DMicDev::InitCtrlTrans()
130 {
131 DHLOGI("InitCtrlTrans enter");
132 if (micCtrlTrans_ == nullptr) {
133 micCtrlTrans_ = std::make_shared<DaudioSourceCtrlTrans>(devId_,
134 SESSIONNAME_MIC_SOURCE, SESSIONNAME_MIC_SINK, shared_from_this());
135 }
136 int32_t ret = micCtrlTrans_->SetUp(shared_from_this());
137 CHECK_AND_RETURN_RET_LOG(ret != DH_SUCCESS, ret, "Mic ctrl SetUp failed.");
138 ret = micCtrlTrans_->Start();
139 CHECK_AND_RETURN_RET_LOG(ret != DH_SUCCESS, ret, "Mic ctrl Start failed.");
140 return ret;
141 }
142
OnCtrlTransEvent(const AVTransEvent & event)143 void DMicDev::OnCtrlTransEvent(const AVTransEvent &event)
144 {
145 if (event.type == EventType::EVENT_START_SUCCESS) {
146 OnStateChange(DATA_OPENED);
147 } else if ((event.type == EventType::EVENT_STOP_SUCCESS) ||
148 (event.type == EventType::EVENT_CHANNEL_CLOSED) ||
149 (event.type == EventType::EVENT_START_FAIL)) {
150 OnStateChange(DATA_CLOSED);
151 }
152 }
153
OnCtrlTransMessage(const std::shared_ptr<AVTransMessage> & message)154 void DMicDev::OnCtrlTransMessage(const std::shared_ptr<AVTransMessage> &message)
155 {
156 CHECK_NULL_VOID(message);
157 DHLOGI("On Engine message, type : %{public}s.", GetEventNameByType(message->type_).c_str());
158 DAudioSourceManager::GetInstance().HandleDAudioNotify(message->dstDevId_, message->dstDevId_,
159 message->type_, message->content_);
160 }
161
EnableDevice(const int32_t dhId,const std::string & capability)162 int32_t DMicDev::EnableDevice(const int32_t dhId, const std::string &capability)
163 {
164 DHLOGI("Enable IO device, device pin: %{public}d.", dhId);
165 int32_t ret = DAudioHdiHandler::GetInstance().RegisterAudioDevice(devId_, dhId, capability, shared_from_this());
166 if (ret != DH_SUCCESS) {
167 DHLOGE("Register device failed, ret: %{public}d.", ret);
168 DAudioHisysevent::GetInstance().SysEventWriteFault(DAUDIO_REGISTER_FAIL, devId_, std::to_string(dhId), ret,
169 "daudio register device failed.");
170 return ret;
171 }
172 dhId_ = dhId;
173 GetCodecCaps(capability);
174 return DH_SUCCESS;
175 }
176
AddToVec(std::vector<AudioCodecType> & container,const AudioCodecType value)177 void DMicDev::AddToVec(std::vector<AudioCodecType> &container, const AudioCodecType value)
178 {
179 auto it = std::find(container.begin(), container.end(), value);
180 if (it == container.end()) {
181 container.push_back(value);
182 }
183 }
184
GetCodecCaps(const std::string & capability)185 void DMicDev::GetCodecCaps(const std::string &capability)
186 {
187 auto pos = capability.find(AAC);
188 if (pos != std::string::npos) {
189 AddToVec(codec_, AudioCodecType::AUDIO_CODEC_AAC_EN);
190 DHLOGI("Daudio codec cap: AAC");
191 }
192 pos = capability.find(OPUS);
193 if (pos != std::string::npos) {
194 AddToVec(codec_, AudioCodecType::AUDIO_CODEC_OPUS);
195 DHLOGI("Daudio codec cap: OPUS");
196 }
197 }
198
DisableDevice(const int32_t dhId)199 int32_t DMicDev::DisableDevice(const int32_t dhId)
200 {
201 DHLOGI("Disable IO device, device pin: %{public}d.", dhId);
202 int32_t ret = DAudioHdiHandler::GetInstance().UnRegisterAudioDevice(devId_, dhId);
203 if (ret != DH_SUCCESS) {
204 DHLOGE("UnRegister failed, ret: %{public}d.", ret);
205 DAudioHisysevent::GetInstance().SysEventWriteFault(DAUDIO_UNREGISTER_FAIL, devId_, std::to_string(dhId), ret,
206 "daudio unregister device failed.");
207 return ret;
208 }
209 return DH_SUCCESS;
210 }
211
IsMimeSupported(const AudioCodecType coder)212 bool DMicDev::IsMimeSupported(const AudioCodecType coder)
213 {
214 auto iter = std::find(codec_.begin(), codec_.end(), coder);
215 if (iter == codec_.end()) {
216 DHLOGI("devices have no cap: %{public}d", static_cast<int>(coder));
217 return false;
218 }
219 return true;
220 }
221
CreateStream(const int32_t streamId)222 int32_t DMicDev::CreateStream(const int32_t streamId)
223 {
224 DHLOGI("Open stream of mic device streamId: %{public}d.", streamId);
225 std::shared_ptr<IAudioEventCallback> cbObj = audioEventCallback_.lock();
226 CHECK_NULL_RETURN(cbObj, ERR_DH_AUDIO_NULLPTR);
227
228 cJSON *jParam = cJSON_CreateObject();
229 CHECK_NULL_RETURN(jParam, ERR_DH_AUDIO_NULLPTR);
230 cJSON_AddStringToObject(jParam, KEY_DH_ID, std::to_string(dhId_).c_str());
231 char *jsonData = cJSON_PrintUnformatted(jParam);
232 if (jsonData == nullptr) {
233 cJSON_Delete(jParam);
234 DHLOGE("Failed to create JSON data.");
235 return ERR_DH_AUDIO_NULLPTR;
236 }
237 std::string jsonDataStr(jsonData);
238 AudioEvent event(AudioEventType::OPEN_MIC, jsonDataStr);
239 cbObj->NotifyEvent(event);
240 DAudioHisysevent::GetInstance().SysEventWriteBehavior(DAUDIO_OPEN, devId_, std::to_string(dhId_),
241 "daudio mic device open success.");
242 streamId_ = streamId;
243 cJSON_Delete(jParam);
244 cJSON_free(jsonData);
245 DaudioRadar::GetInstance().ReportMicOpen("Start", MicOpen::CREATE_STREAM,
246 BizState::BIZ_STATE_START, DH_SUCCESS);
247 return DH_SUCCESS;
248 }
249
DestroyStream(const int32_t streamId)250 int32_t DMicDev::DestroyStream(const int32_t streamId)
251 {
252 DHLOGI("Close stream of mic device streamId: %{public}d.", streamId);
253 std::shared_ptr<IAudioEventCallback> cbObj = audioEventCallback_.lock();
254 CHECK_NULL_RETURN(cbObj, ERR_DH_AUDIO_NULLPTR);
255
256 cJSON *jParam = cJSON_CreateObject();
257 CHECK_NULL_RETURN(jParam, ERR_DH_AUDIO_NULLPTR);
258 cJSON_AddStringToObject(jParam, KEY_DH_ID, std::to_string(dhId_).c_str());
259 char *jsonData = cJSON_PrintUnformatted(jParam);
260 if (jsonData == nullptr) {
261 cJSON_Delete(jParam);
262 DHLOGE("Failed to create JSON data.");
263 return ERR_DH_AUDIO_NULLPTR;
264 }
265 std::string jsonDataStr(jsonData);
266 AudioEvent event(AudioEventType::CLOSE_MIC, jsonDataStr);
267 cbObj->NotifyEvent(event);
268 DAudioHisysevent::GetInstance().SysEventWriteBehavior(DAUDIO_CLOSE, devId_, std::to_string(dhId_),
269 "daudio mic device close success.");
270 cJSON_Delete(jParam);
271 cJSON_free(jsonData);
272 curPort_ = 0;
273 DaudioRadar::GetInstance().ReportMicClose("DestroyStream", MicClose::DESTROY_STREAM,
274 BizState::BIZ_STATE_START, DH_SUCCESS);
275 return DH_SUCCESS;
276 }
277
SetParameters(const int32_t streamId,const AudioParamHDF & param)278 int32_t DMicDev::SetParameters(const int32_t streamId, const AudioParamHDF ¶m)
279 {
280 DHLOGD("Set mic parameters {samplerate: %{public}d, channelmask: %{public}d, format: %{public}d, "
281 "period: %{public}d, framesize: %{public}d, ext{%{public}s}}.", param.sampleRate,
282 param.channelMask, param.bitFormat, param.period, param.frameSize, param.ext.c_str());
283 if (param.capturerFlags == MMAP_MODE && param.period != MMAP_NORMAL_PERIOD && param.period != MMAP_VOIP_PERIOD) {
284 DHLOGE("The period is invalid : %{public}" PRIu32, param.period);
285 return ERR_DH_AUDIO_SA_PARAM_INVALID;
286 }
287 curPort_ = dhId_;
288 paramHDF_ = param;
289
290 param_.comParam.sampleRate = paramHDF_.sampleRate;
291 param_.comParam.channelMask = paramHDF_.channelMask;
292 param_.comParam.bitFormat = paramHDF_.bitFormat;
293 param_.comParam.frameSize = paramHDF_.frameSize;
294 if (paramHDF_.streamUsage == StreamUsage::STREAM_USAGE_VOICE_COMMUNICATION) {
295 param_.captureOpts.sourceType = SOURCE_TYPE_VOICE_COMMUNICATION;
296 } else {
297 param_.captureOpts.sourceType = SOURCE_TYPE_MIC;
298 }
299 param_.captureOpts.capturerFlags = paramHDF_.capturerFlags;
300 if (paramHDF_.capturerFlags == MMAP_MODE) {
301 lowLatencyHalfSize_ = LOW_LATENCY_JITTER_TIME_MS / paramHDF_.period;
302 lowLatencyMaxfSize_ = LOW_LATENCY_JITTER_MAX_TIME_MS / paramHDF_.period;
303 }
304 param_.comParam.codecType = AudioCodecType::AUDIO_CODEC_AAC;
305 if (paramHDF_.streamUsage == StreamUsage::STREAM_USAGE_VOICE_COMMUNICATION &&
306 IsMimeSupported(AudioCodecType::AUDIO_CODEC_OPUS)) {
307 param_.comParam.codecType = AudioCodecType::AUDIO_CODEC_OPUS;
308 } else if (IsMimeSupported(AudioCodecType::AUDIO_CODEC_AAC_EN)) {
309 param_.comParam.codecType = AudioCodecType::AUDIO_CODEC_AAC_EN;
310 }
311 DHLOGI("codecType : %{public}d.", static_cast<int>(param_.comParam.codecType));
312 return DH_SUCCESS;
313 }
314
NotifyEvent(const int32_t streamId,const AudioEvent & event)315 int32_t DMicDev::NotifyEvent(const int32_t streamId, const AudioEvent &event)
316 {
317 DHLOGD("Notify mic event, type: %{public}d.", event.type);
318 std::shared_ptr<IAudioEventCallback> cbObj = audioEventCallback_.lock();
319 CHECK_NULL_RETURN(cbObj, ERR_DH_AUDIO_NULLPTR);
320 switch (event.type) {
321 case AudioEventType::AUDIO_START:
322 curStatus_ = AudioStatus::STATUS_START;
323 isExistedEmpty_.store(false);
324 break;
325 case AudioEventType::AUDIO_STOP:
326 curStatus_ = AudioStatus::STATUS_STOP;
327 isExistedEmpty_.store(false);
328 break;
329 default:
330 break;
331 }
332 AudioEvent audioEvent(event.type, event.content);
333 cbObj->NotifyEvent(audioEvent);
334 return DH_SUCCESS;
335 }
336
SetUp()337 int32_t DMicDev::SetUp()
338 {
339 DHLOGI("Set up mic device.");
340 CHECK_NULL_RETURN(micTrans_, ERR_DH_AUDIO_NULLPTR);
341 int32_t ret = micTrans_->SetUp(param_, param_, shared_from_this(), CAP_MIC);
342 if (ret != DH_SUCCESS) {
343 DHLOGE("Mic trans set up failed. ret: %{public}d.", ret);
344 return ret;
345 }
346 frameSize_ = static_cast<int32_t>(param_.comParam.frameSize);
347 {
348 std::lock_guard<std::mutex> lock(ringbufferMutex_);
349 ringBuffer_ = std::make_unique<DaudioRingBuffer>();
350 ringBuffer_->RingBufferInit(frameData_);
351 CHECK_NULL_RETURN(frameData_, ERR_DH_AUDIO_NULLPTR);
352 }
353 isRingbufferOn_.store(true);
354 ringbufferThread_ = std::thread([ptr = shared_from_this()]() {
355 if (!ptr) {
356 return;
357 }
358 ptr->ReadFromRingbuffer();
359 });
360 echoCannelOn_ = true;
361 #ifdef ECHO_CANNEL_ENABLE
362 if (echoCannelOn_ && echoManager_ == nullptr) {
363 echoManager_ = std::make_shared<DAudioEchoCannelManager>();
364 }
365 AudioCommonParam info;
366 info.sampleRate = param_.comParam.sampleRate;
367 info.channelMask = param_.comParam.channelMask;
368 info.bitFormat = param_.comParam.bitFormat;
369 info.frameSize = param_.comParam.frameSize;
370 if (echoManager_ != nullptr) {
371 echoManager_->SetUp(info, shared_from_this());
372 }
373 #endif
374 DumpFileUtil::OpenDumpFile(DUMP_SERVER_PARA, DUMP_DAUDIO_MIC_READ_FROM_BUF_NAME, &dumpFileCommn_);
375 DumpFileUtil::OpenDumpFile(DUMP_SERVER_PARA, DUMP_DAUDIO_LOWLATENCY_MIC_FROM_BUF_NAME, &dumpFileFast_);
376 return DH_SUCCESS;
377 }
378
Start()379 int32_t DMicDev::Start()
380 {
381 DHLOGI("Start mic device.");
382 CHECK_NULL_RETURN(micTrans_, ERR_DH_AUDIO_NULLPTR);
383 int32_t ret = micTrans_->Start();
384 DaudioRadar::GetInstance().ReportMicOpenProgress("Start", MicOpen::TRANS_START, ret);
385 if (ret != DH_SUCCESS) {
386 DHLOGE("Mic trans start failed, ret: %{public}d.", ret);
387 return ret;
388 }
389 std::unique_lock<std::mutex> lck(channelWaitMutex_);
390 auto status = channelWaitCond_.wait_for(lck, std::chrono::seconds(CHANNEL_WAIT_SECONDS),
391 [this]() { return isTransReady_.load(); });
392 if (!status) {
393 DHLOGE("Wait channel open timeout(%{public}ds).", CHANNEL_WAIT_SECONDS);
394 return ERR_DH_AUDIO_SA_WAIT_TIMEOUT;
395 }
396 isOpened_.store(true);
397 return DH_SUCCESS;
398 }
399
Pause()400 int32_t DMicDev::Pause()
401 {
402 DHLOGI("Not support.");
403 return DH_SUCCESS;
404 }
405
Restart()406 int32_t DMicDev::Restart()
407 {
408 DHLOGI("Not surpport.");
409 return DH_SUCCESS;
410 }
411
Stop()412 int32_t DMicDev::Stop()
413 {
414 DHLOGI("Stop mic device.");
415 CHECK_NULL_RETURN(micTrans_, DH_SUCCESS);
416 isOpened_.store(false);
417 isTransReady_.store(false);
418 int32_t ret = micTrans_->Stop();
419 if (ret != DH_SUCCESS) {
420 DHLOGE("Stop mic trans failed, ret: %{public}d.", ret);
421 }
422 #ifdef ECHO_CANNEL_ENABLE
423 CHECK_NULL_RETURN(echoManager_, DH_SUCCESS);
424 ret = echoManager_->Stop();
425 DaudioRadar::GetInstance().ReportMicCloseProgress("Stop", MicClose::STOP_TRANS, ret);
426 CHECK_AND_RETURN_RET_LOG(ret != DH_SUCCESS, ret, "Echo manager stop failed, ret: %{public}d.", ret);
427 #endif
428 return DH_SUCCESS;
429 }
430
Release()431 int32_t DMicDev::Release()
432 {
433 DHLOGI("Release mic device.");
434 if (ashmem_ != nullptr) {
435 ashmem_->UnmapAshmem();
436 ashmem_->CloseAshmem();
437 ashmem_ = nullptr;
438 DHLOGI("UnInit ashmem success.");
439 }
440 if (micCtrlTrans_ != nullptr) {
441 int32_t res = micCtrlTrans_->Release();
442 CHECK_AND_RETURN_RET_LOG(res != DH_SUCCESS, res, "Mic ctrl Release failed.");
443 }
444 CHECK_NULL_RETURN(micTrans_, DH_SUCCESS);
445
446 int32_t ret = micTrans_->Release();
447 DaudioRadar::GetInstance().ReportMicCloseProgress("Release", MicClose::RELEASE_TRANS, ret);
448 if (ret != DH_SUCCESS) {
449 DHLOGE("Release mic trans failed, ret: %{public}d.", ret);
450 return ret;
451 }
452 isRingbufferOn_.store(false);
453 if (ringbufferThread_.joinable()) {
454 ringbufferThread_.join();
455 }
456 {
457 std::lock_guard<std::mutex> lock(ringbufferMutex_);
458 ringBuffer_ = nullptr;
459 if (frameData_ != nullptr) {
460 delete[] frameData_;
461 frameData_ = nullptr;
462 }
463 }
464 #ifdef ECHO_CANNEL_ENABLE
465 if (echoManager_ != nullptr) {
466 echoManager_->Release();
467 echoManager_ = nullptr;
468 }
469 #endif
470 DumpFileUtil::CloseDumpFile(&dumpFileCommn_);
471 DumpFileUtil::CloseDumpFile(&dumpFileFast_);
472 return DH_SUCCESS;
473 }
474
IsOpened()475 bool DMicDev::IsOpened()
476 {
477 return isOpened_.load();
478 }
479
WriteStreamData(const int32_t streamId,std::shared_ptr<AudioData> & data)480 int32_t DMicDev::WriteStreamData(const int32_t streamId, std::shared_ptr<AudioData> &data)
481 {
482 (void)streamId;
483 (void)data;
484 return DH_SUCCESS;
485 }
486
ReadStreamData(const int32_t streamId,std::shared_ptr<AudioData> & data)487 int32_t DMicDev::ReadStreamData(const int32_t streamId, std::shared_ptr<AudioData> &data)
488 {
489 int64_t startTime = GetNowTimeUs();
490 if (curStatus_ != AudioStatus::STATUS_START) {
491 DHLOGE("Distributed audio is not starting status.");
492 return ERR_DH_AUDIO_FAILED;
493 }
494 std::lock_guard<std::mutex> lock(dataQueueMtx_);
495 uint32_t queSize = dataQueue_.size();
496 if (queSize == 0) {
497 isExistedEmpty_.store(true);
498 DHLOGD("Data queue is empty");
499 data = std::make_shared<AudioData>(param_.comParam.frameSize);
500 } else {
501 data = dataQueue_.front();
502 dataQueue_.pop();
503 }
504 CHECK_NULL_RETURN(data, ERR_DH_AUDIO_NULLPTR);
505 DumpFileUtil::WriteDumpFile(dumpFileCommn_, static_cast<void *>(data->Data()), data->Size());
506 int64_t endTime = GetNowTimeUs();
507 if (IsOutDurationRange(startTime, endTime, lastReadStartTime_)) {
508 DHLOGE("This time read data spend: %{public}" PRId64" us, The interval of read data this time and "
509 "the last time: %{public}" PRId64" us", endTime - startTime, startTime - lastReadStartTime_);
510 }
511 lastReadStartTime_ = startTime;
512 return DH_SUCCESS;
513 }
514
ReadMmapPosition(const int32_t streamId,uint64_t & frames,CurrentTimeHDF & time)515 int32_t DMicDev::ReadMmapPosition(const int32_t streamId, uint64_t &frames, CurrentTimeHDF &time)
516 {
517 DHLOGD("Read mmap position. frames: %{public}" PRIu64", tvsec: %{public}" PRId64", tvNSec:%{public}" PRId64,
518 writeNum_, writeTvSec_, writeTvNSec_);
519 frames = writeNum_;
520 time.tvSec = writeTvSec_;
521 time.tvNSec = writeTvNSec_;
522 return DH_SUCCESS;
523 }
524
RefreshAshmemInfo(const int32_t streamId,int32_t fd,int32_t ashmemLength,int32_t lengthPerTrans)525 int32_t DMicDev::RefreshAshmemInfo(const int32_t streamId,
526 int32_t fd, int32_t ashmemLength, int32_t lengthPerTrans)
527 {
528 DHLOGD("RefreshAshmemInfo: fd:%{public}d, ashmemLength: %{public}d, lengthPerTrans: %{public}d",
529 fd, ashmemLength, lengthPerTrans);
530 if (param_.captureOpts.capturerFlags == MMAP_MODE) {
531 DHLOGD("DMic dev low-latency mode");
532 if (ashmem_ != nullptr) {
533 return DH_SUCCESS;
534 }
535 if (ashmemLength < ASHMEM_MAX_LEN) {
536 ashmem_ = sptr<Ashmem>(new Ashmem(fd, ashmemLength));
537 ashmemLength_ = ashmemLength;
538 lengthPerTrans_ = lengthPerTrans;
539 DHLOGD("Create ashmem success. fd:%{public}d, ashmem length: %{public}d, lengthPreTrans: %{public}d",
540 fd, ashmemLength_, lengthPerTrans_);
541 bool mapRet = ashmem_->MapReadAndWriteAshmem();
542 if (!mapRet) {
543 DHLOGE("Mmap ashmem failed.");
544 return ERR_DH_AUDIO_NULLPTR;
545 }
546 }
547 }
548 return DH_SUCCESS;
549 }
550
MmapStart()551 int32_t DMicDev::MmapStart()
552 {
553 CHECK_NULL_RETURN(ashmem_, ERR_DH_AUDIO_NULLPTR);
554 std::lock_guard<std::mutex> lock(writeAshmemMutex_);
555 frameIndex_ = 0;
556 startTime_ = 0;
557 isEnqueueRunning_.store(true);
558 enqueueDataThread_ = std::thread([ptr = shared_from_this()]() {
559 if (!ptr) {
560 return;
561 }
562 ptr->EnqueueThread();
563 });
564 if (pthread_setname_np(enqueueDataThread_.native_handle(), ENQUEUE_THREAD) != DH_SUCCESS) {
565 DHLOGE("Enqueue data thread setname failed.");
566 }
567 return DH_SUCCESS;
568 }
569
EnqueueThread()570 void DMicDev::EnqueueThread()
571 {
572 writeIndex_ = 0;
573 writeNum_ = 0;
574 int64_t timeIntervalns = static_cast<int64_t>(paramHDF_.period * AUDIO_NS_PER_SECOND / AUDIO_MS_PER_SECOND);
575 DHLOGD("Enqueue thread start, lengthPerWrite length: %{public}d, interval: %{public}d.", lengthPerTrans_,
576 paramHDF_.period);
577 FillJitterQueue();
578 while (ashmem_ != nullptr && isEnqueueRunning_.load()) {
579 int64_t timeOffset = UpdateTimeOffset(frameIndex_, timeIntervalns, startTime_);
580 DHLOGD("Write frameIndex: %{public}" PRId64", timeOffset: %{public}" PRId64, frameIndex_, timeOffset);
581 std::shared_ptr<AudioData> audioData = nullptr;
582 {
583 std::lock_guard<std::mutex> lock(dataQueueMtx_);
584 if (dataQueue_.empty()) {
585 DHLOGD("Data queue is Empty.");
586 audioData = std::make_shared<AudioData>(param_.comParam.frameSize);
587 } else {
588 audioData = dataQueue_.front();
589 dataQueue_.pop();
590 }
591 if (audioData == nullptr) {
592 DHLOGD("The audioData is nullptr.");
593 continue;
594 }
595 DumpFileUtil::WriteDumpFile(dumpFileFast_, static_cast<void *>(audioData->Data()), audioData->Size());
596 bool writeRet = ashmem_->WriteToAshmem(audioData->Data(), audioData->Size(), writeIndex_);
597 if (writeRet) {
598 DHLOGD("Write to ashmem success! write index: %{public}d, writeLength: %{public}d.",
599 writeIndex_, lengthPerTrans_);
600 } else {
601 DHLOGE("Write data to ashmem failed.");
602 }
603 }
604 writeIndex_ += lengthPerTrans_;
605 if (writeIndex_ >= ashmemLength_) {
606 writeIndex_ = 0;
607 }
608 writeNum_ += static_cast<uint64_t>(CalculateSampleNum(param_.comParam.sampleRate, paramHDF_.period));
609 GetCurrentTime(writeTvSec_, writeTvNSec_);
610 frameIndex_++;
611 AbsoluteSleep(startTime_ + frameIndex_ * timeIntervalns - timeOffset);
612 }
613 }
614
FillJitterQueue()615 void DMicDev::FillJitterQueue()
616 {
617 while (isEnqueueRunning_.load()) {
618 {
619 std::lock_guard<std::mutex> lock(dataQueueMtx_);
620 if (paramHDF_.period == 0) {
621 DHLOGE("DMicDev paramHDF_.period is zero");
622 break;
623 }
624 if (dataQueue_.size() >= (LOW_LATENCY_JITTER_TIME_MS / paramHDF_.period)) {
625 break;
626 }
627 }
628 usleep(MMAP_WAIT_FRAME_US);
629 }
630 DHLOGD("Mic jitter data queue fill end.");
631 }
632
MmapStop()633 int32_t DMicDev::MmapStop()
634 {
635 std::lock_guard<std::mutex> lock(writeAshmemMutex_);
636 isEnqueueRunning_.store(false);
637 if (enqueueDataThread_.joinable()) {
638 enqueueDataThread_.join();
639 }
640 DHLOGI("Mic mmap stop end.");
641 return DH_SUCCESS;
642 }
643
GetAudioParam() const644 AudioParam DMicDev::GetAudioParam() const
645 {
646 return param_;
647 }
648
NotifyHdfAudioEvent(const AudioEvent & event,const int32_t portId)649 int32_t DMicDev::NotifyHdfAudioEvent(const AudioEvent &event, const int32_t portId)
650 {
651 int32_t ret = DAudioHdiHandler::GetInstance().NotifyEvent(devId_, portId, streamId_, event);
652 if (ret != DH_SUCCESS) {
653 DHLOGE("Notify event: %{public}d, result: %{public}s, streamId: %{public}d.",
654 event.type, event.content.c_str(), streamId_);
655 }
656 return DH_SUCCESS;
657 }
658
OnStateChange(const AudioEventType type)659 int32_t DMicDev::OnStateChange(const AudioEventType type)
660 {
661 DHLOGD("On mic device state change, type: %{public}d", type);
662 AudioEvent event;
663 switch (type) {
664 case AudioEventType::DATA_OPENED:
665 isTransReady_.store(true);
666 channelWaitCond_.notify_one();
667 event.type = AudioEventType::MIC_OPENED;
668 break;
669 case AudioEventType::DATA_CLOSED:
670 isTransReady_.store(false);
671 event.type = AudioEventType::MIC_CLOSED;
672 break;
673 default:
674 break;
675 }
676 event.content = GetCJsonString(KEY_DH_ID, std::to_string(dhId_).c_str());
677 std::shared_ptr<IAudioEventCallback> cbObj = audioEventCallback_.lock();
678 CHECK_NULL_RETURN(cbObj, ERR_DH_AUDIO_NULLPTR);
679 cbObj->NotifyEvent(event);
680 return DH_SUCCESS;
681 }
682
SendMessage(uint32_t type,std::string content,std::string dstDevId)683 int32_t DMicDev::SendMessage(uint32_t type, std::string content, std::string dstDevId)
684 {
685 DHLOGD("Send message to remote.");
686 if (type != static_cast<uint32_t>(OPEN_MIC) && type != static_cast<uint32_t>(CLOSE_MIC)) {
687 DHLOGE("Send message to remote. not OPEN_MIC or CLOSE_MIC. type: %{public}u", type);
688 return ERR_DH_AUDIO_NULLPTR;
689 }
690 CHECK_NULL_RETURN(micCtrlTrans_, ERR_DH_AUDIO_NULLPTR);
691 micCtrlTrans_->SendAudioEvent(type, content, dstDevId);
692 return DH_SUCCESS;
693 }
694
OnDecodeTransDataDone(const std::shared_ptr<AudioData> & audioData)695 int32_t DMicDev::OnDecodeTransDataDone(const std::shared_ptr<AudioData> &audioData)
696 {
697 CHECK_NULL_RETURN(audioData, ERR_DH_AUDIO_NULLPTR);
698 std::lock_guard<std::mutex> lock(dataQueueMtx_);
699 dataQueSize_ = curStatus_ != AudioStatus::STATUS_START ?
700 (param_.captureOpts.capturerFlags == MMAP_MODE ? lowLatencyHalfSize_ : DATA_QUEUE_HALF_SIZE) :
701 (param_.captureOpts.capturerFlags == MMAP_MODE ? lowLatencyMaxfSize_ : DATA_QUEUE_MAX_SIZE);
702 if (isExistedEmpty_.load()) {
703 dataQueSize_ = param_.captureOpts.capturerFlags == MMAP_MODE ? dataQueSize_ : DATA_QUEUE_EXT_SIZE;
704 }
705 uint64_t queueSize;
706 while (dataQueue_.size() > dataQueSize_) {
707 queueSize = static_cast<uint64_t>(dataQueue_.size());
708 DHLOGD("Data queue overflow. buf current size: %{public}" PRIu64, queueSize);
709 dataQueue_.pop();
710 }
711 dataQueue_.push(audioData);
712 queueSize = static_cast<uint64_t>(dataQueue_.size());
713 DHLOGD("Push new mic data, buf len: %{public}" PRIu64, queueSize);
714 return DH_SUCCESS;
715 }
716 } // DistributedHardware
717 } // OHOS
718