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

DESCRIPTION
   Netease && Xunfei speech processing main program
   MSC

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

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

                             REVISION

when                       who why
--------                    ---------
-------------------------------------------
2017/06/28          wangzijiao                                  Created.
============================================================================ */
/* ------------------------------------------------------------------------
** Includes
** ------------------------------------------------------------------------ */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include "base.h"
#include "buffer.h"
#include "cae.h"
#include "cae_thread.h"
#include "dbus.h"
#include "error.h"
#include "msc.h"
#include "yunxin.h"
#include <jansson.h>
#include <sys/time.h>
#include <uvdbus/libuv_dbus.h>
#include <uvdbus/server_addr.h>
//#include <yunxin/helper/nim_sdk_helper.h>
//#include <yunxin/nim_sdk_api.h>
#include <yunxin/api/nim_client.h>
#include <yunxin/api/nim_device.h>
#include <yunxin/api/nim_sysmsg.h>
#include <yunxin/api/nim_talk.h>
#include <yunxin/api/nim_tools.h>
#include <yunxin/api/nim_vchat.h>
#include <yunxin/export_headers/nim_client_def.h>
#include <yunxin/export_headers/nim_device_def.h>
#include <yunxin/export_headers/nim_msglog_def.h>
#include <yunxin/export_headers/nim_vchat_def.h>

#include "linux_alsa_core.h"

#ifdef ENABLE_YUNXIN
/* ------------------------------------------------------------------------
 *
 * Macros
 *
 * ------------------------------------------------------------------------ */
#define PCM_1S_SIZE 16000 * 16 / 8
#define PCM_10MS_SIZE PCM_1S_SIZE / 100
#define YUNXIN_PCM_BUFFER_BLOCK_SIZE PCM_10MS_SIZE

//#define WRITE_YUNXIN_AUDIO_TOFILE
#define YUNXIN_SERVER_KEY_TEST "2e37bc56a9b7ec3f6b8f41f60b81eb92"
#define YUNXIN_SERVER_KEY_ONLINE "dbb00213c23ea3709aae12ceb4c4e54e"

#define JSON_KEY_LOGINSTATUS "IsLogin"
/* ------------------------------------------------------------------------
 *
 * Defines
 *
 * ------------------------------------------------------------------------ */
static unsigned long long logintime;
#define MAX_LOGING_TIME 42 * 1000 * 1000 // usec
audio_alsa_core_t *alsa_hd = NULL;
struct audio_bypass **audio_bypass;
// extern unsigned int g_bIsUsedTestServer;
static char BackupAccount[LEN_UUID] = {0};
void Netease_yunxin_cb_init();
// static NATIVE_MUTEX_HANDLE yunxinlock;
typedef enum {
    YUNXIN_STATUS_NOT_LOGIN,
    YUNXIN_STATUS_LOGIN_START,
    YUNXIN_STATUS_LOGIN_FINISH
} YUNXIN_STATUS;
static YUNXIN_STATUS localyunxinstatus = YUNXIN_STATUS_NOT_LOGIN;

#ifdef WRITE_YUNXIN_AUDIO_TOFILE
int fd_audio_output;
#endif
/* ------------------------------------------------------------------------
 *
 * Types
 *
 * ------------------------------------------------------------------------ */
// static char audio_data[1280];

//*****************测试方案*************
// 登录云信后和对方互发音视频（验证通知是否正常）
//  1.发起。2.挂断。
// 音视频通话是否正常。（有数据流的一方由另一方回流）

// void send_vchat_request(bool);
// void WINAPI chatthread();
char c = '9';
bool login = false;
int64_t channel_id_ = 0;

// void test_start_vchat_device();
// void test_end_vchat_device();
void Netease_yunxin_cb_loginout(const char *json_params, const void *user_data);
// 1 loginin; 2, not login
int Netease_yunxin_checklogin();
void Netease_yunxin_cb_loginout_with_accountchangelogin(const char *json_params,
                                                        const void *user_data);

