
/*
*******************************************************************************
*  Copyright (c) 2010-2015 VATICS Inc. All rights reserved.
*
*  +-----------------------------------------------------------------+
*  | THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY ONLY BE USED |
*  | AND COPIED IN ACCORDANCE WITH THE TERMS AND CONDITIONS OF SUCH  |
*  | A LICENSE AND WITH THE INCLUSION OF THE THIS COPY RIGHT NOTICE. |
*  | THIS SOFTWARE OR ANY OTHER COPIES OF THIS SOFTWARE MAY NOT BE   |
*  | PROVIDED OR OTHERWISE MADE AVAILABLE TO ANY OTHER PERSON. THE   |
*  | OWNERSHIP AND TITLE OF THIS SOFTWARE IS NOT TRANSFERRED.        |
*  |                                                                 |
*  | THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT   |
*  | ANY PRIOR NOTICE AND SHOULD NOT BE CONSTRUED AS A COMMITMENT BY |
*  | VATICS INC.                                                     |
*  +-----------------------------------------------------------------+
*
*******************************************************************************
*/

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <string>
#include <poll.h>
#include <limits.h>
#include <time.h>
#include <sys/signalfd.h>
#include <alsa/asoundlib.h>
#include <MsgBroker/msg_broker.h>
#include <SyncRingBuffer/sync_ring_buffer.h>
#include <audiotk/audio_capture_mmap.h>
#include <audiotk/audio_playback_mmap.h>
#include <audiotk/audio_vol_ctrl.h>


#define SRB_HEADER_SIZE 4
#define ATK_AUDIO_MAX_CHANNELS 32
#define PERIOD_SIZE_IN_FRAMES 1024
#define APP_NAME "UAC Speaker"
#define CAP_DIR "./"
#define CMD_UAC_FIFO_PATH "/tmp/uac/c0/command.fifo"
#define UNUSED(x) (void)(x)

enum {
    FALSE = 0,
    TRUE,
};

enum {
    RUNNING = 0,
    INIT,
    CHECKING,
    TERMINATED,
};

static unsigned int g_dwCurrCaptureRate = 0;
static unsigned int g_dwCurrMicMute = 0;
static unsigned int g_dwCurrMicVol = 0;
static unsigned int g_dwCurrPlaybackRate = 0;
static unsigned int g_dwCurrSpkMute = 0;
static unsigned int g_dwCurrSpkVol = 0;

typedef struct {
    ATK_AUDIOPLAY_HANDLE_T **playback_handle;
    ATK_AUDIOCAP_HANDLE_T **capture_handle;
    srb_handle_t **reader_handle;
    srb_handle_t **writer_handle;
    snd_hctl_t **alsa_handle;

    ATK_AUDIOCAP_CONFIG_T	*p_audiocap_config;
    ATK_AUDIOPLAY_CONFIG_T *p_audiopb_config;

    pthread_mutex_t pb_data_mutex;
    pthread_cond_t pb_data_cond;
    pthread_mutex_t cap_data_mutex;
    pthread_cond_t cap_data_cond;

    //pthread_mutex_t play_mutex;
    pthread_cond_t play_cond;
    STATUS pb_process_status;
    STATUS cap_process_status;
} user_data_t;

static int isRunning = 0;
static int is_terminate_ = 0;
static int reset = INIT;
static int savefile = 0;
char const *file_name = NULL;
char filename[128];
static int dwCurrSampleRate = 0;
FILE* fp;
//srb_handle_t* reader_handle = NULL;
//srb_handle_t* writer_handle = NULL;
srb_buffer_t srb_writer_buf;
srb_buffer_t srb_reader_buf;

//======================================
//HELP
static void print_usage(const char *ap_name)
{
    fprintf(stderr, "Usage:\n"
            "    %s [-h]\n"
            "Options:\n"
            "    -h                 This help.\n", ap_name);
}

//======================================
//write to fp
static void write_to_file(unsigned char *data_buf, size_t buf_size)
{
    fwrite(data_buf, buf_size, 1, fp);
    fflush(fp);
}

