/*

 * Copyright (c) 2025 Huawei Device Co., Ltd.

 * Licensed under the Apache License, Version 2.0 (the "License");

 * you may not use this file except in compliance with the License.

 * You may obtain a copy of the License at

 *

 *     http://www.apache.org/licenses/LICENSE-2.0

 *

 * Unless required by applicable law or agreed to in writing, software

 * distributed under the License is distributed on an "AS IS" BASIS,

 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

 * See the License for the specific language governing permissions and

 * limitations under the License.

 */



#include <dlfcn.h>

#include <limits.h>

#include <pthread.h>

#include <securec.h>

#include <signal.h>

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <sys/mman.h>

#include <sys/stat.h>

#include <unistd.h>

#include "framework_common.h"

#include "hdf_base.h"

#include "hdf_io_service_if.h"

#include "hdf_service_status.h"

#include "inttypes.h"

#include "ioservstat_listener.h"

#include "osal_mem.h"

#include "svcmgr_ioservice.h"

#include "v6_1/iaudio_manager.h"

#include "v6_1/audio_types.h"



#define AUDIO_CHANNELCOUNT              2

#define AUDIO_SAMPLE_RATE_16K           16000

#define PATH_LEN                        256

#define BUFFER_PERIOD_SIZE              3840

#define DEEP_BUFFER_RENDER_PERIOD_SIZE  4096

#define DEEP_BUFFER_RENDER_PERIOD_COUNT 8

#define INT_32_MAX                      0x7fffffff

#define BUFFER_SIZE_BASE                1024

#define AUDIO_TOTALSIZE_15M             (1024 * 15)

#define AUDIO_RECORD_INTERVAL_512KB     512

#define MAX_AUDIO_ADAPTER_DESC          5

#define FILE_CAPTURE_SIZE               (1024 * 1024 * 3) // 3M

#define BUFFER_LEN                      256

#define EXT_PARAMS_MAXLEN               107

#define ONE_MS                          1000

#define BITS_TO_FROMAT                  3

#define AUDIO_CHANNEL_LAYOUT            3

#define AUDIO_FRAME_SIZE                4

#define AUDIO_SOURCE_TYPE               4

#define AUDIO_CAPTURE_VOIP_STREAM_ID    22

#define AUDIO_PORT_ID                   12

#define AUDIO_ROUTE_NODE_LEN            1



struct IAudioAdapter *g_adapter = NULL;

struct AudioDeviceDescriptor g_devDesc = {0};

struct AudioSampleAttributes g_attrs = {0};

struct IAudioCapture *g_capture = NULL;

static struct IAudioManager *g_audioManager = NULL;

static struct StrParaCapture g_str = {0};

uint32_t g_captureId = 0;



pthread_t g_tids = 0;

FILE *g_file = NULL;

char *g_frame = NULL;

char g_path[PATH_MAX] = {'\0'};

char g_adapterName[PATH_LEN] = {0};



enum AudioCaptureMode {

    CAPTURE_POLL = 1,

    CAPTURE_INTERUPT,

};



int g_captureModeFlag = CAPTURE_POLL;

int g_receiveFrameCount = 0;

uint64_t g_totalSize = 0;

struct ISvcMgrIoservice *g_servmgr = NULL;

struct ServiceStatusListener *g_listener = NULL;



enum CaptureMenuId {

    CAPTURE_START = 1,

    CAPTURE_STOP,

    CAPTURE_RESUME,

    CAPTURE_PAUSE,

    SET_CAPTURE_VOLUME,

    SET_CAPTURE_GAIN,

    SET_CAPTURE_MUTE,

    SET_CAPTURE_ATTRIBUTES,

    SET_CAPTURE_SLECET_SCENE,

    GET_CAPTURE_EXT_PARAMS,

    GET_CAPTURE_POSITION,

};



enum CaptureInputType {

    INPUT_INT = 0,

    INPUT_FLOAT,

    INPUT_UINT32,

};



typedef int32_t (*AudioCaptureOperation)(struct IAudioCapture **);



struct ProcessCaptureMenuSwitchList {

    enum CaptureMenuId cmd;

    AudioCaptureOperation operation;

};



static int32_t g_closeEnd = 0;



static int32_t CheckInputName(int type, void *val)

{

    if (val == NULL) {

        return HDF_FAILURE;

    }



    int ret;

    int capInputInt = 0;

    float capInputFloat = 0.0;

    uint32_t capInputUint = 0;



    printf("\n");

    switch (type) {

        case INPUT_INT:

            ret = scanf_s("%d", &capInputInt);

            if (capInputInt < 0 || capInputInt > GET_CAPTURE_POSITION + 1) {

                if (g_frame != NULL) {

                    OsalMemFree(g_frame);

                    g_frame = NULL;

                }

                AUDIO_FUNC_LOGE("Input failure");

                return HDF_FAILURE;

            }

            *(int *)val = capInputInt;

            break;

        case INPUT_FLOAT:

            ret = scanf_s("%f", &capInputFloat);

            *(float *)val = capInputFloat;

            break;

        case INPUT_UINT32:

            ret = scanf_s("%u", &capInputUint);

            if (capInputUint > 0xFFFFFFFF) {

                return HDF_FAILURE;

            }

            *(uint32_t *)val = capInputUint;

            break;

        default:

            ret = EOF;

            break;

    }

    if (ret == 0) {

        CleanStdin();

    } else if (ret == EOF) {

        AUDIO_FUNC_LOGE("Input error occurs!");

        return HDF_FAILURE;

    }

    return HDF_SUCCESS;

}



static int32_t InitVoipAttrsCapture(struct AudioSampleAttributes *captureAttrs)

