alsa wav

Posted 周学伟

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了alsa wav相关的知识,希望对你有一定的参考价值。

这段时间在探索ALSA架构,从ALSA Core到ALSA Lib,再到android Audio System。在看ALSA Lib时,写了一个比较典型的基于ALSA的播放录音程序。程序包包含四个部分:WAV Parser、SND Common、Playback和Record。WAV Parser是对WAV文件的分析和封装,这里只针对Standard WAV File;SND Common是Playback 和Record共同操作,如SetParams、ReadPCM和WritePCM等;Playback和Record就分别是播放录音的主体了。原理很 简单,以Playback为例:从WAV文件读取PCM数据,通过I2S或AC97依次送到Audio Codec。

难点在于对snd_pcm_hw_params_t的设置,尤其 完整的源代码你可以在这儿下载到:http://bbs.rosoo.net/forum.php?mod=viewthread&tid=6087

1/ 从WAV文件的头信息可以分析出:sample_format、channels number、sample_rate、sample_length,这些参数要通过snd_pcm_hw_params_set_XXX()接口设置到 snd_pcm_hw_params_t中。

2/ 接着我们要设置buffer_time 和peroid_time。通过snd_pcm_hw_params_get_buffer_time_max()接口可以获取该Audio Codec可以支持的最大buffer_time,这里我们设置buffer_time = (MAX_BUFFER_TIME > 500000) ? 500000 : MAX_BUFFER_TIME; peroid_time = buffer_time/4。

【关 于peroid的概念有这样的描述:The “period” is a term that corresponds to a fragment in the OSS world. The period defines the size at which a PCM interrupt is generated. 从底层驱动看来,应该是PCM DMA单次传送数据帧的大小。其实真正关注底层驱动的话,它并不是关心peroid_time,它关心的是peroid_size,这两者有转换关系。具 体见struct snd_pcm_hardware结构体。】

3/ 通过snd_pcm_hw_params_get_period_size()取得peroid_size,注意在ALSA中peroid_size是以 frame为单位的。The configured buffer and period sizes are stored in “frames” in the runtime. 1 frame = channels * sample_size. 所以要对peroid_size进行转换:chunk_bytes = peroid_size * sample_length / 8。chunk_bytes就是我们单次从WAV读PCM数据的大小。

之后的过程就乏善可陈了。唯一要留意的是snd_pcm_writei()和snd_pcm_readi()的第三个参数size也是以frame为单位,不要忘记frames和bytes的转换。

