Android Audio系统分析1(获得最小buffer部分)

网上有很多Android Audio的分析文章,但大部分都是基于比较老的源码,如Android 2.3, 4.0等,但现在Android都发展到6.0了,好多代码都已经面目全非了。
最近公司正好在做一个项目,涉及到Audio方面,正好将自己的学习工程记录下来,以便以后复习总结使用。
Android对外开放的播放音频文件的API主要有MediaPlayer, SoundPool,RingtoneManager, AudioTrack等。其中MediaPlayer用的最为广泛,使用比较方便,它可以播放多种格式的声音文件,如mp3,Wav等格式的文件;RingtoneManager的接口主要是用来播放提示音等文件,如来电铃声就是使用这个接口;AudioTrack却只能播放已经解码的PCM流,由此可知,其使用并不广泛,但它却是基础,MediaPlayer,SoundPool等接口最终还是要调用AudioTrack来进行播放。所以本篇文章主要是基于AudioTrack接口进行分析,这样也避免了牵涉各种音频格式。
1. 使用AudioTrack播放音频的例子
int bufferSizeInBytes = AudioTrack.getMinBufferSize(44100, AudioFormat.CHANNEL_OUT_STEREO,
AudioFormat.ENCODING_PCM_16BIT); //根据要播放的音频文件的参数获得最小的buffer大小

    byte[] audioData = new byte[bufferSizeInBytes];

    AudioTrack player = new AudioTrack(AudioManager.STREAM_MUSIC, 44100, AudioFormat.CHANNEL_OUT_STEREO,
            AudioFormat.ENCODING_PCM_16BIT, bufferSizeInBytes, AudioTrack.MODE_STREAM); 
    try {
        player.play();  // 准备播放

        while (true) {
            ... ...  // 向buffer中注入PCM数据
            player.write(audioData, 0, audioData.length);  //将数据写到audiotrack的缓冲区中
        }
    } finally {
        player.stop();  // 停止播放
        player.release(); //释放资源
}

