/* =========================================================================

DESCRIPTION
   Netease && Xunfei speech processing main program

Copyright (c) 2017 by Netease, Co,LTD.  All Rights Reserved.
============================================================================ */

/* =========================================================================

                             REVISION

when                  who                                          why
--------            ---------       -------------------------------------------
2017/06/28          wangzijiao                                  Created.
============================================================================ */

/* ------------------------------------------------------------------------
** Includes
** ------------------------------------------------------------------------ */
#include "alsa-pcm.h"
#include "audiobypass.h"
#include "base.h"
#include "dbus.h"
#include "dcapi.h"
#include "error.h"
#include "msc.h"
#include "record.h"
#include "srcwsapi.h"
#include "uvdbus/smart_sound.h"
#include "yunxin.h"
#include <getopt.h>
#include <jansson.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <uvdbus/fifo.h>
#include <uvdbus/log.h>

#if USED_NETEASE_DUILITE
// speech voice cb
#include "nduilite.h"
#include <cae/cae_errors.h>
#include <duilite.h>
#endif

/* ------------------------------------------------------------------------
** Macros
** ------------------------------------------------------------------------ */

/* ------------------------------------------------------------------------
** Defines
** ------------------------------------------------------------------------ */

//#define ENABLE_OEM_DBUS

#define DEBUG_WASTE_TIME
#define MAX_TOAST_TIME 500000 // 500ms
/* ------------------------------------------------------------------------
** Types
** ------------------------------------------------------------------------ */

/* ------------------------------------------------------------------------
** Global Variable Definitions
** ------------------------------------------------------------------------ */
// unsigned int g_bIsUsedTestServer;
static int in_aborting = 0;
static int justrecord = 0;
/* ------------------------------------------------------------------------
** Functions
** ------------------------------------------------------------------------ */
#if USED_NETEASE_FMAE
typedef struct _FMAEUserData {
    void *fp_out;
} FMAEUserData;
FMAE_HANDLE g_hFMAE;
const char *g_fmaeCfgPath = "/usr/share/fmae_res/config.ini";
#else
CAEDATA *caeconfig = NULL;
#endif

struct pcm_config recordconfig = {0};
struct audio_bypass *audiobypassconfig = NULL;
static char been_wakedup = 0;

static long parse_long(const char *str, int *err) {
    long val;
    char *endptr;

    errno = 0;
    val = strtol(str, &endptr, 0);

    if (errno != 0 || *endptr != '\0')
        *err = -1;
    else
        *err = 0;

    return val;
}

static void debug_waste_time(char *where, unsigned long long *tm) {
#ifdef DEBUG_WASTE_TIME
    long long tmp = Netease_caltime(tm, 1);
    if (tmp >= MAX_TOAST_TIME) {
        n_error("Waste too much time in:%s, %lld\n", where, tmp);
    }
#endif
}

#if USED_NETEASE_DC
static struct kfifo g_AudioCacheBuf;
// static DECLARE_KFIFO(g_AudioCacheBuf, unsigned char, WAKE_CACHE_DATA_SIZE);
static unsigned char g_AudioCache[WAKE_CACHE_DATA_SIZE];

static void __cacheCAEAudio(unsigned char *pBuf, unsigned int iSize) {
    int leftSize = kfifo_avail(&g_AudioCacheBuf);

    if (iSize > WAKE_CACHE_DATA_SIZE) {
        LOG_EX(LOG_Warn, "Wave Data Size = %u\n", iSize);

        pBuf = pBuf + (iSize - WAKE_CACHE_DATA_SIZE);
        iSize = WAKE_CACHE_DATA_SIZE;
    }

    if (iSize > leftSize) {
        int drop = iSize - leftSize;

        drop = kfifo_out_locked(&g_AudioCacheBuf, NULL, drop);
    }

    kfifo_in_locked(&g_AudioCacheBuf, pBuf, iSize);
}