wav_parser.h文件:

    //File   : wav_parser.h 
    //Author : Loon <[email protected]> 
     
    #ifndef __WAV_PARSER_H 
    #define __WAV_PARSER_H 
     
    typedef unsigned char  uint8_t; 
    typedef unsigned short uint16_t; 
    typedef unsigned int   uint32_t; 
     
    #if __BYTE_ORDER == __LITTLE_ENDIAN 
    #define COMPOSE_ID(a,b,c,d) ((a) | ((b)<<8) | ((c)<<16) | ((d)<<24)) 
    #define LE_SHORT(v)           (v) 
    #define LE_INT(v)               (v) 
    #define BE_SHORT(v)           bswap_16(v) 
    #define BE_INT(v)               bswap_32(v) 
    #elif __BYTE_ORDER == __BIG_ENDIAN 
    #define COMPOSE_ID(a,b,c,d) ((d) | ((c)<<8) | ((b)<<16) | ((a)<<24)) 
    #define LE_SHORT(v)           bswap_16(v) 
    #define LE_INT(v)               bswap_32(v) 
    #define BE_SHORT(v)           (v) 
    #define BE_INT(v)               (v) 
    #else 
    #error "Wrong endian" 
    #endif 
     
    #define WAV_RIFF        COMPOSE_ID(‘R‘,‘I‘,‘F‘,‘F‘) 
    #define WAV_WAVE        COMPOSE_ID(‘W‘,‘A‘,‘V‘,‘E‘) 
    #define WAV_FMT         COMPOSE_ID(‘f‘,‘m‘,‘t‘,‘ ‘) 
    #define WAV_DATA        COMPOSE_ID(‘d‘,‘a‘,‘t‘,‘a‘) 
     
    /* WAVE fmt block constants from Microsoft mmreg.h header */ 
    #define WAV_FMT_PCM             0x0001 
    #define WAV_FMT_IEEE_FLOAT      0x0003 
    #define WAV_FMT_DOLBY_AC3_SPDIF 0x0092 
    #define WAV_FMT_EXTENSIBLE      0xfffe 
     
    /* Used with WAV_FMT_EXTENSIBLE format */ 
    #define WAV_GUID_TAG "/x00/x00/x00/x00/x10/x00/x80/x00/x00/xAA/x00/x38/x9B/x71" 
     
    /* it‘s in chunks like .voc and AMIGA iff, but my source say there 
       are in only in this combination, so I combined them in one header; 
       it works on all WAVE-file I have 
     */ 
    typedef struct WAVHeader { 
        uint32_t magic;     /* ‘RIFF‘ */ 
        uint32_t length;        /* filelen */ 
        uint32_t type;      /* ‘WAVE‘ */ 
    } WAVHeader_t; 
     
    typedef struct WAVFmt { 
        uint32_t magic;  /* ‘FMT ‘*/ 
        uint32_t fmt_size; /* 16 or 18 */ 
        uint16_t format;        /* see WAV_FMT_* */ 
        uint16_t channels; 
        uint32_t sample_rate;   /* frequence of sample */ 
        uint32_t bytes_p_second; 
        uint16_t blocks_align;  /* samplesize; 1 or 2 bytes */ 
        uint16_t sample_length; /* 8, 12 or 16 bit */ 
    } WAVFmt_t; 
     
    typedef struct WAVFmtExtensible { 
        WAVFmt_t format; 
        uint16_t ext_size; 
        uint16_t bit_p_spl; 
        uint32_t channel_mask; 
        uint16_t guid_format;   /* WAV_FMT_* */ 
        uint8_t guid_tag[14];   /* WAV_GUID_TAG */ 
    } WAVFmtExtensible_t; 
     
    typedef struct WAVChunkHeader { 
        uint32_t type;      /* ‘data‘ */ 
        uint32_t length;        /* samplecount */ 
    } WAVChunkHeader_t; 
     
    typedef struct WAVContainer { 
        WAVHeader_t header; 
        WAVFmt_t format; 
        WAVChunkHeader_t chunk; 
    } WAVContainer_t; 
     
    int WAV_ReadHeader(int fd, WAVContainer_t *container); 
     
    int WAV_WriteHeader(int fd, WAVContainer_t *container); 
     
    #endif /* #ifndef __WAV_PARSER_H */ 

