#include <pthread.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <alsa/asoundlib.h>
#include <math.h>
#define BUFFERSIZE 4096
#define PERIOD_SIZE 1024
#define PERIODS 2
#define SAMPLE_RATE 44100
#define CHANNELS 2
#define FSIZE 2*CHANNELS
/* Use the newer ALSA API */
#define ALSA_PCM_NEW_HW_PARAMS_API
enum MYTHREAD_STATUS {
BGN,
RUNNING,
WAITTING,
CAPTRUING,
STOP,
};
static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
static enum MYTHREAD_STATUS trigger_thread_status = BGN;
static enum MYTHREAD_STATUS audio_capture_thread_status = BGN;
void audio_capture(uint8_t *p_buffer, uint32_t buffer_size);
// This function will be called by another thread to trigger the audio recording
void audio_recording_trigger(void);
void audio_capture(uint8_t *p_buffer, uint32_t buffer_size)
{
long loops; //define the record time.
int rc; //return code.
int size;
snd_pcm_t *handle;
snd_pcm_hw_params_t *params;
unsigned int val;
int dir;
snd_pcm_uframes_t frames;
char *buffer;
int err;
char *file;
int fd;
file = "output.raw";
fd = open(file,O_WRONLY|O_CREAT,0777);
if( fd ==-1) {
printf("open file:%s fail.\n",file);
exit(1);
}
/* Open PCM device for recording (capture). */
err = snd_pcm_open(&handle, "default", SND_PCM_STREAM_CAPTURE, 0);
if (err < 0) {
fprintf(stderr,"unable to open pcm device: %s\n",
snd_strerror(err));
exit(1);
}
/* Allocate a hardware parameters object. */
snd_pcm_hw_params_alloca(¶ms);
/* Fill it in with default values. */
err=snd_pcm_hw_params_any(handle, params);
if (err < 0) {
fprintf(stderr, "Can not configure this PCM device: %s\n",
snd_strerror(err));
exit(1);
}
/* Set the desired hardware parameters. */
/* Interleaved mode */
err=snd_pcm_hw_params_set_access(handle, params,SND_PCM_ACCESS_RW_INTERLEAVED);
if (err < 0) {
fprintf(stderr,
"Failed to set PCM device to interleaved: %s\n",
snd_strerror(err));
exit(1);
}
/* Signed 16-bit little-endian format */
err=snd_pcm_hw_params_set_format(handle, params,SND_PCM_FORMAT_S16_LE);
if (err < 0) {
fprintf(stderr,
"Failed to set PCM device to 16-bit signed PCM: %s\n",
snd_strerror(err));
exit(1);
}
/* One channels (mono) */
/* two channels(stereo) */
// 设置单声道/多声道
err=snd_pcm_hw_params_set_channels(handle, params, CHANNELS);
if (err < 0) {
fprintf(stderr, "Failed to set PCM device to mono: %s\n",
snd_strerror(err));
exit(1);
}
/* 44100 bits/second sampling rate (CD quality) */
val = SAMPLE_RATE;
err=snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir);
if (err < 0) {
fprintf(stderr, "Failed to set PCM device to sample rate =%d: %s\n",
val,snd_strerror(err));
exit(1);
}
/* Set buffer time 500000. */
unsigned int buffer_time, period_time;
snd_pcm_hw_params_get_buffer_time_max(params, &buffer_time, 0);
if ( buffer_time >500000)
buffer_time = 500000;
period_time = buffer_time / 4;
err = snd_pcm_hw_params_set_buffer_time_near(handle, params, &buffer_time, 0);
if (err < 0) {
fprintf(stderr, "Failed to set PCM device to buffer time =%d: %s\n",
buffer_time,snd_strerror(err));
exit(1);
}
err = snd_pcm_hw_params_set_period_time_near(handle, params, &period_time, 0);
if (err < 0) {
fprintf(stderr, "Failed to set PCM device to period time =%d: %s\n",
period_time,snd_strerror(err));
exit(1);
}
/* Write the parameters to the driver */
err = snd_pcm_hw_params(handle, params);
if (err < 0) {
fprintf(stderr,"unable to set hw parameters: %s\n",
snd_strerror(err));
exit(1);
}
/* Use a buffer large enough to hold one period */
snd_pcm_hw_params_get_period_size(params,&frames, &dir);
size = frames * FSIZE; /* 2 bytes/sample, 1 channels */
buffer = (char *) malloc(size);
printf("period size = %d frames\n", (int)frames);
printf("read buffer size = %d\n",size);
/* We want to loop for 10 seconds */
snd_pcm_hw_params_get_period_time(params, &val, &dir);
printf("period time is: %d\n",val);
loops = 10000000 / val;
/*print alsa config parameter*/
snd_pcm_hw_params_get_buffer_time(params, &val, &dir);
printf("buffer time = %d us\n", val);
snd_pcm_hw_params_get_buffer_size(params, (snd_pcm_uframes_t *) &val);
printf("buffer size = %d frames\n", val);
snd_pcm_hw_params_get_periods(params, &val, &dir);
printf("periods per buffer = %d frames\n", val);
while (loops > 0) {
loops--;
//printf("loops = %ld\n", loops);
rc = snd_pcm_readi(handle, buffer, frames);
if (rc == -EPIPE) {
// EPIPE means overrun
fprintf(stderr, "overrun occurred\n");
err=snd_pcm_prepare(handle);
if( err <0) {
fprintf(stderr, "Failed to recover form overrun : %s\n",
snd_strerror(err));
exit(1);
}
} else if (rc < 0) {
fprintf(stderr,"error from read: %s\n",snd_strerror(rc));
exit(1);
} else if (rc != (int)frames) {
fprintf(stderr, "short read, read %d frames\n", rc);
}
rc = write(fd, buffer, size);
if (rc <0) {
perror("fail to write to audio file\n");
}
}
printf("capture thread end.\n");
close(fd);
snd_pcm_drain(handle);
snd_pcm_close(handle);
free(buffer);
}
void *trigger_func(void *);
void *audio_capture_func(void *);
int main(int argc, char *argv[])
{
// TODO: Implement the main function
pthread_t thread1, thread2;
void *thread1_return, *thread2_return;
int wait_thread_end;
pthread_create(&thread1, NULL, trigger_func, NULL);
pthread_create(&thread2, NULL, audio_capture_func, NULL);
wait_thread_end = pthread_join( thread1, &thread1_return );
if( wait_thread_end != 0 ) {
printf("trigger thread call pthread_jion return Error.\n");
} else {
printf("trigger thread call pthread_join success.\n");
}
trigger_thread_status = STOP;
pthread_cond_signal(&cond);
wait_thread_end = pthread_join( thread2, &thread2_return);
if( wait_thread_end != 0 ) {
printf("capture audio thread call pthread_join return Error!\n");
} else {
printf("capture audio thread call pthread_join return success\n");
}
return 0;
}
void *audio_capture_func(void *arg)
{
(void)pthread_mutex_unlock(&mtx); //释放锁
audio_capture_thread_status = BGN;
while (1) {
audio_capture_thread_status = RUNNING;
pthread_mutex_lock(&mtx);
printf("wait triger thread command.\n");
audio_capture_thread_status = WAITTING;
pthread_cond_wait(&cond, &mtx);
audio_capture_thread_status = CAPTRUING;
if (trigger_thread_status == STOP) {
printf("audio_capture_thread end.\n");
pthread_mutex_unlock(&mtx);
break;
}
audio_capture(NULL, 0);
audio_capture_thread_status = WAITTING;
pthread_mutex_unlock(&mtx);
}
return (void *)123;
}
static void print_help(void)
{
printf("Please press a key:\n");
printf(" c : capture audio.\n" );
printf(" e : exit thread.\n");
}
void *trigger_func(void *arg)
{
audio_recording_trigger();
return (void *)456;
}
void audio_recording_trigger(void)
{
// TODO: Implement the audio recording trigger
int i;
print_help();
trigger_thread_status = RUNNING;
while (1) {
i = getchar();
if (i == 'c') {
printf("tell audio capture thread work now.\n");
if (audio_capture_thread_status == CAPTRUING) {
printf("now thread is capture audio.\n");
}
pthread_cond_signal(&cond);
sleep(1);
continue;
} else if (i == 'e') {
trigger_thread_status = STOP;
pthread_cond_signal(&cond);
break;
} else {
printf("Not use this command.\n");
sleep(1);
}
}
printf( "tringger thread end.\n");
}
编译的Makefile:
CC=gcc
CCFLAGS=-g -Wall
LDFLAGS=-lasound -lpthread -lm
all:recordc
recordc:audio.c
$(CC) audio.c $(CCFLAGS) $(LDFLAGS) -o audio
clean:
rm audio output.raw