{

    if (captureAttrs == NULL) {

        return HDF_FAILURE;

    }

    /* Initialization of audio parameters for playback */

    captureAttrs->format = AUDIO_FORMAT_TYPE_PCM_16_BIT;

    captureAttrs->channelCount = AUDIO_CHANNELCOUNT;

    captureAttrs->channelLayout = AUDIO_CHANNEL_LAYOUT;

    captureAttrs->sampleRate = AUDIO_SAMPLE_RATE_16K;

    captureAttrs->interleaved = true;

    captureAttrs->type = AUDIO_MMAP_VOIP;

    captureAttrs->period = 0;

    captureAttrs->frameSize = AUDIO_FRAME_SIZE;

    captureAttrs->isBigEndian = false;

    captureAttrs->isSignedData = true;

    captureAttrs->startThreshold = 0;

    captureAttrs->stopThreshold = INT_32_MAX;

    captureAttrs->streamId = AUDIO_CAPTURE_VOIP_STREAM_ID;

    captureAttrs->sourceType = AUDIO_SOURCE_TYPE;

    return 0;

}



static int32_t InitDevDescCapture(struct AudioDeviceDescriptor *devDesc, uint32_t portId)

{

    if (devDesc == NULL) {

        return HDF_FAILURE;

    }

    /* Initialization of audio parameters for playback */

    devDesc->portId = AUDIO_PORT_ID;

    devDesc->pins = PIN_IN_MIC;

    devDesc->desc = strdup("devName");

    return HDF_SUCCESS;

}



static uint32_t PcmFramesToBytes(const struct AudioSampleAttributes attrs)

{

    return DEEP_BUFFER_RENDER_PERIOD_SIZE * attrs.channelCount * (PcmFormatToBits(attrs.format) >> BITS_TO_FROMAT);

}



static int32_t StopButtonCapture(struct IAudioCapture **captureS)

{

    if (captureS == NULL) {

        return HDF_FAILURE;

    }



    if (!g_closeEnd) {

        g_closeEnd = true;

        usleep(100000); // sleep 100000us

    }



    struct IAudioCapture *capture = *captureS;

    if (capture == NULL) {

        return HDF_FAILURE;

    }



    int ret = capture->Stop((void *)capture);

    if (ret < 0) {

        AUDIO_FUNC_LOGE("Stop capture!");

    }



    if (g_adapter == NULL || g_adapter->DestroyCapture == NULL) {

        return HDF_FAILURE;

    }



    ret = g_adapter->DestroyCapture(g_adapter, g_captureId);

    if (ret < 0) {

        AUDIO_FUNC_LOGE("Capture already destroy!");

    }



    IAudioCaptureRelease(capture, false);

    *captureS = NULL;

    g_capture = NULL;

    if (g_frame != NULL) {

        OsalMemFree(g_frame);

        g_frame = NULL;

    }



    if (AddWavFileHeader(g_file, &g_str) < 0) {

        AUDIO_FUNC_LOGE("AddWavFileHeader Fail");

        return HDF_FAILURE;

    }



    FileClose(&g_file);



    if (g_captureModeFlag == CAPTURE_INTERUPT) {

        AUDIO_FUNC_LOGE("litoOs  not support!");

    }

    printf("Stop Successful\n");

    return HDF_SUCCESS;

}



static int32_t FrameStartCaptureMmap(const struct StrParaCapture *param)

{

    if (param == NULL) {

        return HDF_FAILURE;

    }

    const struct StrParaCapture *strParam = param;

    struct IAudioCapture *capture = strParam->capture;

    struct AudioMmapBufferDescriptor mmapDesc;

    // Modify file size



    int fd = fileno(strParam->file);

    if (fd == -1) {

        printf("fileno failed, fd is %d\n", fd);

        return HDF_FAILURE;

    }

    ftruncate(fd, FILE_CAPTURE_SIZE);

    // Init param

    mmapDesc.memoryFd = 0; // default 0

    mmapDesc.filePath = strdup(g_path);

    mmapDesc.isShareable = 1;                                        // 1:Shareable ,0:Don't share

    mmapDesc.transferFrameSize = DEEP_BUFFER_RENDER_PERIOD_SIZE / 4; // One frame size 4 bit

    mmapDesc.offset = 0;                                             // Recording must be 0

    // start

    if (capture == NULL || capture->ReqMmapBuffer == NULL) {

        free(mmapDesc.filePath);

        return HDF_FAILURE;

    }

    int32_t ret = capture->ReqMmapBuffer(capture, FILE_CAPTURE_SIZE, &mmapDesc);

    if (ret < 0) {

        free(mmapDesc.filePath);

        printf("Request map fail,please check.\n");

        return HDF_FAILURE;

    }

    free(mmapDesc.filePath);

    return HDF_SUCCESS;

}



static int32_t WriteDataToFile(FILE *file, char *buffer, uint64_t replyBytes, uint32_t *failCount, uint64_t *totalSize)

{

    if (file == NULL || buffer == NULL || failCount == NULL || totalSize == NULL) {

        AUDIO_FUNC_LOGE("WriteDataToFile params is null!");

        return HDF_FAILURE;

    }

    *failCount = 0;



    (void)fwrite(buffer, (size_t)replyBytes, 1, file);



    *totalSize += (replyBytes / BUFFER_SIZE_BASE);       // 1024 = 1Kb

    if (*totalSize % AUDIO_RECORD_INTERVAL_512KB < 24) { // 512KB

        printf("\nRecording,the audio file size is %" PRIu64 "Kb\n", *totalSize);

    }

    return HDF_SUCCESS;

}



static int32_t FrameStartCapture(const struct StrParaCapture *param)