wav_parser.c

 

    //File   : wav_parser.c 
    //Author : Loon <[email protected]> 
     
    #include <assert.h> 
    #include <stdio.h> 
    #include <stdlib.h> 
    #include <unistd.h> 
    #include <fcntl.h> 
     
    #include "wav_parser.h" 
     
    #define WAV_PRINT_MSG 
     
    char *WAV_P_FmtString(uint16_t fmt) 
    { 
        switch (fmt) { 
        case WAV_FMT_PCM: 
            return "PCM"; 
            break; 
        case WAV_FMT_IEEE_FLOAT: 
            return "IEEE FLOAT"; 
            break; 
        case WAV_FMT_DOLBY_AC3_SPDIF: 
            return "DOLBY AC3 SPDIF"; 
            break; 
        case WAV_FMT_EXTENSIBLE: 
            return "EXTENSIBLE"; 
            break; 
        default: 
            break; 
        } 
     
        return "NON Support Fmt"; 
    } 
     
    void WAV_P_PrintHeader(WAVContainer_t *container) 
    { 
        printf("+++++++++++++++++++++++++++/n"); 
        printf("/n"); 
         
        printf("File Magic:         [%c%c%c%c]/n",  
            (char)(container->header.magic),  
            (char)(container->header.magic>>8),  
            (char)(container->header.magic>>16),  
            (char)(container->header.magic>>24)); 
    printf("File Length:        [%d]/n", container->header.length); 
    printf("File Type:          [%c%c%c%c]/n", 
      (char)(container->header.type),  
      (char)(container->header.type>>8),  
      (char)(container->header.type>>16),  
      (char)(container->header.type>>24));
    printf("/n"); 
    printf("Fmt Magic:          [%c%c%c%c]/n", 
      (char)(container->format.magic),  
      (char)(container->format.magic>>8),  
      (char)(container->format.magic>>16),  
      (char)(container->format.magic>>24)); 
    printf("Fmt Size:           [%d]/n", container->format.fmt_size); 
    printf("Fmt Format:         [%s]/n", WAV_P_FmtString(container->format.format)); 
    printf("Fmt Channels:       [%d]/n", container->format.channels); 
    printf("Fmt Sample_rate:    [%d](HZ)/n", container->format.sample_rate); 
    printf("Fmt Bytes_p_second: [%d]/n", container->format.bytes_p_second); 
    printf("Fmt Blocks_align:   [%d]/n", container->format.blocks_align); 
    printf("Fmt Sample_length:  [%d]/n", container->format.sample_length); 
         
        printf("/n"); 
     
        printf("Chunk Type:         [%c%c%c%c]/n", 
            (char)(container->chunk.type),  
            (char)(container->chunk.type>>8),  
            (char)(container->chunk.type>>16),  
            (char)(container->chunk.type>>24)); 
        printf("Chunk Length: [%d]/n", container->chunk.length); 
         
        printf("/n"); 
        printf("++++++++++++++++++++++++++++++++++++++/n"); 
    } 
     
    int WAV_P_CheckValid(WAVContainer_t *container) 
    { 
        if (container->header.magic != WAV_RIFF || 
            container->header.type != WAV_WAVE || 
            container->format.magic != WAV_FMT || 
            container->format.fmt_size != LE_INT(16) || 
    (container->format.channels != LE_SHORT(1) && container->format.channels != LE_SHORT(2))
     || container->chunk.type != WAV_DATA) {
            fprintf(stderr, "non standard wav file./n"); 
            return -1; 
        } 
     
        return 0; 
    } 
     
    int WAV_ReadHeader(int fd, WAVContainer_t *container) 
    { 
        assert((fd >=0) && container); 
     
    if (read(fd,&container->header,sizeof(container->header))!=sizeof(container->header)
    ||read(fd,&container->format,sizeof(container->format))!=sizeof(container->format)
    ||read(fd,&container->chunk,sizeof(container->chunk))!=sizeof(container->chunk)){
     
            fprintf(stderr, "Error WAV_ReadHeader/n"); 
            return -1; 
        } 
     
        if (WAV_P_CheckValid(container) < 0) 
            return -1; 
     
    #ifdef WAV_PRINT_MSG 
        WAV_P_PrintHeader(container); 
    #endif 
     
        return 0; 
    } 
     
    int WAV_WriteHeader(int fd, WAVContainer_t *container) 
    { 
        assert((fd >=0) && container); 
         
        if (WAV_P_CheckValid(container) < 0) 
            return -1; 
     
    if (write(fd,&container->header,sizeof(container->header))!=sizeof(container->header)
    ||write(fd,&container->format,sizeof(container->format))!=sizeof(container->format)
    ||write(fd,&container->chunk,sizeof(container->chunk))!=sizeof(container->chunk)) { 
            fprintf(stderr, "Error WAV_WriteHeader/n"); 
            return -1; 
        } 
     
    #ifdef WAV_PRINT_MSG 
        WAV_P_PrintHeader(container); 
    #endif 
     
        return 0; 
    } 

 

sndwav_common.h

 

    //File   : sndwav_common.h 
    //Author : Loon <[email protected]> 
     
    #ifndef __SNDWAV_COMMON_H 
    #define __SNDWAV_COMMON_H 
     
    #include <stdio.h> 
    #include <stdlib.h> 
    #include <unistd.h> 
    #include <fcntl.h> 
    #include "wav_parser.h" 
     
    typedef long long off64_t; 
     
    typedef struct SNDPCMContainer { 
        snd_pcm_t *handle; 
        snd_output_t *log; 
        snd_pcm_uframes_t chunk_size; 
        snd_pcm_uframes_t buffer_size; 
        snd_pcm_format_t format; 
        uint16_t channels; 
        size_t chunk_bytes; 
        size_t bits_per_sample; 
        size_t bits_per_frame; 
     
        uint8_t *data_buf; 
    } SNDPCMContainer_t; 
     
    ssize_t SNDWAV_ReadPcm(SNDPCMContainer_t *sndpcm, size_t rcount); 
     
    ssize_t SNDWAV_WritePcm(SNDPCMContainer_t *sndpcm, size_t wcount); 
     
    int SNDWAV_SetParams(SNDPCMContainer_t *sndpcm, WAVContainer_t *wav); 
    #endif /* #ifndef __SNDWAV_COMMON_H */ 

 

 

 

