关于安卓AudioTrack::getMinFrameCount的分析

本文详细解析了音频处理中软件缓冲区大小的计算方法,包括如何确保软件缓冲区能满足硬件延迟的要求,以及不同采样率下缓冲区帧数的调整策略。

http://blog.youkuaiyun.com/u013150907/article/details/44674805


转载自http://www.cnblogs.com/andriod-html5/archive/2012/06/06/2539531.html,感谢大神分享


  1. // Ensure that buffer depth covers at least audio hardware latency  
  2. uint32_t minBufCount = afLatency / ((1000 * afFrameCount) / afSampleRate);  

minBufCount = 200 / ((1000×1536)/44100) = 5.


消化消化。
afFrameCount的意思是硬件buffer里能放多少frame,afFrameCount/afSampleRate的意思是,播放一次硬件buffer中的数据需要多少时间,算出来的单位是秒。
再乘以个1000,即将秒转为了毫秒。
这样就与afLatency的单位一致了。
这样算出来的结果,就是说,为了满足硬件延迟,软件侧的buffer大小只是要是硬件侧buffer大小的多少倍。


感觉还是没消化彻底。
什么是硬件延迟?为什么软件侧的buffer size需要这个倍数呢?
硬件延迟,就是说,硬件侧可能会延迟这么久,也就是说硬件可能有这么长的时间都没有从软件侧取数据。
而软件侧还在不停地写数据,为了保证软件侧的数据不被丢失,就需要软件侧的buffer足够大。
多大才是足够大呢?
就是在硬件允许的最大时间,不取数据的情况下,软件侧的buffer也不至于爆仓。
这样基本上消化彻底了。


frameCount的计算与传入参数sampleRate有关:

  1. *frameCount = (sampleRate == 0) ? afFrameCount * minBufCount :  
  2.           afFrameCount * minBufCount * sampleRate / afSampleRate;  

如果sampleRate为0,frameCount为 7680.
如果sampleRate不为0,frameCount为7680×sampleRate/44100.


消化一下。
既然上面已经算出来了软件buffer 大小只是要是硬件的多少倍,而硬件buffer中包含的frame个数已经知道为afFrameCount,
算出软件buffer中包含多少frame也没什么困难了。
如果软件侧过来的数据与硬件侧的sampling rate未指定,或者与硬件侧的一样,软件侧的buffer能装的frame个数即为afFrameCount * minBufCount。

如果软件侧的sampling rate与硬件侧不一致,就拿上面的结果再乘以个sampleRate / afSampleRate即可。


         基于以上大神分析,加上我的理解总结如下:

uint32_t minBufCount = afLatency / ((1000 * afFrameCount) / afSampleRate);

afFrameCount为硬件buffer一次能够播放多少个frame,单位为frame。

afSampleRate为每秒采样多少个frame。

afFrameCount/afSampleRate表示硬件buffer能够一次播放多少秒的数据。乘以1000表示播放多少ms的数据。

afLatency 硬件延迟表示硬件从第一次取数据到第二次去数据总共花了多少ms。

所以minBufCount表示上层需要最少准备多少个硬件buffer大小的软件buffer,才能保证传输数据不会出现中断。单位为个。

afFrameCount * minBufCount * sampleRate / afSampleRate; 

afFrameCount * minBufCount表示我这个软件buffer里面有多少个frame。

sampleRate / afSampleRate可看成比值,即所需传输的采样率和硬件支持的采样率比值,表示我这个软件buffer如果用在传输实际sampleRate的数据的话,可以大一些,也可以小一些。那么就看这个比值了。以上公式就表示我软件buffer需要多少个frame才能保证不会断音。

frameCount * nbChannels * (audioFormat == ENCODING_PCM_16BIT ? 2 : 1);

再加上这个就表示我软件buffer需要多少个字节的空间了。


