简介
PortAudio 是一个跨平台采集和播放音频的开源库,不过尚未支持Android平台,笔者决定让PortAudio支持Android。
Android上,处理音频的库是OpenSL ES,从API 9开始支持的技术,通过这个标准,Android已经完全可以在native层采集和播放音频。
换句话说,PortAudio支持Android,也就是支持OpenSL ES。
详情
Opensl es
penSL ES 是无授权费、跨平台、针对嵌入式系统精心优化的硬件音频加速API。它为嵌入式移动多媒体设备上的本地应用程序开发者提供标准化, 高性能,低响应时间的音频
功能实现方法,并实现软/硬件音频性能的直接跨平台部署,降低执行难度,促进高级音频市场的发展。
实现
Android Opensl es 实现可以直接通过官方的Demo了解。官方的demo提供了音频采集、音频缓存播放、音频url播放、音频文件播放、调整混合音效等等功能。
函数如下:
////////////////////////////////////////音频播放器操作 static int CreateAudioPlayer(SLObjectItf *playerObject, SLEngineItf engine, SLObjectItf mix, int numChannels, double sampleRate, PaSampleFormat sampleFormat );//建立音频 static int OpenAudioPlayer(PaOpenSLESStream* stream,unsigned long framesPerBuffer,PaSampleFormat outputSampleFormat);//打开音频播放器 static int SetAudioPlayerVolum(PaOpenSLESStream* stream,int millibel); //设置音频声量 static int PushAudioPlayerQueue(PaOpenSLESStream* stream);//向音频播放器输入数据 static int StartAudioPlayer(PaOpenSLESStream* stream);//开始音频 static int CloseAudioPlayer(PaOpenSLESStream* stream);//关闭音频 static int SetAudioPlayerMuteSolo(PaOpenSLESStream* stream,int chan,int muteSolo);//操作MuteSolo ///////////////////////////////////////麦克风操作 static int CreateAudioRecorder(SLObjectItf *recorderObject, SLEngineItf engine,int numChannels, double sampleRate, PaSampleFormat sampleFormat); static int OpenAudioRecorder(PaOpenSLESStream* stream,unsigned long framesPerBuffer,PaSampleFormat inputSampleFormat);//打开麦克风 static int CloseAudioRecorder(PaOpenSLESStream* stream);//关闭麦克风 static int StartAudioRecorder(PaOpenSLESStream* stream);//开始麦克风 static int PopAudioRecorderQueue(PaOpenSLESStream* stream);//向音频播放器取出数据
PortAudio Opensl es实现
实现机制如下--------音频采集缓存、音频播放缓存然后回调实现数据处理便可。
代码按源码pa_hostapi_skeleton.c模版实现便可。
回调如下:
static int c_callback(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo* outTime, const PaStreamCallbackFlags statusFlags, void *userData)
音频元素
涉及音频的元素挺多,记录如下:
OpenSLES 中 typedef struct SLDataFormat_PCM_ { SLuint32 formatType; 数据格式定义 SL_DATAFORMAT_PCM SLuint32 numChannels; 声道个数(跟channelMask 一致) SLuint32 samplesPerSec; 每秒采集频率 hz SLuint32 bitsPerSample; 采样比特(采样格式) SLuint32 containerSize; 包含大小 SLuint32 channelMask; 通道面具//立体声、左声道、右声道 SLuint32 endianness; 块的字节顺序 从16--32位 } SLDataFormat_PCM; GUID----- SL_IID_VOLUME 音量 SL_IID_PLAY 播放控制 SL_IID_BUFFERQUEUE 缓存接口 SL_IID_EFFECTSEND 音效 SL_IID_MUTESOLO 静音 SL_IID_RECORD 录音接口 SL_IID_PLAYBACKRATE 采样率控制 SL_IID_EQUALIZER 均衡器 SL_IID_PRESETREVERB 预设混响 SL_IID_ENVIRONMENTALREVERB 环境混响 SL_IID_3DLOCATION 3D定位 SL_IID_3DDOPPLER 多普勒效应 SL_IID_BASSBOOST 低音增强 SL_IID_PITCH 升降调 SL_IID_VIRTUALIZER 虚拟化 ……
采集频率:音频的采样频率,每秒钟能够采样的次数,采样率越高,音质越高。给出的实例是44100、22050、11025但不限于这几个参数。例如要采集低质量的音频就可以使
用4000、8000等。
量化位数(数据位数):采样值或取样值,用来衡量声音波动变化的一个参数,也可以说是声卡的分辨率。
1 字节(也就是8bit) 只能记录 256 个数, 也就是只能将振幅划分成 256 个等级;
2 字节(也就是16bit) 可以细到 65536 个数, 这已是 CD 标准了;
4 字节(也就是32bit) 能把振幅细分到 4294967296 个等级, 实在是没必要了。
比特率:它描述了单位时间长度的媒体内容需要空间。每秒的传输速率。
声道:声音的通道的数目。常有单声道和立体声之分。
帧:单位时间内媒体帧的个数,其长度为样本长度(采样位数)和通道数的乘积。
数据量:采集数据需要的缓冲区的大小
数据量(字节每秒) = 采集频率 * 量化位数 * 声道数 / 8(字节) = 帧 * 字节
周期:音频设备一次处理所需要的帧数,对于音频设备的数据访问以及音频数据的存储,都是以此为单位。
交错模式:数字音频信号存储的方式。数据以连续帧的方式存放,即首先记录帧1的左声道样本和右声道样本,再开始帧2的记录...,
非交错模式:首先记录的是一个周期内所有帧的左声道样本,再记录所有右声道样本。
总结
PortAudio支持Android,为Raknet实现语音通话提供了方便。