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

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 <errno.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include "audiobypass.h"
#include "error.h"
#include "msc.h"
#include "record.h"
#include "yunxin.h"
#include <pthread.h>
#include <sched.h>
#include <stdint.h>

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

/* ------------------------------------------------------------------------
** Types
** ------------------------------------------------------------------------ *

/* ------------------------------------------------------------------------
** Global Variable Definitions
** ------------------------------------------------------------------------ */

/* ------------------------------------------------------------------------
** Function Definitions
** ------------------------------------------------------------------------ */
static void *audiobypass_read_thread(void *param);

int Netease_audiobypass_init(struct audio_bypass **bypass, void **cae,
                             unsigned int chan) {
    int ret = NETEASE_SUCCESS;
    size_t cap = 1535 * 8 * 1000 + 1;

    if (NULL == bypass || NULL != *bypass) {
        return NETEASE_ERROR_FAIL;
    }
    (*bypass) = (struct audio_bypass *)malloc(sizeof(struct audio_bypass));
    if (!(*bypass)) {
        ret = NETEASE_ERROR_FAIL;
        goto exit;
    }

    pthread_mutex_init(&(*bypass)->mutex, NULL);
    //(*bypass)->cae = cae;
    (*bypass)->queue_buf = (char *)malloc(cap);
    memset((*bypass)->queue_buf, 0xFF, cap);

    (*bypass)->queue = queue_init((*bypass)->queue_buf, cap);
    (*bypass)->running = 0;
    (*bypass)->chan = chan;

exit:
    return ret;
}

void Netease_audiobypass_start(struct audio_bypass *bypass) {
    bypass->running = 1;
    pthread_create(&(bypass->tid_queue_bypass), NULL,
                   (void *)audiobypass_read_thread, bypass);
}

void Netease_audiobypass_write(struct audio_bypass *bypass, const void *audio,
                               unsigned int audio_len) {
    if (bypass && audio && audio_len > 0 && bypass->queue &&
        bypass->queue_buf) {
        queue_write(bypass->queue, (char *)audio, audio_len);
    }
}

static void *audiobypass_read_thread(void *param) {
    struct audio_bypass *bypass = (struct audio_bypass *)param;
    char *buf = NULL;
    int bufsize = 0;
    while (bypass->running) {
        bufsize = queue_read(bypass->queue, &buf);
        if (!buf)
            continue;
        
        if (bypass->chan & AUDIO_BYPASS_CHANNEL_MSC_IAT) {
            Netease_IAT_write(buf, bufsize);
        }
#ifdef ENABLE_YUNXIN
        if (bypass->chan & AUDIO_BYPASS_CHANNEL_YUNXIN) {
            Netease_yunxin_writeaudio(buf, bufsize);
        }        
#endif
        free(buf);
        buf = NULL;
    }
    n_debug("Audio bypass thread exit");
    return NULL;
}

void Netease_audiobypass_destroy(struct audio_bypass **bypass) {
    struct audio_bypass *tmp;

    if (!bypass || !(*bypass))
        return;

    tmp = *bypass;
    *bypass = NULL;
    tmp->running = 0;
    native_event_set(tmp->queue->sync_event);
    pthread_join(tmp->tid_queue_bypass, NULL);
    if (tmp->queue_buf) {
        free(tmp->queue_buf);
    }
    if (tmp->queue) {
        queue_destroy(tmp->queue);
    }
    free(tmp);
}

void Netease_audiobypass_channel_set(struct audio_bypass *bypass,
                                     AUDIO_BYPASS_CHANNEL_NO no) {
    if (!bypass) {
        return;
    }

    pthread_mutex_lock(&bypass->mutex);
    bypass->chan |= no;
    pthread_mutex_unlock(&bypass->mutex);
}

void Netease_audiobypass_channel_unset(struct audio_bypass *bypass,
                                       AUDIO_BYPASS_CHANNEL_NO no) {
    if (!bypass) {
        return;
    }

    pthread_mutex_lock(&bypass->mutex);
    bypass->chan &= ~no;
    pthread_mutex_unlock(&bypass->mutex);
}