588 lines
16 KiB
C++
588 lines
16 KiB
C++
/*
|
|
*******************************************************************************
|
|
* Copyright (c) 2010-2022 VATICS(KNERON) 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(KNERON) INC. |
|
|
* +-----------------------------------------------------------------+
|
|
*
|
|
*******************************************************************************
|
|
*/
|
|
#include <string>
|
|
|
|
#include <signal.h>
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <fcntl.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
|
|
#include <audiotk/audio_capture_mmap.h>
|
|
#include <audiotk/audio_vol_ctrl.h>
|
|
#include <MsgBroker/msg_broker.h>
|
|
#include <SyncRingBuffer/sync_ring_buffer.h>
|
|
|
|
#include <alac/ALACAudioTypes.h>
|
|
#include <alac/ALACEncoder.h>
|
|
|
|
#define MAX_CONNECT_NUM (5)
|
|
#define DEFAULT_PID (0xffff)
|
|
|
|
// Flag for message broker (main loop).
|
|
static int is_terminate_ = 0;
|
|
|
|
// Adapted from CoreAudioTypes.h
|
|
enum
|
|
{
|
|
kTestFormatFlag_16BitSourceData = 1,
|
|
kTestFormatFlag_20BitSourceData = 2,
|
|
kTestFormatFlag_24BitSourceData = 3,
|
|
kTestFormatFlag_32BitSourceData = 4
|
|
};
|
|
|
|
typedef struct
|
|
{
|
|
//! connect pid
|
|
pid_t connect_pid;
|
|
//! Flag to indicate whether we need to encode data or not.
|
|
unsigned int do_encoding;
|
|
} connect_info_t;
|
|
|
|
connect_info_t g_atconnect_info[MAX_CONNECT_NUM];
|
|
|
|
typedef struct
|
|
{
|
|
// Flag to indicate whether we need to send configuration about each encoder or not.
|
|
bool send_conf;
|
|
|
|
// The handles for SynRingBuf.
|
|
srb_handle_t* srb_handle;
|
|
// The buffers for SynRingBuf.
|
|
srb_buffer_t srb_buf;
|
|
|
|
unsigned int enc_type; // FourCC of encoder.
|
|
unsigned int seq_num;
|
|
|
|
pthread_mutex_t data_mutex;
|
|
pthread_cond_t data_cond;
|
|
STATUS process_status;
|
|
|
|
ATK_AUDIOCAP_CONFIG_T *p_audiocap_config;
|
|
ATK_AUDIOCAP_HANDLE_T **p_cap_handle;
|
|
|
|
AudioFormatDescription inputFormat;
|
|
AudioFormatDescription outputFormat;
|
|
|
|
// encoder handle
|
|
void *enc_handle;
|
|
} user_data_t;
|
|
|
|
//#define DUMP_TIMESTAMP
|
|
//#define DUMP_PCM_DATA
|
|
|
|
#ifdef DUMP_PCM_DATA
|
|
static int audio_fd_ = -1;
|
|
|
|
static int open_pcm_file(/* int is_interleaved, unsigned int channels */)
|
|
{
|
|
const char *filename = "alacaenc_debug_audio.pcm";
|
|
audio_fd_ = open(filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
|
|
if(audio_fd_ == -1)
|
|
{
|
|
fprintf(stderr, "[%s, %s]: Open file error: %s\n", __FILE__, __func__, strerror(errno));
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void close_pcm_file()
|
|
{
|
|
if(audio_fd_ >= 0)
|
|
close(audio_fd_);
|
|
}
|
|
|
|
static int write_pcm_data_to_file(int /*is_interleaved*/, unsigned int /*channels*/, unsigned char* const* audio_bufs, size_t data_bytes)
|
|
{
|
|
ssize_t ret = write(audio_fd_, audio_bufs[0], data_bytes);
|
|
if(ret < 0)
|
|
{
|
|
fprintf(stderr, "[%s, %s]: Write error. %s\n", __FILE__, __func__, strerror(errno));
|
|
return -1;
|
|
}
|
|
else if((size_t) ret != data_bytes)
|
|
{
|
|
fprintf(stderr, "[%s, %s]: Data loss ..............\n", __FILE__, __func__);
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#endif // DUMP_PCM_DATA
|
|
|
|
|
|
static int pid_default(int dwStart)
|
|
{
|
|
unsigned int i;
|
|
for (i = 0; i < MAX_CONNECT_NUM; ++i)
|
|
{
|
|
if (dwStart) {
|
|
//! set default pid and start encoding
|
|
if (!g_atconnect_info[i].connect_pid) {
|
|
g_atconnect_info[i].connect_pid = DEFAULT_PID;
|
|
++g_atconnect_info[i].do_encoding;
|
|
break;
|
|
} else if (g_atconnect_info[i].connect_pid == DEFAULT_PID){
|
|
++g_atconnect_info[i].do_encoding;
|
|
break;
|
|
} else {
|
|
printf("[%s] Error: Something wrong \n", __func__);
|
|
break;
|
|
}
|
|
} else {
|
|
//! set default pid and stop encoding
|
|
if (g_atconnect_info[i].connect_pid == DEFAULT_PID) {
|
|
--g_atconnect_info[i].do_encoding;
|
|
if (!g_atconnect_info[i].do_encoding) {
|
|
g_atconnect_info[i].connect_pid = 0;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(i == MAX_CONNECT_NUM){
|
|
printf("[%s] Error: AENC Connect number to MAX\n",__func__);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int pid_start (pid_t new_pid)
|
|
{
|
|
unsigned int i = 0;
|
|
for (i = 0; i < MAX_CONNECT_NUM; i++)
|
|
{
|
|
if (g_atconnect_info[i].connect_pid == 0 && !g_atconnect_info[i].do_encoding) {
|
|
g_atconnect_info[i].connect_pid = new_pid;
|
|
g_atconnect_info[i].do_encoding++;
|
|
break;
|
|
} else if (g_atconnect_info[i].connect_pid == new_pid) {
|
|
g_atconnect_info[i].do_encoding++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(i == MAX_CONNECT_NUM){
|
|
printf("[%s] Error: AENC Connect number to MAX\n",__func__);
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int pid_stop(pid_t new_pid)
|
|
{
|
|
for (size_t i = 0; i < MAX_CONNECT_NUM; i++)
|
|
{
|
|
if (g_atconnect_info[i].connect_pid != 0
|
|
&& g_atconnect_info[i].connect_pid == new_pid
|
|
&& g_atconnect_info[i].do_encoding) {
|
|
g_atconnect_info[i].do_encoding--;
|
|
if (!g_atconnect_info[i].do_encoding)
|
|
g_atconnect_info[i].connect_pid = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int pid_do_encoding(void)
|
|
{
|
|
for (size_t i = 0; i < MAX_CONNECT_NUM; i++)
|
|
{
|
|
if (g_atconnect_info[i].connect_pid != 0 && g_atconnect_info[i].do_encoding)
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void audiocap_callback(const ATK_AUDIO_NOTIFY_DATA_INFO_T *audio_info, void* user_data)
|
|
{
|
|
//Input pcm data should be interleaved
|
|
user_data_t *temp_data = (user_data_t*) user_data;
|
|
|
|
#ifdef DUMP_TIMESTAMP
|
|
printf("time = %lu.%lu\n", audio_info->tDataTimestamp.tv_sec, audio_info->tDataTimestamp.tv_usec);
|
|
#endif // DUMP_TIMESTAMP
|
|
|
|
#ifdef DUMP_PCM_DATA
|
|
write_pcm_data_to_file(audio_info->bIsInterleaved, audio_info->dwChannels, audio_info->ppbyAudioBufs, audio_info->dwDataBytes);
|
|
#endif
|
|
pthread_mutex_lock(&(temp_data->data_mutex));
|
|
|
|
ALACEncoder* theEncoder = (ALACEncoder*) temp_data->enc_handle;
|
|
if (temp_data->send_conf)
|
|
{
|
|
// Send configuration of encoder.
|
|
printf("send conf .............\n");
|
|
if(FOURCC_ALAC == temp_data->enc_type) {
|
|
unsigned int *values = (unsigned int*) temp_data->srb_buf.buffer;
|
|
uint32_t theMagicCookieSize = theEncoder->GetMagicCookieSize(temp_data->outputFormat.mChannelsPerFrame);
|
|
uint8_t* theMagicCookie = (uint8_t *)calloc(theMagicCookieSize, 1);
|
|
|
|
theEncoder->GetMagicCookie(theMagicCookie, &theMagicCookieSize);
|
|
values[0] = FOURCC_CONF;
|
|
values[1] = 16 + theMagicCookieSize;
|
|
values[2] = FOURCC_ALAC;
|
|
values[3] = temp_data->outputFormat.mSampleRate;
|
|
values[4] = temp_data->outputFormat.mChannelsPerFrame;
|
|
values[5] = theMagicCookieSize;
|
|
memcpy(values + 6, theMagicCookie, theMagicCookieSize);
|
|
free(theMagicCookie);
|
|
}
|
|
SRB_SendGetWriterBuff(temp_data->srb_handle, &temp_data->srb_buf);
|
|
temp_data->send_conf = false;
|
|
}
|
|
|
|
if (temp_data->process_status == STOP) {
|
|
pthread_cond_signal(&(temp_data->data_cond));
|
|
pthread_mutex_unlock(&(temp_data->data_mutex));
|
|
return;
|
|
}
|
|
pthread_mutex_unlock(&(temp_data->data_mutex));
|
|
|
|
if (pid_do_encoding())
|
|
{
|
|
if (FOURCC_ALAC == temp_data->enc_type)
|
|
{
|
|
int32_t encode_data_bytes = audio_info->dwDataBytes;
|
|
int32_t status = -1;
|
|
|
|
status = theEncoder->Encode(temp_data->inputFormat, temp_data->outputFormat,
|
|
audio_info->ppbyAudioBufs[0], temp_data->srb_buf.buffer + MAX_AUDIO_DATA_HEADER_SIZE, &encode_data_bytes);
|
|
if (0 == status && encode_data_bytes > 0)
|
|
{
|
|
unsigned int* buf_ptr = (unsigned int*) temp_data->srb_buf.buffer;
|
|
buf_ptr[0] = temp_data->enc_type;
|
|
buf_ptr[1] = audio_info->tDataTimestamp.tv_sec;
|
|
buf_ptr[2] = audio_info->tDataTimestamp.tv_usec;
|
|
buf_ptr[3] = encode_data_bytes;
|
|
buf_ptr[4] = temp_data->seq_num;
|
|
SRB_SendGetWriterBuff(temp_data->srb_handle, &temp_data->srb_buf);
|
|
}
|
|
else
|
|
{
|
|
fprintf(stderr, "[%s, %s]: Encode error !!! status(%d), encode_data_bytes(%d)\n", __FILE__, __func__, status, encode_data_bytes);
|
|
}
|
|
|
|
++(temp_data->seq_num);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void msg_callback(MsgContext* msg, void* user_data)
|
|
{
|
|
user_data_t *temp_data = (user_data_t*) user_data;
|
|
|
|
if (!strncasecmp(msg->pszHost, "encoder", 7))
|
|
{
|
|
if (!strcasecmp(msg->pszCmd, "start"))
|
|
{
|
|
if (msg->dwDataSize) {
|
|
pid_t *ptNew_pid = (pid_t *)msg->pbyData;
|
|
pid_start(*ptNew_pid);
|
|
} else {
|
|
pid_default(1);
|
|
}
|
|
|
|
printf("start .............. \n");
|
|
}
|
|
else if (!strcasecmp(msg->pszCmd, "stop"))
|
|
{
|
|
|
|
if (msg->dwDataSize) {
|
|
pid_t *ptNew_pid = (pid_t *)msg->pbyData;
|
|
pid_stop(*ptNew_pid);
|
|
} else {
|
|
pid_default(0);
|
|
}
|
|
|
|
printf("stop .............. \n");
|
|
}
|
|
else if (!strcasecmp(msg->pszCmd, "forceCI"))
|
|
{
|
|
printf("forceCI ..............\n");
|
|
temp_data->send_conf = true;
|
|
}
|
|
}
|
|
else if (!strcasecmp(msg->pszHost, SR_MODULE_NAME)) {
|
|
if (!strcasecmp(msg->pszCmd, SUSPEND_CMD)) {
|
|
pthread_mutex_lock(&(temp_data->data_mutex));
|
|
temp_data->process_status = STOP;
|
|
pthread_cond_wait(&(temp_data->data_cond), &(temp_data->data_mutex));
|
|
pthread_mutex_unlock(&(temp_data->data_mutex));
|
|
ATK_AudioCap_Release(*(temp_data->p_cap_handle));
|
|
MsgBroker_SuspendAckMsg();
|
|
} else if(!strcasecmp(msg->pszCmd, RESUME_CMD)) {
|
|
*(temp_data->p_cap_handle) = ATK_AudioCap_Init(temp_data->p_audiocap_config);
|
|
pthread_mutex_lock(&(temp_data->data_mutex));
|
|
temp_data->process_status = START;
|
|
pthread_mutex_unlock(&(temp_data->data_mutex));
|
|
}
|
|
}
|
|
|
|
if (msg->bHasResponse)
|
|
msg->dwDataSize = 0;
|
|
}
|
|
|
|
static void exit_process()
|
|
{
|
|
is_terminate_ = 1;
|
|
}
|
|
|
|
static void sig_kill(int signo)
|
|
{
|
|
fprintf(stderr, "[%s,%s] Receive SIGNAL %d!!!\n", __FILE__, __func__, signo);
|
|
switch(signo)
|
|
{
|
|
case SIGTERM:
|
|
case SIGINT:
|
|
exit_process();
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void print_usage(const char *ap_name)
|
|
{
|
|
fprintf(stderr, "Usage:\n"
|
|
" %s [-b bit_depth] [-c channels] [-d PCM_device_name] [-f command_FIFO_path] [-h] [-i input_type] [-r sample_rate] [-D]\n"
|
|
"Options:\n"
|
|
" -b Bit depth for audio (Default: 16 -> S16_LE).\n"
|
|
" -c Channel number (Default: 2).\n"
|
|
" -d PCM device name for ALSA (Default: hw:0,0).\n"
|
|
" -f The path of command FIFO (Default: /tmp/aenc/c0/command.fifo).\n"
|
|
" -h This help.\n"
|
|
" -i Input type of audio (0: MicIn, 1: LineIn. Default: 1 -> LineIn).\n"
|
|
" -r Sample rate for audio (Default: 8000).\n"
|
|
" -D Run as Daemon.\n"
|
|
, ap_name);
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
int opt;
|
|
bool is_daemon = false;
|
|
// Default setting.
|
|
int input_type = 1; //0: MicIn, 1: LineIn
|
|
int bit_depth = 16;
|
|
std::string srb_name = "aenc_srb_1";
|
|
std::string pcm_name = "hw:0,0";
|
|
std::string cmd_fifo_path = CMD_FIFO_PATH;
|
|
|
|
ATK_AUDIOCAP_CONFIG_T audiocap_config;
|
|
ATK_AUDIOCAP_HANDLE_T *cap_handle = NULL;
|
|
memset(&audiocap_config, 0, sizeof(ATK_AUDIOCAP_CONFIG_T));
|
|
|
|
audiocap_config.szPcmName = pcm_name.c_str();
|
|
audiocap_config.bIsInterleaved = 1;
|
|
audiocap_config.eFormat = SND_PCM_FORMAT_S16_LE;
|
|
audiocap_config.dwChannelsCount = 2;
|
|
audiocap_config.dwSampleRate = 8000;
|
|
audiocap_config.dwPeriodsPerBuffer = 8;
|
|
audiocap_config.dwPeriodSizeInFrames = PERIOD_SIZE_IN_FRAMES;
|
|
audiocap_config.bUseSimpleConfig = 0;
|
|
|
|
while ((opt = getopt(argc, argv, "b:c:d:f:Dh:i:r:")) != -1)
|
|
{
|
|
switch(opt)
|
|
{
|
|
case 'b':
|
|
bit_depth = atoi(optarg);
|
|
break;
|
|
case 'c':
|
|
audiocap_config.dwChannelsCount = atoi(optarg);
|
|
break;
|
|
case 'd':
|
|
pcm_name = optarg;
|
|
audiocap_config.szPcmName = pcm_name.c_str();
|
|
break;
|
|
case 'f':
|
|
cmd_fifo_path = optarg;
|
|
break;
|
|
case 'h':
|
|
print_usage(argv[0]);
|
|
exit(EXIT_FAILURE);
|
|
case 'i':
|
|
input_type = (atoi(optarg) != 0)? 1:0;
|
|
break;
|
|
case 'r':
|
|
audiocap_config.dwSampleRate = atoi(optarg);
|
|
break;
|
|
case 'D':
|
|
is_daemon = true;
|
|
break;
|
|
default:
|
|
print_usage(argv[0]);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
}
|
|
|
|
//audiocap_config.dwPeriodSizeInFrames *= (bit_depth >> 4);
|
|
|
|
switch (bit_depth)
|
|
{
|
|
case 16:
|
|
audiocap_config.eFormat = SND_PCM_FORMAT_S16_LE;
|
|
break;
|
|
case 24:
|
|
audiocap_config.eFormat = SND_PCM_FORMAT_S24_LE;
|
|
break;
|
|
case 32:
|
|
audiocap_config.eFormat = SND_PCM_FORMAT_S32_LE;
|
|
break;
|
|
default:
|
|
print_usage(argv[0]);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
signal(SIGTERM, sig_kill);
|
|
signal(SIGINT, sig_kill);
|
|
|
|
if (is_daemon)
|
|
{
|
|
daemon(1,1);
|
|
}
|
|
|
|
if (input_type == 1)
|
|
{
|
|
ATK_Audio_InputSelection(kTKAudioLineIn);
|
|
|
|
//set audio volume to 90
|
|
ATK_Audio_SetCaptureVolume(90);
|
|
|
|
}
|
|
else
|
|
{
|
|
ATK_Audio_InputSelection(kTKAudioMicIn);
|
|
|
|
//set audio volume to 90
|
|
ATK_Audio_SetCaptureVolume(90);
|
|
}
|
|
|
|
// Callbacks for audio capture and the private user data for callback.
|
|
user_data_t user_data;
|
|
memset(&user_data, 0, sizeof(user_data_t));
|
|
user_data.send_conf = true;
|
|
pthread_mutex_init(&(user_data.data_mutex), NULL);
|
|
pthread_cond_init(&(user_data.data_cond), NULL);
|
|
user_data.process_status = START;
|
|
user_data.p_audiocap_config = &audiocap_config;
|
|
user_data.p_cap_handle = &cap_handle;
|
|
|
|
audiocap_config.pfnCallback = audiocap_callback;
|
|
audiocap_config.pUserData = (void*) (&user_data);
|
|
|
|
// TODO: init ALAC encoder
|
|
{
|
|
ALACEncoder* theEncoder = new ALACEncoder;
|
|
|
|
memset(&user_data.inputFormat, 0, sizeof(AudioFormatDescription));
|
|
memset(&user_data.outputFormat, 0, sizeof(AudioFormatDescription));
|
|
|
|
// setup input format
|
|
user_data.inputFormat.mFormatID = kALACFormatLinearPCM;
|
|
user_data.inputFormat.mChannelsPerFrame = audiocap_config.dwChannelsCount;
|
|
user_data.inputFormat.mSampleRate = audiocap_config.dwSampleRate;
|
|
user_data.inputFormat.mBitsPerChannel = bit_depth;
|
|
user_data.inputFormat.mFormatFlags = kALACFormatFlagIsSignedInteger | kALACFormatFlagIsPacked; // always little endian
|
|
user_data.inputFormat.mBytesPerPacket
|
|
= user_data.inputFormat.mBytesPerFrame
|
|
= (user_data.inputFormat.mBitsPerChannel >> 3) * user_data.inputFormat.mChannelsPerFrame;
|
|
user_data.inputFormat.mFramesPerPacket = 1;
|
|
user_data.inputFormat.mReserved = 0;
|
|
|
|
// setup output format
|
|
user_data.outputFormat.mFormatID = kALACFormatAppleLossless;
|
|
user_data.outputFormat.mSampleRate = audiocap_config.dwSampleRate;
|
|
switch(bit_depth)
|
|
{
|
|
case 16:
|
|
user_data.outputFormat.mFormatFlags = kTestFormatFlag_16BitSourceData;
|
|
break;
|
|
case 24:
|
|
user_data.outputFormat.mFormatFlags = kTestFormatFlag_24BitSourceData;
|
|
break;
|
|
case 32:
|
|
user_data.outputFormat.mFormatFlags = kTestFormatFlag_32BitSourceData;
|
|
break;
|
|
default:
|
|
return -1;
|
|
break;
|
|
}
|
|
user_data.outputFormat.mFramesPerPacket = kALACDefaultFramesPerPacket;
|
|
user_data.outputFormat.mChannelsPerFrame = audiocap_config.dwChannelsCount;
|
|
user_data.outputFormat.mBytesPerPacket
|
|
= user_data.outputFormat.mBytesPerFrame
|
|
= user_data.outputFormat.mBitsPerChannel
|
|
= user_data.outputFormat.mReserved
|
|
= 0;
|
|
theEncoder->SetFrameSize(user_data.outputFormat.mFramesPerPacket);
|
|
theEncoder->InitializeEncoder(user_data.outputFormat);
|
|
user_data.enc_type = FOURCC_ALAC;
|
|
user_data.enc_handle = (void *) theEncoder;
|
|
}
|
|
|
|
//SynRingBuffer
|
|
user_data.srb_handle = SRB_InitWriter(srb_name.c_str(), MAX_RING_BUF_SIZE, 4);
|
|
memset(&user_data.srb_buf, 0, sizeof(srb_buffer_t));
|
|
// Get first buffer from SyncRingBuf.
|
|
SRB_SendGetWriterBuff(user_data.srb_handle, &user_data.srb_buf);
|
|
|
|
// Initialize the audio capture.
|
|
cap_handle = ATK_AudioCap_Init(&audiocap_config);
|
|
if(cap_handle == NULL)
|
|
{
|
|
fprintf(stderr, "[%s,%s] Can't initialize the audio capture.\n", __FILE__, __func__);
|
|
goto main_end;
|
|
}
|
|
|
|
#ifdef DUMP_PCM_DATA
|
|
if(open_pcm_file() < 0)
|
|
{
|
|
goto main_end;
|
|
}
|
|
#endif
|
|
MsgBroker_RegisterMsg(cmd_fifo_path.c_str());
|
|
// Enter the main message loop.
|
|
MsgBroker_Run(cmd_fifo_path.c_str(), msg_callback, &user_data, &is_terminate_);
|
|
MsgBroker_UnRegisterMsg();
|
|
|
|
main_end:
|
|
|
|
#ifdef DUMP_PCM_DATA
|
|
close_pcm_file();
|
|
#endif
|
|
ATK_AudioCap_Release(cap_handle);
|
|
delete (ALACEncoder*)user_data.enc_handle;
|
|
SRB_Release(user_data.srb_handle);
|
|
pthread_mutex_destroy(&(user_data.data_mutex));
|
|
pthread_cond_destroy(&(user_data.data_cond));
|
|
|
|
return 0;
|
|
}
|