今天终于完成一个测试程序,开始感觉特别简单,但做的时候发现并不是想象的那么容易
需求:在开发板平台下利用2个线程交替执行,一个负责录音,一个负责播放
我下面的代码是在PC机测试通过,如果需要在开发板中使用,只需要修改其中的参数
但结果是可以测试的,但其中有些问题,会导致效率很低,但这是测试程序,只要可以
用,而且必须加快项目的进度。想到要将主要精力放到项目代码的编写和优化上面。
我下定决心以后要多写博客,原来也参加了很多的比赛也拿了很多奖品,但发现水平还
是不高,后来看到一些特别好的博客,上面的方法真的值得我们学习。
#define ALSA_PCM_NEW_HW_PARAMS_API
#include <stdio.h>#include <stdlib.h>
#include <pthread.h>
#include <string.h>
#include <alsa/asoundlib.h>
#define THRNUM 2
static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
int flag = 1;//此变量是切换录音和播放的关键
char *buffer;//定义全局的char指针,用来存放录音数据[在这里申请空间],播放的时候打印出数据,且释放char指针
/*录音函数*/
{
long loops;
int rc;
int size;
snd_pcm_t *handle;
snd_pcm_hw_params_t *params;
unsigned int val;
int dir;
snd_pcm_uframes_t frames;
rc=snd_pcm_open(&handle,"default",SND_PCM_STREAM_CAPTURE,0);
if (rc < 0) {
fprintf(stderr,"unable to open pcm device\n");
exit(1);
}
snd_pcm_hw_params_alloca(¶ms);
snd_pcm_hw_params_any(handle,params);
snd_pcm_hw_params_set_access(handle,params,SND_PCM_ACCESS_RW_INTERLEAVED);
snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S16_LE);
snd_pcm_hw_params_set_channels(handle,params,2);
val = 44100;
snd_pcm_hw_params_set_rate_near(handle,params,&val,&dir);
frames = 32;
snd_pcm_hw_params_set_period_size_near(handle,params,&frames,&dir);
rc = snd_pcm_hw_params(handle,params);
if (rc < 0) {
fprintf(stderr,"unable to set hw parameters\n");
exit(1);
}
snd_pcm_hw_params_get_period_size(params,&frames,&dir);
size = frames*4;
//printf("size = %d frames = %d\n",size,(int)frames);
buffer = (char *)malloc(size);
snd_pcm_hw_params_get_period_time(params,&val,&dir);
loops = 1000000/val;
while (loops > 0) {
loops--;
//录音只需要将声卡中的数据读到内存中就可以了
rc = snd_pcm_readi(handle,buffer,frames);
//printf("rc === %d frames == %d\n",rc,(int)frames);
if (rc == -EPIPE) {//在录音例子中,如果应用程序读取数据不够快,
//循环缓存区将会被新的数据覆盖。这种数据的丢失被称为overrun.
fprintf(stderr,"overrun\n");
snd_pcm_prepare(handle);
} else if (rc < 0) {
fprintf(stderr,"error form read\n");
} else if (rc != (int)frames) {
fprintf(stderr,"short read rc = %d frames = %d\n",rc,(int)frames);
}
}
printf("录音数据%s\n",buffer);
//free(buffer);
snd_pcm_drain(handle);
snd_pcm_close(handle);
}
/*播放*/
void aplay(void)
{
long loops;
int rc;
int size;
snd_pcm_t *handle;
snd_pcm_hw_params_t *params;
unsigned int val;
int dir;
snd_pcm_uframes_t frames;
if (buffer != NULL)
{
printf("播放数据%s\n",buffer);
}
//打开声卡设备
rc=snd_pcm_open(&handle,"default",SND_PCM_STREAM_PLAYBACK,0);
if (rc < 0) {
fprintf(stderr,"unable to open pcm device\n");
exit(1);
}
//在栈上分配snd_pcm_hw_params_t
snd_pcm_hw_params_alloca(¶ms);
//初始化params
snd_pcm_hw_params_any(handle,params);
//设置为交错访问[记录完帧1的左声道数据和右声道数据,再记录帧2的左声道数据和右声道数据,依次继续]
snd_pcm_hw_params_set_access(handle,params,SND_PCM_ACCESS_RW_INTERLEAVED);
//设置数据格式 主要控制输入的音频数据的类型,无符号,有符号,小端,大端,位数
snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S16_LE);
//设置通道数 双通道[立体声]
snd_pcm_hw_params_set_channels(handle,params,2);
val = 44100;
//设置采样率
snd_pcm_hw_params_set_rate_near(handle,params,&val,&dir);
frames = 32;
//
snd_pcm_hw_params_set_period_size_near(handle,params,&frames,&dir);
//设置params
rc = snd_pcm_hw_params(handle,params);
if (rc < 0) {
fprintf(stderr,"unable to set hw parameters\n");
exit(1);
}
snd_pcm_hw_params_get_period_size(params,&frames,&dir);
size = frames*4;
snd_pcm_hw_params_get_period_time(params,&val,&dir);
loops = 1000000/val;
while (loops > 0) {
loops--;
rc = snd_pcm_writei(handle,buffer,frames);
if (rc == -EPIPE) {
//
fprintf(stderr,"underrun\n");
snd_pcm_prepare(handle);
} else if (rc < 0) {
fprintf(stderr,"error form read\n");
} else if (rc != (int)frames) {
fprintf(stderr,"short read rc = %d frames = %d\n",rc,(int)frames);
}
}
snd_pcm_drain(handle);
snd_pcm_close(handle);
free(buffer);
}
void *thr_func1(void *p)
{
while(1)
{
//加锁
pthread_mutex_lock(&mut);
while(flag != 1)
pthread_cond_wait(&cond,&mut);
//这里来调用录音函数
printf("录音开始\n");
arecord();
printf("录音结束\n");
printf("##################\n");
flag = 0;
pthread_cond_broadcast(&cond);
pthread_mutex_unlock(&mut);
}
pthread_exit(NULL);
}
void *thr_func2(void *p)
{
while(1)
{
pthread_mutex_lock(&mut);
while(flag != 0)
pthread_cond_wait(&cond,&mut);
//这里要调用播放函数
printf("播放开始\n");
aplay();
printf("播放结束\n");
flag = 1;
pthread_cond_broadcast(&cond);
pthread_mutex_unlock(&mut);
}
pthread_exit(NULL);
}
int main()
{
int i,err;
void *data = NULL;
pthread_t tid[THRNUM];
//for(i = 0 ; i < THRNUM ; i++)
{
err = pthread_create(tid+0,NULL,thr_func1,data);
if(err)
{
fprintf(stderr,"pthread_create():%s\n",strerror(err));
exit(1);
}
err = pthread_create(tid+1,NULL,thr_func2,data);
}
alarm(20);
for(i = 0 ; i < THRNUM ; i++)
pthread_join(tid[i],NULL);
exit(0);
}
最后说下其实这个程序特别简单,高手千万别吐,希望和大家一起进步,一起学习。