sndwav_common.c
    #include <assert.h> 
    #include <stdio.h> 
    #include <stdlib.h> 
    #include <unistd.h> 
    #include <fcntl.h> 
    #include <alsa/asoundlib.h> 
     
    #include "sndwav_common.h" 
     
    int SNDWAV_P_GetFormat(WAVContainer_t *wav, snd_pcm_format_t *snd_format) 
    {    
        if (LE_SHORT(wav->format.format) != WAV_FMT_PCM) 
            return -1; 
         
        switch (LE_SHORT(wav->format.sample_length)) { 
        case 16: 
            *snd_format = SND_PCM_FORMAT_S16_LE; 
            break; 
        case 8: 
            *snd_format = SND_PCM_FORMAT_U8; 
            break; 
        default: 
            *snd_format = SND_PCM_FORMAT_UNKNOWN; 
            break; 
        } 
     
        return 0; 
    } 
     
    ssize_t SNDWAV_ReadPcm(SNDPCMContainer_t *sndpcm, size_t rcount) 
    { 
        ssize_t r; 
        size_t result = 0; 
        size_t count = rcount; 
        uint8_t *data = sndpcm->data_buf; 
     
        if (count != sndpcm->chunk_size) { 
            count = sndpcm->chunk_size; 
        } 
     
        while (count > 0) { 
            r = snd_pcm_readi(sndpcm->handle, data, count); 
            if (r == -EAGAIN || (r >= 0 && (size_t)r < count)) { 
    snd_pcm_wait(sndpcm->handle, 1000); 
            } else if (r == -EPIPE) { 
    snd_pcm_prepare(sndpcm->handle); 
    fprintf(stderr, "<<<<<<<<<<<<<<< Buffer Underrun >>>>>>>>>>>>>>>/n"); 
            } else if (r == -ESTRPIPE) { 
    fprintf(stderr, "<<<<<<<<<<<<<<< Need suspend >>>>>>>>>>>>>>>/n"); 
            } else if (r < 0) { 
    fprintf(stderr, "Error snd_pcm_writei: [%s]", snd_strerror(r)); 
    exit(-1); 
            } 
             
            if (r > 0) { 
                result += r; 
                count -= r; 
                data += r * sndpcm->bits_per_frame / 8; 
            } 
        } 
        return rcount; 
    } 
     
    ssize_t SNDWAV_WritePcm(SNDPCMContainer_t *sndpcm, size_t wcount) 
    { 
        ssize_t r; 
        ssize_t result = 0; 
        uint8_t *data = sndpcm->data_buf; 
     
        if (wcount < sndpcm->chunk_size) { 
            snd_pcm_format_set_silence(sndpcm->format,  
                data + wcount * sndpcm->bits_per_frame / 8,  
                (sndpcm->chunk_size - wcount) * sndpcm->channels); 
            wcount = sndpcm->chunk_size; 
        } 
        while (wcount > 0) { 
            r = snd_pcm_writei(sndpcm->handle, data, wcount); 
            if (r == -EAGAIN || (r >= 0 && (size_t)r < wcount)) { 
    snd_pcm_wait(sndpcm->handle, 1000); 
            } else if (r == -EPIPE) { 
    snd_pcm_prepare(sndpcm->handle); 
    fprintf(stderr, "<<<<<<<<<<<<<<< Buffer Underrun >>>>>>>>>>>>>>>/n"); 
            } else if (r == -ESTRPIPE) {             
    fprintf(stderr, "<<<<<<<<<<<<<<< Need suspend >>>>>>>>>>>>>>>/n");       
            } else if (r < 0) { 
    fprintf(stderr, "Error snd_pcm_writei: [%s]", snd_strerror(r)); 
    exit(-1); 
            } 
            if (r > 0) { 
                result += r; 
                wcount -= r; 
                data += r * sndpcm->bits_per_frame / 8; 
            } 
        } 
        return result; 
    } 
     
    int SNDWAV_SetParams(SNDPCMContainer_t *sndpcm, WAVContainer_t *wav) 
    { 
        snd_pcm_hw_params_t *hwparams; 
        snd_pcm_format_t format; 
        uint32_t exact_rate; 
        uint32_t buffer_time, period_time; 
     
        /* Allocate the snd_pcm_hw_params_t structure on the stack. */ 
        snd_pcm_hw_params_alloca(&hwparams); 
         
        /* Init hwparams with full configuration space */ 
        if (snd_pcm_hw_params_any(sndpcm->handle, hwparams) < 0) { 
            fprintf(stderr, "Error snd_pcm_hw_params_any/n"); 
            goto ERR_SET_PARAMS; 
        } 
     
        if (snd_pcm_hw_params_set_access(sndpcm->handle, hwparams
    , SND_PCM_ACCESS_RW_INTERLEAVED) < 0) { 
            fprintf(stderr, "Error snd_pcm_hw_params_set_access/n"); 
            goto ERR_SET_PARAMS; 
        } 
     
        /* Set sample format */ 
        if (SNDWAV_P_GetFormat(wav, &format) < 0) { 
            fprintf(stderr, "Error get_snd_pcm_format/n"); 
            goto ERR_SET_PARAMS; 
        } 
        if (snd_pcm_hw_params_set_format(sndpcm->handle, hwparams, format) < 0) { 
            fprintf(stderr, "Error snd_pcm_hw_params_set_format/n"); 
            goto ERR_SET_PARAMS; 
        } 
        sndpcm->format = format; 
     
        /* Set number of channels */ 
        if (snd_pcm_hw_params_set_channels(sndpcm->handle, hwparams
    , LE_SHORT(wav->format.channels)) < 0) { 
            fprintf(stderr, "Error snd_pcm_hw_params_set_channels/n"); 
            goto ERR_SET_PARAMS; 
        } 
        sndpcm->channels = LE_SHORT(wav->format.channels); 
     
        /* Set sample rate. If the exact rate is not supported */ 
        /* by the hardware, use nearest possible rate.         */  
        exact_rate = LE_INT(wav->format.sample_rate); 
    if (snd_pcm_hw_params_set_rate_near(sndpcm->handle, hwparams, &exact_rate, 0) < 0) { 
            fprintf(stderr, "Error snd_pcm_hw_params_set_rate_near/n"); 
            goto ERR_SET_PARAMS; 
        } 
        if (LE_INT(wav->format.sample_rate) != exact_rate) { 
            fprintf(stderr
    , "The rate %d Hz is not supported by your hardware./n ==> Using %d Hz instead./n",  
                LE_INT(wav->format.sample_rate), exact_rate); 
        } 
     
        if (snd_pcm_hw_params_get_buffer_time_max(hwparams, &buffer_time, 0) < 0) { 
            fprintf(stderr, "Error snd_pcm_hw_params_get_buffer_time_max/n"); 
            goto ERR_SET_PARAMS; 
        } 
        if (buffer_time > 500000) buffer_time = 500000; 
        period_time = buffer_time / 4; 
     
        if (snd_pcm_hw_params_set_buffer_time_near(sndpcm->handle, hwparams
    , &buffer_time, 0) < 0) { 
            fprintf(stderr, "Error snd_pcm_hw_params_set_buffer_time_near/n"); 
            goto ERR_SET_PARAMS; 
        } 
     
        if (snd_pcm_hw_params_set_period_time_near(sndpcm->handle, hwparams
    , &period_time, 0) < 0) { 
            fprintf(stderr, "Error snd_pcm_hw_params_set_period_time_near/n"); 
            goto ERR_SET_PARAMS; 
        } 
     
        /* Set hw params */ 
        if (snd_pcm_hw_params(sndpcm->handle, hwparams) < 0) { 
            fprintf(stderr, "Error snd_pcm_hw_params(handle, params)/n"); 
            goto ERR_SET_PARAMS; 
        } 
     
        snd_pcm_hw_params_get_period_size(hwparams, &sndpcm->chunk_size, 0);     
        snd_pcm_hw_params_get_buffer_size(hwparams, &sndpcm->buffer_size); 
        if (sndpcm->chunk_size == sndpcm->buffer_size) {         
            fprintf(stderr, ("Can‘t use period equal to buffer size (%lu == %lu)/n")
    , sndpcm->chunk_size, sndpcm->buffer_size);      
            goto ERR_SET_PARAMS; 
        } 
     
        sndpcm->bits_per_sample = snd_pcm_format_physical_width(format); 
        sndpcm->bits_per_frame = sndpcm->bits_per_sample * LE_SHORT(wav->format.channels); 
         
        sndpcm->chunk_bytes = sndpcm->chunk_size * sndpcm->bits_per_frame / 8; 
     
        /* Allocate audio data buffer */ 
        sndpcm->data_buf = (uint8_t *)malloc(sndpcm->chunk_bytes); 
        if (!sndpcm->data_buf) { 
            fprintf(stderr, "Error malloc: [data_buf]/n"); 
            goto ERR_SET_PARAMS; 
        } 
     
        return 0; 
     
    ERR_SET_PARAMS: 
        return -1; 
    } 

 

 

 

 