{

    if (param == NULL) {

        return HDF_FAILURE;

    }

    uint32_t bufferSize = BUFFER_PERIOD_SIZE;

    uint64_t requestBytes = BUFFER_PERIOD_SIZE;

    uint64_t totalSize = 0;

    uint32_t failCount = 0;



    struct IAudioCapture *capture = param->capture;

    if (capture == NULL || capture->CaptureFrame == NULL) {

        return HDF_FAILURE;

    }



    char *frame = (char *)OsalMemCalloc(bufferSize);

    if (frame == NULL) {

        return HDF_FAILURE;

    }



    do {

        int32_t ret = capture->CaptureFrame(capture, (int8_t *)frame, &bufferSize, &requestBytes);

        if (ret < 0) {

            if (ret == HDF_ERR_INVALID_OBJECT) {

                AUDIO_FUNC_LOGE("Record already stop!");

                break;

            }

            usleep(ONE_MS);

            if (failCount++ >= 300000) { // Try 300000 times for CaptureFrame fail

                OsalMemFree(frame);

                return HDF_FAILURE;

            }

            continue;

        }

        if (WriteDataToFile(param->file, frame, bufferSize, &failCount, &totalSize) < 0) {

            OsalMemFree(frame);

            return HDF_FAILURE;

        }

    } while ((totalSize <= AUDIO_TOTALSIZE_15M) && (!g_closeEnd)); // 15 * 1024 = 15M



    OsalMemFree(frame);



    if (!g_closeEnd) {

        if (StopButtonCapture(&g_capture) < 0) {

            return HDF_FAILURE;

        }

    }

    return HDF_SUCCESS;

}



static void PrintPlayMode(void)

{

    printf(" ============= Play Capture start Mode ==========\n");

    printf("| 1. Capture non-mmap                           |\n");

    printf("| 2. Capture mmap                               |\n");

    printf(" ================================================\n");

}



static int32_t SelectRecordMode(int32_t *recordModeFlag)

{

    if (recordModeFlag == NULL) {

        AUDIO_FUNC_LOGE("recordModeFlag is null");

        return HDF_FAILURE;

    }

    int choice = 0;



    system("clear");



    PrintPlayMode();



    printf("Please enter your choice:");



    int32_t ret = CheckInputName(INPUT_INT, (void *)&choice);

    if (ret < 0) {

        AUDIO_FUNC_LOGE("CheckInputName Fail");

        return HDF_FAILURE;

    } else {

        *recordModeFlag = choice;

    }

    return HDF_SUCCESS;

}



static int32_t StartPlayThread(int32_t recordModeFlag)

{

    pthread_attr_t tidsAttr;

    pthread_attr_init(&tidsAttr);

    pthread_attr_setdetachstate(&tidsAttr, PTHREAD_CREATE_DETACHED);

    switch (recordModeFlag) {

        case 1: // 1. Stander Loading

            if (pthread_create(&g_tids, &tidsAttr, (void *)(&FrameStartCapture), &g_str) != 0) {

                AUDIO_FUNC_LOGE("Create Thread Fail");

                return HDF_FAILURE;

            }

            break;

        case 2: // 2. Low latency Loading

            if (pthread_create(&g_tids, &tidsAttr, (void *)(&FrameStartCaptureMmap), &g_str) != 0) {

                AUDIO_FUNC_LOGE("Create Thread Fail");

                return HDF_FAILURE;

            }

            break;

        default:

            printf("Input error,Switched to non-mmap Mode for you,");

            SystemInputFail();

            if (pthread_create(&g_tids, &tidsAttr, (void *)(&FrameStartCapture), &g_str) != 0) {

                AUDIO_FUNC_LOGE("Create Thread Fail");

                return HDF_FAILURE;

            }

            break;

    }

    return HDF_SUCCESS;

}



static int32_t CaptureChoiceModeAndRecording(

    struct StrParaCapture *strParam, struct IAudioCapture *capture, int32_t recordModeFlag)

{

    if (strParam == NULL || capture == NULL) {

        AUDIO_FUNC_LOGE("InitCaptureStrParam is NULL");

        return HDF_FAILURE;

    }



    (void)memset_s(strParam, sizeof(struct StrParaCapture), 0, sizeof(struct StrParaCapture));



    strParam->capture = capture;

    strParam->file = g_file;

    strParam->attrs = g_attrs;

    strParam->frame = g_frame;



    if (g_captureModeFlag == CAPTURE_INTERUPT) {

        printf("not suport liteos!");

    } else {

        if (StartPlayThread(recordModeFlag) < 0) {

            AUDIO_FUNC_LOGE("Create Thread Fail");

            return HDF_FAILURE;

        }

    }

    return HDF_SUCCESS;

}



static int32_t RecordingAudioInitFile(void)

{

    if (g_file != NULL) {

        AUDIO_FUNC_LOGE("the capture is recording, please stop first");

        return HDF_FAILURE;

    }

    g_closeEnd = false;



    g_file = fopen(g_path, "wb+");

    if (g_file == NULL) {

        printf("capture failed to open '%s'\n", g_path);

        return HDF_FAILURE;

    }



    int32_t ret = fseek(g_file, WAV_HEAD_OFFSET, SEEK_SET);

    if (ret != 0) {

        printf("capture write wav file head error");

        return HDF_FAILURE;

    }



    char pathBuf[PATH_MAX] = {'\0'};

    if (realpath(g_path, pathBuf) == NULL) {

        AUDIO_FUNC_LOGE("realpath failed.");

        return HDF_FAILURE;

    }



    if (memcpy_s(g_path, PATH_MAX, pathBuf, PATH_MAX) != EOK) {

        AUDIO_FUNC_LOGE("memcpy failed.");

        return HDF_FAILURE;

    }



    (void)chmod(g_path, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);



    return HDF_SUCCESS;

}



