`
jandroid
  • 浏览: 1916045 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

Android Audio代码分析2 - 函数getMinBufferSize

 
阅读更多
AudioTrack的使用示例中,用到了函数getMinBufferSize,今天把它倒出来,再嚼嚼。


*****************************************源码*************************************************
static public int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat) {
int channelCount = 0;
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:
loge("getMinBufferSize(): Invalid channel configuration.");
return AudioTrack.ERROR_BAD_VALUE;
}

if ((audioFormat != AudioFormat.ENCODING_PCM_16BIT)
&& (audioFormat != AudioFormat.ENCODING_PCM_8BIT)) {
loge("getMinBufferSize(): Invalid audio format.");
return AudioTrack.ERROR_BAD_VALUE;
}

if ( (sampleRateInHz < 4000) || (sampleRateInHz > 48000) ) {
loge("getMinBufferSize(): " + sampleRateInHz +"Hz is not a supported sample rate.");
return AudioTrack.ERROR_BAD_VALUE;
}

int size = native_get_min_buff_size(sampleRateInHz, channelCount, audioFormat);
if ((size == -1) || (size == 0)) {
loge("getMinBufferSize(): error querying hardware");
return AudioTrack.ERROR;
}
else {
return size;
}
}
***********************************************************************************************
源码路径:
frameworks\base\media\java\android\media\AudioTrack.java


###########################################说明##############################################################
先把自带的注释拿来看看吧:
/**
* Returns the minimum buffer size required for the successful creation of an AudioTrack
* object to be created in the {@link #MODE_STREAM} mode. Note that this size doesn't
* guarantee a smooth playback under load, and higher values should be chosen according to
* the expected frequency at which the buffer will be refilled with additional data to play.
* @param sampleRateInHz the sample rate expressed in Hertz.
* @param channelConfig describes the configuration of the audio channels.
* See {@link AudioFormat#CHANNEL_OUT_MONO} and
* {@link AudioFormat#CHANNEL_OUT_STEREO}
* @param audioFormat the format in which the audio data is represented.
* See {@link AudioFormat#ENCODING_PCM_16BIT} and
* {@link AudioFormat#ENCODING_PCM_8BIT}
* @return {@link #ERROR_BAD_VALUE} if an invalid parameter was passed,
* or {@link #ERROR} if the implementation was unable to query the hardware for its output
* properties,
* or the minimum buffer size expressed in bytes.
*/
从注释可以看出,通过该函数获取的最小buffer size,只是保证在MODE_STREAM模式下成功地创建一个AudioTrack对象。
并不能保证流畅地播放。


1、参数就不说了,可以参考上面注释,上一篇文章中也有说。
2、定义了一个内部变量:
int channelCount = 0;
用来记录声道数量。
调用native函数native_get_min_buff_size时会用。
可见buffer size也是由native层来决定的。
3、接下来根据Channel类型,计算声道数量:
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:
loge("getMinBufferSize(): Invalid channel configuration.");
return AudioTrack.ERROR_BAD_VALUE;
}
MONO都是1,Stereo的都是2。
不过,我们之前看过,Channel类型不止这几种。有以下一堆呢:
public static final int CHANNEL_OUT_FRONT_LEFT = 0x4;
public static final int CHANNEL_OUT_FRONT_RIGHT = 0x8;
public static final int CHANNEL_OUT_FRONT_CENTER = 0x10;
public static final int CHANNEL_OUT_LOW_FREQUENCY = 0x20;
public static final int CHANNEL_OUT_BACK_LEFT = 0x40;
public static final int CHANNEL_OUT_BACK_RIGHT = 0x80;
public static final int CHANNEL_OUT_FRONT_LEFT_OF_CENTER = 0x100;
public static final int CHANNEL_OUT_FRONT_RIGHT_OF_CENTER = 0x200;
public static final int CHANNEL_OUT_BACK_CENTER = 0x400;
public static final int CHANNEL_OUT_MONO = CHANNEL_OUT_FRONT_LEFT;
public static final int CHANNEL_OUT_STEREO = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT);
public static final int CHANNEL_OUT_QUAD = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT |
CHANNEL_OUT_BACK_LEFT | CHANNEL_OUT_BACK_RIGHT);
public static final int CHANNEL_OUT_SURROUND = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT |
CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_BACK_CENTER);
public static final int CHANNEL_OUT_5POINT1 = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT |
CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_LOW_FREQUENCY | CHANNEL_OUT_BACK_LEFT | CHANNEL_OUT_BACK_RIGHT);
public static final int CHANNEL_OUT_7POINT1 = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT |
CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_LOW_FREQUENCY | CHANNEL_OUT_BACK_LEFT | CHANNEL_OUT_BACK_RIGHT |
CHANNEL_OUT_FRONT_LEFT_OF_CENTER | CHANNEL_OUT_FRONT_RIGHT_OF_CENTER);


并且,AudioFormat.CHANNEL_CONFIGURATION_MONO和AudioFormat.CHANNEL_CONFIGURATION_STEREO的定义还不包含在这一堆之中,而是在它们之前定义:
/** Mono audio configuration */
/** @deprecated use CHANNEL_OUT_MONO or CHANNEL_IN_MONO instead */
@Deprecated public static final int CHANNEL_CONFIGURATION_MONO = 2;
/** Stereo (2 channel) audio configuration */
/** @deprecated use CHANNEL_OUT_STEREO or CHANNEL_IN_STEREO instead */
@Deprecated public static final int CHANNEL_CONFIGURATION_STEREO = 3;


难道其他的Channel类型都不需要获取这个min buffer size???
还是说,目前只支持单声道和双声道???


4、下面判断音频格式,即采样点数据所占的bit数:
if ((audioFormat != AudioFormat.ENCODING_PCM_16BIT)
&& (audioFormat != AudioFormat.ENCODING_PCM_8BIT)) {
loge("getMinBufferSize(): Invalid audio format.");
return AudioTrack.ERROR_BAD_VALUE;
}
可见,只支持16bit和8bit两种。


5、判断采用率:
if ( (sampleRateInHz < 4000) || (sampleRateInHz > 48000) ) {
loge("getMinBufferSize(): " + sampleRateInHz +"Hz is not a supported sample rate.");
return AudioTrack.ERROR_BAD_VALUE;
}
只支持4000Hz到48000Hz之间。


6、接下来调到native中去:
int size = native_get_min_buff_size(sampleRateInHz, channelCount, audioFormat);
if ((size == -1) || (size == 0)) {
loge("getMinBufferSize(): error querying hardware");
return AudioTrack.ERROR;
}
else {
return size;
}
可见,真正干活的是在native中,java层中只是做些辅助操作。


通过前文中JNI的函数对照表,可知native_get_min_buff_size函数对应的是native中的android_media_AudioTrack_get_min_buff_size函数。
路径:frameworks\base\core\jni\android_media_AudioTrack.cpp


函数android_media_AudioTrack_get_min_buff_size的实现:
// returns the minimum required size for the successful creation of a streaming AudioTrack
// returns -1 if there was an error querying the hardware.
static jint android_media_AudioTrack_get_min_buff_size(JNIEnv *env, jobject thiz,
jint sampleRateInHertz, jint nbChannels, jint audioFormat) {


int frameCount = 0;
if (AudioTrack::getMinFrameCount(&frameCount, AudioSystem::DEFAULT,
sampleRateInHertz) != NO_ERROR) {
return -1;
}
return frameCount * nbChannels * (audioFormat == javaAudioTrackFields.PCM16 ? 2 : 1);
}


可见,最小buffer size是frameCoun乘以声道个数,在根据音频格式乘以1或2得到。
声道个数和音频格式都是传入的,不再说。
frameCount是调用函数AudioTrack::getMinFrameCount取得的。从函数名可知,此处取得的应该是最小frame数。
传入的三个参数:
&frameCount是用来保存frame计数的。
sampleRateInHertz是采样率。
AudioSystem::DEFAULT是写死的。其定义在类AudioSystem中,其他的定义如下:
enum stream_type {
DEFAULT =-1,
VOICE_CALL = 0,
SYSTEM = 1,
RING = 2,
MUSIC = 3,
ALARM = 4,
NOTIFICATION = 5,
BLUETOOTH_SCO = 6,
ENFORCED_AUDIBLE = 7, // Sounds that cannot be muted by user and must be routed to speaker
DTMF = 8,
TTS = 9,
NUM_STREAM_TYPES
};


原来是stream的类型。
为什么不在调用getMinBufferSize的时候传入stream类型,而在此处使用DEFAULT呢???


先放放,继续看函数AudioTrack::getMinFrameCount。


函数AudioTrack::getMinFrameCount的实现:
status_t AudioTrack::getMinFrameCount(
int* frameCount,
int streamType,
uint32_t sampleRate)
{
int afSampleRate;
if (AudioSystem::getOutputSamplingRate(&afSampleRate, streamType) != NO_ERROR) {
return NO_INIT;
}
int afFrameCount;
if (AudioSystem::getOutputFrameCount(&afFrameCount, streamType) != NO_ERROR) {
return NO_INIT;
}
uint32_t afLatency;
if (AudioSystem::getOutputLatency(&afLatency, streamType) != NO_ERROR) {
return NO_INIT;
}


// 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 * sampleRate / afSampleRate;
return NO_ERROR;
}


开始,调用了三个AudioSystem的函数,似曾谋面,不过当时被无视了,今天看看吧。


函数AudioSystem::getOutputSamplingRate的实现:
status_t AudioSystem::getOutputSamplingRate(int* samplingRate, int streamType)
{
OutputDescriptor *outputDesc;
audio_io_handle_t output;


if (streamType == DEFAULT) {
streamType = MUSIC;
}


output = getOutput((stream_type)streamType);
if (output == 0) {
return PERMISSION_DENIED;
}


gLock.lock();
outputDesc = AudioSystem::gOutputs.valueFor(output);
if (outputDesc == 0) {
LOGV("getOutputSamplingRate() no output descriptor for output %d in gOutputs", output);
gLock.unlock();
const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
if (af == 0) return PERMISSION_DENIED;
*samplingRate = af->sampleRate(output);
} else {
LOGV("getOutputSamplingRate() reading from output desc");
*samplingRate = outputDesc->samplingRate;
gLock.unlock();
}


LOGV("getOutputSamplingRate() streamType %d, output %d, sampling rate %d", streamType, output, *samplingRate);


return NO_ERROR;
}


判断流的类型,如果是DEFAULT,将其设置为MUSIC!
纳炉嚎啕!!!
DEFAULT的流类型原来是这么用的。


接下来根据stream type获取output。
然后获取output的描述。


若获取成功,则output描述中的采样率就是要获取的采样率。
否则,尝试从AudioFlinger中获取采样率。


函数AudioSystem::getOutputFrameCount,AudioSystem::getOutputLatency,与函数AudioSystem::getOutputSamplingRate的处理类似。


至此,采样率,frameCount和延迟都取得了。

接下来计算minBufCount:
// Ensure that buffer depth covers at least audio hardware latency
uint32_t minBufCount = afLatency / ((1000 * afFrameCount) / afSampleRate);
if (minBufCount < 2) minBufCount = 2;


从注释可知,buff大小应至少能覆盖audio 硬件的延迟。
公式不太明白。
先看看从链接:http://blog.csdn.net/innost/article/details/6125779
中摘过来的frame的说明:
一个frame就是1个采样点的字节数*声道。为啥搞个frame出来?因为对于多声道的话,用1个采样点的字节数表示不全,
因为播放的时候肯定是多个声道的数据都要播出来才行。所以为了方便,就说1秒钟有多少个frame,这样就能抛开声道数,把意思表示全了。


还不是很明白。先放放。
猜了半天也猜不出来。哪位大侠指点指点。


下面计算frameCount:
*frameCount = (sampleRate == 0) ? afFrameCount * minBufCount :
afFrameCount * minBufCount * sampleRate / afSampleRate;


我们的sampleRate肯定不为0,所以最后的计算应该为:afFrameCount * minBufCount * sampleRate / afSampleRate
分享到:
评论

相关推荐

    Android应用源码之AudioRecord.zip

    通过分析"Android应用源码之AudioRecord.zip"中的示例代码,你可以更深入地理解这些概念,并学会如何在实际项目中应用AudioRecord。源代码通常包括了创建、配置、启动、停止录音以及处理音频数据的关键步骤,这将...

    AudioRecord-master.zip

    2. **创建AudioRecord实例**:使用上述配置参数,通过构造函数创建`AudioRecord`实例。例如: ```java AudioRecord audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, sampleRate, channelConfig, ...

    Android 音频录制例子

    int minBufSize = AudioRecord.getMinBufferSize(sampleRate, channelConfig, audioFormat); // 获取最小缓冲区大小 AudioRecord recorder = new AudioRecord(MediaRecorder.AudioSource.MIC, sampleRate, ...

    Android录音指针实现代码

    int minBufferSize = AudioRecord.getMinBufferSize(sampleRate, channelConfig, audioFormat); AudioRecord audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, sampleRate, channelConfig, ...

    Android深入浅出之Audio

    ### Android Audio 子系统深入解析 #### 一、引言 Android系统因其强大的多媒体功能而备受青睐,其中音频处理作为其重要组成部分,在移动设备中扮演着至关重要的角色。本篇文章旨在通过对Android系统的Audio子系统...

    利用AudioRecord录制音频并播放

    在Android平台上,AudioRecord类是用于低级别音频输入的关键组件,它可以让我们直接访问设备的音频硬件,进行实时的音频数据录制。在这个项目中,“利用AudioRecord录制音频并播放”,我们将会探讨如何使用Audio...

    android 录音为mp3格式demo

    int minBufferSize = AudioRecord.getMinBufferSize(sampleRate, channelConfig, audioFormat); AudioRecord recorder = new AudioRecord(MediaRecorder.AudioSource.MIC, sampleRate, channelConfig, audioFormat, ...

    Android声音监控

    1. **初始化AudioRecord**:在构造函数中,通过`AudioRecord.getMinBufferSize`确定最小缓冲区大小,然后创建`AudioRecord`实例,设置其参数。 2. **启动录音**:在`run`方法中,调用`ar.startRecording()`开始录音...

    第一部分AudioTrack.txt

    考虑到Froyo版本的源代码具有一定的代表性,本文将以Froyo版本为基础进行分析。需要注意的是,虽然Froyo版本的源代码可能相对老旧,但对于理解基本原理已经足够。 #### 四、AudioTrack的核心API与使用示例 ##### ...

    Android pcm转wav格式方法

    在上述代码中,`PcmToWavUtil`类提供了一个构造函数,允许自定义采样率、声道数和编码方式。`pcmToWav`方法接收PCM文件的输入路径和转换后WAV文件的输出路径,然后创建WAV文件头并写入到输出文件。`createWaveHeader...

Global site tag (gtag.js) - Google Analytics