unsigned char *getDCCachebuf(void) {
    int drop = kfifo_len(&g_AudioCacheBuf) - WAKE_CACHE_DATA_SIZE;
    if (drop > 0) {
        drop = kfifo_out_locked(&g_AudioCacheBuf, NULL, drop);
    }

    kfifo_peek_locked(&g_AudioCacheBuf, g_AudioCache, WAKE_CACHE_DATA_SIZE);
    return g_AudioCache;
}
#endif

#if USED_NETEASE_FMAE
static void WkupCallBack(short angle, short channel, float power, short CMScore,
                         short beam, char *param1, void *param2,
                         void *userData) {
    // printf("Wake Up && angle : %d\n", angle);
    char tmp[100];
    been_wakedup = 1;

    n_toast("\nCAEIvwCb ....\nangle:%d\n   score:%d  beam:%d  power:%f  "
            "channel:%d\n",
            angle, CMScore, beam, power, channel);
    Netease_IAT_checkflag(angle);

    sprintf(tmp, "{\"angle\":%d,\"score\":%d,\"beam\":%d,\"power\":%f}", angle,
            CMScore, beam, power);
    Netease_Dbus_Send_CMD(MODULE_VOICEENGINE, MODULE_CONTROLLER,
                          CMD_MSC_MSG_CONTROLLER_WAKEUP, tmp, strlen(tmp));
}

static void AudioCallBack(const void *audioData, unsigned int audioLen,
                          int param1, const void *param2, void *userData) {

    // FMAEUserData *userDataObj = (FMAEUserData *)userData;
    if (!!audiobypassconfig) {
        Netease_audiobypass_write(audiobypassconfig, audioData, audioLen);
    }
}

#elif USED_NETEASE_DUILITE
// speech voice cb
int Duilite_wakeup_cb(void *userdata, int type, char *msg, int len) {
    char tmp[100] = {0};
    json_t *js = NULL;
    char *wakeupword = NULL;
    int major;
    int status;
    double confidence;

    been_wakedup = 1;
    n_toast("Wake up::%s\n", msg);
    setAng(-1);
    Netease_IAT_checkflag(1);

#if USED_NETEASE_DUILITE_VAD
    Netease_duilite_vad_stop(1);
#endif

    js = json_loadb(msg, len, 0, NULL);
    if (js) {
        //{"wakeupWord":"di da di da","major":0,"status":1,
        //"confidence":0.445181}
        json_unpack(js, "{s:s, s:i, s:i, s:f}", "wakeupWord", &wakeupword,
                    "major", &major, "status", &status, "confidence",
                    &confidence);
        setVoiceWakeupword(wakeupword);
        n_toast("json ok, wakeupword:%s\n", wakeupword);
        sprintf(tmp,
                "{\"wakeupwords\":\"%s\",\"angle\":%d,\"score\":%d,\"beam\":%d,"
                "\"power\":%f}",
                wakeupword, 1, 1, 1, 1.1);
        setVoiceConfidence(confidence);
        setVoiceMajor(major);
        setVoiceStatus(status);
        json_decref(js);
    } else {
        n_toast("Wake up json err\n");
        sprintf(tmp, "{\"angle\":%d,\"score\":%d,\"beam\":%d,\"power\":%f}", 1,
                1, 1, 1.2);
    }
    n_toast("Send to cc:%s\n", tmp);
    Netease_Dbus_Send_CMD(MODULE_VOICEENGINE, MODULE_CONTROLLER,
                          CMD_MSC_MSG_CONTROLLER_WAKEUP, tmp, strlen(tmp));
}

static char *g_pQuickWkKey[] = {
    "xia yi shou",
    "da sheng yi dian",
    "xiao sheng yi dian",
};