static int32_t UpdateAudioRoute(void)

{

    struct AudioRouteNode source = {

        .ext.device.type = PIN_IN_MIC,

        .ext.device.desc = (char *)"pin_in_mic",

        .ext.device.moduleId = 0,

        .ext.mix.moduleId = 0,

        .ext.mix.streamId = 0,

        .ext.mix.source = 0,

        .ext.session.sessionType = 0,

        .portId = 12,

        .role = AUDIO_PORT_SOURCE_ROLE,

        .type = AUDIO_PORT_DEVICE_TYPE,

    };



    struct AudioRouteNode sink = {

        .portId = 0,

        .role = AUDIO_PORT_SINK_ROLE,

        .type = AUDIO_PORT_MIX_TYPE,

        .ext.device.moduleId = 0,

        .ext.device.type = 0,

        .ext.device.desc = (char *)"",

        .ext.mix.moduleId = 0,

        .ext.mix.streamId = AUDIO_CAPTURE_VOIP_STREAM_ID,

        .ext.mix.source = 4,

        .ext.session.sessionType = 0,

    };



    struct AudioRoute route = {

        .sources = &source,

        .sourcesLen = AUDIO_ROUTE_NODE_LEN,

        .sinks = &sink,

        .sinksLen = AUDIO_ROUTE_NODE_LEN,

    };



    int routeHandle = 0;

    int32_t ret = g_adapter->UpdateAudioRoute(g_adapter, &route, &routeHandle);

    if (ret < 0) {

        AUDIO_FUNC_LOGE("UpdateAudioRoute failed");

    }

    return ret;

}



static int32_t RecordingAudioInitCapture(struct IAudioCapture **captureTemp)

{

    if (captureTemp == NULL) {

        AUDIO_FUNC_LOGE("captureTemp is null");

        return HDF_FAILURE;

    }



    struct IAudioCapture *capture = NULL;

    int32_t ret = g_adapter->CreateCapture(g_adapter, &g_devDesc, &g_attrs, &capture, &g_captureId);

    if (capture == NULL || ret < 0) {

        return HDF_FAILURE;

    }

    if (UpdateAudioRoute() < 0) {

        return HDF_FAILURE;

    }



    ret = capture->Start((void *)capture);

    if (ret < 0) {

        g_adapter->DestroyCapture(g_adapter, g_captureId);

        IAudioCaptureRelease(capture, false);

        return HDF_FAILURE;

    }



    uint32_t bufferSize = PcmFramesToBytes(g_attrs);

    g_frame = (char *)OsalMemCalloc(bufferSize);

    if (g_frame == NULL) {

        g_adapter->DestroyCapture(g_adapter, g_captureId);

        IAudioCaptureRelease(capture, false);

        return HDF_FAILURE;

    }

    *captureTemp = capture;

    return HDF_SUCCESS;

}



static int32_t StartButtonCapture(struct IAudioCapture **captureS)

{

    if (captureS == NULL || g_adapter == NULL || g_adapter->CreateCapture == NULL) {

        return HDF_FAILURE;

    }



    if (RecordingAudioInitFile() < 0) {

        AUDIO_FUNC_LOGE("RecordingAudioInitFile Fail");

        return HDF_FAILURE;

    }



    int32_t recordModeFlag = 0;

    if (SelectRecordMode(&recordModeFlag) < 0) {

        AUDIO_FUNC_LOGE("SelectRecordMode Fail");

        FileClose(&g_file);

        return HDF_FAILURE;

    }



    struct IAudioCapture *capture = NULL;

    if (RecordingAudioInitCapture(&capture) < 0) {

        AUDIO_FUNC_LOGE("PlayingAudioInitCapture Fail");

        FileClose(&g_file);

        return HDF_FAILURE;

    }



    if (CaptureChoiceModeAndRecording(&g_str, capture, recordModeFlag) < 0) {

        AUDIO_FUNC_LOGE("CaptureChoiceModeAndRecording failed");

        FileClose(&g_file);

        if (g_adapter != NULL && g_adapter->DestroyCapture != NULL) {

            g_adapter->DestroyCapture(g_adapter, g_captureId);

        }

        IAudioCaptureRelease(capture, false);

        return HDF_FAILURE;

    }

    *captureS = capture;

    printf("Start Successful\n");

    return HDF_SUCCESS;

}



void AudioAdapterDescriptorFree(struct AudioAdapterDescriptor *captureDataBlock, bool freeSelf)

{

    if (captureDataBlock == NULL) {

        return;

    }



    if (captureDataBlock->adapterName != NULL) {

        OsalMemFree(captureDataBlock->adapterName);

        captureDataBlock->adapterName = NULL;

    }



    if (captureDataBlock->ports != NULL) {

        OsalMemFree(captureDataBlock->ports);

    }



    if (freeSelf) {

        OsalMemFree(captureDataBlock);

    }

}



static void ReleaseAdapterDescs(struct AudioAdapterDescriptor **descs, uint32_t descsLen)

{

    if (descsLen > 0 && descs != NULL && (*descs) != NULL) {

        for (uint32_t i = 0; i < descsLen; i++) {

            AudioAdapterDescriptorFree(&(*descs)[i], false);

        }

        OsalMemFree(*descs);

        *descs = NULL;

    }

}



static int32_t GetManagerAndLoadAdapter(struct AudioPort *capturePort)

