您的位置:首页 > 其它

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

2014-12-02 14:01 375 查看
转自: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;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: