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

wav_parser.c

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

sndwav_common.h

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

sndwav_common.c

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

lplay.c

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

lrecord.c

  1. //File   : lrecord.c
  2. //Author : Loon <sepnic@gmail.com>
  3. #include <stdio.h>
  4. #include <malloc.h>
  5. #include <unistd.h>
  6. #include <stdlib.h>
  7. #include <string.h>
  8. #include <getopt.h>
  9. #include <fcntl.h>
  10. #include <ctype.h>
  11. #include <errno.h>
  12. #include <limits.h>
  13. #include <time.h>
  14. #include <locale.h>
  15. #include <sys/unistd.h>
  16. #include <sys/stat.h>
  17. #include <sys/types.h>
  18. #include <alsa/asoundlib.h>
  19. #include <assert.h>
  20. #include "wav_parser.h"
  21. #include "sndwav_common.h"
  22. #define DEFAULT_CHANNELS         (2)
  23. #define DEFAULT_SAMPLE_RATE      (8000)
  24. #define DEFAULT_SAMPLE_LENGTH    (16)
  25. #define DEFAULT_DURATION_TIME    (10)
  26. int SNDWAV_PrepareWAVParams(WAVContainer_t *wav)
  27. {
  28. assert(wav);
  29. uint16_t channels = DEFAULT_CHANNELS;
  30. uint16_t sample_rate = DEFAULT_SAMPLE_RATE;
  31. uint16_t sample_length = DEFAULT_SAMPLE_LENGTH;
  32. uint32_t duration_time = DEFAULT_DURATION_TIME;
  33. /* Const */
  34. wav->header.magic = WAV_RIFF;
  35. wav->header.type = WAV_WAVE;
  36. wav->format.magic = WAV_FMT;
  37. wav->format.fmt_size = LE_INT(16);
  38. wav->format.format = LE_SHORT(WAV_FMT_PCM);
  39. wav->chunk.type = WAV_DATA;
  40. /* User definition */
  41. wav->format.channels = LE_SHORT(channels);
  42. wav->format.sample_rate = LE_INT(sample_rate);
  43. wav->format.sample_length = LE_SHORT(sample_length);
  44. /* See format of wav file */
  45. wav->format.blocks_align = LE_SHORT(channels * sample_length / 8);
  46. wav->format.bytes_p_second = LE_INT((uint16_t)(wav->format.blocks_align) * sample_rate);
  47. wav->chunk.length = LE_INT(duration_time * (uint32_t)(wav->format.bytes_p_second));
  48. wav->header.length = LE_INT((uint32_t)(wav->chunk.length) +/
  49. sizeof(wav->chunk) + sizeof(wav->format) + sizeof(wav->header) - 8);
  50. return 0;
  51. }
  52. void SNDWAV_Record(SNDPCMContainer_t *sndpcm, WAVContainer_t *wav, int fd)
  53. {
  54. off64_t rest;
  55. size_t c, frame_size;
  56. if (WAV_WriteHeader(fd, wav) < 0) {
  57. exit(-1);
  58. }
  59. rest = wav->chunk.length;
  60. while (rest > 0) {
  61. c = (rest <= (off64_t)sndpcm->chunk_bytes) ? (size_t)rest : sndpcm->chunk_bytes;
  62. frame_size = c * 8 / sndpcm->bits_per_frame;
  63. if (SNDWAV_ReadPcm(sndpcm, frame_size) != frame_size)
  64. break;
  65. if (write(fd, sndpcm->data_buf, c) != c) {
  66. fprintf(stderr, "Error SNDWAV_Record[write]/n");
  67. exit(-1);
  68. }
  69. rest -= c;
  70. }
  71. }
  72. int main(int argc, char *argv[])
  73. {
  74. char *filename;
  75. char *devicename = "default";
  76. int fd;
  77. WAVContainer_t wav;
  78. SNDPCMContainer_t record;
  79. if (argc != 2) {
  80. fprintf(stderr, "Usage: ./lrecord <FILENAME>/n");
  81. return -1;
  82. }
  83. memset(&record, 0x0, sizeof(record));
  84. filename = argv[1];
  85. remove(filename);
  86. if ((fd = open(filename, O_WRONLY | O_CREAT, 0644)) == -1) {
  87. fprintf(stderr, "Error open: [%s]/n", filename);
  88. return -1;
  89. }
  90. if (snd_output_stdio_attach(&record.log, stderr, 0) < 0) {
  91. fprintf(stderr, "Error snd_output_stdio_attach/n");
  92. goto Err;
  93. }
  94. if (snd_pcm_open(&record.handle, devicename, SND_PCM_STREAM_CAPTURE, 0) < 0) {
  95. fprintf(stderr, "Error snd_pcm_open [ %s]/n", devicename);
  96. goto Err;
  97. }
  98. if (SNDWAV_PrepareWAVParams(&wav) < 0) {
  99. fprintf(stderr, "Error SNDWAV_PrepareWAVParams/n");
  100. goto Err;
  101. }
  102. if (SNDWAV_SetParams(&record, &wav) < 0) {
  103. fprintf(stderr, "Error set_snd_pcm_params/n");
  104. goto Err;
  105. }
  106. snd_pcm_dump(record.handle, record.log);
  107. SNDWAV_Record(&record, &wav, fd);
  108. snd_pcm_drain(record.handle);
  109. close(fd);
  110. free(record.data_buf);
  111. snd_output_close(record.log);
  112. snd_pcm_close(record.handle);
  113. return 0;
  114. Err:
  115. close(fd);
  116. remove(filename);
  117. if (record.data_buf) free(record.data_buf);
  118. if (record.log) snd_output_close(record.log);
  119. if (record.handle) snd_pcm_close(record.handle);
  120. return -1;
  121. }

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播放和录音程序相关推荐

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

    本文转载博客:http://blog.csdn.net/azloong/article/details/6140824 ---------------------------------------- ...

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

    版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/sepnic/article/details/6140824 这段时间在探索ALSA架构,从ALSA ...

  3. 微信小程序音频相关问题:播放,录音等相关

    其实我也知道音频问题,十分尴尬,可以参考的资料极少,研究者也不多,所处的教程也基本是基础的内容,稍微深入几乎一篇都没有:所以前段时间我就准备弄的东西,一直没弄,因为没资料去弄,但是今天,看到一个同学遇 ...

  4. Linux ALSA声卡驱动之七:录音(Capture) 调用流程

    ALSA声卡驱动: 1.Linux ALSA声卡驱动之一:ALSA架构简介和ASOC架构简介 2.Linux ALSA声卡驱动之二:Platform 3. Linux ALSA声卡驱动之三:Platf ...

  5. 【物联网智能网关-15】WAV播放器(WinForm+WavPlay库实例)

    2002年在首钢实施焦炉四大机车自动化项目的时候,为了使系统更加友好,便增加了语音提示功能.不过控制设备是PLC,所以语音模块是通过IO进行控制的.接触WAV解码,是在2009年,为TI DM355平 ...

  6. iOS开发系列--音频播放、录音、视频播放、拍照、视频录制(转)

    概览 随着移动互联网的发展,如今的手机早已不是打电话.发短信那么简单了,播放音乐.视频.录音.拍照等都是很常用的功能.在iOS中对于多媒体的支持是非常强大的,无论是音视频播放.录制,还是对麦克风.摄像 ...

  7. 牛人iOS开发系列--音频播放、录音、视频播放、拍照、视频录制

    概览 随着移动互联网的发展,如今的手机早已不是打电话.发短信那么简单了,播放音乐.视频.录音.拍照等都是很常用的功能.在iOS中对于多媒体的支持是非常强大的,无论是音视频播放.录制,还是对麦克风.摄像 ...

  8. iOS开发系列--音频播放、录音、视频播放、拍照、视频录制

    概览 随着移动互联网的发展,如今的手机早已不是打电话.发短信那么简单了,播放音乐.视频.录音.拍照等都是很常用的功能.在iOS中对于多媒体的支持是非常强大的,无论是音视频播放.录制,还是对麦克风.摄像 ...

  9. iOS 音频播放,录音,视频播放,拍照,视频录制

    iOS开发系列--音频播放.录音.视频播放.拍照.视频录制 2014-12-26 09:15 by KenshinCui, 149110 阅读, 67 评论, 收藏, 编辑 --iOS多媒体 概览 随 ...

