• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 &param)
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