1
2 /*
3 * Copyright (c) 2022-2023 Huawei Device Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <cstdio>
18 #include <cstring>
19 #include <cstdlib>
20 #include <unistd.h>
21 #include <cerrno>
22 #include <fcntl.h>
23 #include <csignal>
24 #include <sys/stat.h>
25
26 #include <iostream>
27 #include <string>
28
29 #include <securec.h>
30 #include "unistd.h"
31 #include "./distributedaudiotest.h"
32
33 std::string deviceId;
34
35 struct Request {
36 pid_t pid;
37 int commandNum;
38 char reqString[70];
39 int seqLen;
40 };
41
42 struct Response {
43 int seqNum;
44 char resString[CMD_EXECUTING_RETURN_LENGHT_MAX];
45 };
46
47 using namespace OHOS::DistributedHardware;
48 static AudioManager *g_manager = nullptr;
49 static AudioAdapter *g_adapter = nullptr;
50 static AudioRender *g_render = nullptr;
51 static AudioCapture *g_capture = nullptr;
52 static AudioAdapterDescriptor *g_devices = nullptr;
53
54 static constexpr const char* PLAY_THREAD = "playThread";
55 static constexpr const char* CAPTURE_THREAD = "captureThread";
56
57 int32_t g_deviceNum = 0;
58 int32_t g_frameNum = 0;
59 int32_t g_frameIndex = 0;
60 int32_t g_micFrameNum = 0;
61 bool g_isInitRenderData = false;
62 static std::vector<uint8_t*> renderData;
63
64 static DeviceStatus g_spkStatus = DEVICE_IDLE;
65 static DeviceStatus g_micStatus = DEVICE_IDLE;
66
67 static std::thread g_palyingThread;
68 static std::thread g_capingThread;
69 FILE *g_micFile = nullptr;
70
GetNowTimeUs()71 static int64_t GetNowTimeUs()
72 {
73 std::chrono::microseconds nowUs =
74 std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now().time_since_epoch());
75 return nowUs.count();
76 }
77
InitTestDemo()78 int32_t InitTestDemo()
79 {
80 DHLOGI("**********************************************************************************");
81 DHLOGI("Distributed Audio Test Demo Bin v1.3.");
82 DHLOGI("**********************************************************************************");
83 DHLOGI("Init distributed audio hdf service.");
84 g_manager = GetAudioManagerFuncs();
85 if (g_manager == nullptr) {
86 DHLOGI("Distributed audio manager is null, quit!");
87 return ERR_DH_AUDIO_HDF_FAIL;
88 }
89 DHLOGI("Load audio manager success.");
90 return DH_SUCCESS;
91 }
92
FindAudioDevice()93 std::string FindAudioDevice()
94 {
95 if (g_manager == nullptr) {
96 return "false";
97 }
98 int32_t ret = g_manager->GetAllAdapters(g_manager, &g_devices, &g_deviceNum);
99 if (ret != DH_SUCCESS) {
100 DHLOGI("Get audio devices failed!");
101 return "false";
102 }
103 std::string res = "true";
104 std::cout << "Get audio devices success, adapter size: " << g_deviceNum << std::endl;
105 for (int32_t index = 0; index < g_deviceNum; index++) {
106 const AudioAdapterDescriptor &desc = g_devices[index];
107 std::cout << "Device[" << index << "] ID: " << desc.adapterName << std::endl;
108 deviceId = deviceId + desc.adapterName;
109 DHLOGI("demo test: Device [%s] ID", desc.adapterName);
110 if (index != g_deviceNum - 1) {
111 }
112 std::cout << "pin list: ";
113 for (uint32_t i = 0; i < desc.portNum; i++) {
114 std::cout << desc.ports[i].portId << ", ";
115 }
116 std::cout << std::endl;
117 }
118 return res;
119 }
120
HandleDevError(const char * condition,const char * value)121 static void HandleDevError(const char *condition, const char *value)
122 {
123 if (condition[TYPE_OFFSET] == DEV_TYPE_SPK && g_spkStatus != DEVICE_IDLE) {
124 CloseSpk();
125 }
126
127 if (condition[TYPE_OFFSET] == DEV_TYPE_MIC && g_micStatus == DEVICE_IDLE) {
128 CloseMic();
129 }
130
131 DHLOGI("Receive abnormal event, Demo quit.");
132 }
133
ParamEventCallback(AudioExtParamKey key,const char * condition,const char * value,void * reserved,void * cookie)134 static int32_t ParamEventCallback(AudioExtParamKey key, const char *condition, const char *value, void *reserved,
135 void *cookie)
136 {
137 std::string val(value);
138 std::string con(condition);
139 std::cout << std::endl;
140 DHLOGI("**********************************************************************************");
141 std::cout << "Event recived: " << key << std::endl;
142 std::cout << "Condition: " << con << std::endl;
143 std::cout << "Value: " << val << std::endl;
144 std::cout << std::endl;
145 DHLOGI("**********************************************************************************");
146
147 if (key == AudioExtParamKey::AUDIO_EXT_PARAM_KEY_STATUS && con.rfind("ERR_EVENT", 0) == 0) {
148 HandleDevError(condition, value);
149 }
150 return DH_SUCCESS;
151 }
152
LoadSpkDev(const std::string & devId)153 static int32_t LoadSpkDev(const std::string &devId)
154 {
155 std::cout << "Open SPK device , device Id:" << devId << std::endl;
156
157 struct AudioAdapterDescriptor *dev = nullptr;
158 for (int32_t index = 0; index < g_deviceNum; index++) {
159 struct AudioAdapterDescriptor &desc = g_devices[index];
160 if (desc.adapterName == devId) {
161 dev = &desc;
162 break;
163 }
164 }
165 if (dev == nullptr) {
166 DHLOGI("Input device id is wrong.");
167 FindAudioDevice();
168 return ERR_DH_AUDIO_HDF_FAIL;
169 }
170 if (g_manager == nullptr) {
171 return ERR_DH_AUDIO_HDF_FAIL;
172 }
173 if (g_adapter == nullptr) {
174 int32_t ret = g_manager->LoadAdapter(g_manager, dev, &g_adapter);
175 if (ret != DH_SUCCESS || g_adapter == nullptr) {
176 std::cout << "Load audio device failed, ret: " << ret << std::endl;
177 return ERR_DH_AUDIO_HDF_FAIL;
178 }
179 }
180 DHLOGI("Load audio device success.");
181 return DH_SUCCESS;
182 }
183
OpenSpk()184 std::string OpenSpk()
185 {
186 if (g_spkStatus != DEVICE_IDLE) {
187 DHLOGI("Speaker device is already opened.");
188 return "true";
189 }
190 if (LoadSpkDev(deviceId) != DH_SUCCESS) {
191 return "true";
192 }
193 ParamCallback callback = ParamEventCallback;
194 int32_t ret = g_adapter->RegExtraParamObserver(g_adapter, callback, nullptr);
195 if (ret != DH_SUCCESS) {
196 std::cout << "Register observer failed, ret: " << ret << std::endl;
197 return "true";
198 }
199
200 struct AudioDeviceDescriptor renderDesc;
201 renderDesc.pins = AudioPortPin::PIN_OUT_SPEAKER;
202 renderDesc.desc = nullptr;
203 AudioSampleAttributes g_rattrs = {};
204 g_rattrs.type = AUDIO_IN_MEDIA;
205 g_rattrs.interleaved = RENDER_INTER_LEAVED;
206 g_rattrs.streamId = RENDER_STREAM_ID;
207 g_rattrs.channelCount = RENDER_CHANNEL_MASK;
208 g_rattrs.sampleRate = AUDIO_SAMPLE_RATE;
209 g_rattrs.format = AudioFormat::AUDIO_FORMAT_TYPE_PCM_16_BIT;
210 ret = g_adapter->CreateRender(g_adapter, &renderDesc, &g_rattrs, &g_render);
211 if (ret != DH_SUCCESS || g_render == nullptr) {
212 std::cout << "Open SPK device failed, ret: " << ret << std::endl;
213 return "true";
214 }
215 g_spkStatus = DEVICE_OPEN;
216 DHLOGI("Open SPK device success.");
217 return "true";
218 }
219
WriteStreamWait(const int64_t & startTime)220 static void WriteStreamWait(const int64_t &startTime)
221 {
222 int64_t endTime = GetNowTimeUs();
223 int64_t passTime = endTime - startTime;
224
225 if (passTime > AUDIO_FRAME_TIME_INTERFAL_DEFAULT) {
226 return;
227 }
228 int64_t remainTime = AUDIO_FRAME_TIME_INTERFAL_DEFAULT - passTime;
229 std::this_thread::sleep_for(std::chrono::microseconds(remainTime));
230 }
231
Play()232 static void Play()
233 {
234 if (g_render == nullptr) {
235 DHLOGI("SPK device is null.");
236 return;
237 }
238 if (pthread_setname_np(pthread_self(), PLAY_THREAD) != DH_SUCCESS) {
239 DHLOGI("Play thread setname failed.");
240 }
241 DHLOGI("Playing thread started.");
242 g_render->control.Start((AudioHandle)g_render);
243 g_spkStatus = DEVICE_START;
244
245 uint64_t size = 0;
246 while (g_spkStatus == DEVICE_START) {
247 int64_t startTime = GetNowTimeUs();
248 int32_t ret = g_render->RenderFrame(g_render, renderData[g_frameIndex], RENDER_FRAME_SIZE, &size);
249 if (ret != DH_SUCCESS) {
250 std::cout<<"RenderFrame failed, index: "<< g_frameIndex << ", ret: " << ret << std::endl;
251 }
252 g_frameIndex++;
253 if (g_frameNum != 0 && g_frameIndex == g_frameNum) {
254 g_frameIndex = 0;
255 }
256 WriteStreamWait(startTime);
257 }
258 DHLOGI("Playing thread stopped.");
259 }
260
StartRender()261 std::string StartRender()
262 {
263 if (g_spkStatus == DEVICE_IDLE || g_spkStatus == DEVICE_OPEN) {
264 return "true";
265 }
266
267 if (g_spkStatus == DEVICE_OPEN) {
268 WavHdr wavHeader;
269 size_t headerSize = sizeof(WavHdr);
270 if (!g_isInitRenderData) {
271 struct stat statbuf;
272 stat(SPK_FILE_PATH, &statbuf);
273 int32_t size = statbuf.st_size;
274 g_frameNum = (size - headerSize) / RENDER_FRAME_SIZE;
275 std::cout << "Audio file frame num: " << g_frameNum << std::endl;
276 for (int32_t j = 0; j < g_frameNum; j++) {
277 uint8_t *frame = new uint8_t[RENDER_FRAME_SIZE]();
278 renderData.push_back(frame);
279 }
280 g_isInitRenderData = true;
281 }
282 FILE *wavFile = fopen(SPK_FILE_PATH, "rb");
283 fread(&wavHeader, 1, headerSize, wavFile);
284 for (int32_t i = 0; i < g_frameNum; i++) {
285 fread(renderData[i], 1, RENDER_FRAME_SIZE, wavFile);
286 }
287 fclose(wavFile);
288 g_frameIndex = 0;
289 g_palyingThread = std::thread(Play);
290 return "true";
291 }
292 if (g_spkStatus == DEVICE_START) {
293 return "Speaker device is started.";
294 }
295 if (g_spkStatus == DEVICE_STOP) {
296 g_palyingThread = std::thread(Play);
297 }
298 return "true";
299 }
300
StopRender()301 std::string StopRender()
302 {
303 if (g_render == nullptr || g_spkStatus == DEVICE_OPEN) {
304 return "true";
305 }
306
307 if (g_spkStatus == DEVICE_IDLE) {
308 return "Speaker device is not opened.";
309 }
310
311 if (g_spkStatus == DEVICE_OPEN) {
312 return "Speaker device is not started.";
313 }
314
315 if (g_spkStatus == DEVICE_STOP) {
316 return "Speaker device is already stoped.";
317 }
318
319 g_spkStatus = DEVICE_STOP;
320 if (g_palyingThread.joinable()) {
321 g_palyingThread.join();
322 }
323 g_render->control.Stop((AudioHandle)g_render);
324 return "true";
325 }
326
CloseSpk()327 std::string CloseSpk()
328 {
329 if (g_spkStatus == DEVICE_IDLE) {
330 return "true";
331 }
332
333 if (g_spkStatus == DEVICE_START) {
334 StopRender();
335 }
336
337 int32_t ret = g_adapter->DestroyRender(g_adapter, g_render);
338 if (ret != DH_SUCCESS) {
339 return "Close speaker failed";
340 }
341 if (g_micStatus == DEVICE_IDLE) {
342 g_manager->UnloadAdapter(g_manager, g_adapter);
343 g_adapter = nullptr;
344 }
345 g_spkStatus = DEVICE_IDLE;
346
347 if (g_isInitRenderData) {
348 for (auto &p : renderData) {
349 delete[] p;
350 }
351 renderData.clear();
352 g_isInitRenderData = false;
353 }
354 return "true";
355 }
356
LoadMicDev(const std::string & devId)357 static int32_t LoadMicDev(const std::string &devId)
358 {
359 std::cout << "Open MIC device ,input device Id:" << devId << std::endl;
360
361 struct AudioAdapterDescriptor *dev = nullptr;
362 for (int32_t index = 0; index < g_deviceNum; index++) {
363 struct AudioAdapterDescriptor &desc = g_devices[index];
364 if (desc.adapterName == devId) {
365 dev = &desc;
366 break;
367 }
368 }
369 if (dev == nullptr) {
370 DHLOGI("Input device id is wrong.");
371 FindAudioDevice();
372 return ERR_DH_AUDIO_HDF_FAIL;
373 }
374 if (g_manager == nullptr) {
375 return ERR_DH_AUDIO_HDF_FAIL;
376 }
377 if (g_adapter == nullptr) {
378 int32_t ret = g_manager->LoadAdapter(g_manager, dev, &g_adapter);
379 if (ret != DH_SUCCESS || g_adapter == nullptr) {
380 std::cout << "Load audio device failed, ret: " << ret << std::endl;
381 return ERR_DH_AUDIO_HDF_FAIL;
382 }
383 }
384 DHLOGI("Load audio device success.");
385 return DH_SUCCESS;
386 }
387
OpenMic()388 std::string OpenMic()
389 {
390 if (g_micStatus != DEVICE_IDLE) {
391 return "true";
392 }
393 if (LoadMicDev(deviceId) != DH_SUCCESS) {
394 return "true";
395 }
396
397 AudioDeviceDescriptor captureDesc;
398 captureDesc.pins = AudioPortPin::PIN_IN_MIC;
399 captureDesc.desc = nullptr;
400 AudioSampleAttributes captureAttr;
401 captureAttr.type = AUDIO_IN_MEDIA;
402 captureAttr.interleaved = CAPTURE_INTER_LEAVED;
403 captureAttr.streamId = CAPTURE_STREAM_ID;
404 captureAttr.channelCount = CAPTURE_CHANNEL_MASK;
405 captureAttr.sampleRate = AUDIO_SAMPLE_RATE;
406 captureAttr.format = AudioFormat::AUDIO_FORMAT_TYPE_PCM_16_BIT;
407 int32_t ret = g_adapter->CreateCapture(g_adapter, &captureDesc, &captureAttr, &g_capture);
408 if (ret != DH_SUCCESS || g_capture == nullptr) {
409 return "true";
410 }
411 g_micStatus = DEVICE_OPEN;
412 return "true";
413 }
414
ReadStreamWait(const int64_t & startTime)415 static void ReadStreamWait(const int64_t &startTime)
416 {
417 int64_t endTime = GetNowTimeUs();
418 int32_t passTime = endTime - startTime;
419
420 if (passTime > AUDIO_FRAME_TIME_INTERFAL_DEFAULT) {
421 return;
422 }
423 int64_t remainTime = AUDIO_FRAME_TIME_INTERFAL_DEFAULT - passTime;
424 std::this_thread::sleep_for(std::chrono::microseconds(remainTime));
425 }
426
Capture()427 static void Capture()
428 {
429 if (g_capture == nullptr) {
430 DHLOGI("MIC device is null.");
431 return;
432 }
433 if (pthread_setname_np(pthread_self(), CAPTURE_THREAD) != DH_SUCCESS) {
434 DHLOGI("Capture thread setname failed.");
435 }
436 DHLOGI("Capturing thread started.");
437 g_capture->control.Start((AudioHandle)g_capture);
438 g_micStatus = DEVICE_START;
439
440 uint64_t size = 0;
441 while (g_micStatus == DEVICE_START) {
442 uint8_t *data[RENDER_FRAME_SIZE];
443 int64_t startTime = GetNowTimeUs();
444 int32_t ret = g_capture->CaptureFrame(g_capture, data, RENDER_FRAME_SIZE, &size);
445 if (ret != DH_SUCCESS) {
446 std::cout << "CaptureFrame failed, ret: " << ret << std::endl;
447 return;
448 }
449 size_t res = fwrite(data, 1, RENDER_FRAME_SIZE, g_micFile);
450 if (res < DH_SUCCESS) {
451 std::cout << "fwrite failed, res: " << res << std::endl;
452 return;
453 }
454 g_micFrameNum++;
455 ReadStreamWait(startTime);
456 }
457 DHLOGI("Capturing thread stopped.");
458 }
459
StartCapture()460 std::string StartCapture()
461 {
462 if (g_micStatus == DEVICE_IDLE) {
463 return "true";
464 }
465
466 if (g_micStatus == DEVICE_OPEN) {
467 g_micFile = fopen(MIC_FILE_PATH, "ab+");
468 if (g_micFile == nullptr) {
469 return "Open pcm file failed.";
470 }
471 g_capingThread = std::thread(Capture);
472 return "true";
473 }
474
475 if (g_micStatus == DEVICE_START) {
476 return "Mic device is already started.";
477 }
478
479 if (g_micStatus == DEVICE_STOP) {
480 g_capingThread = std::thread(Capture);
481 }
482 return "true";
483 }
484
StopCapture()485 std::string StopCapture()
486 {
487 if (g_capture == nullptr) {
488 return "true";
489 }
490
491 if (g_micStatus == DEVICE_IDLE) {
492 return "Mic device is not opened.";
493 }
494
495 if (g_micStatus == DEVICE_OPEN) {
496 return "Mic device is not started.";
497 }
498
499 if (g_micStatus == DEVICE_STOP) {
500 return "Mic device is already started.";
501 }
502
503 g_micStatus = DEVICE_STOP;
504 if (g_capingThread.joinable()) {
505 g_capingThread.join();
506 }
507 g_capture->control.Stop((AudioHandle)g_capture);
508 return "true";
509 }
510
CloseMic()511 std::string CloseMic()
512 {
513 if (g_micStatus == DEVICE_IDLE) {
514 return "true";
515 }
516
517 if (g_micStatus == DEVICE_START) {
518 StopCapture();
519 }
520
521 int32_t ret = g_adapter->DestroyCapture(g_adapter, g_capture);
522 if (ret != DH_SUCCESS) {
523 return "Close mic failed.";
524 }
525 if (g_spkStatus == DEVICE_IDLE) {
526 g_manager->UnloadAdapter(g_manager, g_adapter);
527 g_adapter = nullptr;
528 }
529 if (g_micFile != nullptr) {
530 fclose(g_micFile);
531 g_micFile = nullptr;
532 }
533 g_micStatus = DEVICE_IDLE;
534 return "true";
535 }
536
SetVolume(std::string vol)537 std::string SetVolume(std::string vol)
538 {
539 if (g_spkStatus == DEVICE_IDLE) {
540 return "true";
541 }
542 int32_t volInt = std::stoi(vol);
543 if (volInt < VOLUME_MIN || volInt > VOLUME_MAX) {
544 return "Volume is invalid";
545 }
546 enum AudioExtParamKey key = AudioExtParamKey::AUDIO_EXT_PARAM_KEY_VOLUME;
547 std::string condition = "EVENT_TYPE=1;VOLUME_GROUP_ID=1;AUDIO_VOLUME_TYPE=1;";
548 int32_t ret = g_adapter->SetExtraParams(g_adapter, key, condition.c_str(), vol.c_str());
549 if (ret != DH_SUCCESS) {
550 return "Set volume failed";
551 }
552 return "true";
553 }
554
GetVolume()555 std::string GetVolume()
556 {
557 if (g_spkStatus == DEVICE_IDLE) {
558 return "true";
559 }
560 enum AudioExtParamKey key = AudioExtParamKey::AUDIO_EXT_PARAM_KEY_VOLUME;
561 std::string condition = "EVENT_TYPE=1;VOLUME_GROUP_ID=1;AUDIO_VOLUME_TYPE=1;";
562 char vol[VOLUME_BIT];
563 int32_t ret = g_adapter->GetExtraParams(g_adapter, key, condition.c_str(), vol, VOLUME_BIT);
564 if (ret != DH_SUCCESS) {
565 return "Get Volume failed.";
566 }
567 DHLOGI("demo test:GetVolume = %s", vol);
568 return "true";
569 }