{

    int32_t adapterIndex = 0;

    uint32_t adapterNum = MAX_AUDIO_ADAPTER_DESC;



    if (capturePort == NULL) {

        AUDIO_FUNC_LOGE("The Parameter is NULL");

        return HDF_FAILURE;

    }



    struct IAudioManager *audioManager = IAudioManagerGet(false);

    if (audioManager == NULL) {

        AUDIO_FUNC_LOGE("Get audio Manager Fail");

        return HDF_FAILURE;

    }



    g_audioManager = audioManager;

    struct AudioAdapterDescriptor *captureDescs = (struct AudioAdapterDescriptor *)OsalMemCalloc(

        sizeof(struct AudioAdapterDescriptor) * (MAX_AUDIO_ADAPTER_DESC));

    if (captureDescs == NULL) {

        return HDF_FAILURE;

    }

    int32_t ret = audioManager->GetAllAdapters(audioManager, captureDescs, &adapterNum);

    if (ret < 0 || adapterNum == 0) {

        AUDIO_FUNC_LOGE("Get All Adapters Fail");

        ReleaseAdapterDescs(&captureDescs, MAX_AUDIO_ADAPTER_DESC);

        return HDF_ERR_NOT_SUPPORT;

    }

    if (SelectAudioCard(captureDescs, adapterNum, &adapterIndex) != HDF_SUCCESS) {

        ReleaseAdapterDescs(&captureDescs, MAX_AUDIO_ADAPTER_DESC);

        return HDF_ERR_NOT_SUPPORT;

    }

    if (strcpy_s(g_adapterName, PATH_LEN, captureDescs[adapterIndex - 1].adapterName) < 0) {

        ReleaseAdapterDescs(&captureDescs, MAX_AUDIO_ADAPTER_DESC);

        return HDF_ERR_NOT_SUPPORT;

    }

    if (SwitchAudioPort(&captureDescs[adapterIndex - 1], PORT_IN, capturePort) != HDF_SUCCESS) {

        ReleaseAdapterDescs(&captureDescs, MAX_AUDIO_ADAPTER_DESC);

        return HDF_ERR_NOT_SUPPORT;

    }

    if (audioManager->LoadAdapter(audioManager, &captureDescs[adapterIndex - 1], &g_adapter) != HDF_SUCCESS) {

        AUDIO_FUNC_LOGE("Load Adapter Fail");

        ReleaseAdapterDescs(&captureDescs, MAX_AUDIO_ADAPTER_DESC);

        return HDF_ERR_NOT_SUPPORT;

    }



    ReleaseAdapterDescs(&captureDescs, MAX_AUDIO_ADAPTER_DESC);



    return HDF_SUCCESS;

}



static int32_t InitCaptureParam(uint32_t portId)

{

    if (g_adapter == NULL || g_adapter->InitAllPorts == NULL) {

        AUDIO_FUNC_LOGE("g_adapter is NULL.");

        return HDF_FAILURE;

    }



    // Initialization port information, can fill through mode and other parameters

    (void)g_adapter->InitAllPorts(g_adapter);



    // User needs to set

    if (InitVoipAttrsCapture(&g_attrs) < 0) {

        AUDIO_FUNC_LOGE("InitDevDescCapture failed.");

        return HDF_FAILURE;

    }



    // Specify a hardware device

    if (InitDevDescCapture(&g_devDesc) < 0) {

        AUDIO_FUNC_LOGE("InitDevDescCapture failed.");

        return HDF_FAILURE;

    }

    return HDF_SUCCESS;

}



static int32_t CaptureGetAdapterAndInitEnvParams(void)

{

    struct AudioPort capturePort;



    int32_t ret = GetManagerAndLoadAdapter(&capturePort);

    if (ret < 0) {

        return ret;

    }



    if (InitCaptureParam(capturePort.portId) < 0) {

        g_audioManager->UnloadAdapter(g_audioManager, g_adapterName);

        IAudioAdapterRelease(g_adapter, false);

        g_adapter = NULL;

        return HDF_FAILURE;

    }

    return HDF_SUCCESS;

}



static int32_t InitParam(void)

{

    if (CaptureGetAdapterAndInitEnvParams() < 0) {

        AUDIO_FUNC_LOGE("GetCaptureProxyManagerFunc Fail");

        if (g_audioManager != NULL) {

            IAudioManagerRelease(g_audioManager, false);

            g_audioManager = NULL;

        }

        return HDF_FAILURE;

    }

    return HDF_SUCCESS;

}



static int32_t SetCaptureMute(struct IAudioCapture **capture)

{

    (void)capture;

    int32_t val = 0;

    bool isMute = false;

    if (g_capture == NULL || g_capture->GetMute == NULL) {

        return HDF_FAILURE;

    }



    int32_t ret = g_capture->GetMute((void *)g_capture, &isMute);

    if (ret < 0) {

        AUDIO_FUNC_LOGE("The current mute state was not obtained!");

    }



    printf("Now %s ,Do you need to set mute status(1/0):\n", isMute ? "mute" : "not mute");



    ret = CheckInputName(INPUT_INT, (void *)&val);

    if (ret < 0) {

        AUDIO_FUNC_LOGE("CheckInputName failed!");

        return HDF_FAILURE;

    }



    if (g_capture == NULL || g_capture->SetMute == NULL) {

        AUDIO_FUNC_LOGE("Record already complete,Please record againand,");

        SystemInputFail();

        return HDF_FAILURE;

    }



    if (val == 1) {

        ret = g_capture->SetMute((void *)g_capture, !isMute);

    }

    return ret;

}



static int32_t SetCaptureVolume(struct IAudioCapture **capture)