lplay.c

    #include <stdio.h> 
    #include <malloc.h> 
    #include <unistd.h> 
    #include <stdlib.h> 
    #include <string.h> 
    #include <getopt.h> 
    #include <fcntl.h> 
    #include <ctype.h> 
    #include <errno.h> 
    #include <limits.h> 
    #include <time.h> 
    #include <locale.h> 
    #include <sys/unistd.h> 
    #include <sys/stat.h> 
    #include <sys/types.h> 
    #include <alsa/asoundlib.h> 
    #include <assert.h> 
    #include "wav_parser.h" 
    #include "sndwav_common.h" 
     
    ssize_t SNDWAV_P_SaveRead(int fd, void *buf, size_t count) 
    { 
        ssize_t result = 0, res; 
     
        while (count > 0) { 
            if ((res = read(fd, buf, count)) == 0) 
                break; 
            if (res < 0) 
                return result > 0 ? result : res; 
            count -= res; 
            result += res; 
            buf = (char *)buf + res; 
        } 
        return result; 
    } 
     
    void SNDWAV_Play(SNDPCMContainer_t *sndpcm, WAVContainer_t *wav, int fd) 
    { 
        int load, ret; 
        off64_t written = 0; 
        off64_t c; 
        off64_t count = LE_INT(wav->chunk.length); 
     
        load = 0; 
        while (written < count) { 
            /* Must read [chunk_bytes] bytes data enough. */ 
            do { 
                c = count - written; 
                if (c > sndpcm->chunk_bytes) 
                    c = sndpcm->chunk_bytes; 
                c -= load; 
     
                if (c == 0) 
                    break; 
                ret = SNDWAV_P_SaveRead(fd, sndpcm->data_buf + load, c); 
                if (ret < 0) { 
                    fprintf(stderr, "Error safe_read/n"); 
                    exit(-1); 
                } 
                if (ret == 0) 
                    break; 
                load += ret; 
            } while ((size_t)load < sndpcm->chunk_bytes); 
     
            /* Transfer to size frame */ 
            load = load * 8 / sndpcm->bits_per_frame; 
            ret = SNDWAV_WritePcm(sndpcm, load); 
            if (ret != load) 
                break; 
             
            ret = ret * sndpcm->bits_per_frame / 8; 
            written += ret; 
            load = 0; 
        } 
    } 
     
    int main(int argc, char *argv[]) 
    { 
        char *filename; 
        char *devicename = "default"; 
        int fd; 
        WAVContainer_t wav; 
        SNDPCMContainer_t playback; 
         
        if (argc != 2) { 
            fprintf(stderr, "Usage: ./lplay <FILENAME>/n"); 
            return -1; 
        } 
         
        memset(&playback, 0x0, sizeof(playback)); 
     
        filename = argv[1]; 
        fd = open(filename, O_RDONLY); 
        if (fd < 0) { 
            fprintf(stderr, "Error open [%s]/n", filename); 
            return -1; 
        } 
         
        if (WAV_ReadHeader(fd, &wav) < 0) { 
            fprintf(stderr, "Error WAV_Parse [%s]/n", filename); 
            goto Err; 
        } 
     
        if (snd_output_stdio_attach(&playback.log, stderr, 0) < 0) {
            fprintf(stderr, "Error snd_output_stdio_attach/n"); 
            goto Err; 
        } 
     
        if (snd_pcm_open(&playback.handle, devicename, SND_PCM_STREAM_PLAYBACK, 0) < 0) { 
            fprintf(stderr, "Error snd_pcm_open [ %s]/n", devicename); 
            goto Err; 
        } 
     
        if (SNDWAV_SetParams(&playback, &wav) < 0) { 
            fprintf(stderr, "Error set_snd_pcm_params/n"); 
            goto Err; 
        } 
        snd_pcm_dump(playback.handle, playback.log); 
     
        SNDWAV_Play(&playback, &wav, fd); 
     
        snd_pcm_drain(playback.handle); 
     
        close(fd); 
        free(playback.data_buf); 
        snd_output_close(playback.log); 
        snd_pcm_close(playback.handle); 
        return 0; 
     
    Err: 
        close(fd); 
        if (playback.data_buf) free(playback.data_buf); 
        if (playback.log) snd_output_close(playback.log); 
        if (playback.handle) snd_pcm_close(playback.handle); 
        return -1; 
    } 

 

