http://blog.csdn.net/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. #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 */
  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. }
  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 */
  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, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) {
  103. fprintf(stderr, "Error snd_pcm_hw_params_set_access/n");
  104. goto ERR_SET_PARAMS;
  105. }
  106. /* Set sample format */
  107. if (SNDWAV_P_GetFormat(wav, &format) < 0) {
  108. fprintf(stderr, "Error get_snd_pcm_format/n");
  109. goto ERR_SET_PARAMS;
  110. }
  111. if (snd_pcm_hw_params_set_format(sndpcm->handle, hwparams, format) < 0) {
  112. fprintf(stderr, "Error snd_pcm_hw_params_set_format/n");
  113. goto ERR_SET_PARAMS;
  114. }
  115. sndpcm->format = format;
  116. /* Set number of channels */
  117. if (snd_pcm_hw_params_set_channels(sndpcm->handle, hwparams, LE_SHORT(wav->format.channels)) < 0) {
  118. fprintf(stderr, "Error snd_pcm_hw_params_set_channels/n");
  119. goto ERR_SET_PARAMS;
  120. }
  121. sndpcm->channels = LE_SHORT(wav->format.channels);
  122. /* Set sample rate. If the exact rate is not supported */
  123. /* by the hardware, use nearest possible rate.         */
  124. exact_rate = LE_INT(wav->format.sample_rate);
  125. if (snd_pcm_hw_params_set_rate_near(sndpcm->handle, hwparams, &exact_rate, 0) < 0) {
  126. fprintf(stderr, "Error snd_pcm_hw_params_set_rate_near/n");
  127. goto ERR_SET_PARAMS;
  128. }
  129. if (LE_INT(wav->format.sample_rate) != exact_rate) {
  130. fprintf(stderr, "The rate %d Hz is not supported by your hardware./n ==> Using %d Hz instead./n",
  131. LE_INT(wav->format.sample_rate), exact_rate);
  132. }
  133. if (snd_pcm_hw_params_get_buffer_time_max(hwparams, &buffer_time, 0) < 0) {
  134. fprintf(stderr, "Error snd_pcm_hw_params_get_buffer_time_max/n");
  135. goto ERR_SET_PARAMS;
  136. }
  137. if (buffer_time > 500000) buffer_time = 500000;
  138. period_time = buffer_time / 4;
  139. if (snd_pcm_hw_params_set_buffer_time_near(sndpcm->handle, hwparams, &buffer_time, 0) < 0) {
  140. fprintf(stderr, "Error snd_pcm_hw_params_set_buffer_time_near/n");
  141. goto ERR_SET_PARAMS;
  142. }
  143. if (snd_pcm_hw_params_set_period_time_near(sndpcm->handle, hwparams, &period_time, 0) < 0) {
  144. fprintf(stderr, "Error snd_pcm_hw_params_set_period_time_near/n");
  145. goto ERR_SET_PARAMS;
  146. }
  147. /* Set hw params */
  148. if (snd_pcm_hw_params(sndpcm->handle, hwparams) < 0) {
  149. fprintf(stderr, "Error snd_pcm_hw_params(handle, params)/n");
  150. goto ERR_SET_PARAMS;
  151. }
  152. snd_pcm_hw_params_get_period_size(hwparams, &sndpcm->chunk_size, 0);
  153. snd_pcm_hw_params_get_buffer_size(hwparams, &sndpcm->buffer_size);
  154. if (sndpcm->chunk_size == sndpcm->buffer_size) {
  155. fprintf(stderr, ("Can't use period equal to buffer size (%lu == %lu)/n"), sndpcm->chunk_size, sndpcm->buffer_size);
  156. goto ERR_SET_PARAMS;
  157. }
  158. sndpcm->bits_per_sample = snd_pcm_format_physical_width(format);
  159. sndpcm->bits_per_frame = sndpcm->bits_per_sample * LE_SHORT(wav->format.channels);
  160. sndpcm->chunk_bytes = sndpcm->chunk_size * sndpcm->bits_per_frame / 8;
  161. /* Allocate audio data buffer */
  162. sndpcm->data_buf = (uint8_t *)malloc(sndpcm->chunk_bytes);
  163. if (!sndpcm->data_buf) {
  164. fprintf(stderr, "Error malloc: [data_buf]/n");
  165. goto ERR_SET_PARAMS;
  166. }
  167. return 0;
  168. ERR_SET_PARAMS:
  169. return -1;
  170. }
  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. }
    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. }