{

    (void)capture;

    float val = 0.5;

    if (g_capture == NULL || g_capture->GetVolume == NULL) {

        return HDF_FAILURE;

    }



    int32_t ret = g_capture->GetVolume((void *)g_capture, &val);

    if (ret < 0) {

        AUDIO_FUNC_LOGE("Get current volume failed,");

        SystemInputFail();

        return ret;

    }



    printf("Now the volume is %f ,Please enter the volume value you want to set (0.0-1.0):\n", val);



    ret = CheckInputName(INPUT_FLOAT, (void *)&val);

    if (ret < 0) {

        return HDF_FAILURE;

    }



    if (val < 0.0 || val > 1.0) {

        AUDIO_FUNC_LOGE("Invalid volume value,");

        SystemInputFail();

        return HDF_FAILURE;

    }



    if (g_capture == NULL || g_capture->SetVolume == NULL) {

        AUDIO_FUNC_LOGE("Record already complete,Please record againand,");

        SystemInputFail();

        return HDF_FAILURE;

    }



    ret = g_capture->SetVolume((void *)g_capture, val);

    if (ret < 0) {

        AUDIO_FUNC_LOGE("set volume fail,");

        SystemInputFail();

    }

    return ret;

}



static int32_t SetCaptureGain(struct IAudioCapture **capture)

{

    (void)capture;

    float val = 1.0;



    if (g_capture == NULL || g_capture->GetGain == NULL) {

        return HDF_FAILURE;

    }



    int32_t ret = g_capture->GetGain((void *)g_capture, &val);

    if (ret < 0) {

        AUDIO_FUNC_LOGE("Get current gain failed,");

        SystemInputFail();

        return HDF_FAILURE;

    }



    printf("Now the gain is %f, Please enter the gain value you want to set (0.0-15.0):\n", val);



    ret = CheckInputName(INPUT_FLOAT, (void *)&val);

    if (ret < 0) {

        return HDF_FAILURE;

    }



    // gain is 0.0 ~ 15.0

    if (val < 0.0 || val > 15.0) {

        AUDIO_FUNC_LOGE("Invalid gain value,");

        SystemInputFail();

        return HDF_FAILURE;

    }



    if (g_capture == NULL || g_capture->SetGain == NULL) {

        AUDIO_FUNC_LOGE("Record already complete,Please record againand,");

        SystemInputFail();

        return HDF_FAILURE;

    }



    ret = g_capture->SetGain((void *)g_capture, val);

    if (ret < 0) {

        AUDIO_FUNC_LOGE("Set capture gain failed,");

        SystemInputFail();

    }

    return ret;

}



static int32_t SetCaptyrePause(struct IAudioCapture **capture)

{

    (void)capture;

    int32_t ret;

    if (g_capture == NULL || g_capture->Pause == NULL) {

        return HDF_FAILURE;

    }



    ret = g_capture->Pause((void *)g_capture);

    if (ret != 0) {

        return HDF_FAILURE;

    }

    return HDF_SUCCESS;

}



static int32_t SetCaptureResume(struct IAudioCapture **capture)

{

    (void)capture;



    if (g_capture == NULL || g_capture->Resume == NULL) {

        return HDF_FAILURE;

    }



    if (g_capture->Resume((void *)g_capture) != 0) {

        return HDF_FAILURE;

    }

    return HDF_SUCCESS;

}



static void PrintAttributesFromat(void)

{

    printf(" ============= Capture Sample Attributes Fromat =============== \n");

    printf("| 1. Capture AUDIO_FORMAT_TYPE_PCM_8_BIT                            |\n");

    printf("| 2. Capture AUDIO_FORMAT_TYPE_PCM_16_BIT                           |\n");

    printf("| 3. Capture AUDIO_FORMAT_TYPE_PCM_24_BIT                           |\n");

    printf("| 4. Capture AUDIO_FORMAT_TYPE_PCM_32_BIT                           |\n");

    printf(" ============================================================== \n");

}



static int32_t SelectAttributesFomat(uint32_t *fomat)

{

    if (fomat == NULL) {

        return HDF_FAILURE;

    }



    int val = 0;



    PrintAttributesFromat();



    printf("Please select audio format,If not selected, the default is 16bit:");



    if (CheckInputName(INPUT_INT, (void *)&val) < 0) {

        return HDF_FAILURE;

    }

    switch (val) {

        case AUDIO_FORMAT_TYPE_PCM_8_BIT:

            *fomat = AUDIO_FORMAT_TYPE_PCM_8_BIT;

            break;

        case AUDIO_FORMAT_TYPE_PCM_16_BIT:

            *fomat = AUDIO_FORMAT_TYPE_PCM_16_BIT;

            break;

        case AUDIO_FORMAT_TYPE_PCM_24_BIT:

            *fomat = AUDIO_FORMAT_TYPE_PCM_24_BIT;

            break;

        case AUDIO_FORMAT_TYPE_PCM_32_BIT:

            *fomat = AUDIO_FORMAT_TYPE_PCM_32_BIT;

            break;

        default:

            *fomat = AUDIO_FORMAT_TYPE_PCM_16_BIT;

            break;

    }

    return HDF_SUCCESS;

}



static int32_t SetCaptureAttributes(struct IAudioCapture **capture)