//======================================
//capture thread / SRB writer
static void audiocap_callback(const ATK_AUDIO_NOTIFY_DATA_INFO_T *audio_info, void* user_data)
{
    user_data_t *temp_data = (user_data_t*) user_data;
    srb_handle_t* writer_handle = *(temp_data->writer_handle);

    pthread_mutex_lock(&(temp_data->cap_data_mutex));
    if (temp_data->cap_process_status == STOP) {
        pthread_cond_signal(&(temp_data->cap_data_cond));
        pthread_mutex_unlock(&(temp_data->cap_data_mutex));
        return;
    }
    pthread_mutex_unlock(&(temp_data->cap_data_mutex));
    if(!isRunning)
        return ;
    if(audio_info->dwDataBytes > 0) {

        if (savefile){
            //append data to a file
            write_to_file(audio_info->ppbyAudioBufs[0], audio_info->dwDataBytes);
        }

        unsigned int* buf_ptr = (unsigned int*)srb_writer_buf.buffer;

        buf_ptr[0] = audio_info->dwDataBytes;
        buf_ptr[1] = audio_info->tDataTimestamp.tv_sec;
        buf_ptr[2] = audio_info->tDataTimestamp.tv_usec;
        buf_ptr[3] = audio_info->dwDataBytes;
        buf_ptr[4] = audio_info->bIsInterleaved;
        buf_ptr[5] = audio_info->dwChannels;
        //printf("callback size %d %d %d %d %d %d\n",buf_ptr[0],buf_ptr[1],buf_ptr[2],buf_ptr[3],buf_ptr[4],buf_ptr[5]);
        memcpy(srb_writer_buf.buffer + SRB_HEADER_SIZE, audio_info->ppbyAudioBufs[0], audio_info->dwDataBytes);
        SRB_SendGetWriterBuff(writer_handle, &srb_writer_buf);

    }
    else {
        printf("[%s,%d] sending data to client failed, send bytes: %d, terminating ...\n", __func__,__LINE__, audio_info->dwDataBytes);
        isRunning = false;
    }
}

//playback buff
void* srb_reader(void* args)
{
    user_data_t *temp_data = (user_data_t*) args;
    ATK_AUDIOPLAY_HANDLE_T* playback_handle = *(temp_data->playback_handle);

    srb_handle_t* reader_handle = *(temp_data->reader_handle);
    if (!playback_handle){
        printf(" [%s,%d] playback handle init error \n",__func__,__LINE__);
        return NULL;
    }

    // Audio output buffer.
    unsigned char *pbyBufs[ATK_AUDIO_MAX_CHANNELS] = {NULL};
    unsigned int dwDataBytes;
    SRB_ReturnReceiveReaderBuff(reader_handle, &srb_reader_buf);
    while(isRunning && reset != INIT){

        if (temp_data->pb_process_status == STOP) {
            pthread_mutex_lock(&(temp_data->pb_data_mutex));
            pthread_cond_signal(&(temp_data->pb_data_cond));
            pthread_mutex_unlock(&(temp_data->pb_data_mutex));

            pthread_mutex_lock(&(temp_data->pb_data_mutex));
            pthread_cond_wait(&(temp_data->play_cond), &(temp_data->pb_data_mutex));
            pthread_mutex_unlock(&(temp_data->pb_data_mutex));
        }
        //printf("Play data\n");
        if(ATK_AudioPlay_PlayPeriodFrames(playback_handle, pbyBufs) < 0){
            fprintf(stderr, "[%s,%s] Can't get the audio output buffer..\n", __FILE__, __func__);
            isRunning = false;
            printf("Playback error!!!\n");
            break;
        }
        //printf("...\n");
        if(SRB_ReturnReceiveReaderBuff(reader_handle, &srb_reader_buf)==0 && srb_reader_buf.buffer){
            unsigned int* buf_ptr =  (unsigned int*)(srb_reader_buf.buffer);
            dwDataBytes = buf_ptr[0];
            //printf("receive: data size %d %d %d %d %d %d\n",buf_ptr[0],buf_ptr[1],buf_ptr[2],buf_ptr[3],buf_ptr[4],buf_ptr[5]);
            memcpy(pbyBufs[0],srb_reader_buf.buffer + SRB_HEADER_SIZE,dwDataBytes);
        }
    }
    SRB_ReturnReaderBuff(reader_handle, &srb_reader_buf);
    printf(" [%s,%d] Leaving the UAC_SPK func thread. Please wait. \n",__func__,__LINE__);
    return NULL;
}

