ALSA Lib-简单的播放例子

参考:https://www.alsa-project.org/alsa-doc/alsa-lib/_2test_2pcm_8c-example.html

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <alsa/asoundlib.h>
#include <unistd.h>

typedef struct {
    char *file_name;
    char *device;
    int ch;
    int bit;
    int rate;
    snd_pcm_format_t format;
    unsigned int buffer_time;
    unsigned int period_time;
    snd_pcm_uframes_t buffer;
    snd_pcm_uframes_t period;
}CONFIG_T;

typedef struct {
    char id[4];
    int size;
}RIFF_HEADER_T;

typedef struct {
    char format[4];
    char sub_id_1[4];
    int sub_size_1;
    short fmt;
    short ch;
    int sample_rate;
    int byte_rate;
    short block_align;
    short bits_per_sample;
}WAVE_HEADER_T;

typedef struct {
    char sub_id_2[4];
    int sub_size_2;
}DATA_HEADER_T;

RIFF_HEADER_T riff_header;
WAVE_HEADER_T wave_header;
DATA_HEADER_T data_header;
CONFIG_T config;

static void help(void)
{
    printf(
"Usage: pcm [OPTION]... [FILE]...
"
"-h,--help  help
"
"-D,--device    playback device
"
"-i,--input_file only support wav file
"
"
");
}

static void parse_cmd(int argc, char **argv)
{
    struct option long_option[] =
    {
        {"help", 0, NULL, 'h'},
        {"device", 1, NULL, 'D'},
        {"input_file", 1, NULL, 'i'},
        {NULL, 0, NULL, 0},
    };
    while (1) {
        int c;
        if ((c = getopt_long(argc, argv, "hD:i:", long_option, NULL)) < 0)
            break;
        switch (c) {
        case 'h':
            help();
            break;
        case 'D':
            config.device = strdup(optarg);
            break;
        case 'i':
            config.file_name = strdup(optarg);
            break;
        }
    }  
}

static snd_pcm_format_t get_format(int bits_per_sample)
{
    snd_pcm_format_t format = SND_PCM_FORMAT_S8;
    switch(bits_per_sample) {
        case 8:
           format =  SND_PCM_FORMAT_S8;
           break;
        case 16:
           format =  SND_PCM_FORMAT_S16_LE;
           break;
       case 24:
           format =  SND_PCM_FORMAT_S24_LE;
           break;
       case 32:
           format =  SND_PCM_FORMAT_S32_LE;
           break;
    }
    return format;
}

static int config_init(CONFIG_T *pConfig)
{
    FILE *fp = NULL;
    if (NULL == pConfig) {
        return -1;
    }
    fp = fopen(pConfig->file_name, "rb");
    if (NULL == fp) {
        return -1;
    }
    
    fread((void *)&riff_header, sizeof(RIFF_HEADER_T), 1, fp);
    fread((void *)&wave_header, sizeof(WAVE_HEADER_T), 1, fp);
     if (wave_header.sub_size_1 > sizeof (WAVE_HEADER_T) -12)
        fseek(fp, wave_header.sub_size_1 - (sizeof (WAVE_HEADER_T) - 12), SEEK_CUR);
    fread((void *)&data_header, sizeof(DATA_HEADER_T), 1, fp);
    pConfig->ch = wave_header.ch;
    pConfig->rate= wave_header.sample_rate;
    pConfig->bit= wave_header.bits_per_sample;
    pConfig->format = get_format(wave_header.bits_per_sample);
    fclose(fp);
    return 0;
}

static int set_hwparams(snd_pcm_t *handle)
{
    snd_pcm_hw_params_t *params;
    unsigned int rrate;
    snd_pcm_uframes_t size;
    int err, dir;
    snd_pcm_hw_params_alloca(&params);
    /* choose all parameters */
    err = snd_pcm_hw_params_any(handle, params);
    if (err < 0) {
        printf("Broken configuration for playback: no configurations available: %s
", snd_strerror(err));
        return err;
    }
      /* set the interleaved read/write format */
    err = snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
    if (err < 0) {
        printf("Access type not available for playback: %s
", snd_strerror(err));
        return err;
    }
    /* set the sample format */
    err = snd_pcm_hw_params_set_format(handle, params, config.format);
    if (err < 0) {
        printf("Sample format not available for playback: %s
", snd_strerror(err));
        return err;
    }
    /* set the count of channels */
    err = snd_pcm_hw_params_set_channels(handle, params, config.ch);
    if (err < 0) {
        printf("Channels count (%u) not available for playbacks: %s
", config.ch, snd_strerror(err));
        return err;
    }
    /* set the stream rate */
    rrate = config.rate;
    err = snd_pcm_hw_params_set_rate_near(handle, params, &rrate, 0);
    if (err < 0) {
        printf("Rate %uHz not available for playback: %s
", config.rate, snd_strerror(err));
        return err;
    }
    if (rrate != config.rate) {
        printf("Rate doesn't match (requested %uHz, get %iHz)
", config.rate, err);
        return -EINVAL;
    }
    /* set the buffer time */
    err = snd_pcm_hw_params_set_buffer_time_near(handle, params, &config.buffer_time, &dir);
    if (err < 0) {
        printf("Unable to set buffer time %u for playback: %s
", config.buffer_time, snd_strerror(err));
        return err;
    }
    err = snd_pcm_hw_params_get_buffer_size(params, &size);
    if (err < 0) {
        printf("Unable to get buffer size for playback: %s
", snd_strerror(err));
        return err;
    }
    config.buffer = size;
    /* set the period time */
    err = snd_pcm_hw_params_set_period_time_near(handle, params, &config.period_time, &dir);
    if (err < 0) {
        printf("Unable to set period time %u for playback: %s
", config.period_time, snd_strerror(err));
        return err;
    }
    err = snd_pcm_hw_params_get_period_size(params, &size, &dir);
    if (err < 0) {
        printf("Unable to get period size for playback: %s
", snd_strerror(err));
        return err;
    }
    config.period = size;
    /* write the parameters to device */
    err = snd_pcm_hw_params(handle, params);
    if (err < 0) {
        printf("Unable to set hw params for playback: %s
", snd_strerror(err));
        return err;
    }
    return 0;
}
static int set_swparams(snd_pcm_t *handle)
{
    int err;
snd_pcm_sw_params_t *swparams; snd_pcm_sw_params_alloca(
&swparams); /* get the current swparams */ err = snd_pcm_sw_params_current(handle, swparams); if (err < 0) { printf("Unable to determine current swparams for playback: %s ", snd_strerror(err)); return err; } /* start the transfer when the buffer is almost full: */ /* (buffer_size / avail_min) * avail_min */ err = snd_pcm_sw_params_set_start_threshold(handle, swparams, (config.buffer / config.period) * config.period); if (err < 0) { printf("Unable to set start threshold mode for playback: %s ", snd_strerror(err)); return err; } /* write the parameters to the playback device */ err = snd_pcm_sw_params(handle, swparams); if (err < 0) { printf("Unable to set sw params for playback: %s ", snd_strerror(err)); return err; } return 0; } /* * Underrun and suspend recovery */ static int xrun_recovery(snd_pcm_t *handle, int err) { printf("stream recovery "); if (err == -EPIPE) { /* under-run */ err = snd_pcm_prepare(handle); if (err < 0) printf("Can't recovery from underrun, prepare failed: %s ", snd_strerror(err)); return 0; } else if (err == -ESTRPIPE) { while ((err = snd_pcm_resume(handle)) == -EAGAIN) sleep(1); /* wait until the suspend flag is released */ if (err < 0) { err = snd_pcm_prepare(handle); if (err < 0) printf("Can't recovery from suspend, prepare failed: %s ", snd_strerror(err)); } return 0; } return err; } static int write_loop(snd_pcm_t *handle) { int err; size_t remain, read_size; FILE *fp = NULL; char *read_buffer = NULL, *offset = NULL; int bytes_per_frame = config.ch * (config.bit >> 3); read_size = config.period * bytes_per_frame; fp = fopen(config.file_name, "rb"); if (NULL == fp) { return -1; } read_buffer = (char * )malloc(read_size); fseek(fp, 44, SEEK_CUR); while (1) { memset(read_buffer ,0, read_size); err = fread(read_buffer ,1, read_size, fp); if (err <= 0) break; offset = read_buffer; remain = err / bytes_per_frame; while (remain> 0) { err = snd_pcm_writei(handle, offset, remain); if (err == -EAGAIN) continue; if (err < 0) { if (xrun_recovery(handle, err) < 0) { printf("Write error: %s ", snd_strerror(err)); exit(EXIT_FAILURE); } continue; } offset += err * bytes_per_frame; remain -= err; } } free(read_buffer); fclose(fp); return 0; } int main(int argc, char **argv) { int err = 0; snd_pcm_t *handle; memset (&config, 0, sizeof(CONFIG_T)); config.buffer_time = 500000;//us config.period_time = 100000; parse_cmd(argc, argv); config_init(&config); if ((err = snd_pcm_open(&handle, config.device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) { printf("Playback open error: %s ", snd_strerror(err)); return 0; } if ((err = set_hwparams(handle)) < 0) { printf("Setting of hwparams failed: %s ", snd_strerror(err)); exit(EXIT_FAILURE); } if ((err = set_swparams(handle)) < 0) { printf("Setting of swparams failed: %s ", snd_strerror(err)); exit(EXIT_FAILURE); } write_loop(handle); snd_pcm_close(handle);
return 0; }

Makefile:

ALSA_INC_PATH=/home/fellow/alsa-lib-1.2.2/output/usr/include
ALSA_LIB_PATH=/usr/lib/i386-linux-gnu
ALSA_PLUG_PATH=/usr/lib/i386-linux-gnu/alsa-lib

export LD_LIBRARY_PATH=${ALSA_LIB_PATH}:${ALSA_PLUG_PATH}:$LD_LIBRARY_PATH
export CC=gcc
export CFLAGS=-I${ALSA_INC_PATH}
export LDFLAGS=-L{ALSA_LIB_PATH} -lasound
SOURCE=alsa_test.c
TARGET=alsa_test
all:
    ${CC} ${SOURCE} ${CFLAGS} ${LDFLAGS} -o ${TARGET}

./alsa_test -D default -i xx.wav

原文地址:https://www.cnblogs.com/fellow1988/p/12373104.html