1/*
2 * Copyright (c) 2023 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 <cstdio>
17#include <cstring>
18#include <cstdlib>
19#include <unistd.h>
20#include <cerrno>
21#include <fcntl.h>
22#include <csignal>
23#include <sys/stat.h>
24
25#include <iostream>
26#include <string>
27
28#include <securec.h>
29#include "unistd.h"
30#include "distributedaudiotest.h"
31#include "daudio_errorcode.h"
32#include "daudio_log.h"
33
34using OHOS::HDI::DistributedAudio::Audio::V1_0::IAudioAdapter;
35using OHOS::HDI::DistributedAudio::Audio::V1_0::AudioAdapterDescriptor;
36using OHOS::HDI::DistributedAudio::Audio::V1_0::AudioFormat;
37using OHOS::HDI::DistributedAudio::Audio::V1_0::AudioPort;
38using OHOS::HDI::DistributedAudio::Audio::V1_0::AudioPortDirection;
39using OHOS::HDI::DistributedAudio::Audio::V1_0::IAudioManager;
40using OHOS::HDI::DistributedAudio::Audio::V1_0::IAudioRender;
41using OHOS::HDI::DistributedAudio::Audio::V1_0::IAudioCapture;
42using OHOS::HDI::DistributedAudio::Audio::V1_0::AudioSampleAttributes;
43using OHOS::HDI::DistributedAudio::Audio::V1_0::AudioDeviceDescriptor;
44using OHOS::HDI::DistributedAudio::Audio::V1_0::AudioCategory;
45using OHOS::HDI::DistributedAudio::Audio::V1_0::AudioRouteNode;
46using OHOS::HDI::DistributedAudio::Audio::V1_0::AudioExtParamKey;
47using OHOS::HDI::DistributedAudio::Audio::V1_0::AudioRoute;
48using OHOS::HDI::DistributedAudio::Audio::V1_0::AudioSceneDescriptor;
49using OHOS::HDI::DistributedAudio::Audio::V1_0::IAudioCallback;
50using OHOS::HDI::DistributedAudio::Audio::V1_0::AudioPortPin;
51using OHOS::HDI::DistributedAudio::Audio::V1_0::AudioPortType;
52using OHOS::HDI::DistributedAudio::Audio::V1_0::AudioPortRole;
53using OHOS::HDI::DistributedAudio::Audio::V1_0::AudioCallbackType;
54
55namespace {
56using namespace OHOS::DistributedHardware;
57static int32_t ParamEventCallback(AudioExtParamKey key, const char *condition, const char *value, void *reserved,
58    void *cookie);
59
60class AudioParamCallbackImpl final : public IAudioCallback {
61public:
62    AudioParamCallbackImpl() {}
63    ~AudioParamCallbackImpl() override {}
64
65    int32_t RenderCallback(AudioCallbackType type, int8_t &reserved, int8_t &cookie) override;
66    int32_t ParamCallback(AudioExtParamKey key, const std::string &condition, const std::string &value,
67        int8_t &reserved, int8_t cookie) override;
68};
69
70int32_t AudioParamCallbackImpl::RenderCallback(AudioCallbackType type, int8_t &reserved, int8_t &cookie)
71{
72    (void) type;
73    (void) reserved;
74    (void) cookie;
75    return DH_SUCCESS;
76}
77
78int32_t AudioParamCallbackImpl::ParamCallback(AudioExtParamKey key, const std::string &condition,
79    const std::string &value, int8_t &reserved, int8_t cookie)
80{
81    (void) cookie;
82    void *cookies = nullptr;
83    ParamEventCallback(static_cast<::AudioExtParamKey>(key), condition.c_str(),
84        value.c_str(), static_cast<void *>(&reserved), cookies);
85    return DH_SUCCESS;
86}
87
88const int32_t CMD_QUIT = 0;
89const int32_t CMD_FIND = 9;
90const int32_t CMD_OPEN_SPK = 1;
91const int32_t CMD_CLOSE_SPK = 2;
92const int32_t CMD_START_SPK = 3;
93const int32_t CMD_STOP_SPK = 4;
94const int32_t CMD_OPEN_MIC = 5;
95const int32_t CMD_CLOSE_MIC = 6;
96const int32_t CMD_START_MIC = 7;
97const int32_t CMD_STOP_MIC = 8;
98const int32_t CMD_SET_VOL = 11;
99const int32_t CMD_GET_VOL = 12;
100
101const char DEV_TYPE_SPK = '1';
102const char DEV_TYPE_MIC = '2';
103const char SPK_FILE_PATH[128] = "/data/test.wav";
104const char MIC_FILE_PATH[128] = "/data/mic.pcm";
105constexpr int32_t TYPE_OFFSET = 12;
106constexpr int32_t AUDIO_SAMPLE_RATE = 48000;
107constexpr int32_t VOLUME_MIN = 0;
108constexpr int32_t VOLUME_MAX = 15;
109constexpr int32_t RENDER_FRAME_SIZE = 3840;
110constexpr int32_t RENDER_INTER_LEAVED = 1;
111constexpr int32_t RENDER_STREAM_ID = 0;
112constexpr int32_t RENDER_CHANNEL_MASK = 2;
113constexpr int32_t CAPTURE_INTER_LEAVED = 1;
114constexpr int32_t CAPTURE_STREAM_ID = 2;
115constexpr int32_t CAPTURE_CHANNEL_MASK = 2;
116constexpr int64_t AUDIO_FRAME_TIME_INTERFAL_DEFAULT = 21333;
117
118static OHOS::sptr<IAudioManager> g_manager = nullptr;
119static OHOS::sptr<IAudioAdapter> g_adapter = nullptr;
120static OHOS::sptr<IAudioRender> g_render = nullptr;
121static OHOS::sptr<IAudioCapture> g_capture = nullptr;
122static std::vector<AudioAdapterDescriptor> g_devices;
123static OHOS::sptr<IAudioCallback> g_callbackStub = nullptr;
124static std::string g_devId = "";
125
126static constexpr const char* PLAY_THREAD = "playThread";
127static constexpr const char* CAPTURE_THREAD = "captureThread";
128
129uint32_t g_renderId = 0;
130uint32_t g_captureId = 0;
131int32_t g_frameNum = 0;
132int32_t g_frameIndex = 0;
133int32_t g_micFrameNum = 0;
134bool g_isInitRenderData = false;
135static std::vector<uint8_t*> renderData;
136
137static DeviceStatus g_spkStatus = DeviceStatus::DEVICE_IDLE;
138static DeviceStatus g_micStatus = DeviceStatus::DEVICE_IDLE;
139
140static std::thread g_playingThread;
141static std::thread g_capingThread;
142FILE *g_micFile = nullptr;
143
144static void CloseSpk();
145static void CloseMic();
146
147static int64_t GetNowTimeUs()
148{
149    std::chrono::microseconds nowUs =
150        std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now().time_since_epoch());
151    return nowUs.count();
152}
153
154static int32_t GetUserInput()
155{
156    int32_t res = -1;
157    size_t count = 3;
158    std::cout << ">>";
159    int ret = scanf_s("%d", &res);
160    if (ret == -1) {
161        std::cout << "get input error" << std::endl;
162    }
163    while (std::cin.fail() && count > 0) {
164        std::cin.clear();
165        std::cin.ignore();
166        std::cout << "invalid input, not a number! Please retry with a number." << std::endl;
167        std::cout << ">>";
168        ret = scanf_s("%d", &res);
169        if (ret == -1) {
170            std::cout << "get input error" << std::endl;
171        }
172        count--;
173    }
174    return res;
175}
176
177static void FindAudioDevice()
178{
179    if (g_manager == nullptr) {
180        std::cout << "Audio manager is null, Please Check network!" << std::endl;
181        return;
182    }
183    int32_t ret = g_manager->GetAllAdapters(g_devices);
184    if (ret != DH_SUCCESS) {
185        std::cout << "Get audio devices failed!" << std::endl;
186        return;
187    }
188    for (uint32_t index = 0; index < g_devices.size(); index++) {
189        const AudioAdapterDescriptor desc = g_devices[index];
190        if (index == 0) {
191            g_devId = desc.adapterName;
192            break;
193        }
194    }
195}
196
197static int32_t InitTestDemo()
198{
199    std::cout << "**********************************************************************************" << std::endl;
200    std::cout << "Distributed Audio Test Demo Bin v1.3." << std::endl;
201    std::cout << "**********************************************************************************" << std::endl;
202    std::cout << std::endl;
203    std::cout << "Init distributed audio hdf service." << std::endl;
204    g_manager = IAudioManager::Get("daudio_primary_service", false);
205    if (g_manager == nullptr) {
206        std::cout << "Distributed audio manager is null, Please Check network!" << std::endl;
207        return ERR_DH_AUDIO_FAILED;
208    }
209    std::cout << "Load audio manager success." << std::endl;
210    FindAudioDevice();
211    if (g_devId.empty()) {
212        std::cout << "Cannot find distributed device. Please input 9 to query distribtued device." << std::endl;
213    } else {
214        std::cout << "Find one distributed device: " << g_devId << std::endl;
215    }
216    return DH_SUCCESS;
217}
218
219static void HandleDevError(const char *condition, const char *value)
220{
221    if (condition[TYPE_OFFSET] == DEV_TYPE_SPK && g_spkStatus != DeviceStatus::DEVICE_IDLE) {
222        CloseSpk();
223    }
224
225    if (condition[TYPE_OFFSET] == DEV_TYPE_MIC && g_micStatus == DeviceStatus::DEVICE_IDLE) {
226        CloseMic();
227    }
228
229    std::cout << "Receive abnormal event, Demo quit." << std::endl;
230}
231
232static int32_t ParamEventCallback(AudioExtParamKey key, const char *condition, const char *value, void *reserved,
233    void *cookie)
234{
235    std::string val(value);
236    std::string con(condition);
237    std::cout << std::endl;
238    std::cout << "**********************************************************************************" << std::endl;
239    std::cout << "Event recived: " << key << std::endl;
240    std::cout << "Condition: " << con << std::endl;
241    std::cout << "Value: " << val << std::endl;
242    std::cout << "**********************************************************************************" << std::endl;
243    std::cout << std::endl;
244
245    if (key == AudioExtParamKey::AUDIO_EXT_PARAM_KEY_STATUS && con.rfind("ERR_EVENT", 0) == 0) {
246        HandleDevError(condition, value);
247    }
248    return DH_SUCCESS;
249}
250
251static int32_t LoadSpkDev(const std::string &devId)
252{
253    struct AudioAdapterDescriptor dev;
254    for (uint32_t index = 0; index < g_devices.size(); index++) {
255        struct AudioAdapterDescriptor desc = g_devices[index];
256        if (desc.adapterName == devId) {
257            dev = desc;
258            break;
259        }
260    }
261    if (dev.adapterName.data() == nullptr) {
262        std::cout << "Input device id is wrong." << std::endl;
263        FindAudioDevice();
264        return ERR_DH_AUDIO_FAILED;
265    }
266    if (g_manager == nullptr) {
267        return ERR_DH_AUDIO_FAILED;
268    }
269    if (g_adapter == nullptr) {
270        int32_t ret = g_manager->LoadAdapter(dev, g_adapter);
271        if (ret != DH_SUCCESS || g_adapter == nullptr) {
272            std::cout << "Load audio device failed, ret: " << ret << std::endl;
273            return ERR_DH_AUDIO_FAILED;
274        }
275    }
276    return DH_SUCCESS;
277}
278
279static void OpenSpk(const std::string &devId)
280{
281    if (g_spkStatus != DeviceStatus::DEVICE_IDLE) {
282        std::cout << "Speaker device is already opened." << std::endl;
283        return;
284    }
285    if (LoadSpkDev(devId) != DH_SUCCESS) {
286        std::cout << "Load spk failed" << std::endl;
287        return;
288    }
289
290    g_callbackStub = OHOS::sptr<IAudioCallback>(new AudioParamCallbackImpl());
291    if (g_adapter == nullptr) {
292        return;
293    }
294    int32_t ret = g_adapter->RegExtraParamObserver(g_callbackStub, 0);
295    if (ret != DH_SUCCESS) {
296        std::cout << "Register observer failed, ret: " << ret << std::endl;
297        return;
298    }
299
300    struct AudioDeviceDescriptor renderDesc;
301    renderDesc.pins = AudioPortPin::PIN_OUT_SPEAKER;
302    renderDesc.desc = "";
303    AudioSampleAttributes g_rattrs = {};
304    g_rattrs.type = AudioCategory::AUDIO_IN_MEDIA;
305    g_rattrs.interleaved = RENDER_INTER_LEAVED;
306    g_rattrs.streamId = RENDER_STREAM_ID;
307    g_rattrs.channelCount = RENDER_CHANNEL_MASK;
308    g_rattrs.sampleRate = AUDIO_SAMPLE_RATE;
309    g_rattrs.format = AudioFormat::AUDIO_FORMAT_TYPE_PCM_16_BIT;
310    ret = g_adapter->CreateRender(renderDesc, g_rattrs, g_render, g_renderId);
311    if (ret != DH_SUCCESS || g_render == nullptr) {
312        std::cout << "Open SPK device failed, ret: " << ret << std::endl;
313        return;
314    }
315    g_spkStatus = DeviceStatus::DEVICE_OPEN;
316    std::cout << "Open SPK device success." << std::endl;
317}
318
319static void WriteStreamWait(const int64_t &startTime)
320{
321    int64_t endTime = GetNowTimeUs();
322    int64_t passTime = endTime - startTime;
323
324    if (passTime > AUDIO_FRAME_TIME_INTERFAL_DEFAULT) {
325        return;
326    }
327    int64_t remainTime = AUDIO_FRAME_TIME_INTERFAL_DEFAULT - passTime;
328    std::this_thread::sleep_for(std::chrono::microseconds(remainTime));
329}
330
331static void Play()
332{
333    if (g_render == nullptr) {
334        std::cout << "SPK device is null." << std::endl;
335        return;
336    }
337    if (pthread_setname_np(pthread_self(), PLAY_THREAD) != DH_SUCCESS) {
338        std::cout << "Play thread setname failed." << std::endl;
339    }
340    std::cout << "Playing thread started." << std::endl;
341    g_render->Start();
342    g_spkStatus = DeviceStatus::DEVICE_START;
343
344    uint64_t size = 0;
345    while (g_spkStatus == DeviceStatus::DEVICE_START) {
346        int64_t startTime = GetNowTimeUs();
347
348        std::vector<int8_t> frameHal(RENDER_FRAME_SIZE);
349        int32_t ret = memcpy_s(frameHal.data(), RENDER_FRAME_SIZE, renderData[g_frameIndex], RENDER_FRAME_SIZE);
350        if (ret != EOK) {
351            DHLOGE("Copy render frame failed, error code %{public}d.", ret);
352            return;
353        }
354        ret = g_render->RenderFrame(frameHal, size);
355        if (ret != DH_SUCCESS) {
356            std::cout<<"RenderFrame failed, index: "<< g_frameIndex << ", ret:  " << ret << std::endl;
357        }
358        g_frameIndex++;
359        if (g_frameNum != 0 && g_frameIndex == g_frameNum) {
360            g_frameIndex = 0;
361        }
362        WriteStreamWait(startTime);
363    }
364    std::cout << "Playing thread stopped." << std::endl;
365}
366
367static void StartRender()
368{
369    if (g_spkStatus == DeviceStatus::DEVICE_IDLE) {
370        std::cout << "Speaker device is not opened, start render failed." << std::endl;
371        return;
372    }
373
374    if (g_spkStatus == DeviceStatus::DEVICE_OPEN) {
375        WavHdr wavHeader;
376        size_t headerSize = sizeof(WavHdr);
377        if (!g_isInitRenderData) {
378            struct stat statbuf;
379            stat(SPK_FILE_PATH, &statbuf);
380            int32_t size = statbuf.st_size;
381            g_frameNum = (size - static_cast<int32_t>(headerSize)) / RENDER_FRAME_SIZE;
382            std::cout << "Audio file frame num: " << g_frameNum << std::endl;
383            for (int32_t j = 0; j < g_frameNum; j++) {
384                uint8_t *frame = new uint8_t[RENDER_FRAME_SIZE]();
385                renderData.push_back(frame);
386            }
387            g_isInitRenderData = true;
388        }
389        FILE *wavFile = fopen(SPK_FILE_PATH, "rb");
390        fread(&wavHeader, 1, headerSize, wavFile);
391        for (int32_t i = 0; i < g_frameNum; i++) {
392            fread(renderData[i], 1, RENDER_FRAME_SIZE, wavFile);
393        }
394        fclose(wavFile);
395        g_frameIndex = 0;
396        g_playingThread = std::thread(Play);
397        return;
398    }
399    if (g_spkStatus == DeviceStatus::DEVICE_START) {
400        std::cout << "Speaker device is started." << std::endl;
401        return;
402    }
403    if (g_spkStatus == DeviceStatus::DEVICE_STOP) {
404        g_playingThread = std::thread(Play);
405    }
406}
407
408static void StopRender()
409{
410    if (g_render == nullptr) {
411        std::cout << "SPK device is null." << std::endl;
412        return;
413    }
414
415    if (g_spkStatus == DeviceStatus::DEVICE_IDLE) {
416        std::cout << "Speaker device is not opened." << std::endl;
417        return;
418    }
419
420    if (g_spkStatus == DeviceStatus::DEVICE_OPEN) {
421        std::cout << "Speaker device is not started." << std::endl;
422        return;
423    }
424
425    if (g_spkStatus == DeviceStatus::DEVICE_STOP) {
426        std::cout << "Speaker device is already stoped." << std::endl;
427        return;
428    }
429
430    g_spkStatus = DeviceStatus::DEVICE_STOP;
431    if (g_playingThread.joinable()) {
432        g_playingThread.join();
433    }
434    g_render->Stop();
435}
436
437static void CloseSpk()
438{
439    if (g_spkStatus == DeviceStatus::DEVICE_IDLE) {
440        std::cout << "Speaker device is not opened." << std::endl;
441        return;
442    }
443
444    if (g_spkStatus == DeviceStatus::DEVICE_START) {
445        StopRender();
446    }
447
448    if (g_adapter != nullptr) {
449        int32_t ret = g_adapter->DestroyRender(g_renderId);
450        if (ret != DH_SUCCESS) {
451            std::cout << "Close speaker failed" << std::endl;
452            return;
453        }
454    }
455    if (g_micStatus == DeviceStatus::DEVICE_IDLE && g_manager != nullptr) {
456        g_manager->UnloadAdapter(g_devId);
457        g_adapter = nullptr;
458    }
459    g_spkStatus = DeviceStatus::DEVICE_IDLE;
460
461    if (g_isInitRenderData) {
462        for (auto &p : renderData) {
463            delete[] p;
464        }
465        renderData.clear();
466        g_isInitRenderData = false;
467    }
468    std::cout << "Close SPK device success." << std::endl;
469}
470
471static int32_t LoadMicDev(const std::string &devId)
472{
473    struct AudioAdapterDescriptor dev;
474    for (uint32_t index = 0; index < g_devices.size(); index++) {
475        struct AudioAdapterDescriptor desc = g_devices[index];
476        if (desc.adapterName == devId) {
477            dev = desc;
478            break;
479        }
480    }
481    if (dev.adapterName.data() == nullptr) {
482        std::cout << "Input device id is wrong." << std::endl;
483        FindAudioDevice();
484        return ERR_DH_AUDIO_FAILED;
485    }
486    if (g_manager == nullptr) {
487        return ERR_DH_AUDIO_FAILED;
488    }
489    if (g_adapter == nullptr) {
490        int32_t ret = g_manager->LoadAdapter(dev, g_adapter);
491        if (ret != DH_SUCCESS || g_adapter == nullptr) {
492            std::cout << "Load audio device failed, ret: " << ret << std::endl;
493            return ERR_DH_AUDIO_FAILED;
494        }
495    }
496    return DH_SUCCESS;
497}
498
499static void OpenMic(const std::string &devId)
500{
501    if (g_micStatus != DeviceStatus::DEVICE_IDLE) {
502        std::cout << "Mic device is already opened." << std::endl;
503        return;
504    }
505    if (LoadMicDev(devId) != DH_SUCCESS) {
506        std::cout << "Load audio device failed." << std::endl;
507        return;
508    }
509
510    AudioDeviceDescriptor captureDesc;
511    captureDesc.pins = AudioPortPin::PIN_IN_MIC;
512    captureDesc.desc = "";
513    AudioSampleAttributes captureAttr;
514    captureAttr.type = AudioCategory::AUDIO_IN_MEDIA;
515    captureAttr.interleaved = CAPTURE_INTER_LEAVED;
516    captureAttr.streamId = CAPTURE_STREAM_ID;
517    captureAttr.channelCount = CAPTURE_CHANNEL_MASK;
518    captureAttr.sampleRate = AUDIO_SAMPLE_RATE;
519    captureAttr.format = AudioFormat::AUDIO_FORMAT_TYPE_PCM_16_BIT;
520    if (g_adapter == nullptr) {
521        return;
522    }
523    int32_t ret = g_adapter->CreateCapture(captureDesc, captureAttr, g_capture, g_captureId);
524    if (ret != DH_SUCCESS || g_capture == nullptr) {
525        std::cout << "Open MIC device failed." << std::endl;
526        return;
527    }
528    g_micStatus = DeviceStatus::DEVICE_OPEN;
529    std::cout << "Open MIC device success." << std::endl;
530}
531
532static void ReadStreamWait(const int64_t &startTime)
533{
534    int64_t endTime = GetNowTimeUs();
535    int32_t passTime = endTime - startTime;
536
537    if (passTime > AUDIO_FRAME_TIME_INTERFAL_DEFAULT) {
538        return;
539    }
540    int64_t remainTime = AUDIO_FRAME_TIME_INTERFAL_DEFAULT - passTime;
541    std::this_thread::sleep_for(std::chrono::microseconds(remainTime));
542}
543
544static void Capture()
545{
546    if (g_capture == nullptr) {
547        std::cout << "MIC device is null." << std::endl;
548        return;
549    }
550    if (pthread_setname_np(pthread_self(), CAPTURE_THREAD) != DH_SUCCESS) {
551        std::cout << "Capture thread setname failed." << std::endl;
552    }
553    std::cout << "Capturing thread started." << std::endl;
554    g_capture->Start();
555    g_micStatus = DeviceStatus::DEVICE_START;
556
557    uint64_t size = 0;
558    while (g_micStatus == DeviceStatus::DEVICE_START) {
559        std::vector<int8_t> data(RENDER_FRAME_SIZE);
560        int64_t startTime = GetNowTimeUs();
561        int32_t ret = g_capture->CaptureFrame(data, size);
562        if (ret != DH_SUCCESS) {
563            std::cout << "CaptureFrame failed, ret: " << ret << std::endl;
564            return;
565        }
566        size_t writeCnt = fwrite(data.data(), 1, RENDER_FRAME_SIZE, g_micFile);
567        if (static_cast<int32_t>(writeCnt) != RENDER_FRAME_SIZE) {
568            std::cout << "fwrite data failed." << std::endl;
569        }
570        g_micFrameNum++;
571        ReadStreamWait(startTime);
572    }
573    std::cout << "Capturing thread stopped." << std::endl;
574}
575
576static void StartCapture()
577{
578    if (g_micStatus == DeviceStatus::DEVICE_IDLE) {
579        std::cout << "Mic device is not opened, start capture failed." << std::endl;
580        return;
581    }
582
583    if (g_micStatus == DeviceStatus::DEVICE_OPEN) {
584        g_micFile = fopen(MIC_FILE_PATH, "ab+");
585        if (g_micFile == nullptr) {
586            std::cout << "Open pcm file failed." << std::endl;
587            return;
588        }
589        g_capingThread = std::thread(Capture);
590        return;
591    }
592
593    if (g_micStatus == DeviceStatus::DEVICE_START) {
594        std::cout << "Mic device is already started." << std::endl;
595        return;
596    }
597
598    if (g_micStatus == DeviceStatus::DEVICE_STOP) {
599        g_capingThread = std::thread(Capture);
600    }
601}
602
603static void StopCapture()
604{
605    if (g_capture == nullptr) {
606        std::cout << "MIC device is null." << std::endl;
607        return;
608    }
609    if (g_micStatus == DeviceStatus::DEVICE_IDLE) {
610        std::cout << "Mic device is not opened." << std::endl;
611        return;
612    }
613    if (g_micStatus == DeviceStatus::DEVICE_OPEN) {
614        std::cout << "Mic device is not started." << std::endl;
615        return;
616    }
617    if (g_micStatus == DeviceStatus::DEVICE_STOP) {
618        std::cout << "Mic device is already started." << std::endl;
619        return;
620    }
621    g_micStatus = DeviceStatus::DEVICE_STOP;
622    if (g_capingThread.joinable()) {
623        g_capingThread.join();
624    }
625    g_capture->Stop();
626}
627
628static void CloseMic()
629{
630    if (g_micStatus == DeviceStatus::DEVICE_IDLE) {
631        std::cout << "Mic device is not opened." << std::endl;
632        return;
633    }
634
635    if (g_micStatus == DeviceStatus::DEVICE_START) {
636        StopCapture();
637    }
638
639    if (g_adapter != nullptr) {
640        int32_t ret = g_adapter->DestroyCapture(g_captureId);
641        if (ret != DH_SUCCESS) {
642            std::cout << "Close mic failed." << std::endl;
643            return;
644        }
645    }
646    if (g_spkStatus == DeviceStatus::DEVICE_IDLE && g_manager != nullptr) {
647        g_manager->UnloadAdapter(g_devId);
648        g_adapter = nullptr;
649    }
650    if (g_micFile != nullptr) {
651        fclose(g_micFile);
652        g_micFile = nullptr;
653    }
654    g_micStatus = DeviceStatus::DEVICE_IDLE;
655    std::cout << "Close MIC device success." << std::endl;
656}
657
658static void SetVolume()
659{
660    if (g_spkStatus == DeviceStatus::DEVICE_IDLE) {
661        std::cout << "Speaker is not opened, can not set volume." << std::endl;
662        return;
663    }
664    std::cout << "Please input volum to set [0,15]." << std::endl;
665    int32_t volInt = GetUserInput();
666    if (volInt < VOLUME_MIN || volInt > VOLUME_MAX) {
667        std::cout << "Volume is invalid." << std::endl;
668        return;
669    }
670    std::cout << "Set volume: " << volInt << std::endl;
671    AudioExtParamKey key = AudioExtParamKey::AUDIO_EXT_PARAM_KEY_VOLUME;
672    std::string condition = "EVENT_TYPE=1;VOLUME_GROUP_ID=1;AUDIO_VOLUME_TYPE=1;";
673    std::string volStr = std::to_string(volInt);
674    if (g_adapter != nullptr) {
675    int32_t ret = g_adapter->SetExtraParams(key, condition, volStr);
676        if (ret != DH_SUCCESS) {
677            std::cout << "Set volume failed" << std::endl;
678        }
679    }
680}
681
682static void GetVolume()
683{
684    if (g_spkStatus == DeviceStatus::DEVICE_IDLE) {
685        std::cout << "Speaker is not opened, can not get volume." << std::endl;
686        return;
687    }
688    AudioExtParamKey key = AudioExtParamKey::AUDIO_EXT_PARAM_KEY_VOLUME;
689    std::string condition = "EVENT_TYPE=1;VOLUME_GROUP_ID=1;AUDIO_VOLUME_TYPE=1;";
690    std::string vol;
691    if (g_adapter != nullptr) {
692        int32_t ret = g_adapter->GetExtraParams(key, condition.c_str(), vol);
693        if (ret != DH_SUCCESS) {
694            std::cout << "Get Volume failed." << std::endl;
695            return;
696        }
697    }
698    std::cout << "Get volume success. volume: " << vol <<std::endl;
699}
700
701static void HandleAudioEvent(const int32_t cmd)
702{
703    switch (cmd) {
704        case CMD_FIND:
705            FindAudioDevice();
706            break;
707        case CMD_OPEN_SPK:
708            OpenSpk(g_devId);
709            break;
710        case CMD_START_SPK:
711            StartRender();
712            break;
713        case CMD_STOP_SPK:
714            StopRender();
715            break;
716        case CMD_CLOSE_SPK:
717            CloseSpk();
718            break;
719        case CMD_OPEN_MIC:
720            OpenMic(g_devId);
721            break;
722        case CMD_START_MIC:
723            StartCapture();
724            break;
725        case CMD_STOP_MIC:
726            StopCapture();
727            break;
728        case CMD_CLOSE_MIC:
729            CloseMic();
730            break;
731        case CMD_SET_VOL:
732            SetVolume();
733            break;
734        case CMD_GET_VOL:
735            GetVolume();
736            break;
737        default:
738            std::cout << "Unkown opeartion." << std::endl;
739            break;
740    }
741}
742
743static void PrintInteractiveUsage()
744{
745    std::cout << std::endl << "=============== InteractiveRunTestSelect ================" << std::endl;
746    std::cout << "You can respond to instructions for corresponding option:" << std::endl;
747    std::cout <<  "\t enter 1 to open spk. " << std::endl;
748    std::cout <<  "\t enter 2 to close spk. " << std::endl;
749    std::cout <<  "\t enter 3 to start play. " << std::endl;
750    std::cout <<  "\t enter 4 to stop play. " << std::endl;
751    std::cout <<  "\t enter 5 to open mic. " << std::endl;
752    std::cout <<  "\t enter 6 to clsoe mic. " << std::endl;
753    std::cout <<  "\t enter 7 to start record. " << std::endl;
754    std::cout <<  "\t enter 8 to stop record. " << std::endl;
755    std::cout <<  "\t enter 9 to manullt find device. " << std::endl;
756    std::cout <<  "\t enter 11 to set volume. " << std::endl;
757    std::cout <<  "\t enter 12 to get volume. " << std::endl;
758    std::cout <<  "\t enter 0 to exit. " << std::endl;
759}
760}
761
762int main(int argc, char *argv[])
763{
764    if (InitTestDemo() != DH_SUCCESS) {
765        return ERR_DH_AUDIO_FAILED;
766    }
767    while (true) {
768        PrintInteractiveUsage();
769        int32_t cmd = GetUserInput();
770        if (cmd == CMD_QUIT) {
771            CloseSpk();
772            CloseMic();
773            break;
774        }
775        HandleAudioEvent(cmd);
776    }
777    return 0;
778}