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

转载于:https://www.cnblogs.com/andriod-html5/archive/2011/09/29/2539561.html

Android Audio代码分析2 - 函数getMinBufferSize相关推荐

  1. Android Audio代码分析8 - AudioHardwareALSA::openOutputStream函数

    发现以前写的东西,对调用函数的展开放在了函数的前面,导致不方便找到原来代码及设置的函数参数. 以后打算稍作改动,把对被调函数的展开放在原代码的后面,这样看起来应该方便些. 闲言少叙,跳入代码. 前两天 ...

  2. Android Audio代码分析(2): AudioPoilicyService 启动

    policy: 设备的选择 https://www.cxyzjd.com/article/VNanyesheshou/115659838 Android 音频源码分析--AudioTrack设备选择_ ...

  3. Android Audio代码分析7 - stream type

    在看AudioTrack代码的时候,我们看到,要创建一个AudioTrack对象,需要指定一个StreamType. 今天我们只把stream type相关的代码抽取出来,详细看看stream typ ...

  4. Android Audio代码分析25 - JNI callback

    今天来说说 native 中的代码是如何调用 java 侧代码的. 在看 setEnabled 代码的时候,我们了解到,最终在函数 EffectHandle::setEnabled 中会调用 java ...

  5. android audio代码分析,Android10.0AudioFocus之源码分析(二)

    前言 上一篇我们简单说了AudioFocus如何使用,那么今天就从源码角度看一下AudioFocus的实现原理. 正文 先说下requestAudioFocus,源码如下: public int re ...

  6. Android Audio代码分析(4): audiohalservice 启动

    hal interface IDeviceFactory openDevice得到IDevice, IDevice openInput/outputStream得到IStream android.ha ...

  7. 基于Android T代码分析: 在freeform窗口的标题栏拖动时移动窗口流程和拖动freeform窗口边沿改变大小流程

    基于Android T代码分析: 在freeform窗口的标题栏拖动时移动窗口流程和拖动freeform窗口边沿改变大小流程在线看Android源代码网址: http://aospxref.com/a ...

  8. Android Region代码分析

    一.Region的定义和合法性检查 在Android系统中,定义了Region的概念,它代表屏幕上的一个区域,它是由一个或多个Rect组成的,代码位于frameworks/native/libs/ui ...

  9. Android Audio 架构分析

    一个音频系统大概包括音频的管理.声音播放.声音录音和声音音效几个部分,这几个部分分工协作来完成音频的功能, ·音频管理:负责音量调节.音频设备选择.响铃模式选择等: ·声音播放:负责一个音频流的创建. ...

最新文章

  1. 在线文档预览方案-office web apps
  2. 指纹浏览器 开源 linux,浏览器指纹--Canvas指纹
  3. tensorflow和keras的版本问题
  4. 项目管理中的客户需求变更时需求分析和解决方法
  5. 拥抱.NET Core系列:依赖注入(1)
  6. android加法服务类,iOS越来越像Android:苹果简单做加法远离精致
  7. 单链表实现一元多项式相加_python面试系列 01如何实现单链表的逆序
  8. 特斯拉要退市!马斯克内部信:不受华尔街摆布;股价大涨10%
  9. 记录android离屏渲染的一些资料
  10. 如何“加密”你的email地址
  11. 新旧时代的更替——Turbo码/TCM码
  12. DS18B20使用说明
  13. 物联网-智能家居相关知识了解
  14. IJCAI 2021 | 面向睡眠阶段分类的多模态显著性波形检测网络
  15. 网页打印计算机死机,调用网络打印就死机
  16. 行业分析| 物流对讲
  17. 记录一下iter()的用法
  18. 原生JS实现任意数据的动态表格
  19. 四位数码管IIC-TM1637
  20. 第四届长安杯电子取证大赛个人总结

热门文章

  1. 自然语言处理中的预训练模型 —— 邱锡鹏老师的演讲记录
  2. leetcode —— 41. 缺失的第一个正数
  3. 计算机网络——OSI参考模型和TCP/IP协议
  4. excel 多次筛选后的range数据处理
  5. 断电,软件崩溃,系统中毒,未点击保存,就关闭导致资料丢失,以word文件文件为例,如何找回
  6. Cppcheck 1 54 C/C++静态代码分析工具
  7. 约瑟夫环问题(顺序表和单向链表)
  8. 基于模型协同过滤推荐离线召回:ALS
  9. 迷宫问题(栈解决)--2015年8月9日19:23:23v1.0版
  10. AGV (Automated guided vehicle)基础(二) - AGV的视觉算法 - RGB - D 算法