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

完整的源代码你可以在这儿下载到: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文件:

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

wav_parser.c

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

sndwav_common.h

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

sndwav_common.c

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

lplay.c

 
 
  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.     ssize_t result = 0, res; 
  26.  
  27.     while (count > 0) { 
  28.         if ((res = read(fd, buf, count)) == 0) 
  29.             break
  30.         if (res < 0) 
  31.             return result > 0 ? result : res; 
  32.         count -= res; 
  33.         result += res; 
  34.         buf = (char *)buf + res; 
  35.     } 
  36.     return result; 
  37.  
  38. void SNDWAV_Play(SNDPCMContainer_t *sndpcm, WAVContainer_t *wav, int fd) 
  39.     int load, ret; 
  40.     off64_t written = 0; 
  41.     off64_t c; 
  42.     off64_t count = LE_INT(wav->chunk.length); 
  43.  
  44.     load = 0; 
  45.     while (written < count) { 
  46.         /* Must read [chunk_bytes] bytes data enough. */ 
  47.         do { 
  48.             c = count - written; 
  49.             if (c > sndpcm->chunk_bytes) 
  50.                 c = sndpcm->chunk_bytes; 
  51.             c -= load; 
  52.  
  53.             if (c == 0) 
  54.                 break
  55.             ret = SNDWAV_P_SaveRead(fd, sndpcm->data_buf + load, c); 
  56.             if (ret < 0) { 
  57.                 fprintf(stderr, "Error safe_read/n"); 
  58.                 exit(-1); 
  59.             } 
  60.             if (ret == 0) 
  61.                 break
  62.             load += ret; 
  63.         } while ((size_t)load < sndpcm->chunk_bytes); 
  64.  
  65.         /* Transfer to size frame */ 
  66.         load = load * 8 / sndpcm->bits_per_frame; 
  67.         ret = SNDWAV_WritePcm(sndpcm, load); 
  68.         if (ret != load) 
  69.             break
  70.          
  71.         ret = ret * sndpcm->bits_per_frame / 8; 
  72.         written += ret; 
  73.         load = 0; 
  74.     } 
  75.  
  76. int main(int argc, char *argv[]) 
  77.     char *filename; 
  78.     char *devicename = "default"
  79.     int fd; 
  80.     WAVContainer_t wav; 
  81.     SNDPCMContainer_t playback; 
  82.      
  83.     if (argc != 2) { 
  84.         fprintf(stderr, "Usage: ./lplay <FILENAME>/n"); 
  85.         return -1; 
  86.     } 
  87.      
  88.     memset(&playback, 0x0, sizeof(playback)); 
  89.  
  90.     filename = argv[1]; 
  91.     fd = open(filename, O_RDONLY); 
  92.     if (fd < 0) { 
  93.         fprintf(stderr, "Error open [%s]/n", filename); 
  94.         return -1; 
  95.     } 
  96.      
  97.     if (WAV_ReadHeader(fd, &wav) < 0) { 
  98.         fprintf(stderr, "Error WAV_Parse [%s]/n", filename); 
  99.         goto Err; 
  100.     } 
  101.  
  102.     if (snd_output_stdio_attach(&playback.log, stderr, 0) < 0) {
  103.         fprintf(stderr, "Error snd_output_stdio_attach/n"); 
  104.         goto Err; 
  105.     } 
  106.  
  107.     if (snd_pcm_open(&playback.handle, devicename, SND_PCM_STREAM_PLAYBACK, 0) < 0) { 
  108.         fprintf(stderr, "Error snd_pcm_open [ %s]/n", devicename); 
  109.         goto Err; 
  110.     } 
  111.  
  112.     if (SNDWAV_SetParams(&playback, &wav) < 0) { 
  113.         fprintf(stderr, "Error set_snd_pcm_params/n"); 
  114.         goto Err; 
  115.     } 
  116.     snd_pcm_dump(playback.handle, playback.log); 
  117.  
  118.     SNDWAV_Play(&playback, &wav, fd); 
  119.  
  120.     snd_pcm_drain(playback.handle); 
  121.  
  122.     close(fd); 
  123.     free(playback.data_buf); 
  124.     snd_output_close(playback.log); 
  125.     snd_pcm_close(playback.handle); 
  126.     return 0; 
  127.  
  128. Err: 
  129.     close(fd); 
  130.     if (playback.data_buf) free(playback.data_buf); 
  131.     if (playback.log) snd_output_close(playback.log); 
  132.     if (playback.handle) snd_pcm_close(playback.handle); 
  133.     return -1; 