int Duilite_doa_cb(void *userdata, int type, char *msg, int len) {
    json_t *tmp;
    json_t *js;
    n_toast("Doa cb:%s, wakeup by: %s\n", msg, getVoiceWakeupword());
    if (NULL == msg || len <= 0) {
        return 0;
    }
    js = json_loadb(msg, len, 0, NULL);
    if (!!js) {
        tmp = json_object_get(js, "doa");
        if (tmp != NULL && json_is_integer(tmp)) {
            BaseLock();
            setAng((int)(json_integer_value(tmp)));
            BaseUnlock();
        }
        json_decref(js);
    }
}

int Duilite_beforming_cb(void *userdata, int type, char *msg, int len) {
    int fd;
    size_t hasWritten;

    if (type == DUILITE_MSG_TYPE_BINARY) {
        if (recordconfig.recordata && recordconfig.recordata->finalfilefd > 0) {
            write(recordconfig.recordata->finalfilefd, msg, len);
        }
        if (!!audiobypassconfig) {
            Netease_audiobypass_write(audiobypassconfig, msg, len);
        }
    } else if (type == DUILITE_MSG_TYPE_JSON) {
        n_debug("Beforming cb, get msg:%s\n", msg);
    }
}

int Duilite_vad_cb(void *userdata, int type, char *msg, int len) {
    if (type == DUILITE_MSG_TYPE_JSON)
        n_debug("vad cb:%s\n", msg);
}
#else
/* ------------------------------------------------------------------------
** Function Definitions
** ------------------------------------------------------------------------ */
// CAE wake up callback
static void CAEIvwCb(short angle, short channel, float power, short CMScore,
                     short beam, char *param1, void *param2, void *userData) {
    //    CAEDATA *cae = (CAEDATA *)userData;
    char tmp[100];

    been_wakedup = 1;
    n_toast("\nCAEIvwCb ....\nangle:%d\n   score:%d  beam:%d  power:%f  "
            "channel:%d\n",
            angle, CMScore, beam, power, channel);
    Netease_IAT_checkflag(angle);

    sprintf(tmp, "{\"angle\":%d,\"score\":%d,\"beam\":%d,\"power\":%f}", angle,
            CMScore, beam, power);
    Netease_Dbus_Send_CMD(MODULE_VOICEENGINE, MODULE_CONTROLLER,
                          CMD_MSC_MSG_CONTROLLER_WAKEUP, tmp, strlen(tmp));
}

// CAE audio callback
static void CAEAudioCb(const void *audioData, unsigned int audioLen, int param1,
                       const void *param2, void *userData) {
    if (!!audiobypassconfig) {
        Netease_audiobypass_write(audiobypassconfig, audioData, audioLen);
    }
}
#endif