设置AudioTracker的各种参数可以参考API文档,下面说明两点
1.1 数据加载模式
有两种加载模式,分别是MODE_STATIC和MODE_STREAM,这两种模式的区别可以从源码的注释中看的很清楚:
MODE_STATIC: Creation mode where audio data is transferred from Java to the native layer only once before the audio starts playing.
使用这种模式,要播放的数据在调用play之前只需要传输一次,记住是在调用play之前就要把要播放的数据全部传输到buffer中。
MODE_STREAM:Creation mode where audio data is streamed from Java to the native layer as the audio is playing.
在播放的过程中,不断地将数据写入到buffer中。
1.2 分配Buffer
调用getMinBufferSize获得一个buffer的最小值,这个是最小值,使用这个值,系统不能保证能过顺畅地播放音频流,最好选择一个稍高的值。
Java中获取最小buffer的代码如下:
static public int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat) {
int channelCount = 0;
// 计算通道数,现在支持高达9通道。
switch(channelConfig) {
case AudioFormat.CHANNEL_OUT_MONO:
case AudioFormat.CHANNEL_CONFIGURATION_MONO:
channelCount = 1;
break;
case AudioFormat.CHANNEL_OUT_STEREO:
case AudioFormat.CHANNEL_CONFIGURATION_STEREO:
channelCount = 2;
break;
default:
if ((channelConfig & SUPPORTED_OUT_CHANNELS) != channelConfig) {
// input channel configuration features unsupported channels
loge(“getMinBufferSize(): Invalid channel configuration.”);
return ERROR_BAD_VALUE;
} else {
channelCount = Integer.bitCount(channelConfig);
}
}
// 检查audio格式是否支持,目前支持PCM8,PCM16,PCM单浮点精度,AC3和EAC3压缩数据
if (!AudioFormat.isValidEncoding(audioFormat)) {
loge(“getMinBufferSize(): Invalid audio format.”);
return ERROR_BAD_VALUE;
}
//采样率也是有限制的,最低4000,最高96000
// sample rate, note these values are subject to change
if ( (sampleRateInHz < SAMPLE_RATE_HZ_MIN) || (sampleRateInHz > SAMPLE_RATE_HZ_MAX) ) {
loge(“getMinBufferSize(): ” + sampleRateInHz + ” Hz is not a supported sample rate.”);
return ERROR_BAD_VALUE;
}
// 调用native层查询是否支持这些参数设置,实际上最终是询问硬件是否支持这些参数设置。
int size = native_get_min_buff_size(sampleRateInHz, channelCount, audioFormat);
if (size <= 0) {
loge(“getMinBufferSize(): error querying hardware”);
return ERROR;
}
else {
return size;
}
}
AudioTrack.java对应的jni代码的文件位于frameworks/base/core/jni目录下的android_media_AudioTrack.cpp文件。
static jint android_media_AudioTrack_get_min_buff_size(JNIEnv *env, jobject thiz,
jint sampleRateInHertz, jint channelCount, jint audioFormat) {

size_t frameCount;
//获得最小的帧数
const status_t status = AudioTrack::getMinFrameCount(&frameCount, AUDIO_STREAM_DEFAULT,
        sampleRateInHertz);
if (status != NO_ERROR) {
    ALOGE("AudioTrack::getMinFrameCount() for sample rate %d failed with status %d",
            sampleRateInHertz, status);
    return -1;
}
// 计算buffer的大小。分为是否是PCM数据,如果是PCM格式,bufrer是由每帧的字节数,通道数量和采样一次的字节数的乘机计算而出;
// 每帧的字节说是通道数乘以每采次样需要的字节数计算出来的。
// 如果不是PCM格式(如AMR, ACC等等),则其buffer的大小就是帧数。
const audio_format_t format = audioFormatToNative(audioFormat);
if (audio_is_linear_pcm(format)) {
    const size_t bytesPerSample = audio_bytes_per_sample(format);
    return frameCount * channelCount * bytesPerSample;
} else {
    return frameCount;
}

}
下面看是如何获得帧数的。
【frameworks/av/media/libmedia/AudioTrack.cpp】
status_t AudioTrack::getMinFrameCount(
size_t* frameCount,
audio_stream_type_t streamType,
uint32_t sampleRate)
{
if (frameCount == NULL) {
return BAD_VALUE;
}
uint32_t afSampleRate;
status_t status;
// 上一步调用时传进来的streamType为AUDIO_STREAM_DEFAULT,而该制在查询时是对应的是AUDIO_STREAM_MUSIC,也就是说java层不管是想获得什么类型的audio类型,实际上native层查询的就是Music类型的。
// 通过AudioFlinger获得输出设备支持的采样率
status = AudioSystem::getOutputSamplingRate(&afSampleRate, streamType);
… …
size_t afFrameCount;
status = AudioSystem::getOutputFrameCount(&afFrameCount, streamType);
… …
uint32_t afLatency;
status = AudioSystem::getOutputLatency(&afLatency, streamType);
… …

// Ensure that buffer depth covers at least audio hardware latency
uint32_t minBufCount = afLatency / ((1000 * afFrameCount) / afSampleRate);
if (minBufCount < 2) {
    minBufCount = 2;
}


*frameCount = (sampleRate == 0) ? afFrameCount * minBufCount :
        afFrameCount * minBufCount * uint64_t(sampleRate) / afSampleRate;
// The formula above should always produce a non-zero value, but return an error
// in the unlikely event that it does not, as that's part of the API contract.
if (*frameCount == 0) {
    ALOGE("AudioTrack::getMinFrameCount failed for streamType %d, sampleRate %d",
            streamType, sampleRate);
    return BAD_VALUE;
}
ALOGV("getMinFrameCount=%zu: afFrameCount=%zu, minBufCount=%d, afSampleRate=%d, afLatency=%d",
        *frameCount, afFrameCount, minBufCount, afSampleRate, afLatency);
return NO_ERROR;

}
上面是以AudioSystem,实际上是通过AudioFlinger访问HAL层的framecount,latency等,所以可以看到在每个变量前面有af字样,af实际上就是AudioFlinger的缩写。
本章大致分析了如何获得最小的缓冲buffer,写一节将分析刚刚出现的AudioSystem。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值