lrecord.c

 

    #include <stdio.h> 
    #include <malloc.h> 
    #include <unistd.h> 
    #include <stdlib.h> 
    #include <string.h> 
    #include <getopt.h> 
    #include <fcntl.h> 
    #include <ctype.h> 
    #include <errno.h> 
    #include <limits.h> 
    #include <time.h> 
    #include <locale.h> 
    #include <sys/unistd.h> 
    #include <sys/stat.h> 
    #include <sys/types.h> 
    #include <alsa/asoundlib.h> 
    #include <assert.h> 
    #include "wav_parser.h" 
    #include "sndwav_common.h" 
     
    #define DEFAULT_CHANNELS         (2) 
    #define DEFAULT_SAMPLE_RATE      (8000) 
    #define DEFAULT_SAMPLE_LENGTH    (16) 
    #define DEFAULT_DURATION_TIME    (10) 
     
    int SNDWAV_PrepareWAVParams(WAVContainer_t *wav) 
    { 
        assert(wav); 
     
        uint16_t channels = DEFAULT_CHANNELS; 
        uint16_t sample_rate = DEFAULT_SAMPLE_RATE; 
        uint16_t sample_length = DEFAULT_SAMPLE_LENGTH; 
        uint32_t duration_time = DEFAULT_DURATION_TIME; 
     
        /* Const */ 
        wav->header.magic = WAV_RIFF; 
        wav->header.type = WAV_WAVE; 
        wav->format.magic = WAV_FMT; 
        wav->format.fmt_size = LE_INT(16); 
        wav->format.format = LE_SHORT(WAV_FMT_PCM); 
        wav->chunk.type = WAV_DATA; 
     
        /* User definition */ 
        wav->format.channels = LE_SHORT(channels); 
        wav->format.sample_rate = LE_INT(sample_rate); 
        wav->format.sample_length = LE_SHORT(sample_length); 
     
        /* See format of wav file */ 
    wav->format.blocks_align = LE_SHORT(channels * sample_length / 8); 
    wav->format.bytes_p_second = LE_INT((uint16_t)(wav->format.blocks_align) * sample_rate); 
         
    wav->chunk.length = LE_INT(duration_time * (uint32_t)(wav->format.bytes_p_second)); 
    wav->header.length = LE_INT((uint32_t)(wav->chunk.length) +/ 
            sizeof(wav->chunk) + sizeof(wav->format) + sizeof(wav->header) - 8); 
     
        return 0; 
    } 
     
    void SNDWAV_Record(SNDPCMContainer_t *sndpcm, WAVContainer_t *wav, int fd) 
    { 
        off64_t rest; 
        size_t c, frame_size; 
         
        if (WAV_WriteHeader(fd, wav) < 0) { 
            exit(-1); 
        } 
     
        rest = wav->chunk.length; 
        while (rest > 0) { 
            c = (rest <= (off64_t)sndpcm->chunk_bytes) ? (size_t)rest : sndpcm->chunk_bytes; 
            frame_size = c * 8 / sndpcm->bits_per_frame; 
            if (SNDWAV_ReadPcm(sndpcm, frame_size) != frame_size) 
                break; 
             
            if (write(fd, sndpcm->data_buf, c) != c) { 
                fprintf(stderr, "Error SNDWAV_Record[write]/n"); 
                exit(-1); 
            } 
     
            rest -= c; 
        } 
    } 
     
    int main(int argc, char *argv[]) 
    { 
        char *filename; 
        char *devicename = "default"; 
        int fd; 
        WAVContainer_t wav; 
        SNDPCMContainer_t record; 
         
        if (argc != 2) { 
            fprintf(stderr, "Usage: ./lrecord <FILENAME>/n"); 
            return -1; 
        } 
         
        memset(&record, 0x0, sizeof(record)); 
     
        filename = argv[1]; 
        remove(filename); 
        if ((fd = open(filename, O_WRONLY | O_CREAT, 0644)) == -1) { 
            fprintf(stderr, "Error open: [%s]/n", filename); 
            return -1; 
        } 
     
        if (snd_output_stdio_attach(&record.log, stderr, 0) < 0) { 
            fprintf(stderr, "Error snd_output_stdio_attach/n"); 
            goto Err; 
        } 
     
        if (snd_pcm_open(&record.handle, devicename, SND_PCM_STREAM_CAPTURE, 0) < 0) { 
            fprintf(stderr, "Error snd_pcm_open [ %s]/n", devicename); 
            goto Err; 
        } 
     
        if (SNDWAV_PrepareWAVParams(&wav) < 0) { 
            fprintf(stderr, "Error SNDWAV_PrepareWAVParams/n"); 
            goto Err; 
        } 
     
        if (SNDWAV_SetParams(&record, &wav) < 0) { 
            fprintf(stderr, "Error set_snd_pcm_params/n"); 
            goto Err; 
        } 
        snd_pcm_dump(record.handle, record.log); 
     
        SNDWAV_Record(&record, &wav, fd); 
     
        snd_pcm_drain(record.handle); 
     
        close(fd); 
        free(record.data_buf); 
        snd_output_close(record.log); 
        snd_pcm_close(record.handle); 
        return 0; 
     
    Err: 
        close(fd); 
        remove(filename); 
        if (record.data_buf) free(record.data_buf); 
        if (record.log) snd_output_close(record.log); 
        if (record.handle) snd_pcm_close(record.handle); 
        return -1; 
    } 

 

 

 

 

 

 