static void record_audio_cb(const void *audio, unsigned int audio_len,
                            int err_code) {
    unsigned long long cachetime;

#ifdef DEBUG_WASTE_TIME
    Netease_caltime(&cachetime, 1);
#endif

#if USED_NETEASE_FMAE
    int ret = 0;
#endif

#if USED_NETEASE_FMAE
    if (1) {
#elif USED_NETEASE_DUILITE
    Netease_nduilite_writeaudio(audio, audio_len);
    debug_waste_time("duilite_writeaudio", &cachetime);
    if (1) {
#else
    if (caeconfig != NULL && caeconfig->cae != NULL) {
        // n_debug("write audio to cae !\n");
#endif
#if USED_NETEASE_DC
        // unsigned char* pBuf = (unsigned char*)audio;
#if 1
        if (Netease_IAT_GetStatus() == IAT_STATUS_AUDIOIN) {
            DCWriteAudioRec(audio, audio_len);
            debug_waste_time("DCWriteAudioRec", &cachetime);
        }

#if 0
        if (netease_dc_status()) {
            netease_dc_clean_status();
            DCWriteAudioWk(g_AudioCache, WAKE_CACHE_DATA_SIZE);
            debug_waste_time("DCWriteAudioWk", &cachetime);
        }
#endif

#else
        if (netease_dc_status()) {
            if (isSendCache) {
                isSendCache = 0;
                DCWriteAudioWk(g_AudioCache, WAKE_CACHE_DATA_SIZE);
                debug_waste_time("DCWriteAudioWk", &cachetime);
            } else {
                DCWriteAudioRec(audio, audio_len);
                debug_waste_time("DCWriteAudioRec", &cachetime);
            }
        } else {
            isSendCache = 1;
        }
#endif
        __cacheCAEAudio((unsigned char *)audio, audio_len);
        debug_waste_time("__cacheCAEAudio", &cachetime);
#endif

#if USED_NETEASE_FMAE
        ret = FMAEAudioWrite(g_hFMAE, audio, audio_len);

        // printf("write %d at %p ret = %d\n", audio_len, audio, ret);
#elif USED_XUNFEI_CAE
        Netease_CAEAudioWrite(caeconfig, audio, audio_len);
#endif
        // n_debug("write finish!\n");
    } else {
        n_error("write adudio fail!\n");
    }
}

// Dbus msg callback
static PDBUS_MSG_PACK DBusMessageCb(uv_loop_t *pLoop, DBusConnection *pConn,
                                    PDBUS_MSG_PACK pMsg) {
    // int err;
    // uint32_t tm = LIBUV_CURRENT_TIME_US();
    // PCFG_API_RSP pRsp = NULL;
    json_t *js = NULL;
    json_t *tmp = NULL;
    json_t *uuid = NULL;
#ifdef ENABLE_YUNXIN
    char *tmpbuf = NULL;
#endif
    char *recType = NULL;
    char *confirmParam = NULL;
    char *playerStatus = NULL;

    if (!pMsg || !pConn) {
        return NULL;
    }
#if 0
    n_debug("Process Message(%u --> 0x%08X): cmd = %u, "
            "size = %u, key = %d, msg(%d) = [%s]\n",
            pMsg->msgSrc, pMsg->msgDests, pMsg->busCmd, pMsg->msgSize,
            pMsg->msgKey, pMsg->msgSize, pMsg->pMsg);
#endif
    switch (pMsg->busCmd) {
    case CMD_CC_MSC_END_SESSION:
        n_toast("CC tells end session!");
        Netease_IAT_end_session();
        break;

    case CMD_CC_MSC_BEGIN_SESSION:
        n_toast("Recv cc create session command! msg:%s\n", pMsg->pMsg);
        if (been_wakedup == 0 && caeconfig != NULL) {
            // todo do not waked up, do wake here
            n_toast("has not waked up!todo waked up!");
#if USED_XUNFEI_CAE
            Netease_CAESetRealBeam(caeconfig, 0);
#endif
        }
        js = json_loadb(pMsg->pMsg, pMsg->msgSize, 0, NULL);
        if (NULL != js) {
            json_unpack(js, "{s:s,s:s,s:s}", "recType", &recType,
                        "confirmParam", &confirmParam, "playerStatus",
                        &playerStatus);
        } else {
            n_error("Decode error, begin session!!\n");
        }
        //        n_debug("\nType:%s\nConfirm:%s\nplayerstataus:%s\n", recType,
        //                confirmParam, playerStatus);
        setVadStatus(VadStatus_NULL);

#if USED_NETEASE_DUILITE && USED_NETEASE_DUILITE_VAD
        Netease_duilite_vad_start();
#endif
        if (1 ==
            Netease_IAT_begin_session(recType, confirmParam, playerStatus)) {
#if USED_NETEASE_DUILITE && USED_NETEASE_DUILITE_VAD
            Netease_duilite_vad_stop(1);
#endif
        }
        if (NULL != js) {
            json_decref(js);
        }
        break;
    case CMD_CONTROLLER_RSPMSG_INITARGS:
        js = json_loadb(pMsg->pMsg, pMsg->msgSize, 0, NULL);
        if (js != NULL) {
            uuid = json_object_get(js, "uuid");
            if (uuid != NULL && json_is_string(uuid)) {
                BaseLock();
                char *uuidChar = json_string_value(uuid);
                setUuid(uuidChar, strlen(uuidChar));
                BaseUnlock();
            }

            tmp = json_object_get(js, "bind_user");
            if (tmp != NULL && json_is_string(tmp)) {
                BaseLock();
                setBindUser(json_string_value(tmp),
                            strlen(json_string_value(tmp)));
                BaseUnlock();
            }

            tmp = json_object_get(js, "yx_token");
            if (tmp != NULL && json_is_string(tmp)) {
                BaseLock();
                setYxToken(json_string_value(tmp),
                           strlen(json_string_value(tmp)));
                BaseUnlock();
#ifdef ENABLE_YUNXIN
                n_debug("Begin to tell yx login from dbus:%s", pMsg->pMsg);
                Netease_yunxin_login();
#endif
            }

            json_decref(js);
        }

        break;

    case CMD_CONTROLLER_RSPMSG_PLAYERSTATUS:
        BaseLock();
        setSongInfo(pMsg->pMsg, pMsg->msgSize);
        BaseUnlock();
        js = json_pack("{s:i, s:s, s:b}", "cmd", 5500, "detail", pMsg->pMsg,
                       "hasMore", 0);
        if (!!js) {
            tmp = json_dumps(js, 0);
            if (!!tmp) {
#ifdef ENABLE_YUNXIN
                Netease_yunxin_sendmsg1(tmp);
#endif
                free(tmp);
            } else {
                n_toast("json dump error\n");
            }
            json_decref(js);
        } else {
            n_error("json pack err\n");
        }
        break;

    case CMD_YUNXIN_SENDMSG:
#ifdef ENABLE_YUNXIN
        Netease_yunxin_sendmsg(pMsg->pMsg);
#endif
        break;

    case CMD_MSC_REQMSG_MIC_CONTROL:
        break;
#ifdef ENABLE_YUNXIN
    case CMD_YUNXIN_STATUS:
        tmpbuf = Netease_yunxin_dbus_getstatus();
        if (!!tmpbuf) {
            Netease_Dbus_Send_CMD(MODULE_VOICEENGINE, MODULE_CONTROLLER,
                                  CMD_YUNXIN_STATUS, tmpbuf, strlen(tmpbuf));
            free(tmpbuf);
        }
        break;
#endif

    case CMD_NDUILITE_FESPA_SET_ARG:
        Netease_duilite_fespa_set(pMsg->pMsg);
        break;

    default:
        break;
    }

    return NULL;
}

void LogFunc(int logLevel, const char *log, void *userData) {
    IHW_LogRawString(logLevel, (char *)log);
}

static void signal_handler(int sig) {
    if (in_aborting)
        return;

    in_aborting = 1;
    n_debug("Aborted by signal:%d, %s\n", sig, strsignal(sig));
    Netease_record_stop(&recordconfig);

    signal(sig, SIG_DFL);
}

static void usage() {
    printf(
        "Usage:\n"
        "-h, --help                 help\n"
        "-l, --list-devices         list all soundcards and digital audio "
        "devices\n"
        "-L, --list-pcms            list device names\n"
        "-w, --work-mode=#          work mode: 0: r311_pv1\n"
        "-f, --list-format          list all format in alsa\n"
        "-r, --just-record           Only record voice to file\n"
        "-t, --type=#               sample format (case insensitive): raw,wav\n"
        "--rawfile=#                record raw data to filepath\n"
        "--finalfile=#              record duilite output to filepath\n");
}
enum { OPT_RAW_FILE = 1, OPT_FINAL_FILE };

void main(int argc, char **argv) {
    int ret, c, option_index, err, tmp;
    char *rawfile = "/dev/null";
    char *finalfile = "/dev/null";
    static const char short_options[] = "hlt:w:Lfr";
    static const struct option long_options[] = {
        {"help", 0, 0, 'h'},
        {"list-devices", 0, 0, 'l'},
        {"list-pcms", 0, 0, 'L'},
        {"list-format", 0, 0, 'f'},
        {"just-record", 0, 0, 'r'},
        {"rawfile", 1, 0, OPT_RAW_FILE},
        {"finalfile", 1, 0, OPT_FINAL_FILE},
        {"type", 1, 0, 't'},
        {"work-mode", 1, 0, 'w'},
        {0, 0, 0, 0}};

    recordconfig.backupfile_waveformat = 1;
    recordconfig.audio_cb = record_audio_cb;
    setWorkMode(WorkMode_R311_PV1);

    if (argc == 1) {
        printf("Not enough arg!\n");
        usage();
        return;
    }

    while ((c = getopt_long(argc, argv, short_options, long_options,
                            &option_index)) != -1) {
        switch (c) {
        case 'h':
            usage();
            return;

        case 'l':
            device_list();
            return;

        case 'L':
            pcm_list();
            return;

        case 'r':
            justrecord = 1;
            break;

        case 't':
            if (strcasecmp(optarg, "wav") == 0) {
                recordconfig.backupfile_waveformat = 1;
            } else if (strcasecmp(optarg, "raw") == 0) {
                recordconfig.backupfile_waveformat = 0;
            }
            printf("Wave format:%d\n", recordconfig.backupfile_waveformat);
            break;

        case 'w':
            tmp = parse_long(optarg, &err);
            if (err < 0) {
                printf("invalid work mode!%s\n", optarg);
                return;
            } else {
                setWorkMode((WorkMode)tmp);
            }
            break;

        case OPT_RAW_FILE:
            rawfile = optarg;
            printf("Raw file:%s\n", optarg);
            break;

        case OPT_FINAL_FILE:
            finalfile = optarg;
            printf("Final file:%s\n", optarg);
            break;

        default:
            printf("Unknow cmd!(%d)\n", c);
            usage();
            exit(0);
        }
    }
    printf("parse arg end!\n");
    // Base module init
    BaseInit();

    printf("Work mode:%d\n", getWorkMode());

    // resetAdc();

    if (justrecord == 1) {
        if (rawfile == NULL && finalfile == NULL) {
            printf("Must input rawfile or finalfile!\n");
            return;
        }
        if (rawfile != NULL) {
            recordconfig.backupfilename = rawfile;
            printf("Will record raw to file:%s\n", rawfile);
        }
        if (finalfile != NULL) {
            recordconfig.finalfilename = finalfile;
            printf("Will record final data to file:%s\n", finalfile);
        }

        recordconfig.audio_cb = NULL;
        Neteasae_record_start(&recordconfig);

        signal(SIGINT, signal_handler);
        signal(SIGTERM, signal_handler);
        signal(SIGABRT, signal_handler);

        while (1)
            usleep(1000000);
    }

#ifdef ENABLE_OEM_DBUS
    ret = Netease_dbus_oem_init(DBusMessageCb);
#else
    ret = Netease_Dbus_Init(DBusMessageCb);
#endif
    if (NETEASE_SUCCESS == ret) {
        n_debug("Dbus init success\n");
    } else {
        n_error("Dbus init fail: %d\n", ret);
        // return;
    }

#if USED_NETEASE_FMAE
    FMAEUserData userData;
#endif

    SRCWsSetLogFunc(LogFunc);

#if USED_NETEASE_DC
    ret = kfifo_alloc(&g_AudioCacheBuf, WAKE_CACHE_DATA_SIZE);
    if (ret) {
        fprintf(stderr, "error kfifo_alloc\n");
        return;
    }
#endif

#if 0
    if (access(TEST_SERVER_CFG_FILE, F_OK) == 0) {
        g_bIsUsedTestServer = 1;
    } else {
        g_bIsUsedTestServer = 0;
    }
#endif

#if USED_NETEASE_FMAE
    ret = Netease_audiobypass_init(&audiobypassconfig, NULL,
                                   AUDIO_BYPASS_CHANNEL_MSC_IAT);
#else

#if !USED_NETEASE_AI
    ret = Netease_MSP_Init(&caeconfig);
    if (NETEASE_SUCCESS == ret) {
        n_debug("MSP init success!aaa\n");
    } else {
        n_error("MSP init fail!\n");
        return;
    }
#endif

    ret = Netease_audiobypass_init(&audiobypassconfig, NULL, //&caeconfig,
                                   AUDIO_BYPASS_CHANNEL_MSC_IAT);
#endif

    if (NETEASE_SUCCESS == ret) {
        n_debug("Audio bypass init success!\n");
    } else {
        n_error("Audio bypass init fail!\n");
        return;
    }

#if USED_NETEASE_FMAE
    ret = FMAENew(&g_hFMAE, g_fmaeCfgPath, WkupCallBack, AudioCallBack, NULL,
                  &userData);
    if (0 == ret) {
        n_debug("Fmae init success!\n");
    } else {
        n_error("Fmae init fail!\n");
        return;
    }

    FMAESetAngle(g_hFMAE, 0);

#elif USED_NETEASE_DUILITE
    // init duilife
    Netease_nduilite_init(Duilite_wakeup_cb, Duilite_doa_cb,
                          Duilite_beforming_cb, Duilite_vad_cb);

#else
    n_debug("Begin to init cae modules!\n");
    ret = Netease_CaeInit(&caeconfig, CAEIvwCb, CAEAudioCb);
    if (NETEASE_SUCCESS == ret) {
        n_debug("Cae init success!\n");
    } else {
        n_error("Cae init fail!\n");
        return;
    }
#endif

    SRCWsCreat();
#if USED_NETEASE_DC
    DCCreat();
#endif
    ret = Netease_IAT_Init();
    if (NETEASE_SUCCESS == ret) {
        n_debug("IAT init success!\n");
    } else {
        n_error("IAT init fail!");
        return;
    }

    Netease_audiobypass_start(audiobypassconfig);
    ret = Neteasae_record_start(&recordconfig);
    if (NETEASE_SUCCESS == ret) {
        n_debug("Record start success\n");
    } else {
        n_error("Record start fail\n");
        return;
    }

#ifdef ENABLE_YUNXIN
    Netease_yunxin_init(&audiobypassconfig);
#endif
    // Netease_Dbus_Start_Sync();

    pthread_t tid;
#ifdef ENABLE_OEM_DBUS
    pthread_create(&tid, NULL, Netease_dbus_oem_start, NULL);
#else
    pthread_create(&tid, NULL, Netease_Dbus_Start_Sync, NULL);
#endif
    // Netease_yunxin_test();

#if 0
    while (1) {
        if (1 == Netease_nduilite_init(Duilite_wakeup_cb, Duilite_doa_cb,
                                       Duilite_beforming_cb, Duilite_vad_cb)) {
            n_toast("Nduilite init success, exit!\n");
            break;
        } else {
            n_toast("Nduilite init fail, sleep and redo!\n");
            usleep(1000000);
        }
    }

    while (1)
        usleep(1000000);

#endif

    while (1) {
        if (strlen(getUuid()) == 0 || strlen(getYxToken()) == 0) {
            n_toast("Get args frome cc\n");
            Netease_dbus_initargs();
            usleep(1000000);
        } else {
            break;
        }
    }
    while (1) {
        if (1 == Netease_nduilite_init(Duilite_wakeup_cb, Duilite_doa_cb,
                                       Duilite_beforming_cb, Duilite_vad_cb)) {
            n_toast("Nduilite init success, exit!\n");
            Netease_Dbus_Send_CMD(MODULE_VOICEENGINE, MODULE_CONTROLLER,
                                  CMD_NDUILITE_FESPA_SET_ARG, "", 0);
            break;
        } else {
            n_toast("Nduilite init fail, sleep and redo!\n");
            usleep(1000000);
        }
    }

    while (1)
        usleep(1000000);
}