这个代码: 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: if (!isMultichannelConfigSupported(channelConfig)) { loge("getMinBufferSize(): Invalid channel configuration."); return ERROR_BAD_VALUE; } else { channelCount = AudioFormat.channelCountFromOutChannelMask(channelConfig); } } if (!AudioFormat.isPublicEncoding(audioFormat)) { loge("getMinBufferSize(): Invalid audio format."); return ERROR_BAD_VALUE; } // sample rate, note these values are subject to change // Note: AudioFormat.SAMPLE_RATE_UNSPECIFIED is not allowed /*就是采样率,人耳朵在20hz到20khz之间。 *采样率支持:4KHz~192KHz好像可以找到设定的值 */ if ( (sampleRateInHz < AudioFormat.SAMPLE_RATE_HZ_MIN) || (sampleRateInHz > AudioFormat.SAMPLE_RATE_HZ_MAX) ) { loge("getMinBufferSize(): " + sampleRateInHz + " Hz is not a supported sample rate."); return ERROR_BAD_VALUE; } /*frameworks/base/core/jni/android_media_AudioTrack.cpp中 android_media_AudioTrack_get_min_buff_size这个函数来实现的 */ int size = native_get_min_buff_size(sampleRateInHz, channelCount, audioFormat); if (size <= 0) { loge("getMinBufferSize(): error querying hardware"); return ERROR; } else { return size; } } 和这个代码:static jint android_media_AudioTrack_get_min_buff_size(JNIEnv *env, jobject thiz, jint sampleRateInHertz, jint channelCount, jint audioFormat) { size_t frameCount; /*这个函数用于确定至少设置多少个 frame 才能保证声音正常播放,也就是最低帧数*/ 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; } const audio_format_t format = audioFormatToNative(audioFormat); if (audio_has_proportional_frames(format)) { const size_t bytesPerSample = audio_bytes_per_sample(format); /*PCM 数据最小缓冲区大小 *最小缓冲区的大小 = 最低帧数 * 声道数 * 采样深度,(采样深度以字节为单位) */ return frameCount * channelCount * bytesPerSample; } else { return frameCount; } } 是怎么联系起来的
07-23
<think> 我们正在分析AudioTrack::restartIfDisabled函数的调用条件。根据用户提供的引用和问题,我们需要从引用中提取相关信息。 引用[1]描述了AudioTrack创建过程,其中提到AudioFlinger创建track时使用input和output参数,但未直接提及restartIfDisabled。 引用[2]提到在特定情况下(锁屏、返回后台、点击home键)出现声音卡顿,并输出log:W/AudioTrack: releaseBuffer() track ... disabled due to previous underrun, restarting。这里的关键词是“underrun”(欠载)和“restarting”(重启)。这暗示了当发生underrun时,AudioTrack会被标记为disabled,然后需要重启。 引用[3]提到在MODE_STREAM模式下,写入数据后需要调用releaseBuffer()来更新环形缓冲区的写指针。而releaseBuffer()函数中可能会检测到欠载情况。 结合引用[2]的log信息,我们可以推断:当AudioTrack在releaseBuffer()调用时检测到先前的欠载(underrun)情况,会将轨道标记为disabled,并触发重启。因此,restartIfDisabled函数很可能就是在这种情况下被调用的。 另外,根据Android源码的常见逻辑,restartIfDisabled函数应该在AudioTrack被标记为disabled并且需要重新激活时调用。通常,在写入数据之前或之后(例如在write或releaseBuffer中)可能会检查是否需要重启。 因此,AudioTrack::restartIfDisabled函数的调用条件可能是: 1. 当发生欠载(underrun)导致AudioTrack被禁用(disabled)时,在后续的操作(如写入数据或释放缓冲区)中会尝试重启。 2. 具体来说,在releaseBuffer()函数中,如果检测到轨道因先前的欠载而被禁用,就会调用restartIfDisabled(或类似的函数)来重启轨道。 由于引用[2]的log直接提到了“disabled due to previous underrun, restarting”,我们可以确定在underrun导致disabled的情况下,会触发重启。 总结:AudioTrack::restartIfDisabled函数在AudioTrack因欠载(underrun)被禁用(disabled)后,尝试重新启动该轨道时被调用。这通常发生在释放缓冲区(releaseBuffer)时检测到轨道处于禁用状态。 注意:以上分析基于提供的引用和一般知识。如需更精确的细节,需要查阅Android源码中AudioTrack::restartIfDisabled的具体实现。 </think> 根据提供的引用信息和Android音频系统的工作原理,`AudioTrack::restartIfDisabled` 函数主要在以下场景被调用: ### 主要触发条件: 1. **音频欠载恢复** 当发生 **underrun(缓冲区欠载)** 导致 AudioTrack 被禁用时(常见于高负载或系统资源不足)。如引用[2]所述: > `W/AudioTrack: releaseBuffer() track ... disabled due to previous underrun, restarting` 当 `releaseBuffer()` 检测到轨道因欠载被禁用时,会触发重启流程[^2]。 2. **环形缓冲区状态异常** 在 `MODE_STREAM` 模式下(引用[3]),当 `releaseBuffer()` 更新环形缓冲区写指针时,若检测到: - 缓冲区数据不足(欠载) - 音频管线异常中断 - 硬件抽象层(HAL)反馈状态错误 会触发重启机制[^3]。 3. **系统策略变更** 当系统音频策略动态调整时(如引用[1]中提到的输入输出参数变化),若当前 AudioTrack 配置失效: ```cpp audioFlinger->createTrack(input, output, &status); // 参数不匹配时需重建 ``` 可能触发重启[^1]。 4. **应用状态切换** 如引用[2]所示场景: - 设备锁屏/进入后台时音频焦点丢失 - 回到前台时需恢复播放 此时需重启被系统禁用的 AudioTrack[^2]。 ### 工作流程总结: `restartIfDisabled` 本质是 AudioTrack 的**异常恢复机制**,核心逻辑为: ``` 检测到轨道禁用标志 → 释放旧资源 → 通过 AudioFlinger 重建轨道 → 恢复播放状态 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值