//初始化云信sdk
void nim_sdk_init() {
    // char *nim_sdk_dll_path = "/usr/lib/libnim.so";
    char *app_data_dir = "/mnt/UDISK";
    char *app_install_dir = "/mnt/UDISK";

    int ret;

    char *json =
        "{\"global_config\":{"
        "\"write_timeout\":15000,\"read_timeout\":15000,\"heartping_timeout\":"
        "15000,\"db_encrypt_key\":\"\", "
        "\"preload_attach\" : true, \"not_need_save_custom_msg\" : true,"
        "\"sdk_log_level\" : 6, \"private_server_setting\" : false}, "
        "\"app_key\" "
        ": \"\"}";
    // char* json =
    // "{\"global_config\":{\"db_encrypt_key\":\"Netease\",\"preload_attach\":true,\"preload_image_quality\":
    // -1,\"preload_image_resize\":\"\",\"sdk_log_level\":5},\"private_server_setting\":{\"default_link\":[\"223.252.220.222:2000\"],\"default_nos_download\":[\"http
    // ://nos.netease.com\"],\"default_nos_upload\":[\"http://223.252.196.40\"],\"lbs\":\"http://223.252.220.223/lbs/conf\",\"nos_lbs\":\"http://wanproxy.127.net/lbs?version=1.0\",\"rsa_public_key_module\":\"00e3afe7487e6ac9ba69654672672ceddc05d5b6d45850859f11004d30c63e3691afd55722bdd2c75232b2a3561776201f84def8e38c508870ca7692b4228b0478e104460d7800dee3b6c3d8f89746ed48ee94f268f42b9c911437083d3815624e50de3fec3c0ec8ab3e71d5bdce3f4291d20538893cacdc00da9d1390ee39440d\",\"rsa_version\":0}}
    // ";
    ret = nim_client_init(app_data_dir, app_install_dir, json);
    n_debug("Nim client init: %d\n", ret);

    //初始化云信音视频
    // ret = nim_vchat_init("");
    // printf("Nim vchat init:%d\n", ret);
}

void Netease_send_yunxinstatus() {
    char *tmpbuf = NULL;
    tmpbuf = Netease_yunxin_dbus_getstatus();
    if (!!tmpbuf) {
        Netease_Dbus_Send_CMD(MODULE_VOICEENGINE, MODULE_CONTROLLER,
                              CMD_YUNXIN_STATUS, tmpbuf, strlen(tmpbuf));
        free(tmpbuf);
    }
}

//登录回调
static void nim_login_callback(const char *json_params, const void *user_data) {
    //{ "err_code": 200, "relogin" : false, "login_step" : 0 }
    n_debug("Login callback: %s\n", json_params);
    json_t *value = json_loads(json_params, 0, NULL);

    if (value) {
        long code = json_integer_value(json_object_get(value, "err_code"));
        long step = json_integer_value(json_object_get(value, "login_step"));
        n_debug("Json:get err:%ld, login_step:%ld\n", code, step);
        if (302 == code || 416 == code) {
            // 302 账号密码错误
            // 416 登录太频繁
            // 账号和密码不匹配不再继续登录,等用户下次发送新的账号和密码触发再次登录
            nim_client_logout(
                kNIMLogoutChangeAccout, NULL,
                Netease_yunxin_cb_loginout_with_accountchangelogin, NULL);
        } else if (200 != code && code != 20002) {
            n_debug("Code != 200 and 20002, just do relogin!\n");

            nim_client_logout(kNIMLogoutChangeAccout, NULL,
                              Netease_yunxin_cb_loginout, NULL);
        } else if (20002 == code) {
            localyunxinstatus = YUNXIN_STATUS_LOGIN_FINISH;
        } else if (200 == code) {
            switch (step) {
            case kNIMLoginStepLinking:
                break;
            case kNIMLoginStepLink:
                break;
            case kNIMLoginStepLogining:
                break;
            case kNIMLoginStepLogin:
                //登录鉴权结果
                n_debug("Should login successfully! nim_login_state:%d\n",
                        nim_client_get_login_state(NULL));
                Netease_yunxin_cb_init();

                if (strncmp(BackupAccount, getUuid(), LEN_UUID)) {
                    n_debug(
                        "Login success! But not the same account, loginout\n");
                    nim_client_logout(kNIMLogoutChangeAccout, NULL,
                                      Netease_yunxin_cb_loginout, NULL);
                } else {
                    n_debug("The same account, Login success!\n");
                    Netease_send_yunxinstatus();
                    localyunxinstatus = YUNXIN_STATUS_LOGIN_FINISH;
                }
                break;
            default:
                n_error("Unknown login step!");
                break;
            }
        }
        json_decref(value);
    } else {
        n_error("Decode server data error! force relogin!\n");

        nim_client_logout(kNIMLogoutChangeAccout, NULL,
                          Netease_yunxin_cb_loginout, NULL);
    }
}

// 1 loginin; 2, not login
int Netease_yunxin_checklogin() {
    int loginStatus = nim_client_get_login_state(NULL);
    long long logincoasttime;
    if (loginStatus != kNIMLoginStateLogin) {
        n_debug("Yunxin not login, do not send msg!, cur login %d != %d, "
                "localYunxinStatus:%d, logintime:%llu\n",
                loginStatus, kNIMLoginStateLogin, localyunxinstatus,
                logintime / 1000 / 1000);

        if (localyunxinstatus == YUNXIN_STATUS_LOGIN_START) {
            logincoasttime = Netease_monotonic_caltime(&logintime, 0);
            if (logincoasttime > MAX_LOGING_TIME) {
                Netease_monotonic_caltime(&logintime, 1);
                n_debug(
                    "Yun xin maybe have some issue, login coast time:%lld, do "
                    "login out and relogin\n",
                    logincoasttime);
                nim_client_logout(kNIMLogoutChangeAccout, NULL,
                                  Netease_yunxin_cb_loginout, NULL);
            }
        }

        // if (localyunxinstatus != YUNXIN_STATUS_LOGIN_START) {
        //     n_debug("Yunxin login not start, just do login!\n");
        //     Netease_yunxin_login();
        // }
    }

    return loginStatus;
}

