2026-04-12 17:47:54 +08:00

672 lines
24 KiB
C++

/*
*******************************************************************************
* 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);
}