Errorget_snd_pcm_format/n ); goto ERR_S北京速记ET_PARAMS; } if

日期:2016-08-12 / 人气: / 来源:网络整理

这段时间在摸索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的转换。

[cpp] view plain

//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 */  


[cpp] view plain

//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)  

{  

作者:北京速记公司


现在致电 010-63797486 OR 查看更多联系方式 →

Go To Top 回顶部