void Netease_yunxin_sendmsg(char *data) {
    json_t *tmp = NULL;
    char msgid[LEN_UNIXMS] = {0};
    char bduser[LEN_UUID] = {0};

    if (kNIMLoginStateUnLogin == Netease_yunxin_checklogin()) {
        n_error("Yunxin not login, do not send:%s\n", data);
        return;
    }

    snprintf(msgid, sizeof(msgid), "%llu", Netease_gettime_ms());
    BaseLock();
    strncpy(bduser, getBindUser(), sizeof(bduser));
    BaseUnlock();

    if (strnlen(bduser, LEN_UUID) == 0) {
        n_debug("Send msg len == 0,exit!\n");
        return;
    }

    tmp = json_pack("{s:i, s:s, s:i, s:s, s:s, s:i}", kNIMMsgKeyToType,
                    kNIMSessionTypeP2P, kNIMMsgKeyToAccount, bduser,
                    kNIMMsgKeyType, kNIMMessageTypeCustom, kNIMMsgKeyBody, data,
                    kNIMMsgKeyClientMsgid, msgid, kNIMMsgKeyHistorySave, 1);

    if (!!tmp) {
        char *body = json_dumps(tmp, 0);
        if (!!body) {
            n_toast("YunXin send msg: %s\n", body);
            nim_talk_send_msg(body, NULL, NULL, NULL);
            free(body);
        } else {
            n_error("json dump error !\n");
        }

        json_decref(tmp);
    } else {
        n_error("json pack err!!\n");
        if (NULL != data) {
            n_debug("data:%s\n", data);
        } else {
            n_debug("JSON data is nil\n");
        }
    }
}

void Netease_yunxin_sendmsg1(char *data) {
    json_t *tmp = NULL;
    char msgid[LEN_UNIXMS];
    char bduser[LEN_UUID];

    if (kNIMLoginStateUnLogin == Netease_yunxin_checklogin()) {
        n_error("Yunxin not login, do not send:%s\n", data);
        return;
    }

    snprintf(msgid, sizeof(msgid), "%llu", Netease_gettime_ms());
    BaseLock();
    strncpy(bduser, getBindUser(), sizeof(bduser));
    BaseUnlock();

    if (strnlen(bduser, LEN_UUID) == 0) {
        n_debug("Send msg bduser len == 0,exit!\n");
        return;
    }

    tmp = json_pack("{s:i, s:s, s:i, s:s, s:s, s:i}", kNIMMsgKeyToType,
                    kNIMSessionTypeP2P, kNIMMsgKeyToAccount, bduser,
                    kNIMMsgKeyType, kNIMMessageTypeCustom, kNIMMsgKeyBody, data,
                    kNIMMsgKeyClientMsgid, msgid, kNIMMsgKeyHistorySave, 0);

    if (!!tmp) {
        char *body = json_dumps(tmp, 0);
        if (!!body) {
            // n_toast("YunXin send msg: %s\n", body);
            nim_talk_send_msg(body, NULL, NULL, NULL);
            free(body);
        } else {
            n_error("json dump error !\n");
        }

        json_decref(tmp);
    } else {
        n_error("json pack err!!\n");
    }
}

char *Netease_yunxin_dbus_getstatus() {
    json_t *js = json_pack("{s:i}", JSON_KEY_LOGINSTATUS,
                           nim_client_get_login_state(NULL));
    if (!!js) {
        char *pVal = json_dumps(js, NULL);
        json_decref(js);
        return pVal;
    } else {
        return (char *)NULL;
    }
}

static void Netease_yunxin_audiocb(uint64_t time, const char *data,
                                   uint32_t size, const char *json_extension,
                                   const void *user_data) {
    if (!!alsa_hd) {
        nrtc_alsa_write_data(alsa_hd, (char *)data, size);
    }
#ifdef WRITE_YUNXIN_AUDIO_TOFILE
    if (fd_audio_output > 0) {
        write(fd_audio_output, data, size);
    }
#endif
}

static void Netease_yunxin_msgcb(const char *content,
                                 const char *json_extension,
                                 const void *user_data) {
    n_debug("Recv msg(%llu):\n%s\n", Netease_gettime_ms(), content);
    json_error_t err;
    json_t *js = json_loads(content, 0, &err);
    if (!js) {
        n_error("Yunxin msg decode error: %d\n", err);
    } else {
        // n_toast("%s\n", json_dumps(js, 0));
        char *body = NULL;
        char *talk_id = NULL;
        long long ts = 0;
        long long cTs = Netease_gettime_ms();
        int offline = -1;

        json_unpack(js, "{s:{s:s, s:s, s:I, s:i}}", kNIMSessionListContent,
                    kNIMSessionMsgBody, &body, "talk_id", &talk_id, "time", &ts,
                    "offline_msg", &offline);
        if (body && talk_id) {
            n_toast("\nBody:%s\n body-len:%d\n Id:%s "
                    "offline:%d\ntimeStamp:%llu curTs:%llu\n",
                    body, strlen(body), talk_id, offline, ts, cTs);

            Netease_Dbus_Send_CMD(MODULE_VOICEENGINE, MODULE_CONTROLLER,
                                  CMD_YUNXIN_RECVMSG, content, strlen(content));
        } else {
            n_error("Decode error!!!!!\n");
        }
        json_decref(js);
    }
}

