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