基于ALSA的WAV播放和录音程序

ALSA音频开发实战:如何用snd_pcm_avail避免缓冲区溢出(附完整代码) 本文深入探讨了在ALSA音频开发中,如何利用`snd_pcm_avail`函数有效管理环形缓冲区,从而避免音频数据溢出或下溢。通过实战代码示例,详细解析了该函数在播放场景下的核心作用,即实时查询可写入的帧数,并构建了自适应写入循环以实现稳健的流量控制,确保音频流的平滑与稳定。 阅读详情

转自:http://blog.youkuaiyun.com/azloong/article/details/6140824

这段时间在探索ALSA架构,从ALSA Core到ALSA Lib,再到Android Audio System。在看ALSA Lib时,写了一个比较典型的基于ALSA的播放录音程序。程序包包含四个部分:

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的设置,尤其要确定每次要送到Audio Codec的数据帧大小(peroid_size),这个稍后解释。

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的转换。

  1. //File   : wav_parser.h  
  2. //Author : Loon <sepnic@gmail.com>  
  3.   
  4. #ifndef __WAV_PARSER_H  
  5. #define __WAV_PARSER_H  
  6.   
  7. typedef unsigned char  uint8_t;  
  8. typedef unsigned short uint16_t;  
  9. typedef unsigned int   uint32_t;  
  10.   
  11. #if __BYTE_ORDER == __LITTLE_ENDIAN  
  12. #define COMPOSE_ID(a,b,c,d) ((a) | ((b)<<8) | ((c)<<16) | ((d)<<24))  
  13. #define LE_SHORT(v)           (v)  
  14. #define LE_INT(v)               (v)  
  15. #define BE_SHORT(v)           bswap_16(v)  
  16. #define BE_INT(v)               bswap_32(v)  
  17. #elif __BYTE_ORDER == __BIG_ENDIAN  
  18. #define COMPOSE_ID(a,b,c,d) ((d) | ((c)<<8) | ((b)<<16) | ((a)<<24))  
  19. #define LE_SHORT(v)           bswap_16(v)  
  20. #define LE_INT(v)               bswap_32(v)  
  21. #define BE_SHORT(v)           (v)  
  22. #define BE_INT(v)               (v)  
  23. #else  
  24. #error "Wrong endian"  
  25. #endif  
  26.   
  27. #define WAV_RIFF        COMPOSE_ID('R','I','F','F')  
  28. #define WAV_WAVE        COMPOSE_ID('W','A','V','E')  
  29. #define WAV_FMT         COMPOSE_ID('f','m','t',' ')  
  30. #define WAV_DATA        COMPOSE_ID('d','a','t','a')  
  31.   
  32. /* WAVE fmt block constants from Microsoft mmreg.h header */  
  33. #define WAV_FMT_PCM             0x0001  
  34. #define WAV_FMT_IEEE_FLOAT      0x0003  
  35. #define WAV_FMT_DOLBY_AC3_SPDIF 0x0092  
  36. #define WAV_FMT_EXTENSIBLE      0xfffe  
  37.   
  38. /* Used with WAV_FMT_EXTENSIBLE format */  
  39. #define WAV_GUID_TAG        "/x00/x00/x00/x00/x10/x00/x80/x00/x00/xAA/x00/x38/x9B/x71"  
  40.   
  41. /* it's in chunks like .voc and AMIGA iff, but my source say there 
  42.    are in only in this combination, so I combined them in one header; 
  43.    it works on all WAVE-file I have 
  44.  */  
  45. typedef struct WAVHeader {  
  46.     uint32_t magic;     /* 'RIFF' */  
  47.     uint32_t length;        /* filelen */  
  48.     uint32_t type;      /* 'WAVE' */  
  49. } WAVHeader_t;  
  50.   
  51. typedef struct WAVFmt {  
  52.     uint32_t magic;  /* 'FMT '*/  
  53.     uint32_t fmt_size; /* 16 or 18 */  
  54.     uint16_t format;        /* see WAV_FMT_* */  
  55.     uint16_t channels;  
  56.     uint32_t sample_rate;   /* frequence of sample */  
  57.     uint32_t bytes_p_second;  
  58.     uint16_t blocks_align;  /* samplesize; 1 or 2 bytes */  
  59.     uint16_t sample_length; /* 8, 12 or 16 bit */  
  60. } WAVFmt_t;  
  61.   
  62. typedef struct WAVFmtExtensible {  
  63.     WAVFmt_t format;  
  64.     uint16_t ext_size;  
  65.     uint16_t bit_p_spl;  
  66.     uint32_t channel_mask;  
  67.     uint16_t guid_format;   /* WAV_FMT_* */  
  68.     uint8_t guid_tag[14];   /* WAV_GUID_TAG */  
  69. } WAVFmtExtensible_t;  
  70.   
  71. typedef struct WAVChunkHeader {  
  72.     uint32_t type;      /* 'data' */  
  73.     uint32_t length;        /* samplecount */  
  74. } WAVChunkHeader_t;  
  75.   
  76. typedef struct WAVContainer {  
  77.     WAVHeader_t header;  
  78.     WAVFmt_t format;  
  79.     WAVChunkHeader_t chunk;  
  80. } WAVContainer_t;  
  81.   
  82. int WAV_ReadHeader(int fd, WAVContainer_t *container);  
  83.   
  84. int WAV_WriteHeader(int fd, WAVContainer_t *container);  
  85.   
  86. #endif /* #ifndef __WAV_PARSER_H */  

  1. //File   : wav_parser.c  
  2. //Author : Loon <sepnic@gmail.com>  
  3.   
  4. #include <assert.h>  
  5. #include <stdio.h>  
  6. #include <stdlib.h>  
  7. #include <unistd.h>  
  8. #include <fcntl.h>  
  9.   
  10. #include "wav_parser.h"  
  11.   
  12. #define WAV_PRINT_MSG  
  13.   
  14. char *WAV_P_FmtString(uint16_t fmt)  
  15. {  
  16.     switch (fmt) {  
  17.     case WAV_FMT_PCM:  
  18.         return "PCM";  
  19.         break;  
  20.     case WAV_FMT_IEEE_FLOAT:  
  21.         return "IEEE FLOAT";  
  22.         break;  
  23.     case WAV_FMT_DOLBY_AC3_SPDIF:  
  24.         return "DOLBY AC3 SPDIF";  
  25.         break;  
  26.     case WAV_FMT_EXTENSIBLE:  
  27.         return "EXTENSIBLE";  
  28.         break;  
  29.     default:  
  30.         break;  
  31.     }  
  32.   
  33.     return "NON Support Fmt";  
  34. }  
  35.   
  36. void WAV_P_PrintHeader(WAVContainer_t *container)  
  37. {  
  38.     printf("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++/n");  
  39.     printf("/n");  
  40.       
  41.     printf("File Magic:         [%c%c%c%c]/n",   
  42.         (char)(container->header.magic),   
  43.         (char)(container->header.magic>>8),   
  44.         (char)(container->header.magic>>16),   
  45.         (char)(container->header.magic>>24));  
  46.     printf("File Length:        [%d]/n", container->header.length);  
  47.     printf("File Type:          [%c%c%c%c]/n",  
  48.         (char)(container->header.type),   
  49.         (char)(container->header.type>>8),   
  50.         (char)(container->header.type>>16),   
  51.         (char)(container->header.type>>24));  
  52.           
  53.     printf("/n");  
  54.   
  55.     printf("Fmt Magic:          [%c%c%c%c]/n",  
  56.         (char)(container->format.magic),   
  57.         (char)(container->format.magic>>8),   
  58.         (char)(container->format.magic>>16),   
  59.         (char)(container->format.magic>>24));  
  60.     printf("Fmt Size:           [%d]/n", container->format.fmt_size);  
  61.     printf("Fmt Format:         [%s]/n", WAV_P_FmtString(container->format.format));  
  62.     printf("Fmt Channels:       [%d]/n", container->format.channels);  
  63.     printf("Fmt Sample_rate:    [%d](HZ)/n", container->format.sample_rate);  
  64.     printf("Fmt Bytes_p_second: [%d]/n", container->format.bytes_p_second);  
  65.     printf("Fmt Blocks_align:   [%d]/n", container->format.blocks_align);  
  66.     printf("Fmt Sample_length:  [%d]/n", container->format.sample_length);  
  67.       
  68.     printf("/n");  
  69.   
  70.     printf("Chunk Type:         [%c%c%c%c]/n",  
  71.         (char)(container->chunk.type),   
  72.         (char)(container->chunk.type>>8),   
  73.         (char)(container->chunk.type>>16),   
  74.         (char)(container->chunk.type>>24));  
  75.     printf("Chunk Length:       [%d]/n", container->chunk.length);  
  76.       
  77.     printf("/n");  
  78.     printf("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++/n");  
  79. }  
  80.   
  81. int WAV_P_CheckValid(WAVContainer_t *container)  
  82. {  
  83.     if (container->header.magic != WAV_RIFF ||  
  84.         container->header.type != WAV_WAVE ||  
  85.         container->format.magic != WAV_FMT ||  
  86.         container->format.fmt_size != LE_INT(16) ||  
  87.         (container->format.channels != LE_SHORT(1) && container->format.channels != LE_SHORT(2)) ||  
  88.         container->chunk.type != WAV_DATA) {  
  89.           
  90.         fprintf(stderr, "non standard wav file./n");  
  91.         return -1;  
  92.     }  
  93.   
  94.     return 0;  
  95. }  
  96.   
  97. int WAV_ReadHeader(int fd, WAVContainer_t *container)  
  98. {  
  99.     assert((fd >=0) && container);  
  100.   
  101.     if (read(fd, &container->header, sizeof(container->header)) != sizeof(container->header) ||   
  102.         read(fd, &container->format, sizeof(container->format)) != sizeof(container->format) ||  
  103.         read(fd, &container->chunk, sizeof(container->chunk)) != sizeof(container->chunk)) {  
  104.   
  105.         fprintf(stderr, "Error WAV_ReadHeader/n");  
  106.         return -1;  
  107.     }  
  108.   
  109.     if (WAV_P_CheckValid(container) < 0)  
  110.         return -1;  
  111.   
  112. #ifdef WAV_PRINT_MSG  
  113.     WAV_P_PrintHeader(container);  
  114. #endif  
  115.   
  116.     return 0;  
  117. }  
  118.   
  119. int WAV_WriteHeader(int fd, WAVContainer_t *container)  
  120. {  
  121.     assert((fd >=0) && container);  
  122.       
  123.     if (WAV_P_CheckValid(container) < 0)  
  124.         return -1;  
  125.   
  126.     if (write(fd, &container->header, sizeof(container->header)) != sizeof(container->header) ||   
  127.         write(fd, &container->format, sizeof(container->format)) != sizeof(container->format) ||  
  128.         write(fd, &container->chunk, sizeof(container->chunk)) != sizeof(container->chunk)) {  
  129.           
  130.         fprintf(stderr, "Error WAV_WriteHeader/n");  
  131.         return -1;  
  132.     }  
  133.   
  134. #ifdef WAV_PRINT_MSG  
  135.     WAV_P_PrintHeader(container);  
  136. #endif  
  137.   
  138.     return 0;  
  139. }  

  1. //File   : sndwav_common.h  
  2. //Author : Loon <sepnic@gmail.com>  
  3.   
  4. #ifndef __SNDWAV_COMMON_H  
  5. #define __SNDWAV_COMMON_H  
  6.   
  7. #include <stdio.h>  
  8. #include <stdlib.h>  
  9. #include <unistd.h>  
  10. #include <fcntl.h>  
  11. #include "wav_parser.h"  
  12.   
  13. typedef long long off64_t;  
  14.   
  15. typedef struct SNDPCMContainer {  
  16.     snd_pcm_t *handle;  
  17.     snd_output_t *log;  
  18.     snd_pcm_uframes_t chunk_size;  
  19.     snd_pcm_uframes_t buffer_size;  
  20.     snd_pcm_format_t format;  
  21.     uint16_t channels;  
  22.     size_t chunk_bytes;  
  23.     size_t bits_per_sample;  
  24.     size_t bits_per_frame;  
  25.   
  26.     uint8_t *data_buf;  
  27. } SNDPCMContainer_t;  
  28.   
  29. ssize_t SNDWAV_ReadPcm(SNDPCMContainer_t *sndpcm, size_t rcount);  
  30.   
  31. ssize_t SNDWAV_WritePcm(SNDPCMContainer_t *sndpcm, size_t wcount);  
  32.   
  33. int SNDWAV_SetParams(SNDPCMContainer_t *sndpcm, WAVContainer_t *wav);  
  34. #endif /* #ifndef __SNDWAV_COMMON_H */  

  1. //File   : sndwav_common.c  
  2. //Author : Loon <sepnic@gmail.com>  
  3.   
  4. #include <assert.h>  
  5. #include <stdio.h>  
  6. #include <stdlib.h>  
  7. #include <unistd.h>  
  8. #include <fcntl.h>  
  9. #include <alsa/asoundlib.h>  
  10.   
  11. #include "sndwav_common.h"  
  12.   
  13. int SNDWAV_P_GetFormat(WAVContainer_t *wav, snd_pcm_format_t *snd_format)  
  14. {     
  15.     if (LE_SHORT(wav->format.format) != WAV_FMT_PCM)  
  16.         return -1;  
  17.       
  18.     switch (LE_SHORT(wav->format.sample_length)) {  
  19.     case 16:  
  20.         *snd_format = SND_PCM_FORMAT_S16_LE;  
  21.         break;  
  22.     case 8:  
  23.         *snd_format = SND_PCM_FORMAT_U8;  
  24.         break;  
  25.     default:  
  26.         *snd_format = SND_PCM_FORMAT_UNKNOWN;  
  27.         break;  
  28.     }  
  29.   
  30.     return 0;  
  31. }  
  32.   
  33. ssize_t SNDWAV_ReadPcm(SNDPCMContainer_t *sndpcm, size_t rcount)  
  34. {  
  35.     ssize_t r;  
  36.     size_t result = 0;  
  37.     size_t count = rcount;  
  38.     uint8_t *data = sndpcm->data_buf;  
  39.   
  40.     if (count != sndpcm->chunk_size) {  
  41.         count = sndpcm->chunk_size;  
  42.     }  
  43.   
  44.     while (count > 0) {  
  45.         r = snd_pcm_readi(sndpcm->handle, data, count);  
  46.           
  47.         if (r == -EAGAIN || (r >= 0 && (size_t)r < count)) {  
  48.             snd_pcm_wait(sndpcm->handle, 1000);  
  49.         } else if (r == -EPIPE) {  
  50.             snd_pcm_prepare(sndpcm->handle);  
  51.             fprintf(stderr, "<<<<<<<<<<<<<<< Buffer Underrun >>>>>>>>>>>>>>>/n");  
  52.         } else if (r == -ESTRPIPE) {  
  53.             fprintf(stderr, "<<<<<<<<<<<<<<< Need suspend >>>>>>>>>>>>>>>/n");  
  54.         } else if (r < 0) {  
  55.             fprintf(stderr, "Error snd_pcm_writei: [%s]", snd_strerror(r));  
  56.             exit(-1);  
  57.         }  
  58.           
  59.         if (r > 0) {  
  60.             result += r;  
  61.             count -= r;  
  62.             data += r * sndpcm->bits_per_frame / 8;  
  63.         }  
  64.     }  
  65.     return rcount;  
  66. }  
  67.   
  68. ssize_t SNDWAV_WritePcm(SNDPCMContainer_t *sndpcm, size_t wcount)  
  69. {  
  70.     ssize_t r;  
  71.     ssize_t result = 0;  
  72.     uint8_t *data = sndpcm->data_buf;  
  73.   
  74.     if (wcount < sndpcm->chunk_size) {  
  75.         snd_pcm_format_set_silence(sndpcm->format,   
  76.             data + wcount * sndpcm->bits_per_frame / 8,   
  77.             (sndpcm->chunk_size - wcount) * sndpcm->channels);  
  78.         wcount = sndpcm->chunk_size;  
  79.     }  
  80.     while (wcount > 0) {  
  81.         r = snd_pcm_writei(sndpcm->handle, data, wcount);  
  82.         if (r == -EAGAIN || (r >= 0 && (size_t)r < wcount)) {  
  83.             snd_pcm_wait(sndpcm->handle, 1000);  
  84.         } else if (r == -EPIPE) {  
  85.             snd_pcm_prepare(sndpcm->handle);  
  86.             fprintf(stderr, "<<<<<<<<<<<<<<< Buffer Underrun >>>>>>>>>>>>>>>/n");  
  87.         } else if (r == -ESTRPIPE) {              
  88.             fprintf(stderr, "<<<<<<<<<<<<<<< Need suspend >>>>>>>>>>>>>>>/n");          
  89.         } else if (r < 0) {  
  90.             fprintf(stderr, "Error snd_pcm_writei: [%s]", snd_strerror(r));  
  91.             exit(-1);  
  92.         }  
  93.         if (r > 0) {  
  94.             result += r;  
  95.             wcount -= r;  
  96.             data += r * sndpcm->bits_per_frame / 8;  
  97.         }  
  98.     }  
  99.     return result;  
  100. }  
  101.   
  102. int SNDWAV_SetParams(SNDPCMContainer_t *sndpcm, WAVContainer_t *wav)  
  103. {  
  104.     snd_pcm_hw_params_t *hwparams;  
  105.     snd_pcm_format_t format;  
  106.     uint32_t exact_rate;  
  107.     uint32_t buffer_time, period_time;  
  108.   
  109.     /* Allocate the snd_pcm_hw_params_t structure on the stack. */  
  110.     snd_pcm_hw_params_alloca(&hwparams);  
  111.       
  112.     /* Init hwparams with full configuration space */  
  113.     if (snd_pcm_hw_params_any(sndpcm->handle, hwparams) < 0) {  
  114.         fprintf(stderr, "Error snd_pcm_hw_params_any/n");  
  115.         goto ERR_SET_PARAMS;  
  116.     }  
  117.   
  118.     if (snd_pcm_hw_params_set_access(sndpcm->handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) {  
  119.         fprintf(stderr, "Error snd_pcm_hw_params_set_access/n");  
  120.         goto ERR_SET_PARAMS;  
  121.     }  
  122.   
  123.     /* Set sample format */  
  124.     if (SNDWAV_P_GetFormat(wav, &format) < 0) {  
  125.         fprintf(stderr, "Error get_snd_pcm_format/n");  
  126.         goto ERR_SET_PARAMS;  
  127.     }  
  128.     if (snd_pcm_hw_params_set_format(sndpcm->handle, hwparams, format) < 0) {  
  129.         fprintf(stderr, "Error snd_pcm_hw_params_set_format/n");  
  130.         goto ERR_SET_PARAMS;  
  131.     }  
  132.     sndpcm->format = format;  
  133.   
  134.     /* Set number of channels */  
  135.     if (snd_pcm_hw_params_set_channels(sndpcm->handle, hwparams, LE_SHORT(wav->format.channels)) < 0) {  
  136.         fprintf(stderr, "Error snd_pcm_hw_params_set_channels/n");  
  137.         goto ERR_SET_PARAMS;  
  138.     }  
  139.     sndpcm->channels = LE_SHORT(wav->format.channels);  
  140.   
  141.     /* Set sample rate. If the exact rate is not supported */  
  142.     /* by the hardware, use nearest possible rate.         */   
  143.     exact_rate = LE_INT(wav->format.sample_rate);  
  144.     if (snd_pcm_hw_params_set_rate_near(sndpcm->handle, hwparams, &exact_rate, 0) < 0) {  
  145.         fprintf(stderr, "Error snd_pcm_hw_params_set_rate_near/n");  
  146.         goto ERR_SET_PARAMS;  
  147.     }  
  148.     if (LE_INT(wav->format.sample_rate) != exact_rate) {  
  149.         fprintf(stderr, "The rate %d Hz is not supported by your hardware./n ==> Using %d Hz instead./n",   
  150.             LE_INT(wav->format.sample_rate), exact_rate);  
  151.     }  
  152.   
  153.     if (snd_pcm_hw_params_get_buffer_time_max(hwparams, &buffer_time, 0) < 0) {  
  154.         fprintf(stderr, "Error snd_pcm_hw_params_get_buffer_time_max/n");  
  155.         goto ERR_SET_PARAMS;  
  156.     }  
  157.     if (buffer_time > 500000) buffer_time = 500000;  
  158.     period_time = buffer_time / 4;  
  159.   
  160.     if (snd_pcm_hw_params_set_buffer_time_near(sndpcm->handle, hwparams, &buffer_time, 0) < 0) {  
  161.         fprintf(stderr, "Error snd_pcm_hw_params_set_buffer_time_near/n");  
  162.         goto ERR_SET_PARAMS;  
  163.     }  
  164.   
  165.     if (snd_pcm_hw_params_set_period_time_near(sndpcm->handle, hwparams, &period_time, 0) < 0) {  
  166.         fprintf(stderr, "Error snd_pcm_hw_params_set_period_time_near/n");  
  167.         goto ERR_SET_PARAMS;  
  168.     }  
  169.   
  170.     /* Set hw params */  
  171.     if (snd_pcm_hw_params(sndpcm->handle, hwparams) < 0) {  
  172.         fprintf(stderr, "Error snd_pcm_hw_params(handle, params)/n");  
  173.         goto ERR_SET_PARAMS;  
  174.     }  
  175.   
  176.     snd_pcm_hw_params_get_period_size(hwparams, &sndpcm->chunk_size, 0);   
  177.     snd_pcm_hw_params_get_buffer_size(hwparams, &sndpcm->buffer_size);  
  178.     if (sndpcm->chunk_size == sndpcm->buffer_size) {        
  179.         fprintf(stderr, ("Can't use period equal to buffer size (%lu == %lu)/n"), sndpcm->chunk_size, sndpcm->buffer_size);         
  180.         goto ERR_SET_PARAMS;  
  181.     }  
  182.   
  183.     sndpcm->bits_per_sample = snd_pcm_format_physical_width(format);  
  184.     sndpcm->bits_per_frame = sndpcm->bits_per_sample * LE_SHORT(wav->format.channels);  
  185.       
  186.     sndpcm->chunk_bytes = sndpcm->chunk_size * sndpcm->bits_per_frame / 8;  
  187.   
  188.     /* Allocate audio data buffer */  
  189.     sndpcm->data_buf = (uint8_t *)malloc(sndpcm->chunk_bytes);  
  190.     if (!sndpcm->data_buf) {  
  191.         fprintf(stderr, "Error malloc: [data_buf]/n");  
  192.         goto ERR_SET_PARAMS;  
  193.     }  
  194.   
  195.     return 0;  
  196.   
  197. ERR_SET_PARAMS:  
  198.     return -1;  
  199. }  

  1. //File   : lplay.c  
  2. //Author : Loon <sepnic@gmail.com>  
  3.   
  4. #include <stdio.h>  
  5. #include <malloc.h>  
  6. #include <unistd.h>  
  7. #include <stdlib.h>  
  8. #include <string.h>  
  9. #include <getopt.h>  
  10. #include <fcntl.h>  
  11. #include <ctype.h>  
  12. #include <errno.h>  
  13. #include <limits.h>  
  14. #include <time.h>  
  15. #include <locale.h>  
  16. #include <sys/unistd.h>  
  17. #include <sys/stat.h>  
  18. #include <sys/types.h>  
  19. #include <alsa/asoundlib.h>  
  20. #include <assert.h>  
  21. #include "wav_parser.h"  
  22. #include "sndwav_common.h"  
  23.   
  24. ssize_t SNDWAV_P_SaveRead(int fd, void *buf, size_t count)  
  25. {  
  26.     ssize_t result = 0, res;  
  27.   
  28.     while (count > 0) {  
  29.         if ((res = read(fd, buf, count)) == 0)  
  30.             break;  
  31.         if (res < 0)  
  32.             return result > 0 ? result : res;  
  33.         count -= res;  
  34.         result += res;  
  35.         buf = (char *)buf + res;  
  36.     }  
  37.     return result;  
  38. }  
  39.   
  40. void SNDWAV_Play(SNDPCMContainer_t *sndpcm, WAVContainer_t *wav, int fd)  
  41. {  
  42.     int load, ret;  
  43.     off64_t written = 0;  
  44.     off64_t c;  
  45.     off64_t count = LE_INT(wav->chunk.length);  
  46.   
  47.     load = 0;  
  48.     while (written < count) {  
  49.         /* Must read [chunk_bytes] bytes data enough. */  
  50.         do {  
  51.             c = count - written;  
  52.             if (c > sndpcm->chunk_bytes)  
  53.                 c = sndpcm->chunk_bytes;  
  54.             c -= load;  
  55.   
  56.             if (c == 0)  
  57.                 break;  
  58.             ret = SNDWAV_P_SaveRead(fd, sndpcm->data_buf + load, c);  
  59.             if (ret < 0) {  
  60.                 fprintf(stderr, "Error safe_read/n");  
  61.                 exit(-1);  
  62.             }  
  63.             if (ret == 0)  
  64.                 break;  
  65.             load += ret;  
  66.         } while ((size_t)load < sndpcm->chunk_bytes);  
  67.   
  68.         /* Transfer to size frame */  
  69.         load = load * 8 / sndpcm->bits_per_frame;  
  70.         ret = SNDWAV_WritePcm(sndpcm, load);  
  71.         if (ret != load)  
  72.             break;  
  73.           
  74.         ret = ret * sndpcm->bits_per_frame / 8;  
  75.         written += ret;  
  76.         load = 0;  
  77.     }  
  78. }  
  79.   
  80. int main(int argc, char *argv[])  
  81. {  
  82.     char *filename;  
  83.     char *devicename = "default";  
  84.     int fd;  
  85.     WAVContainer_t wav;  
  86.     SNDPCMContainer_t playback;  
  87.       
  88.     if (argc != 2) {  
  89.         fprintf(stderr, "Usage: ./lplay <FILENAME>/n");  
  90.         return -1;  
  91.     }  
  92.       
  93.     memset(&playback, 0x0, sizeof(playback));  
  94.   
  95.     filename = argv[1];  
  96.     fd = open(filename, O_RDONLY);  
  97.     if (fd < 0) {  
  98.         fprintf(stderr, "Error open [%s]/n", filename);  
  99.         return -1;  
  100.     }  
  101.       
  102.     if (WAV_ReadHeader(fd, &wav) < 0) {  
  103.         fprintf(stderr, "Error WAV_Parse [%s]/n", filename);  
  104.         goto Err;  
  105.     }  
  106.   
  107.     if (snd_output_stdio_attach(&playback.log, stderr, 0) < 0) {  
  108.         fprintf(stderr, "Error snd_output_stdio_attach/n");  
  109.         goto Err;  
  110.     }  
  111.   
  112.     if (snd_pcm_open(&playback.handle, devicename, SND_PCM_STREAM_PLAYBACK, 0) < 0) {  
  113.         fprintf(stderr, "Error snd_pcm_open [ %s]/n", devicename);  
  114.         goto Err;  
  115.     }  
  116.   
  117.     if (SNDWAV_SetParams(&playback, &wav) < 0) {  
  118.         fprintf(stderr, "Error set_snd_pcm_params/n");  
  119.         goto Err;  
  120.     }  
  121.     snd_pcm_dump(playback.handle, playback.log);  
  122.   
  123.     SNDWAV_Play(&playback, &wav, fd);  
  124.   
  125.     snd_pcm_drain(playback.handle);  
  126.   
  127.     close(fd);  
  128.     free(playback.data_buf);  
  129.     snd_output_close(playback.log);  
  130.     snd_pcm_close(playback.handle);  
  131.     return 0;  
  132.   
  133. Err:  
  134.     close(fd);  
  135.     if (playback.data_buf) free(playback.data_buf);  
  136.     if (playback.log) snd_output_close(playback.log);  
  137.     if (playback.handle) snd_pcm_close(playback.handle);  
  138.     return -1;  
  139. }  

  1. //File   : lrecord.c  
  2. //Author : Loon <sepnic@gmail.com>  
  3.   
  4. #include <stdio.h>  
  5. #include <malloc.h>  
  6. #include <unistd.h>  
  7. #include <stdlib.h>  
  8. #include <string.h>  
  9. #include <getopt.h>  
  10. #include <fcntl.h>  
  11. #include <ctype.h>  
  12. #include <errno.h>  
  13. #include <limits.h>  
  14. #include <time.h>  
  15. #include <locale.h>  
  16. #include <sys/unistd.h>  
  17. #include <sys/stat.h>  
  18. #include <sys/types.h>  
  19. #include <alsa/asoundlib.h>  
  20. #include <assert.h>  
  21. #include "wav_parser.h"  
  22. #include "sndwav_common.h"  
  23.   
  24. #define DEFAULT_CHANNELS         (2)  
  25. #define DEFAULT_SAMPLE_RATE      (8000)  
  26. #define DEFAULT_SAMPLE_LENGTH    (16)  
  27. #define DEFAULT_DURATION_TIME    (10)  
  28.   
  29. int SNDWAV_PrepareWAVParams(WAVContainer_t *wav)  
  30. {  
  31.     assert(wav);  
  32.   
  33.     uint16_t channels = DEFAULT_CHANNELS;  
  34.     uint16_t sample_rate = DEFAULT_SAMPLE_RATE;  
  35.     uint16_t sample_length = DEFAULT_SAMPLE_LENGTH;  
  36.     uint32_t duration_time = DEFAULT_DURATION_TIME;  
  37.   
  38.     /* Const */  
  39.     wav->header.magic = WAV_RIFF;  
  40.     wav->header.type = WAV_WAVE;  
  41.     wav->format.magic = WAV_FMT;  
  42.     wav->format.fmt_size = LE_INT(16);  
  43.     wav->format.format = LE_SHORT(WAV_FMT_PCM);  
  44.     wav->chunk.type = WAV_DATA;  
  45.   
  46.     /* User definition */  
  47.     wav->format.channels = LE_SHORT(channels);  
  48.     wav->format.sample_rate = LE_INT(sample_rate);  
  49.     wav->format.sample_length = LE_SHORT(sample_length);  
  50.   
  51.     /* See format of wav file */  
  52.     wav->format.blocks_align = LE_SHORT(channels * sample_length / 8);  
  53.     wav->format.bytes_p_second = LE_INT((uint16_t)(wav->format.blocks_align) * sample_rate);  
  54.       
  55.     wav->chunk.length = LE_INT(duration_time * (uint32_t)(wav->format.bytes_p_second));  
  56.     wav->header.length = LE_INT((uint32_t)(wav->chunk.length) +/  
  57.         sizeof(wav->chunk) + sizeof(wav->format) + sizeof(wav->header) - 8);  
  58.   
  59.     return 0;  
  60. }  
  61.   
  62. void SNDWAV_Record(SNDPCMContainer_t *sndpcm, WAVContainer_t *wav, int fd)  
  63. {  
  64.     off64_t rest;  
  65.     size_t c, frame_size;  
  66.       
  67.     if (WAV_WriteHeader(fd, wav) < 0) {  
  68.         exit(-1);  
  69.     }  
  70.   
  71.     rest = wav->chunk.length;  
  72.     while (rest > 0) {  
  73.         c = (rest <= (off64_t)sndpcm->chunk_bytes) ? (size_t)rest : sndpcm->chunk_bytes;  
  74.         frame_size = c * 8 / sndpcm->bits_per_frame;  
  75.         if (SNDWAV_ReadPcm(sndpcm, frame_size) != frame_size)  
  76.             break;  
  77.           
  78.         if (write(fd, sndpcm->data_buf, c) != c) {  
  79.             fprintf(stderr, "Error SNDWAV_Record[write]/n");  
  80.             exit(-1);  
  81.         }  
  82.   
  83.         rest -= c;  
  84.     }  
  85. }  
  86.   
  87. int main(int argc, char *argv[])  
  88. {  
  89.     char *filename;  
  90.     char *devicename = "default";  
  91.     int fd;  
  92.     WAVContainer_t wav;  
  93.     SNDPCMContainer_t record;  
  94.       
  95.     if (argc != 2) {  
  96.         fprintf(stderr, "Usage: ./lrecord <FILENAME>/n");  
  97.         return -1;  
  98.     }  
  99.       
  100.     memset(&record, 0x0, sizeof(record));  
  101.   
  102.     filename = argv[1];  
  103.     remove(filename);  
  104.     if ((fd = open(filename, O_WRONLY | O_CREAT, 0644)) == -1) {  
  105.         fprintf(stderr, "Error open: [%s]/n", filename);  
  106.         return -1;  
  107.     }  
  108.   
  109.     if (snd_output_stdio_attach(&record.log, stderr, 0) < 0) {  
  110.         fprintf(stderr, "Error snd_output_stdio_attach/n");  
  111.         goto Err;  
  112.     }  
  113.   
  114.     if (snd_pcm_open(&record.handle, devicename, SND_PCM_STREAM_CAPTURE, 0) < 0) {  
  115.         fprintf(stderr, "Error snd_pcm_open [ %s]/n", devicename);  
  116.         goto Err;  
  117.     }  
  118.   
  119.     if (SNDWAV_PrepareWAVParams(&wav) < 0) {  
  120.         fprintf(stderr, "Error SNDWAV_PrepareWAVParams/n");  
  121.         goto Err;  
  122.     }  
  123.   
  124.     if (SNDWAV_SetParams(&record, &wav) < 0) {  
  125.         fprintf(stderr, "Error set_snd_pcm_params/n");  
  126.         goto Err;  
  127.     }  
  128.     snd_pcm_dump(record.handle, record.log);  
  129.   
  130.     SNDWAV_Record(&record, &wav, fd);  
  131.   
  132.     snd_pcm_drain(record.handle);  
  133.   
  134.     close(fd);  
  135.     free(record.data_buf);  
  136.     snd_output_close(record.log);  
  137.     snd_pcm_close(record.handle);  
  138.     return 0;  
  139.   
  140. Err:  
  141.     close(fd);  
  142.     remove(filename);  
  143.     if (record.data_buf) free(record.data_buf);  
  144.     if (record.log) snd_output_close(record.log);  
  145.     if (record.handle) snd_pcm_close(record.handle);  
  146.     return -1;  
  147. } 
六、ALSA lib库接口 使用 ALSA 的 lib 库中的 snd_pcm_xxx 等标准接口函数,操作 /dev/snd/pcmC0D0c或pcmC0D0p 等录放音设备节点,相当于在 OSS 框架下通过 ioctl 设置不同参数去操作 /dev/dsp 设备ALSA功能丰富,可以设置音频参数,DMA buffer 大小、分块数量,buffer 阀值等。 阅读详情

相关推荐

经典alsa 录音和播放程序

这里贴上虚拟机ubuntu下alsa的录音程序(capture.c)和播放程序(playback.c)的源码。 首先要测试一下自己的ubuntu是否打开了声音。这个可以打开/系统/首选项/声音  来调节。另外也可以在终端下输入alsaMixer 来调节,之前我的耳机就是只能放音不能录音,因为没有打开一些设置,在进入alsamixer界面后,按F4也就是capture选项,把声音调大就可以录音了。其

JAVAweb学习 653

ALSA  lib接口调用简介

ALSA lib接口调用简介 ALSA逻辑,在我当前看来,总共有两条线:1、录放音流控,2、amixer cset控件。 录放音流控(自定义名称),相当于操作OSS的/dev/dsp设备,可以设置三大参数等,并且启动录放音。这里,aplay,mplayer等播放器,调用ALSA lib中的sn...

佛系程序员 6096

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

文章目录ALSA框架环境搭建ALSA 交叉编译移植alsa-libalsa-util配置USB声卡查看声卡设备并测试查看音卡:录音测试播放测试音频采集常见参数WAV文件头编程实现录音的播放audio.cppaudio.haudio_wav.cppaudio_wav.h播放录音测试代码运行方式audio_recordaudio_play ALSA框架 ALSA 是 Advanced Linux Sound Architecture 的缩写,即高级 Linux声音架构,在 Linux 操作系统上提供了对音频和

yy197696的博客 4024

JZ2440 基于ALSA的WAV播放和录音程序

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.youkuaiyun.com/sepnic/article/details/6140824 这段时间在探索ALSA架构,从ALSA Core到ALSA Lib,再到Android Audio System。在看ALSA Lib时,写了一个比较典型的基于ALSA的播放录音程序。程序包包含四个部分: WAV Par...

739

alsa-lib应用层接口分析

ALSA lib接口调用简介 ALSA逻辑,在我当前看来,总共有两条线:1、录放音流控,2、amixer cset控件。 录放音流控(自定义名称),相当于操作OSS的/dev/dsp设备,可以设置三大参数等,并且启动录放音。这里,aplay,mplayer等播放器,调用ALSA lib中的snd_pcm_***等,标准接口函数,再通过该函数,操作/...

sinat_37817094的博客 9848

【ESP32-IDF】I2S音频协议实战:从PDM麦克风到PCM扬声器的全链路解析

本文深入解析ESP32-S3的I2S音频协议,从PDM麦克风采集到PCM扬声器输出的全链路实现。详细介绍了硬件PDM转PCM、Standard模式配置及混合模式协同工作,提供实战代码与性能优化建议,助力开发者高效完成嵌入式音频项目开发。

pea55的博客 889

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 Com

jack_a8的专栏 3095

华为防火墙双线路配置实战:5分钟搞定主备自动切换(含健康检查避坑指南)

本文详细介绍了华为防火墙双线路配置实战,包括主备自动切换和健康检查机制的优化技巧。通过智能健康检查机制,华为防火墙能实现毫秒级故障自动切换,确保网络高可用性。文章提供了从架构设计到实战配置的全流程指南,并分享了常见配置误区与解决方案,帮助中小企业快速搭建稳定可靠的网络架构。

weixin_30872337的博客 605

linux下如何用C进行录音,录成.WAV格式,或者其他格式

http://bbs.youkuaiyun.com/topics/190024886 alsa官网上有资料,下面是个例程: Linux下的录音编程(转摘)   /* 此文件中定义了下面所有形如SND_的变量*/ #include  #include  #include  #include  #include  #include  int main() { /* id:读取音

北极洲的博客 4944

如何设计QR反激变换器

摘要:本文分析了基于GaN技术的PD适配器市场现状,重点探讨了准谐振反激变换器(QR Flyback)的工作原理及设计方法。文章首先介绍了反激变换器的三种工作模式(CCM、DCM、CRM/QR)及其特点,指出QR模式通过谷底开通技术能显著降低开关损耗。随后以65W适配器为例,详细阐述了变压器参数设计流程,包括匝比确定、原边电感计算和绕组匝数设计等关键步骤。文章强调QR反激变换器凭借高效率、小体积和低成本优势,已成为20W-65W PD适配器的主流拓扑方案,配合GaN技术进一步提升了功率密度和便携性。

m0_62868254的博客 1496

SAP 集成泛微 OA Open API 新建流程申请接口

《SAP ERP 与泛微 OA 的系统集成》系列文章。泛微 Open API 是基于 HTTPS 的 Restful 接口,上篇文章,我已经完成了调用业务接口之前的准备工作,这篇文章我以新建流程申请这个系统集成最重要的接口为例,讲解接口设计、泛微 API 调用的过程、遇到的问题、解决的办法。

SAP李斌,本人承诺所有原创文章均不使用任何AI生成技术,请大家放心阅读。 3555

alsa录音,播放调试

本次调试基于全志v3s芯片linux系统,刚开始毫无头绪,即使都调试完成了,还是有很多地方不明白。 1、首先确保硬件和驱动都可以正常使用,用如下命令测试 录音测试 amixer cset numid=10,iface=MIXER,name='Audio main mic' 1 arecord -d 3 -f S16_LE -r 16000 tmp.wav 播放测试 amixer cset num...

yzs_110的博客 2227

医疗数据采集:Python爬虫爬取医学文献与药品信息(2026合规与伦理版)

医疗数据采集不同于爬取新闻或房价,它直接关系到人的生命健康和法律底线。技术层面:优先使用官方 API (PubMed E-utilities, BioThings),避免解析复杂HTML。法律层面:严守“不碰隐私、不破付费、不传谣言”三条红线。伦理层面:保持对生命的敬畏,确保数据的准确性和用途的正当性。在2026年,一个优秀的医疗数据工程师,不是那个能爬取最多数据的人,而是那个能在合规框架下,利用公开数据解决真实医疗问题的人。请务必珍视您的职业生涯和法律责任,切勿以身试法。

专注于Python爬虫开发,分享爬虫技巧、项目实战与反爬经验,使用Scrapy、BeautifulSoup等工具,解决数据抓取难题。 285

使用alsa-lib实现录音

虽然网上已经有了很多的参考资料,但是不是很详细,而且注释也很少。有些看起来似懂非懂,所以在我这里提供了一版详细的实现代码,方便大家一起学习。头文件的声明在 alsa_record.h#ifndef COM_HXIONG_ALSA_RECORD_H #define COM_HXIONG_ALSA_RECORD_H //宏定义 #define RECORD_FAIL -1 #define REC...

xiongtiancheng的博客 7070

UWB 多传感器通信的纳秒无线位置和时钟同步方法

利用UWB高精度的特点,实现多节点下的无线时钟同步和定位。通过优化硬件架构,减少不确定延迟的影响,系统可以提供纳秒级时钟同步消息

DT程序员的博客 1329

DiffusionDriveV2 (1) : 端到端自动驾驶中受强化学习约束的截断扩散建模

DiffusionDriveV2:强化学习约束的截断扩散模型在端到端自动驾驶中的应用 本文针对端到端自动驾驶中扩散模型面临的模式崩溃问题,提出DiffusionDriveV2框架。该方法通过引入强化学习约束,解决了DiffusionDrive依赖模仿学习导致的多样性与持续高质量之间的困境。主要创新包括: 采用尺度自适应乘法噪声促进广泛探索 提出锚点内GRPO管理单个锚点样本间的优势估计 设计锚点间截断GRPO整合全局视角,避免不同驾驶意图间的不当比较 实验表明,该方法在NAVSIM基准测试中达到最先进水平(

@bangbang的博客 381
上一篇: ALSA SOC在Linux3.1上的一些改进
下一篇: 基于uda34x的ALSA声卡驱动之设备建立流程
lininglive
博客等级 码龄18年 33粉丝 9原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值