static void Netease_yunxin_msgresultcb(const char *result,
                                       const void *user_data) {
    n_debug("Msg result cb:\n%s\n", result);
    // printf("Netease_monotonic_gettime_ms:%llu\n",
    //        Netease_monotonic_gettime_ms());
    // printf("Msg result cb:\n%s\n", result);
}

void Netease_yunxin_cb_loginout(const char *json_params,
                                const void *user_data) {
    n_debug("login cb: %s\n go on relogin", json_params);
    localyunxinstatus = YUNXIN_STATUS_NOT_LOGIN;
    Netease_yunxin_login();
}

void Netease_yunxin_cb_loginout_with_accountchangelogin(const char *json_params,
                                                        const void *user_data) {
    char account[128];
    BaseLock();
    strcpy(account, getUuid());
    localyunxinstatus = YUNXIN_STATUS_NOT_LOGIN;
    BaseUnlock();

    n_debug("loginout cb: %s\n", json_params);

    if (strcmp(BackupAccount, account)) {
        n_debug("Login out, but account change, relogin\n");
        Netease_yunxin_login();
    }
}

void Netease_yunxin_login() {
    ////////////////////测试服////////// ///////////////正式服//////////////
    // fe416640c8e8a72734219e1847ad2547 "45c6af3c98409b18a84451215d0bdd6e";
    char *app_key = GetCurServerAddr(YUNXIN_MODULE);
#if 0
    if (g_bIsUsedTestServer) {
        app_key = YUNXIN_SERVER_KEY_TEST;
    } else {
        app_key = YUNXIN_SERVER_KEY_ONLINE;
    }
#endif
    char account[128];
    char password[128];
    char *json_extension = "";
    // char *user_data = "";
    // char *pwd = NULL;
    int loginStatus = nim_client_get_login_state(NULL);

    // printf("input account:\n");
    // scanf("%s", &account);
    // printf("input password:\n");
    // scanf("%s", &password);

    BaseLock();
    if (YUNXIN_STATUS_LOGIN_START == localyunxinstatus) {
        n_debug("Yunxin is logining,do nothing!test:%d\n",
                GetCurrentServerMode());
        BaseUnlock();
        return;
    }
    if (strlen(getYxToken()) == 0 || strlen(getUuid()) == 0) {
        n_debug("Yunx token or uuid is nil, exit!\n");
        BaseUnlock();
        return;
    }

    Netease_monotonic_caltime(&logintime, 1);
    localyunxinstatus = YUNXIN_STATUS_LOGIN_START;

    // pwd = nim_tool_get_md5(getYxToken());
    strcpy(password, getYxToken());
    strcpy(account, getUuid());
    BaseUnlock();
    n_toast("Begin to login, account: %s, password: %s, loginstatus:%d, "
            "key:%s, localLoginStatus:%d, test:%d\n",
            account, password, loginStatus, app_key, loginStatus,
            GetCurrentServerMode());

    if (loginStatus == kNIMLoginStateLogin) {
        n_debug("already logined, maybe login out firstly, %s ------- %s\n",
                BackupAccount, account);
        if (strcmp(BackupAccount, account)) {
            n_debug("Not the same account, loginout\n");
            strcpy(BackupAccount, account);
            nim_client_logout(kNIMLogoutChangeAccout, NULL,
                              Netease_yunxin_cb_loginout, NULL);
        } else {
            n_debug("The same account, do nothing\n");
            localyunxinstatus = YUNXIN_STATUS_LOGIN_FINISH;
        }
    } else {
        n_debug("Not login, begin to login...\n");
        strcpy(BackupAccount, account);
        nim_client_login(app_key, account, password, json_extension,
                         nim_login_callback, NULL);
    }
}

// system notice callback
void Netease_yunxin_cb_sysmsg(const char *content, const char *json_extension,
                              const void *user_data) {
    if (NULL == content) {
        n_error("Recv sysmsg null!");
        return;
    }
    n_debug("Recv system notice(%llu):%s\n", Netease_gettime_ms(), content);

    Netease_Dbus_Send_CMD(MODULE_VOICEENGINE, MODULE_CONTROLLER,
                          CMD_YUNXIN_SYSMSG, content, strlen(content));
}
// disconnect notice
void Netease_yunxin_cb_disconnect(const char *json_params,
                                  const void *user_data) {
    n_debug("Recv disconnect:%s\n", json_params);
    nim_client_logout(kNIMLogoutChangeAccout, NULL, Netease_yunxin_cb_loginout,
                      NULL);
}

