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)
{
作者:北京速记公司
推荐内容 Recommended
- 以及六个分论坛:普惠金融与创新09-28
- 用法式文化中最求极致精神录音整09-27
- 有66个大二速录公司学生在学09-23
- 在经济环境、政策环境、政治法律09-23
- 所以结构优化是我们要录音整理提09-23
- 地里的迎庆桃眼现场速记看着就要09-21
相关内容 Related
- 其实围绕智能家居北京速记跟机器09-29
- 吴江警方官方微现场速记信粉丝上09-29
- 郑州日产郭振甫北京速记公司2015两09-29
- 学生量忽略不计;北京速记速读速09-29
- 2015中国国际厨卫展现场速记 博世家09-29
- 潼关县、澄城县创现场速记建省级09-29