static void sig_kill(int signo)
{
    printf("[%s,%d] Received SIGNAL %d!!!\n", __func__,__LINE__, signo);
    switch(signo){
        case SIGTERM:
        case SIGINT:
            isRunning = false;
            reset = TERMINATED;
            is_terminate_ = 1;
            //SRB_WakeupReader(reader_handle);
            break;
        default:
            break;
    }
}
//======================================
unsigned int VolumeMapping(unsigned int value)
{
    if (value == 58272)
        return 0;
    else if (value < 59964)
        return 10;
    else if (value < 61139)
        return 20;
    else if (value < 62040)
        return 30;
    else if (value < 62771)
        return 40;
    else if (value < 63386)
        return 50;
    else if (value < 63917)
        return 60;
    else if (value < 64384)
        return 70;
    else if (value < 64801)
        return 80;
    else if (value < 65178)
        return 90;
    else
        return 100;
}
static int alsa_GetSampleRate(void)
{
    int err;
    snd_hctl_t *handle;
    snd_hctl_elem_t *elem;
    snd_ctl_elem_id_t *id;
    snd_ctl_elem_value_t *control;
    snd_ctl_elem_id_alloca(&id);
    int sample_rate;
    unsigned int dwNewVolume = 0, dwIsMute = 0;
    if ((err = snd_hctl_open(&handle, "hw:1", 0)) < 0) {
        printf("Control %s open error: %s", "hw:1", snd_strerror(err));
        return 1;
    }
    if ((err = snd_hctl_load(handle)) < 0) {
        printf("Control %s local error: %s\n", "hw:1", snd_strerror(err));
        return 1;
    }
    for (elem = snd_hctl_first_elem(handle); elem; elem = snd_hctl_elem_next(elem)) {
        unsigned int value = 0;
        snd_hctl_elem_get_id(elem, id);
        snd_ctl_elem_value_alloca(&control);
        if ((err = snd_hctl_elem_read(elem, control)) < 0) {
            printf("Control %s element read error: %s\n", "hw:1", snd_strerror(err));
            return err;
        }
        //printf("[UAC_SPK] List item  %s value :%ld\n",snd_ctl_elem_id_get_name(id),snd_ctl_elem_value_get_integer(control, 0));
        value = (unsigned int)snd_ctl_elem_value_get_integer(control, 0);
        if(strcmp("Capture Rate",snd_ctl_elem_id_get_name(id)) == 0) {
            //printf("Found [Capture Rate]\n");
            g_dwCurrCaptureRate = value;
        } else if(strcmp("Mic Mute",snd_ctl_elem_id_get_name(id)) == 0) {
            //printf("Found [Mic Mute]\n");
                g_dwCurrMicMute = value;
        } else if(strcmp("Mic Volume",snd_ctl_elem_id_get_name(id)) == 0) {
            //printf("Found [Mic Volume]\n");
            g_dwCurrMicVol = value;
        } else if(strcmp("Playback Rate",snd_ctl_elem_id_get_name(id)) == 0) {
            //printf("Found [Playback Rate]\n");
            g_dwCurrPlaybackRate = value;
        } else if(strcmp("Speaker Mute",snd_ctl_elem_id_get_name(id)) == 0) {
            //printf("Found [Speaker Mute]\n");
            dwIsMute = value; //g_dwCurrSpkMute = value;
        }else if(strcmp("Speaker Volume",snd_ctl_elem_id_get_name(id)) == 0) {
            //printf("Found [Speaker Volume]\n");
            dwNewVolume = VolumeMapping(value);//g_dwCurrSpkVol = value;
        }
    }
    snd_hctl_close(handle);
    //printf("%s C_rate_%d M_mute_%d M_Vol_%d P_rate_%d S_mute_%d S_Vol_%d\n",__func__, g_dwCurrCaptureRate,g_dwCurrMicMute,g_dwCurrMicVol,
    //g_dwCurrPlaybackRate,g_dwCurrSpkMute,g_dwCurrSpkVol);

    if (g_dwCurrSpkMute != dwIsMute) {
        if (dwIsMute == 1) {
            ATK_Audio_SetPlaybackVolume(0);
            g_dwCurrSpkMute = dwIsMute;
            g_dwCurrSpkVol = dwNewVolume;
        } else{
            ATK_Audio_SetPlaybackVolume(dwNewVolume);
            g_dwCurrSpkMute = dwIsMute;
            g_dwCurrSpkVol = dwNewVolume;
        }
    } else if (g_dwCurrSpkVol != dwNewVolume) {
            ATK_Audio_SetPlaybackVolume(dwNewVolume);
            g_dwCurrSpkVol = dwNewVolume;
    }
    sample_rate = g_dwCurrCaptureRate;
    return sample_rate;
}