void listAlsaDev() {
    char *dev = nrtc_alsa_available_devices(false);
    n_toast("Avalible dev: %s\n", dev);
}

int Netease_yunxin_init(struct audio_bypass **bypass) {
    // alsa_hd = nrtc_audio_alsa_core_create(false, 1, 16000, 16);
    // if (!alsa_hd) {
    //     n_error("Alsa hd create error\n");
    //     return NETEASE_ERROR_FAIL;
    // }
    // char *dev = nrtc_alsa_available_devices(false);
    // dev[199] = '\0';
    // n_toast("Avalible dev: %s\n", dev);
    // TODO here should not open dev
    // ret = nrtc_alsa_open_device(alsa_hd, "plug:dmix");

#ifdef WRITE_YUNXIN_AUDIO_TOFILE
    fd_audio_output = open("/mnt/UDISK/yunxin.pcm", O_CREAT | O_TRUNC | O_RDWR);
#endif

    nim_sdk_init();
    Netease_yunxin_cb_init();

    audio_bypass = bypass;

    return NETEASE_SUCCESS;
}

void Netease_yunxin_cb_relogin(const char *json_params, const void *user_data) {
    n_debug("ReLogin callback: %s\n", json_params);
    nim_login_callback(json_params, user_data);
}

void Netease_yunxin_cb_init() {
    // Set userf def Mic data
    // nim_vchat_set_custom_data(TRUE, FALSE, NULL, NULL, NULL);
    // Set the inputing audio cb
    // nim_vchat_set_audio_data_cb(false, NULL, Netease_yunxin_audiocb, NULL);
    // Set the inputing msg cb
    nim_talk_reg_receive_cb(NULL, Netease_yunxin_msgcb, NULL);
    // Set sys notice msg cb
    nim_sysmsg_reg_sysmsg_cb(NULL, Netease_yunxin_cb_sysmsg, NULL);
    // Set the msg/notifications  cb
    nim_talk_reg_ack_cb(NULL, Netease_yunxin_msgresultcb, NULL);
    // Network disconnec notice
    nim_client_reg_disconnect_cb(NULL, Netease_yunxin_cb_disconnect, NULL);
    // video or audio status cb
    // nim_vchat_set_cb_func(Netease_vchat_cb, NULL);
    nim_client_reg_auto_relogin_cb(NULL, Netease_yunxin_cb_relogin, NULL);
}

void Netease_yunxin_writeaudio(const char *inputbuf, size_t inputsize) {
#if 0
    static char tmpbuf[YUNXIN_PCM_BUFFER_BLOCK_SIZE];
    static size_t bufsize = 0;
    size_t sum = bufsize + inputsize;
    char *inputcur = (char *)inputbuf;
    if (inputsize == 0 || !inputbuf) {
        n_error("Write audio error, size:%d, funcprt:%p \n", inputsize,
                inputbuf);
        return;
    }
    while (sum >= YUNXIN_PCM_BUFFER_BLOCK_SIZE) {
        memcpy(tmpbuf + bufsize, inputcur,
               YUNXIN_PCM_BUFFER_BLOCK_SIZE - bufsize);
        nim_vchat_custom_audio_data(0, tmpbuf, YUNXIN_PCM_BUFFER_BLOCK_SIZE,
                                    NULL);
        sum = sum - YUNXIN_PCM_BUFFER_BLOCK_SIZE;
        inputcur = inputcur + YUNXIN_PCM_BUFFER_BLOCK_SIZE - bufsize;
        bufsize = 0;
    }

    if ((inputcur - inputbuf) < inputsize) {
        memcpy(tmpbuf, inputcur, (inputsize - (inputcur - inputbuf)));
        bufsize = inputsize - (inputcur - inputbuf);
    }
#endif
}
#endif

#if 0
void nim_vchat_start_device_callback(enum NIMDeviceType type, bool ret,
                                     const char *json_extension,
                                     const void *user_data) {
    switch (type) {
    case kNIMDeviceTypeAudioIn:
        break;
    case kNIMDeviceTypeAudioOut:
        break;
    case kNIMDeviceTypeAudioOutChat:
        break;
    case kNIMDeviceTypeVideo:
        break;
    // case kNIMDeviceTypeSoundcardCapturer:
    //    break;
    default:
        break;
    }
}

// capture数据发送
void nim_vchat_audio_capture_data_callback(uint64_t time, const char *data,
                                           unsigned int size,
                                           const char *json_extension,
                                           const void *user_data) {
    //发送数据
    nim_vchat_custom_audio_data(time, data, size, json_extension);
}

// play数据发送
void nim_vchat_audio_play_data_callback(uint64_t time, const char *data,
                                        unsigned int size,
                                        const char *json_extension,
                                        const void *user_data) {
    // test 将对方数据发送
    // nim_vchat_custom_audio_data(time, data, size, json_extension);
}