基于ALSA的WAV播放和录音程序的更多相关文章

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

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

  2. iOS开发----音频播放、录音、视频播放、拍照、视频录制

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

  3. 音频播放、录音、视频播放、拍照、视频录制-b

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

  4. iOS音频播放、录音、视频播放、拍照、视频录制

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

  5. iOS开发系列--音频播放、录音、

    音频 在iOS中音频播放从形式上可以分为音效播放和音乐播放.前者主要指的是一些短音频播放,通常作为点缀音频,对于这类音频不需要进行进度.循环等控制.后者指的是一些较长的音频,通常是主音频,对于这些音频 ...

  6. 第38章 I2S—音频播放与录音输入—零死角玩转STM32-F429系列

    第38章     I2S—音频播放与录音输入 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.com/ ...

  7. Android基于发展Service音乐播放器

    这是一个基于Service组件的音乐播放器,程序的音乐将会由后台的Service组件负责播放,当后台的播放状态改变时,程序将会通过发送广播通知前台Activity更新界面:当用户单击前台Activit ...

  8. 基于ffmpeg的C++播放器1

    基于ffmpeg的C++播放器 (1) 2011年12月份的时候发了这篇博客 http://blog.csdn.net/qq316293804/article/details/7107049 ,博文最 ...

  9. 基于FFMPEG的跨平台播放器实现(二)

    基于FFMPEG的跨平台播放器实现(二) 上一节讲到了在Android平台下采用FFmpeg+surface组合打造播放器的方法,这一节讲一下Windows平台FFmpeg + D3D.Linux平台 ...

随机推荐

  1. spring mvc接收http参数

    1.http协议携带参数,无外乎两个三个存储地点:1.url上 ,2.header里 3.body里. 2.get请求是没有body的,数据全都放在url上,以?xx&xxx形式.注:get请 ...

  2. windowsclient开发--为你clientsign一个签名证书

    郑重声明:该方法自娱自乐,尽管写入了签名,可是在微软系统免签证书不是合格的. 什么是签名? 话不多说,上图(没图说个xx): 微信windowsclient.exe安装文件: 再看还有一个.exe文件 ...

  3. 怎样手动的干净的删除linux上的ORACLE数据库

    近期在用VMWARE虚拟机做ORACLE的数据库实验.我们都知道在WINDOWS上,我能够到加入删除程序里去自己主动删除已经安装的全部的应用程序.可是在LINUX上没有这个服务能够进行自己主动的删除. ...

  4. 使用makeself创建安装文件

    Makeself.sh是一个小的Shell脚本.用于从一个文件夹中生成自解压的tar.gz压缩包. 结果文件以一个shell脚本显示(大多数以.run作为后缀名).能够自己主动执行.该文档会解压自己到 ...

  5. Running the app on your device

    So far, you've run the app on the Simulator. That's nice and all but probably notwhy you're learning ...

  6. POJ3177 Redundant Paths 图的边双连通分量

    题目大意:问一个图至少加多少边能使该图的边双连通分量成为它本身. 图的边双连通分量为极大的不存在割边的子图.图的边双连通分量之间由割边连接.求法如下: 求出图的割边 在每个边双连通分量内Dfs,标记每 ...

  7. ASP.NET Razor - C# Variables

    http://www.w3schools.com/aspnet/razor_cs_variables.asp Variables are named entities used to store da ...

  8. HP Z240组建磁盘阵列RAID1

  9. 第4章 部署模式 Deployment Plan(部署规划)

    已开发了基于组件的应用程序,该应用程序在逻辑上构造为多层结构,如 Three-Layered Services Application. 中所述.您希望将它分布到一组在物理上为多级结构的服务器上,如 ...

  10. 前端学习笔记-HTML(一)