{

    (void)capture;



    struct AudioSampleAttributes captureAttrs;



    if (g_capture == NULL || g_capture->GetSampleAttributes == NULL) {

        AUDIO_FUNC_LOGE("pointer is NULL");

        return HDF_FAILURE;

    }



    int32_t ret = g_capture->GetSampleAttributes((void *)g_capture, &captureAttrs);

    if (ret < 0) {

        AUDIO_FUNC_LOGE("GetCaptureAttributes failed\n");

    } else {

        printf("Current sample attributes:\n");

        printf("audioType is %u\nfomat is %u\nsampleRate is %u\nchannalCount is"

               "%u\nperiod is %u\nframesize is %u\nbigEndian is %u\nSignedData is %u\n",

            captureAttrs.type, captureAttrs.format, captureAttrs.sampleRate, captureAttrs.channelCount,

            captureAttrs.period, captureAttrs.frameSize, captureAttrs.isBigEndian, captureAttrs.isSignedData);

    }



    printf("Set Sample Attributes,");



    SystemInputFail();



    system("clear");



    printf("The sample attributes you want to set,Step by step, please.\n");



    ret = SelectAttributesFomat((uint32_t *)(&captureAttrs.format));

    if (ret < 0) {

        AUDIO_FUNC_LOGE("SetCaptureAttributes format failed");

        return HDF_FAILURE;

    }



    printf("\nPlease input sample rate(48000,44100,32000...):");



    ret = CheckInputName(INPUT_UINT32, (void *)(&captureAttrs.sampleRate));

    if (ret < 0) {

        return HDF_FAILURE;

    }



    printf("\nPlease input bigEndian(false=0/true=1):");



    ret = CheckInputName(INPUT_UINT32, (void *)(&captureAttrs.isBigEndian));

    if (ret < 0) {

        return HDF_FAILURE;

    }

    if (g_capture == NULL || g_capture->SetSampleAttributes == NULL) {

        AUDIO_FUNC_LOGE("Record already complete,Please record againand set the attrbutes,");

        SystemInputFail();

        return HDF_FAILURE;

    }



    ret = g_capture->SetSampleAttributes((void *)g_capture, &captureAttrs);

    if (ret < 0) {

        AUDIO_FUNC_LOGE("Set capture attributes failed,");

        SystemInputFail();

    }

    return ret;

}



static int32_t PrintCaptureSelectPin(struct AudioSceneDescriptor *scene)

{

    system("clear");

    printf(" ==================== Select Pin =====================  \n");

    printf("| 0. MIC                                                |\n");

    printf("| 1. MIC HeadSet                                        |\n");

    printf(" =====================================================  \n");



    printf("Please input your choice:\n");

    int32_t val = 0;

    int32_t ret = CheckInputName(INPUT_INT, (void *)&val);

    if (ret < 0) {

        AUDIO_FUNC_LOGE("Invalid value!");

        SystemInputFail();

        return HDF_FAILURE;

    }



    if (val == 1) {

        scene->desc.pins = PIN_IN_HS_MIC;

    } else {

        scene->desc.pins = PIN_IN_MIC;

    }



    return HDF_SUCCESS;

}



static void SelectSceneMenu(void)

{

    printf(" ====================  Select Scene ==================== \n");

    printf("0 is Midea.                                             |\n");

    printf("1 is Communication.                                     |\n");

    printf("2 is Voice-all.                                         |\n");

    printf(" ======================================================= \n");

}



static int32_t SelectCaptureScene(struct IAudioCapture **capture)

{

    (void)capture;

    int32_t val = 0;

    struct AudioSceneDescriptor captureScene;

    system("clear");

    SelectSceneMenu();

    printf("Please input your choice:\n");



    int32_t ret = CheckInputName(INPUT_INT, (void *)&val);

    if (ret < 0) {

        AUDIO_FUNC_LOGE("Invalid value,");

        SystemInputFail();

        return HDF_FAILURE;

    }



    switch (val) {

        case AUDIO_IN_MEDIA:

            captureScene.scene.id = AUDIO_IN_MEDIA;

            break;

        case AUDIO_IN_COMMUNICATION:

            captureScene.scene.id = AUDIO_IN_COMMUNICATION;

            break;

        case AUDIO_IN_CALL - 1:

            captureScene.scene.id = AUDIO_IN_CALL;

            break;

        default:

            AUDIO_FUNC_LOGE("Select Scene invaild.");

            return HDF_FAILURE;

    }

    ret = PrintCaptureSelectPin(&captureScene);

    if (ret != HDF_SUCCESS) {

        AUDIO_FUNC_LOGE("Select pin failed");

        return HDF_FAILURE;

    }



    captureScene.desc.desc = "mic";



    if (g_capture == NULL || g_capture->SelectScene == NULL) {

        AUDIO_FUNC_LOGE("Record already stop,");

        SystemInputFail();

        return HDF_FAILURE;

    }



    ret = g_capture->SelectScene((void *)g_capture, &captureScene);

    if (ret < 0) {

        AUDIO_FUNC_LOGE("Select scene fail");

    }

    return ret;

}



static int32_t GetCaptureExtParams(struct IAudioCapture **capture)

{

    (void)capture;

    char keyValueList[BUFFER_LEN] = {0};



    if (g_capture == NULL || g_capture->GetExtraParams == NULL) {

        return HDF_FAILURE;

    }



    int32_t ret = g_capture->GetExtraParams((void *)g_capture, keyValueList, EXT_PARAMS_MAXLEN);

    if (ret < 0) {

        AUDIO_FUNC_LOGE("Get EXT params failed!");

        SystemInputFail();

        return HDF_FAILURE;

    }

    printf("keyValueList = %s\n", keyValueList);

    return HDF_SUCCESS;

}



static int32_t GetCaptureMmapPosition(struct IAudioCapture **capture)

{

    (void)capture;



    if (g_capture == NULL || g_capture->GetMmapPosition == NULL) {

        return HDF_FAILURE;

    }



    uint64_t frames = 0;

    struct AudioTimeStamp time;

    time.tvNSec = 0;

    time.tvSec = 0;



    int32_t ret = g_capture->GetMmapPosition((void *)g_capture, &frames, &time);

    if (ret < 0) {

        AUDIO_FUNC_LOGE("Get current Mmap frames Position failed!");

        SystemInputFail();

        return HDF_FAILURE;

    }

    printf("Now the Position is %" PRIu64 "\n", frames);

    SystemInputFail();

    return HDF_SUCCESS;

}



