672 lines
24 KiB
C++
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);
|
|
|
|
}
|