static void Netease_vchat_cb(enum NIMVideoChatSessionType type,
                             int64_t channel_id, int code,
                             const char *json_extension,
                             const void *user_data) {
    n_toast(
        "nim_vchat_cb type->%d,channel_id_->%lld,code->%d,json_extension->%s\n",
        type, channel_id, code, json_extension);
    //  { "uid": "leewp01", "type" : 1, "accept" : 1 }
    if (code == 200) {
        switch (type) {
        case kNIMVideoChatSessionTypeStartRes:

            break;
        case kNIMVideoChatSessionTypeInviteNotify:
            // TODO notify control center : a call coming

            break;
        case kNIMVideoChatSessionTypeCalleeAckRes:
            //启动设备
            printf("kNIMVideoChatSessionTypeCalleeAckRes======================="
                   "====="
                   "\n");
            // test_nim_vchat_start_device(kNIMDeviceTypeAudioIn, NULL, 15, "",
            // nim_vchat_start_device_callback, NULL);
            // test_nim_vchat_start_device(kNIMDeviceTypeAudioOutChat, NULL, 15,
            // "",
            // nim_vchat_start_device_callback, NULL);
            break;
        case kNIMVideoChatSessionTypeCalleeAckNotify:
            //启动设备 check json if accept
            printf("kNIMVideoChatSessionTypeCalleeAckNotify===================="
                   "======="
                   "=\n");
            // test_nim_vchat_start_device(kNIMDeviceTypeAudioIn, NULL, 15, "",
            // nim_vchat_start_device_callback, NULL);
            // test_nim_vchat_start_device(kNIMDeviceTypeAudioOutChat, NULL, 15,
            // "",
            // nim_vchat_start_device_callback, NULL);
            //设置数据回调
            // test_nim_vchat_set_audio_data_cb(true, "",
            // nim_vchat_audio_capture_data_callback, NULL);
            // test_nim_vchat_set_audio_data_cb(false, "",
            // nim_vchat_audio_play_data_callback, NULL);
            break;
        case kNIMVideoChatSessionTypeControlRes:
            break;
        case kNIMVideoChatSessionTypeControlNotify:
            break;
        // todo check connection
        case kNIMVideoChatSessionTypeConnect:
            break;
        case kNIMVideoChatSessionTypePeopleStatus:
            break;
        case kNIMVideoChatSessionTypeNetStatus:
            break;
        case kNIMVideoChatSessionTypeHangupRes:
            // test_end_vchat_device();
            break;
        case kNIMVideoChatSessionTypeHangupNotify:
            // test_end_vchat_device();
            break;
        case kNIMVideoChatSessionTypeSyncAckNotify:
            break;
        // case kNIMVideoChatSessionTypeMp4Notify:
        //    break;
        // case kNIMVideoChatSessionTypeInfoNotify:
        //    break;
        // case kNIMVideoChatSessionTypeVolumeNotify:
        //    break;
        default:
            break;
        }
        channel_id_ = channel_id;
    }
}

//登录成功后，向对方发起音视频
void send_vchat_request(bool audio) {
    //正式服
    // lwp02 123123
    // lwp01 123123
    // lwp 123123

    // json:
    // {"need_badge":0,"need_nick":0,"record":0,"session_id":"leewp01","sound":"video_chat_tip_receiver.aac","uids":["leewp01"],"video_quality":0,"video_record":0}
    enum NIMVideoChatMode mode = kNIMVideoChatModeAudio;
    char *apns_text = "视频通话邀请";
    char *custom_info = "test";
    char *json_info_1 = "{ \"need_badge\":0, \"need_nick\" : 0, \"record\" : "
                        "0, \"session_id\" : "
                        "\"";
    char *json_info_2 =
        "\", \"sound\" : \"video_chat_tip_receiver.aac\", \"uids\" : [\"";
    char *json_info_3 = "\"], \"video_quality\" : 0, \"video_record\" : 0 }";
    char *user_data = "";
    char account[128];
    char dest[300];
    n_toast("input talk account:\n");
    scanf("%128s", (char *)&account);

    snprintf(dest, sizeof(dest), "%s%s%s%s%s", json_info_1, account,
             json_info_2, account, json_info_3);
    if (!audio) {
        mode = kNIMVideoChatModeVideo;
        apns_text = "语音通话邀请";
    }
    nim_vchat_start(mode, apns_text, custom_info, dest, user_data);
}

void test_end_vchat_device() {
    nim_vchat_end_device(kNIMDeviceTypeAudioIn, "");
    nim_vchat_end_device(kNIMDeviceTypeAudioOutChat, "");
    nim_vchat_end_device(kNIMDeviceTypeAudioOut, "");
}