lrecord.c

 
 
  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.     assert(wav); 
  31.  
  32.     uint16_t channels = DEFAULT_CHANNELS; 
  33.     uint16_t sample_rate = DEFAULT_SAMPLE_RATE; 
  34.     uint16_t sample_length = DEFAULT_SAMPLE_LENGTH; 
  35.     uint32_t duration_time = DEFAULT_DURATION_TIME; 
  36.  
  37.     /* Const */ 
  38.     wav->header.magic = WAV_RIFF; 
  39.     wav->header.type = WAV_WAVE; 
  40.     wav->format.magic = WAV_FMT; 
  41.     wav->format.fmt_size = LE_INT(16); 
  42.     wav->format.format = LE_SHORT(WAV_FMT_PCM); 
  43.     wav->chunk.type = WAV_DATA; 
  44.  
  45.     /* User definition */ 
  46.     wav->format.channels = LE_SHORT(channels); 
  47.     wav->format.sample_rate = LE_INT(sample_rate); 
  48.     wav->format.sample_length = LE_SHORT(sample_length); 
  49.  
  50.     /* See format of wav file */ 
  51. wav->format.blocks_align = LE_SHORT(channels * sample_length / 8); 
  52. wav->format.bytes_p_second = LE_INT((uint16_t)(wav->format.blocks_align) * sample_rate); 
  53.      
  54. wav->chunk.length = LE_INT(duration_time * (uint32_t)(wav->format.bytes_p_second)); 
  55. wav->header.length = LE_INT((uint32_t)(wav->chunk.length) +/ 
  56.         sizeof(wav->chunk) + sizeof(wav->format) + sizeof(wav->header) - 8); 
  57.  
  58.     return 0; 
  59.  
  60. void SNDWAV_Record(SNDPCMContainer_t *sndpcm, WAVContainer_t *wav, int fd) 
  61.     off64_t rest; 
  62.     size_t c, frame_size; 
  63.      
  64.     if (WAV_WriteHeader(fd, wav) < 0) { 
  65.         exit(-1); 
  66.     } 
  67.  
  68.     rest = wav->chunk.length; 
  69.     while (rest > 0) { 
  70.         c = (rest <= (off64_t)sndpcm->chunk_bytes) ? (size_t)rest : sndpcm->chunk_bytes; 
  71.         frame_size = c * 8 / sndpcm->bits_per_frame; 
  72.         if (SNDWAV_ReadPcm(sndpcm, frame_size) != frame_size) 
  73.             break
  74.          
  75.         if (write(fd, sndpcm->data_buf, c) != c) { 
  76.             fprintf(stderr, "Error SNDWAV_Record[write]/n"); 
  77.             exit(-1); 
  78.         } 
  79.  
  80.         rest -= c; 
  81.     } 
  82.  
  83. int main(int argc, char *argv[]) 
  84.     char *filename; 
  85.     char *devicename = "default"
  86.     int fd; 
  87.     WAVContainer_t wav; 
  88.     SNDPCMContainer_t record; 
  89.      
  90.     if (argc != 2) { 
  91.         fprintf(stderr, "Usage: ./lrecord <FILENAME>/n"); 
  92.         return -1; 
  93.     } 
  94.      
  95.     memset(&record, 0x0, sizeof(record)); 
  96.  
  97.     filename = argv[1]; 
  98.     remove(filename); 
  99.     if ((fd = open(filename, O_WRONLY | O_CREAT, 0644)) == -1) { 
  100.         fprintf(stderr, "Error open: [%s]/n", filename); 
  101.         return -1; 
  102.     } 
  103.  
  104.     if (snd_output_stdio_attach(&record.log, stderr, 0) < 0) { 
  105.         fprintf(stderr, "Error snd_output_stdio_attach/n"); 
  106.         goto Err; 
  107.     } 
  108.  
  109.     if (snd_pcm_open(&record.handle, devicename, SND_PCM_STREAM_CAPTURE, 0) < 0) { 
  110.         fprintf(stderr, "Error snd_pcm_open [ %s]/n", devicename); 
  111.         goto Err; 
  112.     } 
  113.  
  114.     if (SNDWAV_PrepareWAVParams(&wav) < 0) { 
  115.         fprintf(stderr, "Error SNDWAV_PrepareWAVParams/n"); 
  116.         goto Err; 
  117.     } 
  118.  
  119.     if (SNDWAV_SetParams(&record, &wav) < 0) { 
  120.         fprintf(stderr, "Error set_snd_pcm_params/n"); 
  121.         goto Err; 
  122.     } 
  123.     snd_pcm_dump(record.handle, record.log); 
  124.  
  125.     SNDWAV_Record(&record, &wav, fd); 
  126.  
  127.     snd_pcm_drain(record.handle); 
  128.  
  129.     close(fd); 
  130.     free(record.data_buf); 
  131.     snd_output_close(record.log); 
  132.     snd_pcm_close(record.handle); 
  133.     return 0; 
  134.  
  135. Err: 
  136.     close(fd); 
  137.     remove(filename); 
  138.     if (record.data_buf) free(record.data_buf); 
  139.     if (record.log) snd_output_close(record.log); 
  140.     if (record.handle) snd_pcm_close(record.handle); 
  141.     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

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值