static int element_callback(snd_hctl_elem_t *elem __attribute__((unused)), unsigned int mask)
{
    if (mask & SND_CTL_EVENT_MASK_VALUE) {
        if (isRunning) reset = CHECKING;
    }
    return -EAGAIN;
}
static void events_add(snd_hctl_elem_t *helem)
{
    snd_ctl_elem_id_t *id;
    snd_ctl_elem_id_alloca(&id);
    snd_hctl_elem_get_id(helem, id);
    snd_hctl_elem_set_callback(helem, element_callback);
}
static int ctl_callback(snd_hctl_t *ctl __attribute__((unused)), unsigned int mask,
        snd_hctl_elem_t *elem)
{
    if (mask & SND_CTL_EVENT_MASK_ADD)
        events_add(elem);
    return 0;
}

int init_service(user_data_t * temp_data)
{
    ATK_AUDIOPLAY_CONFIG_T *playback_config = temp_data->p_audiopb_config;
    ATK_AUDIOCAP_CONFIG_T *capture_config = temp_data->p_audiocap_config;
    int sample_rate = alsa_GetSampleRate();

    playback_config->dwSampleRate = sample_rate;
    capture_config->dwSampleRate = sample_rate;
    //printf("New Samplerate is %d\n",sample_rate);
    *(temp_data->writer_handle) = SRB_InitWriter("uac_sp_srb_1", MAX_RING_BUF_SIZE, 4);
    if (!*(temp_data->writer_handle)){
        printf(" [%s,%d] srb writer handle init error \n",__func__,__LINE__);
        isRunning = false;
    }
    memset(&srb_writer_buf, 0, sizeof(srb_buffer_t));
    SRB_SendGetWriterBuff(*(temp_data->writer_handle), &srb_writer_buf);

    *(temp_data->capture_handle) = ATK_AudioCap_Init(capture_config);
    if(!*(temp_data->capture_handle)){
        printf(" [%s,%d] ATK_AudioCap_Init error \n",__func__,__LINE__);
        isRunning = false;
    }
    //printf("init playback\n");
    *(temp_data->playback_handle) = ATK_AudioPlay_Init(playback_config);
    if(!*(temp_data->playback_handle)){
        printf(" [%s,%d] ATK_AudioPlay_Init error \n",__func__,__LINE__);
        isRunning = false;
    }
    *(temp_data->reader_handle) = SRB_InitReader("uac_sp_srb_1");
    if (!*(temp_data->reader_handle)){
        printf(" [%s,%d] srb reader handle init error \n",__func__,__LINE__);
        isRunning = false;
    }
    if (isRunning == TRUE)
        dwCurrSampleRate = sample_rate;

    return isRunning;
}
//playback buff
void* main_thread(void* args)
{
    user_data_t *temp_data = (user_data_t*) args;
    snd_hctl_elem_t *helem;
    int err, res;
    pthread_t tid = 0;
    while (isRunning)
    {
        while (reset == RUNNING)
        {

            if (*(temp_data->alsa_handle) == NULL && ((err = snd_hctl_open(temp_data->alsa_handle, "hw:1", 0)) < 0)) {
                printf("Control %s open error: %s\n", "hw:1", snd_strerror(err));
                return NULL;
            }
            snd_hctl_set_callback(*(temp_data->alsa_handle), ctl_callback);
            if ((err = snd_hctl_load(*(temp_data->alsa_handle))) < 0) {
                printf("Control %s hbuild error: %s\n",  "hw:1", snd_strerror(err));
                return NULL;
            }
            for (helem = snd_hctl_first_elem(*(temp_data->alsa_handle)); helem; helem = snd_hctl_elem_next(helem)) {
                snd_hctl_elem_set_callback(helem, element_callback);
            }
            //helem = snd_hctl_first_elem(alsa_handle);
            //snd_hctl_elem_set_callback(helem, element_callback);
            while (isRunning && reset == RUNNING)
            {
                res = snd_hctl_wait(*(temp_data->alsa_handle), 100);
                if (res > 0) {
                    snd_hctl_handle_events(*(temp_data->alsa_handle));
                    break;
                } else if (res == 0) {	// timeout
                    continue;
                } else {    // error
                    // program exit:
                    snd_hctl_close(*(temp_data->alsa_handle));
                    *(temp_data->alsa_handle) = NULL;
                    break;
                }
            }

            while(isRunning){
                if (reset == INIT || reset == CHECKING) {
                    snd_hctl_close(*(temp_data->alsa_handle));
                    *(temp_data->alsa_handle) = NULL;
                    //printf("try get SampleRate %d\n",dwCurrSampleRate);
                    if (dwCurrSampleRate == alsa_GetSampleRate()){
                        //printf("same rate\n");
                        reset = RUNNING;
                    } else
                    reset = INIT;
                    break;
                }
            }

            if (reset == RUNNING)
                continue;

            if (tid != 0) {
                    SRB_WakeupReader(*(temp_data->reader_handle));
                    pthread_join(tid, NULL);
                    //printf("%s::%d joined thread\n", __func__, __LINE__);
                    tid = 0;
            }

            //release playabck and capture change state to 0
            if (*(temp_data->capture_handle)) {
                ATK_AudioCap_Release(*(temp_data->capture_handle));
                *(temp_data->capture_handle) = NULL;
                //printf("release cap handle\n");
            }
            if (*(temp_data->playback_handle)) {
                ATK_AudioPlay_Release(*(temp_data->playback_handle));
                *(temp_data->playback_handle) = NULL;
                //printf("release play handle\n");
            }
            //release srb handles
            if(*(temp_data->writer_handle)) {
                SRB_Release(*(temp_data->writer_handle));
                *(temp_data->writer_handle) = NULL;
                //printf("release srb w\n");
            }
            if(*(temp_data->reader_handle)) {
                SRB_Release(*(temp_data->reader_handle));
                *(temp_data->reader_handle) = NULL;
                //printf("release srb r\n");
            }
        }

        if(reset == INIT && init_service(temp_data)) {
            reset = RUNNING;
            pthread_create(&tid, NULL, srb_reader, temp_data);
            //printf(" [%s,%d] pthread_create tid = %lu \n",__func__,__LINE__,tid);
        }
    }

    isRunning = false;

    if (tid != 0) {
        pthread_join(tid, NULL);
        tid = 0;
    }

    return NULL;
}


