Android RakNet 系列之三 移植Portaudio

简介

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实现语音通话提供了方便。


你可能感兴趣的:(Android RakNet 系列之三 移植Portaudio)