void test_start_vchat_device() {
    //启动设备
    nim_vchat_start_device(kNIMDeviceTypeAudioIn, NULL, 15, "",
                           nim_vchat_start_device_callback, NULL);
    nim_vchat_start_device(kNIMDeviceTypeAudioOutChat, NULL, 15, "",
                           nim_vchat_start_device_callback, NULL);
    nim_vchat_start_device(kNIMDeviceTypeAudioOut, NULL, 15, "",
                           nim_vchat_start_device_callback, NULL);
}

char *room_name = "";

void nim_vchat_join_room_callback(int code, int64_t channel_id,
                                  const char *json_extension,
                                  const void *user_data) {
    printf(
        "nim_vchat_join_room  code->%d,channel_id ->%lld,json_extension->%s\n",
        code, channel_id, json_extension);
    if (code == 200) {
        nim_vchat_start_device(kNIMDeviceTypeAudioIn, NULL, 15, "",
                               nim_vchat_start_device_callback, NULL);
        nim_vchat_start_device(kNIMDeviceTypeAudioOutChat, NULL, 15, "",
                               nim_vchat_start_device_callback, NULL);
    }
}

void nim_vchat_create_room_callback(int code, int64_t channel_id,
                                    const char *json_extension,
                                    const void *user_data) {
    /*char *json_extension_ex =
        "{ \"custom_video\":0, \"custom_audio\" : 0, \"video_quality\" : 0, "
        "\"session_id\" : \"\"}";*/
    printf(
        "nim_vchat_create_room  code->%d,channel_id->%lld,json_extension->%s\n",
        code, channel_id, json_extension);
}

void test_crate_room() {
    char *custom_info = "";
    char *json_extension = "";
    char room_name[128];
    printf("input create room name:\n");
    scanf("%128s", (char *)&room_name);
    nim_vchat_create_room(room_name, custom_info, json_extension,
                          nim_vchat_create_room_callback, NULL);
}

void test_join_room() {
    char room_name[128];
    /*char *json_extension =
        "{ \"custom_video\":0, \"custom_audio\" : 0, \"video_quality\" : 0, "
        "\"session_id\" : \"leewp\"}";*/
    printf("input join room name:\n");
    scanf("%128s", &room_name);
    nim_vchat_join_room(kNIMVideoChatModeAudio, room_name, "",
                        nim_vchat_join_room_callback, NULL);
}

void test_mute_enabled() {
    bool muted = nim_vchat_audio_mute_enabled();
    printf("nim_vchat_audio_mute_enabled->%d\n", muted);
}

void test_set_audio_mute() {
    int i = 0;
    printf("input muted:1 or 0\n");
    scanf("%d", &i);
    nim_vchat_set_audio_mute(i);
    test_mute_enabled();
}

void set_member_in_blacklist_callback(bool ret, int code,
                                      const char *json_extension,
                                      const void *user_data) {
    printf("demo_nim_vchat_set_member_in_blacklist "
           "ret->%d,code->%d,json_extension->%s\n",
           ret, code, json_extension);
}

void demo_test_nim_vchat_set_member_in_blacklist() {
    char uid[128];
    int add = 0;
    int audio = 0;
    printf("input uid:\n");
    scanf("%128s", (char *)&uid);
    printf("input add 1 or 0:\n");
    scanf("%d", (char *)&add);
    printf("input audio:1 or 0:\n");
    scanf("%d", (char *)&audio);
    nim_vchat_set_member_in_blacklist(uid, add, audio, NULL,
                                      set_member_in_blacklist_callback, NULL);
}

void demo_test_nim_vchat_setting_audio_volume() {
#if 0
    int volume = 0;
    int capture = 0;
    printf("input volume:\n");
    scanf("%d", &volume);
    printf("input capture:\n");
    scanf("%d", &capture);
    nim_vchat_set_audio_volumn(volume, capture);

    volume = nim_vchat_get_audio_volumn(capture);
    printf("capture:%d-----volume:%d\n", capture, volume);
#endif
}

void nim_vchat_custom_data_cb(bool ret, int code, const char *json_extension,
                              const void *user_data) {
    printf("nim_vchat_set_custom_data ret->%d,code->%d\n", ret, code);
}

void demo_test_custom_data() {
    int custom_audio = 0;
    printf("input custom_audio：\n");
    scanf("%d", &custom_audio);
    nim_vchat_set_custom_data(custom_audio, false, "", nim_vchat_custom_data_cb,
                              NULL);
}

void demo_test_send_data() {
    bool ret = false;
    int i = 20;
    while (i > 0) {
        memset(audio_data, 'c', 1280);
        ret = nim_vchat_custom_audio_data(0, audio_data, 1280, NULL);
        printf("nrtc_custom_audio_data ret->%d", ret);
        i--;
    }
}

void demo_test_end_vchat_device() {
    int type = 0;
    printf("input end device type 0,1,2:\n");
    scanf("%d", &type);
    nim_vchat_end_device(type, "");
}

