?? recorder.c
字號:
/*File Name: Recorder.c*/
#include <fcntl.h>
#include <linux/soundcard.h>
#include <sys/ioctl.h>
#include <pthread.h>
#include "Ldb.h"
#include "Recorder.h"
#include "Adpcm.h"
#include "Utility.h"
#include "LocoSystem.h"
#include "SoundDesc.h"
#include "ComMonitor.h"
#include "LocoLog.h"
#define ADPCM_COMPRESSION 1
/********************************************/
#define SAMPLE_BIT 16
#define SAMPLE_CHANNEL 1
int SAMPLE_RATE;
int SAMPLE_PER_BLOCK;
int BLOCK_ALIGN;
int SAMPLE_BUFFER_SIZE;
int CODE_BUFFER_SIZE;
/********************************************
讀寫的文件及buffer
********************************************/
/*設備fd*/
int f_audiofd;
/*當前正在錄音的文件*/
FILE *f_pCurrFile;
char f_prevFileName[SYS_PATH_MAX_LEN];
char f_currFileName[SYS_PATH_MAX_LEN];
/*當前錄音文件得長度*/
int f_rcdSize;
/*讀寫文件buffer*/
unsigned char* f_bufSample;
unsigned char* f_bufCode;
/********************************************
錄音線程
********************************************/
/*錄音線程*/
pthread_t f_rcdThrd;
/*錄音停止標志*/
volatile char f_rcdStop;
pthread_mutex_t f_pauseMutex = PTHREAD_MUTEX_INITIALIZER;
#define pause_Lock {pthread_mutex_lock(&f_pauseMutex);}
#define pause_Unlock {pthread_mutex_unlock(&f_pauseMutex);}
/*錄音暫停標志*/
volatile char f_rcdPause;
volatile char f_forceStop;
/*錄音線程函數*/
void *loco_recorder(void *arg);
void loco_rcdPlayFile(FILE *pfile);
void loco_rcdStop();
int loco_rcdStart();
/*******************************************
讀寫方式打開聲音設備
mode: O_WRONLY, O_RDONLY, O_RDWR
*******************************************/
int loco_openAudioDev(int mode)
{
int status, arg;
f_audiofd = open(LOCO_SOUND_DEV, mode);
if(f_audiofd < 0)
{
LDB_ERR_MSGF("open audio device failed!");
return -1;
}
arg = AFMT_U16_BE;
status= ioctl(f_audiofd, SNDCTL_DSP_SETFMT, &arg);
if(status == -1)
{
LDB_ERR_MSGF("AFMT_U16_BE error!");
return -1;
}
else if(arg != AFMT_U16_BE)
{
LDB_ERR_MSGF("Failed to set sample format %d! arg = %d", AFMT_U16_BE, arg);
return -1;
}
else
{
//printf("Set sample bits sucessfully\r\n");
}
arg = SAMPLE_BIT;
status= ioctl(f_audiofd, SNDCTL_DSP_SAMPLESIZE, &arg);
if(status == -1)
{
LDB_ERR_MSGF("SNDCTL_DSP_SAMPLESIZE error!");
return -1;
}
else if(arg != SAMPLE_BIT)
{
LDB_ERR_MSGF("Failed to set sample bits!arg = %d", arg);
return -1;
}
else
{
//printf("Set sample bits sucessfully\r\n");
}
arg = SAMPLE_CHANNEL;
status= ioctl(f_audiofd, SNDCTL_DSP_CHANNELS, &arg);
if(status == -1)
{
LDB_ERR_MSGF("SNDCTL_DSP_CHANNELS error!");
return -1;
}
else if(arg != SAMPLE_CHANNEL)
{
LDB_ERR_MSGF("unable to set numble of channels!arg = %d",arg);
return -1;
}
else
{
//printf("Set channels sucessfully\r\n");
}
arg = SAMPLE_RATE;
status= ioctl(f_audiofd, SNDCTL_DSP_SPEED, &arg);
if(status == -1)
{
LDB_ERR_MSGF("SNDCTL_DSP_SPEED error!");
return -1;
}
else if(arg != SAMPLE_RATE)
{
LDB_ERR_MSGF("unable to set rate:%d! arg = %d",SAMPLE_RATE,arg);
return -1;
}
else
{
//printf("Set sample rate sucessfully\r\n");
}
return f_audiofd;
}
int loco_dspRead(unsigned char *buffer, int size)
{
int nread;
if (f_audiofd == -1)
{
return -1;
}
nread = read(f_audiofd, buffer, size);
return nread;
}
int loco_dspWrite(unsigned char *buffer, int size)
{
int nwrite;
if (f_audiofd == -1)
{
return -1;
}
nwrite = write(f_audiofd, buffer, size);
return nwrite;
}
void loco_dspClose()
{
if (f_audiofd != -1)
{
close(f_audiofd);
f_audiofd = -1;
}
printf("dsp closed \n");
}
/*******************************************/
int loco_rcdInit()
{
if (g_sysSampleRate == 8)
{
SAMPLE_RATE = 8000;
SAMPLE_PER_BLOCK = 505;
BLOCK_ALIGN = 256;
SAMPLE_BUFFER_SIZE = 2020;
CODE_BUFFER_SIZE = 512;
}
else
{
SAMPLE_RATE = 16000;
SAMPLE_PER_BLOCK = 1017;
BLOCK_ALIGN = 512;
SAMPLE_BUFFER_SIZE = 4068;
CODE_BUFFER_SIZE = 1024;
}
f_forceStop = 0;
/*分配工作buffer*/
f_bufSample = (unsigned char*)malloc(SAMPLE_BUFFER_SIZE);
f_bufCode = (unsigned char*)malloc(CODE_BUFFER_SIZE);
if (NULL == f_bufSample || NULL == f_bufCode)
return -1;
return loco_rcdStart();
}
void loco_rcdFree()
{
loco_rcdStop();
free(f_bufSample);
f_bufSample = NULL;
free(f_bufCode);
f_bufCode = NULL;
f_forceStop = 0;
}
int loco_rcdStart()
{
f_pCurrFile = NULL;
if (g_rcdAuto == 1)
f_rcdPause = 0;
else
f_rcdPause = 1;
f_audiofd = -1;
/*創建語音保存文件夾*/
if (ldb_fileCreateDir(SYS_SOUND_SAVE_DIR) == -1)
{
LDB_ERR_MSGF("can not create recorder directory");
return -1;
}
/*打開聲音設備*/
if (-1 == loco_openAudioDev(O_RDONLY))//O_RDWR
{
LDB_ERR_MSGF("unable to open audio device: %s!", LOCO_SOUND_DEV);
loco_rcdFree();
return -1;
}
/*創建錄音工作線程*/
f_rcdStop = 0;
if( pthread_create(&f_rcdThrd, NULL, loco_recorder, NULL) != 0)
{
LDB_ERR_MSGF("can not create recorder thread");
return -1;
}
return 0;
}
//在開始播放的時候將錄音設備關閉,然后以Writer only方式打開
void loco_rcdStop()
{
/*停止線程*/
f_rcdStop = 1;
f_rcdPause = 0;
if (f_rcdThrd != -1)
{
if ( pthread_join(f_rcdThrd, NULL) != 0)
{
LDB_DEBUG_MSGF("recorder thread exits abnormally");
}
f_rcdThrd = -1;
}
/*關閉設備*/
loco_dspClose();
/*關閉錄音文件*/
if (NULL != f_pCurrFile)
fclose(f_pCurrFile);
f_pCurrFile = NULL;
}
void loco_rcdPause()
{
pause_Lock
LDB_DEBUG_MSGF("Pause recording...");
f_rcdPause++;
pause_Unlock
}
void loco_rcdResume()
{
//如果已經停止,啟動之
if(f_rcdStop == 1)
{
loco_rcdFree();
loco_rcdInit();
}
if (f_rcdPause == 0)
return;
loco_adpcmResetEncoder();
pause_Lock
f_rcdPause--;
LDB_DEBUG_MSGF("Resume recording...");
pause_Unlock
}
int loco_rcdEnsureSoundDir(S_SndDesc *pdesc, char *pdir)
{
char dir[SYS_PATH_MAX_LEN];
char date[9], train[6];
memset(date, 0, sizeof(date));
strncpy(date, pdesc->date_start, 8);
memset(train, 0, sizeof(train));
snd_descGetTrain(pdesc->train_id, train, sizeof(train));
memset(dir, 0, SYS_PATH_MAX_LEN);
sprintf(dir, "%s/%s.%05d.%s", SYS_SOUND_SAVE_DIR, train, pdesc->driver, date);
if ( strcmp(dir, pdir) == 0)
return 0;
memset(pdir, 0, SYS_PATH_MAX_LEN);
strcpy(pdir, dir);
if (-1 == ldb_fileCreateDir(pdir) )
return -1;
memset(dir, 0, SYS_PATH_MAX_LEN);
sprintf(dir, "save sound file to %s", pdir);
log_info(dir);
return 0;
}
//最小檢查個數
#define CHECK_NUM_MIN 1024
int loco_rcdGetValue(int checknum)
{
int i, count, value;
short sample;
value = 0;
count = checknum/2;
for (i=0; i<count; )
{
sample = f_bufSample[i++] & 0xff;
sample |= (f_bufSample[i++] << 8) & 0xff00;
value += abs(sample);
}
value = value*2 / count;
return value;
}
void *loco_recorder(void *arg)
{
char b_pause, silence_count;
char dir[SYS_PATH_MAX_LEN];
char log[SYS_PATH_MAX_LEN];
int test_counter;
int nread, nblock, check_value;
S_SndDesc *pdesc;
int sample_size, sample_min_size;
sample_min_size = g_voiceMinLen*SAMPLE_RATE*2;
while(-1 != f_audiofd && f_rcdStop == 0)
{
loco_adpcmResetEncoder();
f_pCurrFile = NULL;
b_pause = 1;
test_counter = 0;
//語音檢測暫停
while(b_pause == 1)
{
if (f_rcdStop == 1)
{
goto RECORDER_END;
}
nread = loco_dspRead(f_bufSample, SAMPLE_BUFFER_SIZE);
if (nread <= 0)
goto RECORDER_END;
if (nread < CHECK_NUM_MIN)
continue;
check_value = loco_rcdGetValue(nread);
#if 0
//#if _TEST
if (test_counter++ == 5)
{
printf("Before Recording: v=%d\n", check_value);
test_counter = 0;
}
//#endif
#endif
if (check_value > g_voiceMin)
{
memset(log, 0, sizeof(log));
sprintf(log, "Recording start for voice %d", check_value);
log_info(log);
printf(log);
printf("\n");
b_pause = 0;
}
}
sample_size = nread;
//通知串口單元開始錄音了
loco_commReply(COMM_MSG_RESUME);
//得到當前的列車信息
pdesc = snd_descGet();
//確保錄音目錄存在
if (-1 == loco_rcdEnsureSoundDir(pdesc, dir) )
{
g_stopRequest = 1;
goto RECORDER_END;
}
//確保磁盤空間足夠
if ( 0 != loco_ensureDiskSpace(dir))
{
g_stopRequest = 1;
goto RECORDER_END;
}
//創建一個新文件
memset(f_currFileName, 0, SYS_PATH_MAX_LEN);
f_pCurrFile = ldb_fileCreate(dir, pdesc->date_start, f_currFileName);
if (NULL == f_pCurrFile)
continue;
LDB_DEBUG_MSGF("Record a new file %s", f_currFileName);
//在文件頭寫入描述信息
fwrite(pdesc, 1, sizeof(S_SndDesc), f_pCurrFile);
//壓縮
nblock = loco_adpcmEncode(f_bufSample, nread, SAMPLE_PER_BLOCK, BLOCK_ALIGN, f_bufCode, CODE_BUFFER_SIZE);
//寫入文件
if (nblock > 0)
ldb_fileWrite(f_pCurrFile, f_bufCode, nblock*BLOCK_ALIGN);
//開始錄音
silence_count = 0;
while(b_pause == 0 && f_rcdStop == 0)// && f_rcdPause == 0
{
memset(f_bufSample, 0, SAMPLE_BUFFER_SIZE);
memset(f_bufCode, 0, CODE_BUFFER_SIZE);
//讀數據
nread = loco_dspRead(f_bufSample, SAMPLE_BUFFER_SIZE);
if (nread <= 0)
goto RECORDER_END;
#if 0
//#if _TEST
check_value = loco_rcdGetValue(nread);
memset(log, 0, sizeof(log));
sprintf(log, "In Recording: v=%d", check_value);
log_info(log);
printf(log);
printf("\n");
//#endif
#endif
//壓縮
nblock = loco_adpcmEncode(f_bufSample, nread, SAMPLE_PER_BLOCK, BLOCK_ALIGN, f_bufCode, CODE_BUFFER_SIZE);
//寫入文件
if (0 != ldb_fileWrite(f_pCurrFile, f_bufCode, nblock*BLOCK_ALIGN))
break;
sample_size += nread;
if (nread < CHECK_NUM_MIN)
continue;
//檢查是否應該暫停
if (sample_size > sample_min_size || silence_count > 0)
{
check_value = loco_rcdGetValue(CHECK_NUM_MIN);
if (check_value <= g_voiceMin )
silence_count++;
else
{
sample_size = 0;
silence_count = 0;
}
if (silence_count > 5)
{
memset(log, 0, sizeof(log));
sprintf(log, "Recording stop for voice %d", check_value);
log_info(log);
printf(log);
printf("\n");
b_pause = 1;
}
}
}
//通知串口單元暫停錄音了
loco_commReply(COMM_MSG_PAUSE);
fclose(f_pCurrFile);
f_pCurrFile = NULL;
memset(f_prevFileName, 0, SYS_PATH_MAX_LEN);
strcpy(f_prevFileName, f_currFileName);
LDB_DEBUG_MSGF("Close file %s", f_currFileName);
}
RECORDER_END:
LDB_DEBUG_MSGF("Exiting recorder thread...");
/*清理工作*/
loco_dspClose();
if (NULL != f_pCurrFile)
{
fclose(f_pCurrFile);
f_pCurrFile = NULL;
}
memset(f_prevFileName, 0, SYS_PATH_MAX_LEN);
strcpy(f_prevFileName, f_currFileName);
f_rcdStop = 1;
f_rcdThrd = -1;
return NULL;
}
int loco_rcdIsStop()
{
return f_rcdStop;
}
int loco_rcdIsForceStop()
{
return f_forceStop;
}
void loco_rcdSetForceStop()
{
f_forceStop = 1;
}
void loco_rcdClearForceStop()
{
f_forceStop = 0;
}
/*************************************************/
/*************************************************/
void loco_rcdPlayFile(FILE *pfile)
{
int nblock, ncode;
loco_adpcmResetDecoder();
/*打開聲音設備*/
if (-1 == loco_openAudioDev(O_WRONLY) )
{
log_error("failed to open audio device!");
return;
}
do
{
memset(f_bufSample, 0, SAMPLE_BUFFER_SIZE);
memset(f_bufCode, 0, CODE_BUFFER_SIZE);
//讀數據
ncode = fread(f_bufCode, 1, CODE_BUFFER_SIZE, pfile);
if (ncode == EOF || ncode <= 0)
break;
#if ADPCM_COMPRESSION
//解壓縮
nblock = loco_adpcmDecode(f_bufCode, ncode, BLOCK_ALIGN, f_bufSample, SAMPLE_BUFFER_SIZE, SAMPLE_PER_BLOCK);
//寫到設備
if (0 > loco_dspWrite(f_bufSample, nblock*2*SAMPLE_PER_BLOCK))
break;
#else
if (0 > write(f_audiofd, f_bufCode, ncode))
break;
#endif
}while(1);
loco_dspClose();
}
void loco_audioPrompt(const char *apid)
{
FILE *pfile;
char path[SYS_PATH_MAX_LEN];
memset(path, 0, sizeof(path));
if (f_forceStop == 1)
{
return;
}
loco_rcdSetForceStop();
//播放的時候,暫停錄音
loco_rcdStop();
sleep(1);
if (g_sysSampleRate == 16)
{
sprintf(path, "%s%d", apid, g_sysSampleRate);
if (ldb_fileExists(path) == 0)
goto AUDIO_PROMPT_END;
pfile = fopen(path, "rb");
}
else
{
if (ldb_fileExists(apid) == 0)
goto AUDIO_PROMPT_END;
pfile = fopen(apid, "rb");
}
if (pfile != NULL)
{
loco_rcdPlayFile(pfile);
fclose(pfile);
pfile = NULL;
}
AUDIO_PROMPT_END:
loco_rcdStart();
loco_rcdClearForceStop();
}
int loco_testerStart()
{
FILE *pfile;
S_SndDesc tmpDesc;
if (f_forceStop == 1)
{
return 0;
}
loco_rcdSetForceStop();
//停止錄音
loco_rcdStop();
sleep(1);
if (ldb_fileExists(f_prevFileName) == 0)
{
//繼續錄音
loco_rcdStart();
loco_rcdClearForceStop();
return -1;
}
pfile = fopen(f_prevFileName, "rb");
if (pfile == NULL)
{
//繼續錄音
loco_rcdStart();
loco_rcdClearForceStop();
return -1;
}
fread(&tmpDesc, 1, sizeof(tmpDesc), pfile);
loco_rcdPlayFile(pfile);
fclose(pfile);
pfile = NULL;
sleep(1);
loco_rcdStart();
loco_rcdClearForceStop();
return 0;
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -