1 /*
2  * Copyright (c) 2022-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_client.h"
17 
18 #include <chrono>
19 
20 #include "cJSON.h"
21 
22 #include "daudio_constants.h"
23 #include "daudio_hisysevent.h"
24 #include "daudio_sink_hidumper.h"
25 #include "daudio_sink_manager.h"
26 
27 #undef DH_LOG_TAG
28 #define DH_LOG_TAG "DMicClient"
29 
30 namespace OHOS {
31 namespace DistributedHardware {
~DMicClient()32 DMicClient::~DMicClient()
33 {
34     if (micTrans_ != nullptr) {
35         DHLOGI("Release mic client.");
36         StopCapture();
37     }
38 }
39 
OnEngineTransEvent(const AVTransEvent & event)40 void DMicClient::OnEngineTransEvent(const AVTransEvent &event)
41 {
42     if (event.type == EventType::EVENT_START_SUCCESS) {
43         OnStateChange(DATA_OPENED);
44     } else if ((event.type == EventType::EVENT_STOP_SUCCESS) ||
45         (event.type == EventType::EVENT_CHANNEL_CLOSED) ||
46         (event.type == EventType::EVENT_START_FAIL)) {
47         OnStateChange(DATA_CLOSED);
48     }
49 }
50 
OnEngineTransMessage(const std::shared_ptr<AVTransMessage> & message)51 void DMicClient::OnEngineTransMessage(const std::shared_ptr<AVTransMessage> &message)
52 {
53     CHECK_NULL_VOID(message);
54     DHLOGI("On Engine message, type : %{public}s.", GetEventNameByType(message->type_).c_str());
55     DAudioSinkManager::GetInstance().HandleDAudioNotify(message->dstDevId_, message->dstDevId_,
56         static_cast<int32_t>(message->type_), message->content_);
57 }
58 
InitSenderEngine(IAVEngineProvider * providerPtr)59 int32_t DMicClient::InitSenderEngine(IAVEngineProvider *providerPtr)
60 {
61     DHLOGI("Init SenderEngine");
62     if (micTrans_ == nullptr) {
63         micTrans_ = std::make_shared<AVTransSenderTransport>(devId_, shared_from_this());
64     }
65     int32_t ret = micTrans_->InitEngine(providerPtr);
66     if (ret != DH_SUCCESS) {
67         DHLOGE("Mic client initialize av sender adapter failed.");
68         return ERR_DH_AUDIO_NULLPTR;
69     }
70     return DH_SUCCESS;
71 }
72 
OnStateChange(const AudioEventType type)73 int32_t DMicClient::OnStateChange(const AudioEventType type)
74 {
75     DHLOGD("On state change type: %{public}d.", type);
76     AudioEvent event;
77     cJSON *jParam = cJSON_CreateObject();
78     CHECK_NULL_RETURN(jParam, ERR_DH_AUDIO_NULLPTR);
79 
80     cJSON_AddStringToObject(jParam, KEY_DH_ID, std::to_string(dhId_).c_str());
81     char *jsonData = cJSON_PrintUnformatted(jParam);
82     if (jsonData == nullptr) {
83         DHLOGE("Failed to create JSON data.");
84         cJSON_Delete(jParam);
85         return ERR_DH_AUDIO_NULLPTR;
86     }
87     event.content = std::string(jsonData);
88     cJSON_Delete(jParam);
89     cJSON_free(jsonData);
90     switch (type) {
91         case AudioEventType::DATA_OPENED: {
92             isBlocking_.store(true);
93             if (audioParam_.captureOpts.capturerFlags != MMAP_MODE) {
94                 isCaptureReady_.store(true);
95                 captureDataThread_ = std::thread([this]() { this->CaptureThreadRunning(); });
96             }
97             event.type = AudioEventType::MIC_OPENED;
98             break;
99         }
100         case AudioEventType::DATA_CLOSED: {
101             event.type = AudioEventType::MIC_CLOSED;
102             break;
103         }
104         default:
105             DHLOGE("Invalid parameter type: %{public}d.", type);
106             return ERR_DH_AUDIO_NOT_SUPPORT;
107     }
108 
109     std::shared_ptr<IAudioEventCallback> cbObj = eventCallback_.lock();
110     CHECK_NULL_RETURN(cbObj, ERR_DH_AUDIO_NULLPTR);
111     cbObj->NotifyEvent(event);
112     return DH_SUCCESS;
113 }
114 
AudioFwkClientSetUp()115 int32_t DMicClient::AudioFwkClientSetUp()
116 {
117     AudioStandard::AudioCapturerOptions capturerOptions = {
118         {
119             static_cast<AudioStandard::AudioSamplingRate>(audioParam_.comParam.sampleRate),
120             AudioStandard::AudioEncodingType::ENCODING_PCM,
121             static_cast<AudioStandard::AudioSampleFormat>(audioParam_.comParam.bitFormat),
122             static_cast<AudioStandard::AudioChannel>(audioParam_.comParam.channelMask),
123         },
124         {
125             static_cast<AudioStandard::SourceType>(audioParam_.captureOpts.sourceType),
126             audioParam_.captureOpts.capturerFlags == MMAP_MODE ? AudioStandard::STREAM_FLAG_FAST : 0,
127         }
128     };
129     std::lock_guard<std::mutex> lck(devMtx_);
130     audioCapturer_ = AudioStandard::AudioCapturer::Create(capturerOptions);
131     CHECK_NULL_RETURN(audioCapturer_, ERR_DH_AUDIO_CLIENT_CAPTURER_CREATE_FAILED);
132     if (audioParam_.captureOpts.capturerFlags == MMAP_MODE) {
133         int32_t ret = audioCapturer_->SetCapturerReadCallback(shared_from_this());
134         if (ret != DH_SUCCESS) {
135             DHLOGE("Client save read callback failed.");
136             return ERR_DH_AUDIO_CLIENT_CAPTURER_CREATE_FAILED;
137         }
138     }
139     return TransSetUp();
140 }
141 
TransSetUp()142 int32_t DMicClient::TransSetUp()
143 {
144     CHECK_NULL_RETURN(micTrans_, ERR_DH_AUDIO_NULLPTR);
145     int32_t ret = micTrans_->SetUp(audioParam_, audioParam_, shared_from_this(), CAP_MIC);
146     if (ret != DH_SUCCESS) {
147         DHLOGE("Mic trans setup failed.");
148         return ret;
149     }
150     clientStatus_ = AudioStatus::STATUS_READY;
151     return DH_SUCCESS;
152 }
153 
SetUp(const AudioParam & param)154 int32_t DMicClient::SetUp(const AudioParam &param)
155 {
156     DHLOGI("Set up mic client, param: {sampleRate: %{public}d, bitFormat: %{public}d,"
157         "channelMask: %{public}d, sourceType: %{public}d, capturerFlags: %{public}d, frameSize: %{public}d}.",
158         param.comParam.sampleRate, param.comParam.bitFormat, param.comParam.channelMask, param.captureOpts.sourceType,
159         param.captureOpts.capturerFlags, param.comParam.frameSize);
160     audioParam_ = param;
161     DumpFileUtil::OpenDumpFile(DUMP_SERVER_PARA, DUMP_DAUDIO_MIC_BEFORE_TRANS_NAME, &dumpFile_);
162     return AudioFwkClientSetUp();
163 }
164 
SendMessage(uint32_t type,std::string content,std::string dstDevId)165 int32_t DMicClient::SendMessage(uint32_t type, std::string content, std::string dstDevId)
166 {
167     DHLOGD("Send message to remote.");
168     if (type != static_cast<uint32_t>(NOTIFY_OPEN_MIC_RESULT) &&
169         type != static_cast<uint32_t>(NOTIFY_OPEN_CTRL_RESULT) &&
170         type != static_cast<uint32_t>(NOTIFY_CLOSE_MIC_RESULT) &&
171         type != static_cast<uint32_t>(CLOSE_MIC)) {
172         DHLOGE("event type is not NOTIFY_OPEN_MIC or NOTIFY_CLOSE_MIC or"
173             "CLOSE_MIC or OPEN_CTRL. type: %{public}u", type);
174         return ERR_DH_AUDIO_NULLPTR;
175     }
176     CHECK_NULL_RETURN(micTrans_, ERR_DH_AUDIO_NULLPTR);
177     micTrans_->SendMessage(type, content, dstDevId);
178     return DH_SUCCESS;
179 }
180 
Release()181 int32_t DMicClient::Release()
182 {
183     DHLOGI("Release mic client.");
184     std::lock_guard<std::mutex> lck(devMtx_);
185     CHECK_NULL_RETURN(micTrans_, ERR_DH_AUDIO_SA_STATUS_ERR);
186     if (clientStatus_ != AudioStatus::STATUS_READY && clientStatus_ != AudioStatus::STATUS_STOP) {
187         DHLOGE("Mic status is wrong, %{public}d.", (int32_t)clientStatus_);
188         return ERR_DH_AUDIO_SA_STATUS_ERR;
189     }
190     bool isReleaseError = false;
191     if (audioCapturer_ == nullptr || !audioCapturer_->Release()) {
192         DHLOGE("Audio capturer release failed.");
193         isReleaseError = true;
194     }
195     int32_t ret = micTrans_->Release();
196     if (ret != DH_SUCCESS) {
197         DHLOGE("Mic trans release failed.");
198         isReleaseError = true;
199     }
200     micTrans_ = nullptr;
201     clientStatus_ = AudioStatus::STATUS_IDLE;
202     if (isReleaseError) {
203         return ERR_DH_AUDIO_FAILED;
204     }
205     DumpFileUtil::CloseDumpFile(&dumpFile_);
206     return DH_SUCCESS;
207 }
208 
StartCapture()209 int32_t DMicClient::StartCapture()
210 {
211     DHLOGI("Start capturer.");
212     std::lock_guard<std::mutex> lck(devMtx_);
213     CHECK_NULL_RETURN(micTrans_, ERR_DH_AUDIO_SA_STATUS_ERR);
214     CHECK_NULL_RETURN(audioCapturer_, ERR_DH_AUDIO_NULLPTR);
215 
216     if (clientStatus_ != AudioStatus::STATUS_READY) {
217         DHLOGE("Audio capturer init failed or mic status wrong, status: %{public}d.", (int32_t)clientStatus_);
218         DAudioHisysevent::GetInstance().SysEventWriteFault(DAUDIO_OPT_FAIL, ERR_DH_AUDIO_SA_STATUS_ERR,
219             "daudio init failed or mic status wrong.");
220         return ERR_DH_AUDIO_SA_STATUS_ERR;
221     }
222     if (!audioCapturer_->Start()) {
223         DHLOGE("Audio capturer start failed.");
224         audioCapturer_->Release();
225         DAudioHisysevent::GetInstance().SysEventWriteFault(DAUDIO_OPT_FAIL,
226             ERR_DH_AUDIO_CLIENT_CAPTURER_START_FAILED, "daudio capturer start failed.");
227         return ERR_DH_AUDIO_CLIENT_CAPTURER_START_FAILED;
228     }
229     int32_t ret = micTrans_->Start();
230     if (ret != DH_SUCCESS) {
231         DHLOGE("Mic trans start failed.");
232         micTrans_->Release();
233         DAudioHisysevent::GetInstance().SysEventWriteFault(DAUDIO_OPT_FAIL, ret, "daudio mic trans start failed.");
234         return ret;
235     }
236     clientStatus_ = AudioStatus::STATUS_START;
237     return DH_SUCCESS;
238 }
239 
AudioFwkCaptureData()240 void DMicClient::AudioFwkCaptureData()
241 {
242     std::shared_ptr<AudioData> audioData = std::make_shared<AudioData>(audioParam_.comParam.frameSize);
243     size_t bytesRead = 0;
244     bool errorFlag = false;
245     int64_t startTime = GetNowTimeUs();
246     CHECK_NULL_VOID(audioCapturer_);
247 
248     while (bytesRead < audioParam_.comParam.frameSize) {
249         int32_t len = audioCapturer_->Read(*(audioData->Data() + bytesRead),
250             audioParam_.comParam.frameSize - bytesRead, isBlocking_.load());
251         if (len >= 0) {
252             bytesRead += static_cast<size_t>(len);
253         } else {
254             errorFlag = true;
255             break;
256         }
257         int64_t endTime = GetNowTimeUs();
258         if (IsOutDurationRange(startTime, endTime, lastCaptureStartTime_)) {
259             DHLOGE("This time capture spend: %{public}" PRId64" us, The interval of capture this time and "
260                 "the last time: %{public}" PRId64" us", endTime - startTime, startTime - lastCaptureStartTime_);
261         }
262         lastCaptureStartTime_ = startTime;
263     }
264     if (errorFlag) {
265         DHLOGE("Bytes read failed.");
266         return;
267     }
268     if (isPauseStatus_.load()) {
269         memset_s(audioData->Data(), audioData->Size(), 0, audioData->Size());
270     }
271     DumpFileUtil::WriteDumpFile(dumpFile_, static_cast<void *>(audioData->Data()), audioData->Size());
272     int64_t startTransTime = GetNowTimeUs();
273     CHECK_NULL_VOID(micTrans_);
274     int32_t ret = micTrans_->FeedAudioData(audioData);
275     if (ret != DH_SUCCESS) {
276         DHLOGE("Failed to send data.");
277     }
278     int64_t endTransTime = GetNowTimeUs();
279     if (IsOutDurationRange(startTransTime, endTransTime, lastTransStartTime_)) {
280         DHLOGE("This time send data spend: %{public}" PRId64" us, The interval of send data this time and "
281             "the last time: %{public}" PRId64" us",
282             endTransTime - startTransTime, startTransTime - lastTransStartTime_);
283     }
284     lastTransStartTime_ = startTransTime;
285 }
286 
CaptureThreadRunning()287 void DMicClient::CaptureThreadRunning()
288 {
289     DHLOGD("Start the capturer thread.");
290     if (pthread_setname_np(pthread_self(), CAPTURETHREAD) != DH_SUCCESS) {
291         DHLOGE("Capture data thread setname failed.");
292     }
293     while (isCaptureReady_.load()) {
294         AudioFwkCaptureData();
295     }
296 }
297 
OnDecodeTransDataDone(const std::shared_ptr<AudioData> & audioData)298 int32_t DMicClient::OnDecodeTransDataDone(const std::shared_ptr<AudioData> &audioData)
299 {
300     (void)audioData;
301     return DH_SUCCESS;
302 }
303 
OnReadData(size_t length)304 void DMicClient::OnReadData(size_t length)
305 {
306     AudioStandard::BufferDesc bufDesc;
307     CHECK_NULL_VOID(audioCapturer_);
308 
309     if (audioCapturer_->GetBufferDesc(bufDesc) != DH_SUCCESS || bufDesc.bufLength == 0) {
310         DHLOGE("Get buffer desc failed.");
311         return;
312     }
313     CHECK_NULL_VOID(bufDesc.buffer);
314 
315     std::shared_ptr<AudioData> audioData = std::make_shared<AudioData>(audioParam_.comParam.frameSize);
316     if (audioData->Capacity() != bufDesc.bufLength) {
317         uint64_t capacity = static_cast<uint64_t>(audioData->Capacity());
318         uint64_t bufLength = static_cast<uint64_t>(bufDesc.bufLength);
319         DHLOGE("Audio data length is not equal to buflength. datalength: %{public}" PRIu64
320             ", bufLength: %{public}" PRIu64, capacity, bufLength);
321     }
322     if (memcpy_s(audioData->Data(), audioData->Capacity(), bufDesc.buffer, bufDesc.bufLength) != EOK) {
323         DHLOGE("Copy audio data failed.");
324     }
325 
326     if (isPauseStatus_.load()) {
327         memset_s(audioData->Data(), audioData->Size(), 0, audioData->Size());
328     }
329     audioCapturer_->Enqueue(bufDesc);
330 
331     CHECK_NULL_VOID(micTrans_);
332     if (micTrans_->FeedAudioData(audioData) != DH_SUCCESS) {
333         DHLOGE("Failed to send data.");
334     }
335 }
336 
StopCapture()337 int32_t DMicClient::StopCapture()
338 {
339     DHLOGI("Stop capturer.");
340     std::lock_guard<std::mutex> lck(devMtx_);
341     if (clientStatus_ != AudioStatus::STATUS_START) {
342         DHLOGE("Capturee is not start or mic status wrong, status: %{public}d.", (int32_t)clientStatus_);
343         DAudioHisysevent::GetInstance().SysEventWriteFault(DAUDIO_OPT_FAIL, ERR_DH_AUDIO_SA_STATUS_ERR,
344             "daudio capturer is not start or mic status wrong.");
345         return ERR_DH_AUDIO_SA_STATUS_ERR;
346     }
347     CHECK_NULL_RETURN(micTrans_, ERR_DH_AUDIO_NULLPTR);
348 
349     isBlocking_.store(false);
350     if (audioParam_.captureOpts.capturerFlags != MMAP_MODE && isCaptureReady_.load()) {
351         isCaptureReady_.store(false);
352         if (captureDataThread_.joinable()) {
353             captureDataThread_.join();
354         }
355     }
356 
357     bool status = true;
358     int32_t ret = micTrans_->Stop();
359     if (ret != DH_SUCCESS) {
360         DHLOGE("Mic trans stop failed.");
361         status = false;
362     }
363     if (audioCapturer_ == nullptr || !audioCapturer_->Stop()) {
364         DHLOGE("Audio capturer stop failed.");
365         status = false;
366     }
367     clientStatus_ = AudioStatus::STATUS_STOP;
368     if (!status) {
369         return ERR_DH_AUDIO_FAILED;
370     }
371     return DH_SUCCESS;
372 }
373 
SetAttrs(const std::string & devId,const std::shared_ptr<IAudioEventCallback> & callback)374 void DMicClient::SetAttrs(const std::string &devId, const std::shared_ptr<IAudioEventCallback> &callback)
375 {
376     DHLOGE("Set attrs, not support yet.");
377 }
378 
PauseCapture()379 int32_t DMicClient::PauseCapture()
380 {
381     DHLOGI("Pause capture.");
382     isPauseStatus_.store(true);
383     return DH_SUCCESS;
384 }
385 
ResumeCapture()386 int32_t DMicClient::ResumeCapture()
387 {
388     DHLOGI("Resume capture.");
389     isPauseStatus_.store(false);
390     return DH_SUCCESS;
391 }
392 } // DistributedHardware
393 } // OHOS
394