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


    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.   
    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. }  
  • 相关阅读:
    vue使用axios调用api接口
    vue引用echarts
    C# 倒计时,显示天,时,分,秒。时间可以是从数据库捞出来
    DataGridView 控件操作大全 (内容居中显示,右键绑定菜单)
    Oracle使用row_number()函数查询时增加序号列
    Oracle 相关操作SQL
    oracle rac切换到单实例DG后OGG的处理
    oracle dg库因为standby_file_management参数导致应用停止
    oracle rac与单实例DG切换
    oracle rac搭建单实例DG步骤(阅读全篇后再做)
  • 原文地址:https://www.cnblogs.com/cainiaoaixuexi/p/3920437.html
Copyright © 2020-2023  润新知