static void PrintMenu2(void)

{

    printf(" ================== Play Capture Menu ================== \n");

    printf("| 1. Capture Start                                      |\n");

    printf("| 2. Capture Stop                                       |\n");

    printf("| 3. Capture Resume                                     |\n");

    printf("| 4. Capture Pause                                      |\n");

    printf("| 5. Capture SetVolume                                  |\n");

    printf("| 6. Capture SetGain                                    |\n");

    printf("| 7. Capture SetMute                                    |\n");

    printf("| 8. Capture SetAttributes                              |\n");

    printf("| 9. Capture SelectScene                                |\n");

    printf("| 10. Capture GetExtParams                              |\n");

    printf("| 11. Capture getMmapPosition                           |\n");

    printf("| 12.Exit                                               |\n");

    printf(" ======================================================= \n");

}



static struct ProcessCaptureMenuSwitchList g_processCaptureMenuSwitchList[] = {

    {CAPTURE_START,            StartButtonCapture    },

    {CAPTURE_STOP,             StopButtonCapture     },

    {CAPTURE_RESUME,           SetCaptureResume      },

    {CAPTURE_PAUSE,            SetCaptyrePause       },

    {SET_CAPTURE_VOLUME,       SetCaptureVolume      },

    {SET_CAPTURE_GAIN,         SetCaptureGain        },

    {SET_CAPTURE_MUTE,         SetCaptureMute        },

    {SET_CAPTURE_ATTRIBUTES,   SetCaptureAttributes  },

    {SET_CAPTURE_SLECET_SCENE, SelectCaptureScene    },

    {GET_CAPTURE_EXT_PARAMS,   GetCaptureExtParams   },

    {GET_CAPTURE_POSITION,     GetCaptureMmapPosition},

};



static void ProcessMenu(int32_t choice)

{

    if (choice == GET_CAPTURE_POSITION + 1) {

        return;

    }



    if (g_capture == NULL && choice != 1) {

        AUDIO_FUNC_LOGE("this capture already release,");

        SystemInputFail();

        return;

    }



    for (int32_t i = CAPTURE_START; i <= GET_CAPTURE_POSITION; ++i) {

        if ((choice == (int32_t)g_processCaptureMenuSwitchList[i - 1].cmd) &&

            (g_processCaptureMenuSwitchList[i - 1].operation != NULL)) {

            g_processCaptureMenuSwitchList[i - 1].operation(&g_capture);

        }

    }

}



static void PrintMenu0(void)

{

    printf(" ============== Play Capture select ===========\n");

    printf("| 1. Capture Poll                             |\n");

    printf("| 2. Capture Interrupt                        |\n");

    printf(" ==============================================\n");

}



static void Choice0(void)

{

    int choice = 0;



    system("clear");



    PrintMenu0();



    printf("Please enter your choice:");



    int32_t ret = CheckInputName(INPUT_INT, (void *)&choice);

    if (ret < 0) {

        return;

    }



    switch (choice) {

        case CAPTURE_POLL:

            g_captureModeFlag = CAPTURE_POLL;

            break;

        case CAPTURE_INTERUPT:

            g_captureModeFlag = CAPTURE_INTERUPT;

            break;

        default:

            printf("Input error,Switched to Poll mode in for you,");

            SystemInputFail();

            break;

    }

    return;

}



static void Choice(void)

{

    int32_t option = 0;

    while (option < GET_CAPTURE_POSITION + 1 && option >= 0) {

        system("clear");

        PrintMenu2();

        printf("your choice is:\n");



        int32_t ret = CheckInputName(INPUT_INT, (void *)&option);

        if (ret < 0) {

            continue;

        }

        if (option < CAPTURE_START || option > GET_CAPTURE_POSITION + 1) {

            printf("You input is wrong,");

            option = 0;

            SystemInputFail();

            continue;

        }

        ProcessMenu(option);

    }

}



static int32_t CheckAndOpenFile(int32_t argc, char const *argv[])

{

    if (argc < 2 || argv == NULL || argv[0] == NULL) { // The parameter number is not greater than 2

        printf("usage:[1]sample [2]/data/test.wav\n");

        return HDF_FAILURE;

    }



    if (argv[1] == NULL || strlen(argv[1]) == 0) {

        return HDF_FAILURE;

    }



    int32_t ret = strncpy_s(g_path, PATH_LEN - 1, argv[1], strlen(argv[1]) + 1);

    if (ret != 0) {

        AUDIO_FUNC_LOGE("copy fail");

        return HDF_FAILURE;

    }



    return HDF_SUCCESS;

}



int32_t main(int32_t argc, char const *argv[])

{

    int32_t ret = CheckAndOpenFile(argc, argv);

    if (ret != HDF_SUCCESS) {

        return ret;

    }



    if (InitParam() < 0) { // init

        AUDIO_FUNC_LOGE("InitParam Fail");

        return HDF_FAILURE;

    }

    Choice0();



    Choice();

    if (g_capture != NULL && g_adapter != NULL) {

        StopButtonCapture(&g_capture);

    }



    if (g_audioManager != NULL && g_audioManager->UnloadAdapter != NULL) {

        g_audioManager->UnloadAdapter(g_audioManager, g_adapterName);

        IAudioAdapterRelease(g_adapter, false);

        g_adapter = NULL;

        IAudioManagerRelease(g_audioManager, false);

        g_audioManager = NULL;

    }

    printf("Record file path:%s\n", g_path);

    return 0;

}