基于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的转换。
- //File : wav_parser.h
- //Author : Loon <sepnic@gmail.com>
- #ifndef __WAV_PARSER_H
- #define __WAV_PARSER_H
- typedef unsigned char uint8_t;
- typedef unsigned short uint16_t;
- typedef unsigned int uint32_t;
- #if __BYTE_ORDER == __LITTLE_ENDIAN
- #define COMPOSE_ID(a,b,c,d) ((a) | ((b)<<8) | ((c)<<16) | ((d)<<24))
- #define LE_SHORT(v) (v)
- #define LE_INT(v) (v)
- #define BE_SHORT(v) bswap_16(v)
- #define BE_INT(v) bswap_32(v)
- #elif __BYTE_ORDER == __BIG_ENDIAN
- #define COMPOSE_ID(a,b,c,d) ((d) | ((c)<<8) | ((b)<<16) | ((a)<<24))
- #define LE_SHORT(v) bswap_16(v)
- #define LE_INT(v) bswap_32(v)
- #define BE_SHORT(v) (v)
- #define BE_INT(v) (v)
- #else
- #error "Wrong endian"
- #endif
- #define WAV_RIFF COMPOSE_ID('R','I','F','F')
- #define WAV_WAVE COMPOSE_ID('W','A','V','E')
- #define WAV_FMT COMPOSE_ID('f','m','t',' ')
- #define WAV_DATA COMPOSE_ID('d','a','t','a')
- /* WAVE fmt block constants from Microsoft mmreg.h header */
- #define WAV_FMT_PCM 0x0001
- #define WAV_FMT_IEEE_FLOAT 0x0003
- #define WAV_FMT_DOLBY_AC3_SPDIF 0x0092
- #define WAV_FMT_EXTENSIBLE 0xfffe
- /* Used with WAV_FMT_EXTENSIBLE format */
- #define WAV_GUID_TAG "/x00/x00/x00/x00/x10/x00/x80/x00/x00/xAA/x00/x38/x9B/x71"
- /* it's in chunks like .voc and AMIGA iff, but my source say there
- are in only in this combination, so I combined them in one header;
- it works on all WAVE-file I have
- */
- typedef struct WAVHeader {
- uint32_t magic; /* 'RIFF' */
- uint32_t length; /* filelen */
- uint32_t type; /* 'WAVE' */
- } WAVHeader_t;
- typedef struct WAVFmt {
- uint32_t magic; /* 'FMT '*/
- uint32_t fmt_size; /* 16 or 18 */
- uint16_t format; /* see WAV_FMT_* */
- uint16_t channels;
- uint32_t sample_rate; /* frequence of sample */
- uint32_t bytes_p_second;
- uint16_t blocks_align; /* samplesize; 1 or 2 bytes */
- uint16_t sample_length; /* 8, 12 or 16 bit */
- } WAVFmt_t;
- typedef struct WAVFmtExtensible {
- WAVFmt_t format;
- uint16_t ext_size;
- uint16_t bit_p_spl;
- uint32_t channel_mask;
- uint16_t guid_format; /* WAV_FMT_* */
- uint8_t guid_tag[14]; /* WAV_GUID_TAG */
- } WAVFmtExtensible_t;
- typedef struct WAVChunkHeader {
- uint32_t type; /* 'data' */
- uint32_t length; /* samplecount */
- } WAVChunkHeader_t;
- typedef struct WAVContainer {
- WAVHeader_t header;
- WAVFmt_t format;
- WAVChunkHeader_t chunk;
- } WAVContainer_t;
- int WAV_ReadHeader(int fd, WAVContainer_t *container);
- int WAV_WriteHeader(int fd, WAVContainer_t *container);
- #endif /* #ifndef __WAV_PARSER_H */
- //File : wav_parser.c
- //Author : Loon <sepnic@gmail.com>
- #include <assert.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <fcntl.h>
- #include "wav_parser.h"
- #define WAV_PRINT_MSG
- char *WAV_P_FmtString(uint16_t fmt)
- {
- switch (fmt) {
- case WAV_FMT_PCM:
- return "PCM";
- break;
- case WAV_FMT_IEEE_FLOAT:
- return "IEEE FLOAT";
- break;
- case WAV_FMT_DOLBY_AC3_SPDIF:
- return "DOLBY AC3 SPDIF";
- break;
- case WAV_FMT_EXTENSIBLE:
- return "EXTENSIBLE";
- break;
- default:
- break;
- }
- return "NON Support Fmt";
- }
- void WAV_P_PrintHeader(WAVContainer_t *container)
- {
- printf("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++/n");
- printf("/n");
- printf("File Magic: [%c%c%c%c]/n",
- (char)(container->header.magic),
- (char)(container->header.magic>>8),
- (char)(container->header.magic>>16),
- (char)(container->header.magic>>24));
- printf("File Length: [%d]/n", container->header.length);
- printf("File Type: [%c%c%c%c]/n",
- (char)(container->header.type),
- (char)(container->header.type>>8),
- (char)(container->header.type>>16),
- (char)(container->header.type>>24));
- printf("/n");
- printf("Fmt Magic: [%c%c%c%c]/n",
- (char)(container->format.magic),
- (char)(container->format.magic>>8),
- (char)(container->format.magic>>16),
- (char)(container->format.magic>>24));
- printf("Fmt Size: [%d]/n", container->format.fmt_size);
- printf("Fmt Format: [%s]/n", WAV_P_FmtString(container->format.format));
- printf("Fmt Channels: [%d]/n", container->format.channels);
- printf("Fmt Sample_rate: [%d](HZ)/n", container->format.sample_rate);
- printf("Fmt Bytes_p_second: [%d]/n", container->format.bytes_p_second);
- printf("Fmt Blocks_align: [%d]/n", container->format.blocks_align);
- printf("Fmt Sample_length: [%d]/n", container->format.sample_length);
- printf("/n");
- printf("Chunk Type: [%c%c%c%c]/n",
- (char)(container->chunk.type),
- (char)(container->chunk.type>>8),
- (char)(container->chunk.type>>16),
- (char)(container->chunk.type>>24));
- printf("Chunk Length: [%d]/n", container->chunk.length);
- printf("/n");
- printf("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++/n");
- }
- int WAV_P_CheckValid(WAVContainer_t *container)
- {
- if (container->header.magic != WAV_RIFF ||
- container->header.type != WAV_WAVE ||
- container->format.magic != WAV_FMT ||
- container->format.fmt_size != LE_INT(16) ||
- (container->format.channels != LE_SHORT(1) && container->format.channels != LE_SHORT(2)) ||
- container->chunk.type != WAV_DATA) {
- fprintf(stderr, "non standard wav file./n");
- return -1;
- }
- return 0;
- }
- int WAV_ReadHeader(int fd, WAVContainer_t *container)
- {
- assert((fd >=0) && container);
- if (read(fd, &container->header, sizeof(container->header)) != sizeof(container->header) ||
- read(fd, &container->format, sizeof(container->format)) != sizeof(container->format) ||
- read(fd, &container->chunk, sizeof(container->chunk)) != sizeof(container->chunk)) {
- fprintf(stderr, "Error WAV_ReadHeader/n");
- return -1;
- }
- if (WAV_P_CheckValid(container) < 0)
- return -1;
- #ifdef WAV_PRINT_MSG
- WAV_P_PrintHeader(container);
- #endif
- return 0;
- }
- int WAV_WriteHeader(int fd, WAVContainer_t *container)
- {
- assert((fd >=0) && container);
- if (WAV_P_CheckValid(container) < 0)
- return -1;
- if (write(fd, &container->header, sizeof(container->header)) != sizeof(container->header) ||
- write(fd, &container->format, sizeof(container->format)) != sizeof(container->format) ||
- write(fd, &container->chunk, sizeof(container->chunk)) != sizeof(container->chunk)) {
- fprintf(stderr, "Error WAV_WriteHeader/n");
- return -1;
- }
- #ifdef WAV_PRINT_MSG
- WAV_P_PrintHeader(container);
- #endif
- return 0;
- }
- //File : sndwav_common.h
- //Author : Loon <sepnic@gmail.com>
- #ifndef __SNDWAV_COMMON_H
- #define __SNDWAV_COMMON_H
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <fcntl.h>
- #include "wav_parser.h"
- typedef long long off64_t;
- typedef struct SNDPCMContainer {
- snd_pcm_t *handle;
- snd_output_t *log;
- snd_pcm_uframes_t chunk_size;
- snd_pcm_uframes_t buffer_size;
- snd_pcm_format_t format;
- uint16_t channels;
- size_t chunk_bytes;
- size_t bits_per_sample;
- size_t bits_per_frame;
- uint8_t *data_buf;
- } SNDPCMContainer_t;
- ssize_t SNDWAV_ReadPcm(SNDPCMContainer_t *sndpcm, size_t rcount);
- ssize_t SNDWAV_WritePcm(SNDPCMContainer_t *sndpcm, size_t wcount);
- int SNDWAV_SetParams(SNDPCMContainer_t *sndpcm, WAVContainer_t *wav);
- #endif /* #ifndef __SNDWAV_COMMON_H */
- //File : sndwav_common.c
- //Author : Loon <sepnic@gmail.com>
- #include <assert.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <fcntl.h>
- #include <alsa/asoundlib.h>
- #include "sndwav_common.h"
- int SNDWAV_P_GetFormat(WAVContainer_t *wav, snd_pcm_format_t *snd_format)
- {
- if (LE_SHORT(wav->format.format) != WAV_FMT_PCM)
- return -1;
- switch (LE_SHORT(wav->format.sample_length)) {
- case 16:
- *snd_format = SND_PCM_FORMAT_S16_LE;
- break;
- case 8:
- *snd_format = SND_PCM_FORMAT_U8;
- break;
- default:
- *snd_format = SND_PCM_FORMAT_UNKNOWN;
- break;
- }
- return 0;
- }
- ssize_t SNDWAV_ReadPcm(SNDPCMContainer_t *sndpcm, size_t rcount)
- {
- ssize_t r;
- size_t result = 0;
- size_t count = rcount;
- uint8_t *data = sndpcm->data_buf;
- if (count != sndpcm->chunk_size) {
- count = sndpcm->chunk_size;
- }
- while (count > 0) {
- r = snd_pcm_readi(sndpcm->handle, data, count);
- if (r == -EAGAIN || (r >= 0 && (size_t)r < count)) {
- snd_pcm_wait(sndpcm->handle, 1000);
- } else if (r == -EPIPE) {
- snd_pcm_prepare(sndpcm->handle);
- fprintf(stderr, "<<<<<<<<<<<<<<< Buffer Underrun >>>>>>>>>>>>>>>/n");
- } else if (r == -ESTRPIPE) {
- fprintf(stderr, "<<<<<<<<<<<<<<< Need suspend >>>>>>>>>>>>>>>/n");
- } else if (r < 0) {
- fprintf(stderr, "Error snd_pcm_writei: [%s]", snd_strerror(r));
- exit(-1);
- }
- if (r > 0) {
- result += r;
- count -= r;
- data += r * sndpcm->bits_per_frame / 8;
- }
- }
- return rcount;
- }
- ssize_t SNDWAV_WritePcm(SNDPCMContainer_t *sndpcm, size_t wcount)
- {
- ssize_t r;
- ssize_t result = 0;
- uint8_t *data = sndpcm->data_buf;
- if (wcount < sndpcm->chunk_size) {
- snd_pcm_format_set_silence(sndpcm->format,
- data + wcount * sndpcm->bits_per_frame / 8,
- (sndpcm->chunk_size - wcount) * sndpcm->channels);
- wcount = sndpcm->chunk_size;
- }
- while (wcount > 0) {
- r = snd_pcm_writei(sndpcm->handle, data, wcount);
- if (r == -EAGAIN || (r >= 0 && (size_t)r < wcount)) {
- snd_pcm_wait(sndpcm->handle, 1000);
- } else if (r == -EPIPE) {
- snd_pcm_prepare(sndpcm->handle);
- fprintf(stderr, "<<<<<<<<<<<<<<< Buffer Underrun >>>>>>>>>>>>>>>/n");
- } else if (r == -ESTRPIPE) {
- fprintf(stderr, "<<<<<<<<<<<<<<< Need suspend >>>>>>>>>>>>>>>/n");
- } else if (r < 0) {
- fprintf(stderr, "Error snd_pcm_writei: [%s]", snd_strerror(r));
- exit(-1);
- }
- if (r > 0) {
- result += r;
- wcount -= r;
- data += r * sndpcm->bits_per_frame / 8;
- }
- }
- return result;
- }
- int SNDWAV_SetParams(SNDPCMContainer_t *sndpcm, WAVContainer_t *wav)
- {
- snd_pcm_hw_params_t *hwparams;
- snd_pcm_format_t format;
- uint32_t exact_rate;
- uint32_t buffer_time, period_time;
- /* Allocate the snd_pcm_hw_params_t structure on the stack. */
- snd_pcm_hw_params_alloca(&hwparams);
- /* Init hwparams with full configuration space */
- if (snd_pcm_hw_params_any(sndpcm->handle, hwparams) < 0) {
- fprintf(stderr, "Error snd_pcm_hw_params_any/n");
- goto ERR_SET_PARAMS;
- }
- if (snd_pcm_hw_params_set_access(sndpcm->handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) {
- fprintf(stderr, "Error snd_pcm_hw_params_set_access/n");
- goto ERR_SET_PARAMS;
- }
- /* Set sample format */
- if (SNDWAV_P_GetFormat(wav, &format) < 0) {
- fprintf(stderr, "Error get_snd_pcm_format/n");
- goto ERR_SET_PARAMS;
- }
- if (snd_pcm_hw_params_set_format(sndpcm->handle, hwparams, format) < 0) {
- fprintf(stderr, "Error snd_pcm_hw_params_set_format/n");
- goto ERR_SET_PARAMS;
- }
- sndpcm->format = format;
- /* Set number of channels */
- if (snd_pcm_hw_params_set_channels(sndpcm->handle, hwparams, LE_SHORT(wav->format.channels)) < 0) {
- fprintf(stderr, "Error snd_pcm_hw_params_set_channels/n");
- goto ERR_SET_PARAMS;
- }
- sndpcm->channels = LE_SHORT(wav->format.channels);
- /* Set sample rate. If the exact rate is not supported */
- /* by the hardware, use nearest possible rate. */
- exact_rate = LE_INT(wav->format.sample_rate);
- if (snd_pcm_hw_params_set_rate_near(sndpcm->handle, hwparams, &exact_rate, 0) < 0) {
- fprintf(stderr, "Error snd_pcm_hw_params_set_rate_near/n");
- goto ERR_SET_PARAMS;
- }
- if (LE_INT(wav->format.sample_rate) != exact_rate) {
- fprintf(stderr, "The rate %d Hz is not supported by your hardware./n ==> Using %d Hz instead./n",
- LE_INT(wav->format.sample_rate), exact_rate);
- }
- if (snd_pcm_hw_params_get_buffer_time_max(hwparams, &buffer_time, 0) < 0) {
- fprintf(stderr, "Error snd_pcm_hw_params_get_buffer_time_max/n");
- goto ERR_SET_PARAMS;
- }
- if (buffer_time > 500000) buffer_time = 500000;
- period_time = buffer_time / 4;
- if (snd_pcm_hw_params_set_buffer_time_near(sndpcm->handle, hwparams, &buffer_time, 0) < 0) {
- fprintf(stderr, "Error snd_pcm_hw_params_set_buffer_time_near/n");
- goto ERR_SET_PARAMS;
- }
- if (snd_pcm_hw_params_set_period_time_near(sndpcm->handle, hwparams, &period_time, 0) < 0) {
- fprintf(stderr, "Error snd_pcm_hw_params_set_period_time_near/n");
- goto ERR_SET_PARAMS;
- }
- /* Set hw params */
- if (snd_pcm_hw_params(sndpcm->handle, hwparams) < 0) {
- fprintf(stderr, "Error snd_pcm_hw_params(handle, params)/n");
- goto ERR_SET_PARAMS;
- }
- snd_pcm_hw_params_get_period_size(hwparams, &sndpcm->chunk_size, 0);
- snd_pcm_hw_params_get_buffer_size(hwparams, &sndpcm->buffer_size);
- if (sndpcm->chunk_size == sndpcm->buffer_size) {
- fprintf(stderr, ("Can't use period equal to buffer size (%lu == %lu)/n"), sndpcm->chunk_size, sndpcm->buffer_size);
- goto ERR_SET_PARAMS;
- }
- sndpcm->bits_per_sample = snd_pcm_format_physical_width(format);
- sndpcm->bits_per_frame = sndpcm->bits_per_sample * LE_SHORT(wav->format.channels);
- sndpcm->chunk_bytes = sndpcm->chunk_size * sndpcm->bits_per_frame / 8;
- /* Allocate audio data buffer */
- sndpcm->data_buf = (uint8_t *)malloc(sndpcm->chunk_bytes);
- if (!sndpcm->data_buf) {
- fprintf(stderr, "Error malloc: [data_buf]/n");
- goto ERR_SET_PARAMS;
- }
- return 0;
- ERR_SET_PARAMS:
- return -1;
- }
- //File : lplay.c
- //Author : Loon <sepnic@gmail.com>
- #include <stdio.h>
- #include <malloc.h>
- #include <unistd.h>
- #include <stdlib.h>
- #include <string.h>
- #include <getopt.h>
- #include <fcntl.h>
- #include <ctype.h>
- #include <errno.h>
- #include <limits.h>
- #include <time.h>
- #include <locale.h>
- #include <sys/unistd.h>
- #include <sys/stat.h>
- #include <sys/types.h>
- #include <alsa/asoundlib.h>
- #include <assert.h>
- #include "wav_parser.h"
- #include "sndwav_common.h"
- ssize_t SNDWAV_P_SaveRead(int fd, void *buf, size_t count)
- {
- ssize_t result = 0, res;
- while (count > 0) {
- if ((res = read(fd, buf, count)) == 0)
- break;
- if (res < 0)
- return result > 0 ? result : res;
- count -= res;
- result += res;
- buf = (char *)buf + res;
- }
- return result;
- }
- void SNDWAV_Play(SNDPCMContainer_t *sndpcm, WAVContainer_t *wav, int fd)
- {
- int load, ret;
- off64_t written = 0;
- off64_t c;
- off64_t count = LE_INT(wav->chunk.length);
- load = 0;
- while (written < count) {
- /* Must read [chunk_bytes] bytes data enough. */
- do {
- c = count - written;
- if (c > sndpcm->chunk_bytes)
- c = sndpcm->chunk_bytes;
- c -= load;
- if (c == 0)
- break;
- ret = SNDWAV_P_SaveRead(fd, sndpcm->data_buf + load, c);
- if (ret < 0) {
- fprintf(stderr, "Error safe_read/n");
- exit(-1);
- }
- if (ret == 0)
- break;
- load += ret;
- } while ((size_t)load < sndpcm->chunk_bytes);
- /* Transfer to size frame */
- load = load * 8 / sndpcm->bits_per_frame;
- ret = SNDWAV_WritePcm(sndpcm, load);
- if (ret != load)
- break;
- ret = ret * sndpcm->bits_per_frame / 8;
- written += ret;
- load = 0;
- }
- }
- int main(int argc, char *argv[])
- {
- char *filename;
- char *devicename = "default";
- int fd;
- WAVContainer_t wav;
- SNDPCMContainer_t playback;
- if (argc != 2) {
- fprintf(stderr, "Usage: ./lplay <FILENAME>/n");
- return -1;
- }
- memset(&playback, 0x0, sizeof(playback));
- filename = argv[1];
- fd = open(filename, O_RDONLY);
- if (fd < 0) {
- fprintf(stderr, "Error open [%s]/n", filename);
- return -1;
- }
- if (WAV_ReadHeader(fd, &wav) < 0) {
- fprintf(stderr, "Error WAV_Parse [%s]/n", filename);
- goto Err;
- }
- if (snd_output_stdio_attach(&playback.log, stderr, 0) < 0) {
- fprintf(stderr, "Error snd_output_stdio_attach/n");
- goto Err;
- }
- if (snd_pcm_open(&playback.handle, devicename, SND_PCM_STREAM_PLAYBACK, 0) < 0) {
- fprintf(stderr, "Error snd_pcm_open [ %s]/n", devicename);
- goto Err;
- }
- if (SNDWAV_SetParams(&playback, &wav) < 0) {
- fprintf(stderr, "Error set_snd_pcm_params/n");
- goto Err;
- }
- snd_pcm_dump(playback.handle, playback.log);
- SNDWAV_Play(&playback, &wav, fd);
- snd_pcm_drain(playback.handle);
- close(fd);
- free(playback.data_buf);
- snd_output_close(playback.log);
- snd_pcm_close(playback.handle);
- return 0;
- Err:
- close(fd);
- if (playback.data_buf) free(playback.data_buf);
- if (playback.log) snd_output_close(playback.log);
- if (playback.handle) snd_pcm_close(playback.handle);
- return -1;
- }
- //File : lrecord.c
- //Author : Loon <sepnic@gmail.com>
- #include <stdio.h>
- #include <malloc.h>
- #include <unistd.h>
- #include <stdlib.h>
- #include <string.h>
- #include <getopt.h>
- #include <fcntl.h>
- #include <ctype.h>
- #include <errno.h>
- #include <limits.h>
- #include <time.h>
- #include <locale.h>
- #include <sys/unistd.h>
- #include <sys/stat.h>
- #include <sys/types.h>
- #include <alsa/asoundlib.h>
- #include <assert.h>
- #include "wav_parser.h"
- #include "sndwav_common.h"
- #define DEFAULT_CHANNELS (2)
- #define DEFAULT_SAMPLE_RATE (8000)
- #define DEFAULT_SAMPLE_LENGTH (16)
- #define DEFAULT_DURATION_TIME (10)
- int SNDWAV_PrepareWAVParams(WAVContainer_t *wav)
- {
- assert(wav);
- uint16_t channels = DEFAULT_CHANNELS;
- uint16_t sample_rate = DEFAULT_SAMPLE_RATE;
- uint16_t sample_length = DEFAULT_SAMPLE_LENGTH;
- uint32_t duration_time = DEFAULT_DURATION_TIME;
- /* Const */
- wav->header.magic = WAV_RIFF;
- wav->header.type = WAV_WAVE;
- wav->format.magic = WAV_FMT;
- wav->format.fmt_size = LE_INT(16);
- wav->format.format = LE_SHORT(WAV_FMT_PCM);
- wav->chunk.type = WAV_DATA;
- /* User definition */
- wav->format.channels = LE_SHORT(channels);
- wav->format.sample_rate = LE_INT(sample_rate);
- wav->format.sample_length = LE_SHORT(sample_length);
- /* See format of wav file */
- wav->format.blocks_align = LE_SHORT(channels * sample_length / 8);
- wav->format.bytes_p_second = LE_INT((uint16_t)(wav->format.blocks_align) * sample_rate);
- wav->chunk.length = LE_INT(duration_time * (uint32_t)(wav->format.bytes_p_second));
- wav->header.length = LE_INT((uint32_t)(wav->chunk.length) +/
- sizeof(wav->chunk) + sizeof(wav->format) + sizeof(wav->header) - 8);
- return 0;
- }
- void SNDWAV_Record(SNDPCMContainer_t *sndpcm, WAVContainer_t *wav, int fd)
- {
- off64_t rest;
- size_t c, frame_size;
- if (WAV_WriteHeader(fd, wav) < 0) {
- exit(-1);
- }
- rest = wav->chunk.length;
- while (rest > 0) {
- c = (rest <= (off64_t)sndpcm->chunk_bytes) ? (size_t)rest : sndpcm->chunk_bytes;
- frame_size = c * 8 / sndpcm->bits_per_frame;
- if (SNDWAV_ReadPcm(sndpcm, frame_size) != frame_size)
- break;
- if (write(fd, sndpcm->data_buf, c) != c) {
- fprintf(stderr, "Error SNDWAV_Record[write]/n");
- exit(-1);
- }
- rest -= c;
- }
- }
- int main(int argc, char *argv[])
- {
- char *filename;
- char *devicename = "default";
- int fd;
- WAVContainer_t wav;
- SNDPCMContainer_t record;
- if (argc != 2) {
- fprintf(stderr, "Usage: ./lrecord <FILENAME>/n");
- return -1;
- }
- memset(&record, 0x0, sizeof(record));
- filename = argv[1];
- remove(filename);
- if ((fd = open(filename, O_WRONLY | O_CREAT, 0644)) == -1) {
- fprintf(stderr, "Error open: [%s]/n", filename);
- return -1;
- }
- if (snd_output_stdio_attach(&record.log, stderr, 0) < 0) {
- fprintf(stderr, "Error snd_output_stdio_attach/n");
- goto Err;
- }
- if (snd_pcm_open(&record.handle, devicename, SND_PCM_STREAM_CAPTURE, 0) < 0) {
- fprintf(stderr, "Error snd_pcm_open [ %s]/n", devicename);
- goto Err;
- }
- if (SNDWAV_PrepareWAVParams(&wav) < 0) {
- fprintf(stderr, "Error SNDWAV_PrepareWAVParams/n");
- goto Err;
- }
- if (SNDWAV_SetParams(&record, &wav) < 0) {
- fprintf(stderr, "Error set_snd_pcm_params/n");
- goto Err;
- }
- snd_pcm_dump(record.handle, record.log);
- SNDWAV_Record(&record, &wav, fd);
- snd_pcm_drain(record.handle);
- close(fd);
- free(record.data_buf);
- snd_output_close(record.log);
- snd_pcm_close(record.handle);
- return 0;
- Err:
- close(fd);
- remove(filename);
- if (record.data_buf) free(record.data_buf);
- if (record.log) snd_output_close(record.log);
- if (record.handle) snd_pcm_close(record.handle);
- return -1;
- }
基于ALSA的WAV播放和录音程序的更多相关文章
- iOS开发系列--音频播放、录音、视频播放、拍照、视频录制
--iOS多媒体 概览 随着移动互联网的发展,如今的手机早已不是打电话.发短信那么简单了,播放音乐.视频.录音.拍照等都是很常用的功能.在iOS中对于多媒体的支持是非常强大的,无论是音视频播放.录制, ...
- iOS开发----音频播放、录音、视频播放、拍照、视频录制
随着移动互联网的发展,如今的手机早已不是打电话.发短信那么简单了,播放音乐.视频.录音.拍照等都是很常用的功能.在iOS中对于多媒体的支持是非常强大的,无论是音视频播放.录制,还是对麦克风.摄像头的操 ...
- 音频播放、录音、视频播放、拍照、视频录制-b
随着移动互联网的发展,如今的手机早已不是打电话.发短信那么简单了,播放音乐.视频.录音.拍照等都是很常用的功能.在iOS中对于多媒体的支持是非常强大的,无论是音视频播放.录制,还是对麦克风.摄像头的操 ...
- iOS音频播放、录音、视频播放、拍照、视频录制
随着移动互联网的发展,如今的手机早已不是打电话.发短信那么简单了,播放音乐.视频.录音.拍照等都是很常用的功能.在iOS中对于多媒体的支持是非常强大的,无论是音视频播放.录制,还是对麦克风.摄像头的操 ...
- iOS开发系列--音频播放、录音、
音频 在iOS中音频播放从形式上可以分为音效播放和音乐播放.前者主要指的是一些短音频播放,通常作为点缀音频,对于这类音频不需要进行进度.循环等控制.后者指的是一些较长的音频,通常是主音频,对于这些音频 ...
- 第38章 I2S—音频播放与录音输入—零死角玩转STM32-F429系列
第38章 I2S—音频播放与录音输入 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.com/ ...
- Android基于发展Service音乐播放器
这是一个基于Service组件的音乐播放器,程序的音乐将会由后台的Service组件负责播放,当后台的播放状态改变时,程序将会通过发送广播通知前台Activity更新界面:当用户单击前台Activit ...
- 基于ffmpeg的C++播放器1
基于ffmpeg的C++播放器 (1) 2011年12月份的时候发了这篇博客 http://blog.csdn.net/qq316293804/article/details/7107049 ,博文最 ...
- 基于FFMPEG的跨平台播放器实现(二)
基于FFMPEG的跨平台播放器实现(二) 上一节讲到了在Android平台下采用FFmpeg+surface组合打造播放器的方法,这一节讲一下Windows平台FFmpeg + D3D.Linux平台 ...
随机推荐
- 安装10gR2的硬件要求
1.至少1G的RAM. 2.RAM与swap关系: RAM swap 512M以上 2*RAM (非常奇怪.至少1G的RAM.还写512的 ...
- 【solr基础教程之中的一个】Solr相关知识点串讲
Solr是Apache Lucene的一个子项目.Lucene为全文搜索功能提供了完备的API.但它仅仅作为一个API库存在.而不能直接用于搜索. 因此,Solr基于Lucene构建了一 ...
- Qt 3D的研究(十):描边渲染(轮廓渲染)以及Silhouette Shader
Qt 3D的研究(十):描边渲染(轮廓渲染)以及Silhouette Shader 之前写了两篇文章,介绍了我在边缘检測上面的研究.实际上.使用GPU对渲染图像进行边缘检測.前提是须要进行两遍渲染.前 ...
- maven 镜像使用
maven中的snapshot来源与注意事项 maven中的snapshot来源与注意事项 (2012-04-23 15:37:48) 转载▼ 标签: 杂谈 分类: java maven的依赖管理是基 ...
- Iterator - 迭代器模式
定义 提供一个方法顺序訪问一个聚合对象中个各个元素,而又不须要暴露该对象的内部结构. 案例 一个聚合对象.如一个列表List.应该提供一种方法来让别人能够訪问它的元素.而又不用暴露内部结构.迭代器模式 ...
- 使用美橙主机建站(jsp+mysql+tomcat建站)
1.注冊美橙互联账号:http://www.cndns.com/ 2.选择橙云主机: 3.选择你须要的主机类型. 3.能够随时与客服进行沟通.购买完毕后登陆 管理中心 4.点击左边 主机类管理--&g ...
- Qt5.8 提供 Apple tvOS,watchOS的技术预览版
New Platforms Apple tvOS (technology preview) Apple watchOS (technology preview) https://wiki.qt.io/ ...
- EOJ 2822 内存显示
一个 int 类型变量或 double 类型变量在连续几个字节的内存中存放.读取数值时,当数值中包含小数点时类型为 double,否则类型为 int.将读入的数值存放在 int 类型变量或 doubl ...
- Python 3.x 判断 dict 是否包含某个键
Python 3.x不再支持 has_key() 函数,而被__contains__('key')所替代,会返回bool,可以用其做判断. 代码示例: >>> user = 'dad ...
- SqlServer执行存储过程时,参数值为null,sql语句参数值变成default
从C#代码里传入参数到调用存储过程,参数的值为null,执行存储过程一直提示需要参数 '@xxx',但未提供该参数.通过profiler发现生成的参数值变成为default. 解决方案:1.将Para ...