#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(&params);

    /* 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

05-12 07:04