int Netease_yunxin_test() {
    char json_msg[128];
    struct timeval curtime;
    // struct tm *timenow;
    char *tmp;

    while (c != '0') {
        char *json_info = "";
        c = getchar();
        switch (c) {
        case '1':
            send_vchat_request(true); //开始发起通话
            // test_start_vchat_device();
            c = '9';
            break;
        case '2':
            json_info = "{ \"session_id\":\"leewp01\" }";
            nim_vchat_end(""); //断开通话
            // test_end_vchat_device();
            c = '9';
            break;
        case '3': //拒绝通话
            json_info = "{\"record\":0,\"session_id\":\"leewp01\", "
                        "\"video_quality\":0,\"video_record\":0}";
            nim_vchat_callee_ack(channel_id_, false, json_info, NULL);
            // test_set_audio_mute(false);
            // test_mute_enabled();
            c = '9';
            break;
        case '4': //接受通话
            json_info = "{\"record\":0,\"session_id\":\"leewp01\", "
                        "\"video_quality\":0,\"video_record\":0}";
            nim_vchat_callee_ack(channel_id_, true, json_info, NULL);
            c = '9';
            break;
        case '5': //请求从音频切到视频
            nim_vchat_control(channel_id_, 5, "", NULL);
            c = '9';
            break;
        case '6': //视频切音频
            nim_vchat_control(channel_id_, 8, "", NULL);
            c = '9';
            break;
        case '7': //同意从音频切到视频
            nim_vchat_control(channel_id_, 6, "", NULL);
            c = '9';
            break;
        case '8': //拒绝从音频切到视频
            nim_vchat_control(channel_id_, 7, "", NULL);
            c = '9';
            break;
        case 'a': //开启本地设备
            nim_vchat_start_device(kNIMDeviceTypeAudioOut, NULL, 15, "",
                                   nim_vchat_start_device_callback, NULL);
            c = '9';
            break;
        case 'b':
            demo_test_nim_vchat_set_member_in_blacklist();
            c = '9';
            break;
        case 'e': //关闭本地设备
            demo_test_end_vchat_device();
            c = '9';
            break;
        case 'c': //创建房间
            test_crate_room();
            c = '9';
            break;
        case 'j': //加入房间
            test_join_room();
            c = '9';
            break;
        case 'm':
            test_set_audio_mute();
            c = '9';
            break;
        case 'l':
            // nim_login();
            c = '9';
            break;
        case 'v':
            demo_test_nim_vchat_setting_audio_volume();
            c = '9';
            break;
        case 'z':
            demo_test_custom_data();
            break;
        case 's':
            demo_test_send_data();
            break;
        case 'q':
            printf("program exit\n");
            exit(0);
            break;
        case 'y':
            gettimeofday(&curtime, NULL);
            sprintf(
                json_msg,
                "{ \"to_type\": 0, \"to_accid\": \"zijiao\", \"msg_type\": 0, "
                "\"msg_body\": \"From board:%s\", \"client_msg_id\": "
                "\"%ld%ld\"}",
                Netease_gettime_string(), curtime.tv_sec, curtime.tv_usec);
            sprintf(json_msg, "%ld%ld", curtime.tv_sec, curtime.tv_usec);
            json_t *send =
                json_pack("{s:i, s:s, s:i, s:s+, s:s}", kNIMMsgKeyToType,
                          kNIMSessionTypeP2P, kNIMMsgKeyToAccount, "zijiao",
                          kNIMMsgKeyType, kNIMMessageTypeText, kNIMMsgKeyBody,
                          "From R16 board:", Netease_gettime_string(),
                          kNIMMsgKeyClientMsgid, json_msg);
            n_toast("MSG: %s\n", json_dumps(send, 0));
            nim_talk_send_msg(json_dumps(send, 0), NULL, NULL, NULL);
            json_decref(send);
            break;

        case 'u':
            gettimeofday(&curtime, NULL);
            sprintf(
                json_msg,
                "{ \"to_type\": 0, \"to_accid\": \"zijiao\", \"msg_type\": 0, "
                "\"msg_body\": \"From board:%s\", \"client_msg_id\": "
                "\"%ld%ld\"}",
                Netease_gettime_string(), curtime.tv_sec, curtime.tv_usec);
            sprintf(json_msg, "%ld%ld", curtime.tv_sec, curtime.tv_usec);
            json_t *send2 = json_pack(
                "{s:i, s:s, s:i, s:s+, s:s}", kNIMMsgKeyToType,
                kNIMSessionTypeP2P, kNIMMsgKeyToAccount, getBindUser(),
                kNIMMsgKeyType, kNIMMessageTypeCustom, kNIMMsgKeyBody,
                "From R16 board:", Netease_gettime_string(),
                kNIMMsgKeyClientMsgid, json_msg);
            tmp = json_dumps(send2, 0);
            if (tmp) {
                n_toast("MSG: %s\n", tmp);
                nim_talk_send_msg(tmp, NULL, NULL, NULL);
                free(tmp);
            }
            json_decref(send2);
            break;
        default:
            break;
        }
    }
}
#endif