最新文章

  1. 论文简述 | EAO-SLAM:基于集成数据关联的单目半稠密物体级SLAM
  2. php 打开报错,php模式下 运行start.php 报错
  3. PDU知识全集,值得收藏!
  4. Linux与Windows比较出的20个优势
  5. python 二分查找_二分查找算法总结
  6. DevOps组织如何有效地实施MSA
  7. 货物与产品的区别_商品与一般物品和其他产品有什么区别?
  8. 定位日站大法之-社会工程学
  9. DSP的入门学习(一)
  10. 2022-2027年(新版)中国石油化工行业发展建议及投资前景展望报告
  11. 服务器系统开启telnet,开启Telnet服务
  12. 代码自动生成-宏递归思想
  13. win10设置宽带拨号断线重连
  14. 性能分析之响应时间拆分及 258 原则误区
  15. 哪些iPhone具有纵向模式?
  16. 关于《推背图》,《奇门遁甲》
  17. 租一个月的云服务器要花费多少?
  18. [自动化测试] 去哪儿机票搜索
  19. 快速上手 TinyXML-2 不完全教程
  20. webgis开发参考资料

热门文章

  1. 手写输入和软键盘输入
  2. linux卸载软件出现依赖,关于ubuntu循环依赖软件的删除
  3. 声网Agora发布实时互动云行业首个体验质量标准XLA
  4. 旅通软件:旅行社如何快人一步?
  5. 固高 倒立摆 matlab,MATLAB-Control-Software 针对固高直线一级倒立摆 - 下载 - 搜珍网...
  6. 微信上墙-sdut(转)
  7. 有些事现在不做,一辈子都不会做了。
  8. banana pro远程监控摄像头motion
  9. 多目标优化算法:多目标白鲨优化算法MOWSO(提供Matlab代码)
  10. IDEA删除一行的快捷键