makefile

CC =/home/yuanpengjun/ngi/prebuilt/toolchains/arm-fsl-Linux-gnueabi/4.6.2/bin/arm-fsl-linux-gnueabi-gcc
CFLAGS = -g -Wall -O0 -I/home/yuanpengjun/ngi/externals/alsa-lib/include
LIBS = -L/home/yuanpengjun/ngi/out/target/product/rome/system/usr/lib -lasound

lplay: lplay.o sndwav_common.o wav_parser.o
 $(CC) $(CFLAGS) lplay.o sndwav_common.o wav_parser.o -o lplay $(LIBS)

lplay.o: lplay.c  sndwav_common.h wav_parser.h

$(CC) $(CFLAGS) -c lplay.c  

lrecord: lrecord.o sndwav_common.o wav_parser.o

 $(CC) $(CFLAGS) lrecord.o sndwav_common.o wav_parser.o -o lrecord $(LIBS)

lrecord.o: lrecord.c sndwav_common.h  wav_parser.h

$(CC) $(CFLAGS) -c lrecord.c 

sndwav_common.o: sndwav_common.c sndwav_common.h

$(CC) $(CFLAGS) -c sndwav_common.c 

wav_parser.o: wav_parser.c wav_parser.h

$(CC) $(CFLAGS) -c wav_parser.c

clean:

rm lplay lrecord *.o

 

以上是关于alsa wav的主要内容,如果未能解决你的问题,请参考以下文章

嵌入式流媒体开发Linux ALSA 声卡数据采集与播放

在 C 中使用 ALSA 以不同的音量播放多个 wav 文件

A40i使用笔记:使用QT调用aplay播放wav音频/混音

如何在 Windows 上使用 gstreamer 播放 .wav 音频文件?

C++如何播放wav声音文件.Linux系统

Linux ALSA 音频库 配置和使用