static void msg_callback(MsgContext* msg, void* args)
{
    user_data_t *temp_data = (user_data_t*) args;
    ATK_AUDIOPLAY_CONFIG_T *playback_config = temp_data->p_audiopb_config;
    ATK_AUDIOCAP_CONFIG_T *capture_config = temp_data->p_audiocap_config;
    if( !strcasecmp(msg->pszHost, SR_MODULE_NAME) ){
        if( !strcasecmp(msg->pszCmd, SUSPEND_CMD) ) {
            struct timeval now;
            struct timespec outtime;

            printf("receive SUSPEND cmd\n");
            //Playback
            printf("try to hold playback\n");
            pthread_mutex_lock(&(temp_data->pb_data_mutex));
            SRB_WakeupReader(*(temp_data->reader_handle));
            temp_data->pb_process_status = STOP;
            pthread_cond_wait(&(temp_data->pb_data_cond), &(temp_data->pb_data_mutex));
            pthread_mutex_unlock(&(temp_data->pb_data_mutex));
            if(*(temp_data->playback_handle))
                ATK_AudioPlay_Release(*(temp_data->playback_handle));

            //Capture
            printf("try to hold capture\n");
            pthread_mutex_lock(&(temp_data->cap_data_mutex));
            gettimeofday(&now, NULL);
            outtime.tv_sec = now.tv_sec + 2;

            temp_data->cap_process_status = STOP;
            //pthread_cond_wait(&(temp_data->cap_data_cond), &(temp_data->cap_data_mutex));
            pthread_cond_timedwait(&(temp_data->cap_data_cond), &(temp_data->cap_data_mutex),&outtime);
            pthread_mutex_unlock(&(temp_data->cap_data_mutex));
            ATK_AudioCap_Release(*(temp_data->capture_handle));
            //Send susspend response
            printf("Ready to suspend.\n");
            MsgBroker_SuspendAckMsg();
        }else if( !strcasecmp(msg->pszCmd, RESUME_CMD) ) {
            //Playback
            *(temp_data->playback_handle) = ATK_AudioPlay_Init(playback_config);
            pthread_mutex_lock(&(temp_data->pb_data_mutex));
            temp_data->pb_process_status = START;
            pthread_cond_signal(&(temp_data->play_cond));
            pthread_mutex_unlock(&(temp_data->pb_data_mutex));
            //Capture
            *(temp_data->capture_handle) = ATK_AudioCap_Init(capture_config);
            pthread_mutex_lock(&(temp_data->cap_data_mutex));
            temp_data->cap_process_status = START;
            pthread_mutex_unlock(&(temp_data->cap_data_mutex));
        }
    }

    if (msg->bHasResponse)
        msg->dwDataSize = 0;
}

int main(int argc, char* argv[])
{
    //int ret;
    int opt = -1;
    //int input = 0; //Mic
    unsigned int interleaved = 1;  // is playing interleaved audio
    unsigned int sample_rate = 48000; // audio sample rate
    unsigned int channels = 2 ;  //number of channels
    int simple_conf = 0;  //use_simple_config
    unsigned int periods = 8; //periods_per_buffer
    ATK_AUDIOPLAY_HANDLE_T *playback_handle;
    ATK_AUDIOCAP_HANDLE_T *capture_handle;
    srb_handle_t* reader_handle = NULL;
    srb_handle_t* writer_handle = NULL;
    snd_hctl_t *alsa_handle = NULL;

    ATK_AUDIOCAP_CONFIG_T capture_config; //Capture
    ATK_AUDIOPLAY_CONFIG_T playback_config;//Playback
    user_data_t user_data;

    //int err, res;
    pthread_t main_tid = 0;
    while ((opt = getopt(argc, argv, "s:f:t:o:p:d:")) != -1){

        switch(opt){
            case 's':
                savefile = atoi(optarg);
                break;
            case 'f':
                file_name = strdup(optarg);
                break;
            case 't':
                interleaved = atoi(optarg);
                break;
            case 'o':
                simple_conf = atoi(optarg);
                break;
            case 'p':
                periods = atoi(optarg);
                break;
            default:
                print_usage(APP_NAME);
                goto end;
                break;
        }
    }

    memset(&user_data, 0, sizeof(user_data_t));
    pthread_mutex_init(&(user_data.pb_data_mutex), NULL);
    pthread_cond_init(&(user_data.pb_data_cond), NULL);
    pthread_cond_init(&(user_data.play_cond), NULL);
    pthread_mutex_init(&(user_data.cap_data_mutex), NULL);
    pthread_cond_init(&(user_data.cap_data_cond), NULL);
    user_data.playback_handle = &playback_handle;
    user_data.capture_handle = &capture_handle;
    user_data.reader_handle = &reader_handle;
    user_data.writer_handle = &writer_handle;
    user_data.alsa_handle = &alsa_handle;
    user_data.p_audiocap_config = &capture_config;
    user_data.p_audiopb_config = &playback_config;
    user_data.pb_process_status = START;
    user_data.cap_process_status = START;

    if (savefile && NULL == file_name){
        file_name = "audio_lookback.wav";
    }


    //initial configuration
    memset(&playback_config,0,sizeof(ATK_AUDIOPLAY_CONFIG_T));
    memset(&capture_config,0,sizeof(ATK_AUDIOCAP_CONFIG_T));
    //Playback
    playback_config.szPcmName = "hw:0,0";
    playback_config.bIsInterleaved = interleaved;
    playback_config.eFormat = SND_PCM_FORMAT_S16_LE;
    playback_config.dwChannelsCount = channels;
    playback_config.dwSampleRate = sample_rate;
    playback_config.bUseSimpleConfig = simple_conf;
    playback_config.dwPeriodsPerBuffer = periods;
    playback_config.dwPeriodSizeInFrames = PERIOD_SIZE_IN_FRAMES;
    playback_config.bDropFramesBeforeStop = TRUE;
    //Capture
    capture_config.szPcmName = "hw:1,0";
    capture_config.bIsInterleaved = interleaved;
    capture_config.eFormat = SND_PCM_FORMAT_S16_LE;
    capture_config.dwChannelsCount = channels;
    capture_config.dwSampleRate = sample_rate;
    capture_config.bUseSimpleConfig = simple_conf;
    capture_config.dwPeriodsPerBuffer = periods;
    capture_config.dwPeriodSizeInFrames = PERIOD_SIZE_IN_FRAMES;
    capture_config.pfnCallback = audiocap_callback;
    capture_config.pUserData = (void*) (&user_data);

    //save audio to file...
    if(savefile){
        snprintf(filename, sizeof(filename), CAP_DIR "%s", file_name);
        fp = fopen(filename, "ab");
    }

    signal(SIGPIPE, SIG_IGN);
    signal(SIGTERM, sig_kill);
    signal(SIGINT, sig_kill);
    isRunning = true;
    pthread_create(&main_tid, NULL, main_thread, &user_data);

    MsgBroker_RegisterMsg(CMD_UAC_FIFO_PATH);
    MsgBroker_Run(CMD_UAC_FIFO_PATH, msg_callback, &user_data, &is_terminate_);
    MsgBroker_UnRegisterMsg();
    if (main_tid != 0) {
        pthread_join(main_tid, NULL);
        printf(" [%s,%d] Leaving the main thread \n",__func__,__LINE__);
    }
end:
    if(savefile)
        fclose(fp);
    if(NULL!=writer_handle)
        SRB_Release(writer_handle);
    if(NULL!=reader_handle)
        SRB_Release(reader_handle);
    pthread_mutex_destroy(&(user_data.cap_data_mutex));
    pthread_cond_destroy(&(user_data.cap_data_cond));
    pthread_mutex_destroy(&(user_data.pb_data_mutex));
    pthread_cond_destroy(&(user_data.pb_data_cond));
    pthread_cond_destroy(&(user_data.play_cond));
    if(NULL!=playback_handle)
        ATK_AudioPlay_Release(playback_handle);
    if(NULL!=capture_handle)
        ATK_AudioCap_Release(capture_handle);
    if(NULL!=alsa_handle)
        snd_hctl_close(alsa_handle);

}
