转自:https://www.cnblogs.com/wulizhi/p/8183658.html 感谢博主!
2018-01-03 14:36 wulizhi 阅读(2981)
一。 简介:
我们知道,在Android Audio框架中,主要有四种播放模式: Deep buffer Playback, Low latency Playback, Offload playback和Mutichannel Playback。
Deep buffer Playback:音频文件是在AP侧解码成PCM文件,然后再送到ADSP中处理,音效部分处理的话是在AP侧或者ADSP中进行的。
标志: AUDIO_OUTPUT_FLAG_PRIMARY
支持的声道: 双声道
支持的采样率: 44.1Khz和48Khz
应用场景: 铃声,音视频播放,YouTube等
Low Latency Playback : 和Deep buffer Playback方式类似,但是它所分配的buffer更小些,并且在ADSP侧只做很少或者基本不做处理, 主要是播放一些对延迟要求较高的音频,
比如触碰音和游戏音。
标志:AUDIO_OUTPUT_FLAG_FAST
支持的声道:双声道
支持的采样率:44.1Khz和48Khz
应用场景: 触碰音,游戏音等
Offload Playback: 音频解码部分的工作是在ADSP中完成,AP侧只负责把音频数据送到ADSP中,送出去后,AP侧会进行休眠,ADSP中会分配一块较大的buffer去处理此数据,
在ADSP中进行解码,音效的处理工作,在ADSP解码器处理完数据之前,它会唤醒AP侧去送下一包数据。
支持的格式:MP3, AC3, EAC3, AAC, FLAC, 24bit PCM, 16 bit PCM
标志:AUDIO_OUTPUT_FLAG_DIRECT,AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD,AUDIO_OUTPUT_FLAG_NON_BLOCKING
支持的声道:1, 2, 2,1, 4, 5, 5.1, 6, 7.1
Mutichannel Playback: 和Deep buffer playback类似,但是,它多应用于处理多声道音频数据,采样的解码器是Multichannel Decoder
标志: AUDIO_OUTPUT_FLAG_DIRECT
支持的采样率: 44.1KHZ, 48k
应用场景:播放AAC格式5.1声道音源, 播放杜比AC3/eAC3格式音频
至于每个平台支持哪几种播放模式,以及个播放模式的标志,支持的格式,声道数,输出设备等信息,都是在audio_policy.conf文件里配置的。如下:
1 primary { 2 sampling_rates 44100|48000 3 channel_masks AUDIO_CHANNEL_OUT_STEREO 4 formats AUDIO_FORMAT_PCM_16_BIT 5 devices AUDIO_DEVICE_OUT_EARPIECE|AUDIO_DEVICE_OUT_SPEAKER|AUDIO_DEVICE_OUT_WIRED_HEADSET|AUDIO_DEVICE_OUT_WIRED_HEADPHONE|AUDIO_DEVICE_OUT_ALL_SCO|AUDIO_DEVICE_OUT_PROXY|AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET|AUDIO_DEVICE_OUT_FM|AUDIO_DEVICE_OUT_FM_TX 6 flags AUDIO_OUTPUT_FLAG_PRIMARY 7 } 8 low_latency { 9 sampling_rates 44100|48000 10 channel_masks AUDIO_CHANNEL_OUT_STEREO 11 formats AUDIO_FORMAT_PCM_16_BIT 12 devices AUDIO_DEVICE_OUT_SPEAKER|AUDIO_DEVICE_OUT_EARPIECE|AUDIO_DEVICE_OUT_WIRED_HEADSET|AUDIO_DEVICE_OUT_WIRED_HEADPHONE|AUDIO_DEVICE_OUT_ALL_SCO|AUDIO_DEVICE_OUT_PROXY|AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET|AUDIO_DEVICE_OUT_FM|AUDIO_DEVICE_OUT_FM_TX 13 flags AUDIO_OUTPUT_FLAG_FAST 14 } 15 compress_offload { 16 sampling_rates 8000|11025|16000|22050|32000|44100|48000 17 channel_masks AUDIO_CHANNEL_OUT_MONO|AUDIO_CHANNEL_OUT_STEREO 18 formats AUDIO_FORMAT_MP3|AUDIO_FORMAT_AAC_LC|AUDIO_FORMAT_AAC_HE_V1|AUDIO_FORMAT_AAC_HE_V2 19 devices AUDIO_DEVICE_OUT_SPEAKER|AUDIO_DEVICE_OUT_EARPIECE|AUDIO_DEVICE_OUT_WIRED_HEADSET|AUDIO_DEVICE_OUT_WIRED_HEADPHONE|AUDIO_DEVICE_OUT_ALL_SCO|AUDIO_DEVICE_OUT_PROXY|AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET|AUDIO_DEVICE_OUT_FM_TX 20 flags AUDIO_OUTPUT_FLAG_DIRECT|AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD|AUDIO_OUTPUT_FLAG_NON_BLOCKING 21 }
二. 播放模式的选择
1. 在AudioPlayer::start()中会选择一次播放模式:
1 status_t AudioPlayer::start(bool sourceAlreadyStarted) { 2 if (mAudioSink.get() != NULL) { 3 4 uint32_t flags = AUDIO_OUTPUT_FLAG_NONE; 5 6 /*如果支持DeepBuffer Playback模式,mCreateFlags & ALLOW_DEEP_BUFFERING != 0*/ 7 if (allowDeepBuffering()) { 8 flags |= AUDIO_OUTPUT_FLAG_DEEP_BUFFER; 9 } 10 /*如果支持Offload模式,mCreateFlags & USE_OFFLOAD != 0*/ 11 if (useOffload()) { 12 flags |= AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD; 13 } 14 } 15 }
mCreateFlags 是在创建AudioPlayer的时候传入的:
void AwesomePlayer::createAudioPlayer_l() { /*如果mOffloadAudio为true,选择OFFLOAD, 否则如果是纯音频,并且播放时长大于5s,就选择deep-buffer模式*/ if (mOffloadAudio) { flags |= AudioPlayer::USE_OFFLOAD; } else if (mVideoSource == NULL && (mDurationUs > AUDIO_SINK_MIN_DEEP_BUFFER_DURATION_US || (getCachedDuration_l(&cachedDurationUs, &eos) && cachedDurationUs > AUDIO_SINK_MIN_DEEP_BUFFER_DURATION_US))) { flags |= AudioPlayer::ALLOW_DEEP_BUFFERING; } } mOffloadAudio的值是在初始化解码器的时候赋值的: 1 status_t AwesomePlayer::initAudioDecoder() { 2 /*查询是否支持Offload模式播放,*/ 3 mOffloadAudio = canOffloadStream(meta, (mVideoSource != NULL), vMeta, 4 (isStreamingHTTP() || isWidevineContent()), 5 streamType); 6 7 8 if (!mOffloadAudio && mAudioSource != NULL) { 9 ALOGI("Could not offload audio decode, try pcm offload"); 10 sp<MetaData> format = mAudioSource->getFormat(); 11 if (durationUs >= 0) { 12 format->setInt64(kKeyDuration, durationUs); 13 } 14 /*又查询了一次是否支持Offload模式播放,*/ 15 mOffloadAudio = canOffloadStream(format, (mVideoSource != NULL), vMeta, 16 (isStreamingHTTP() || isWidevineContent()), streamType); 17 } 18 }
canOffloadStream()函数会从音频数据中获取格式,采样率,采样精度,播放时长,声道数,是否有视频源等信息,然后调用AudioSystem::isOffloadSupported()去进行查询,最终的判断是在AudioPolicyManager中进行的,它主要有以下判断标准: 1). stream type必须是 AUDIO_STREAM_MUSIC 2). 如果音源是PCM格式,audio.offload.pcm.enable 属性必须为true 3). audio.offload.disable 属性必须为false 4). 如果音源是Multichannel类型的,例如声道数大于2,并且是AAC或者FLAC格式的,也不行 5). 如果有视频源,即has_video为true, av.offload.enable属性必须为true, av.streaming.offload.enable也要为true 6). 如果播放的音源格式是MP3, AAC, FLAC或者PCM,长度要大于audio.offload.min.duration.secs配置的值,例如该值被配置成30s,播放音源就得大于30s, 其他格式的,例如杜比AAC/AC3, ARMWB+格 式的没有这个要求。 7). 如果有其他基于PCM进行调试的音效处理的话,也不支持Offload模式 8). 最后一个, offload模式下的参数,采样率,格式,声道,必须要符合audio_policy.conf文件里面的配置 另外,播放时长,是在音视频分离器中计算出来的,例如AMR,是在AMRExtrator.cpp文件中:
1 AMRExtractor::AMRExtractor(const sp<DataSource> &source) 2 : mDataSource(source), 3 mInitCheck(NO_INIT), 4 mOffsetTableLength(0) { 5 String8 mimeType; 6 float confidence; 7 /*读取文件类型,NB或者WB, 它们的解码方式,采样率都是不一样的*/ 8 if (!SniffAMR(mDataSource, &mimeType, &confidence, NULL)) { 9 return; 10 } 11 12 mIsWide = (mimeType == MEDIA_MIMETYPE_AUDIO_AMR_WB); 13 14 mMeta = new MetaData; 15 mMeta->setCString( 16 kKeyMIMEType, mIsWide ? MEDIA_MIMETYPE_AUDIO_AMR_WB 17 : MEDIA_MIMETYPE_AUDIO_AMR_NB); 18 19 mMeta->setInt32(kKeyChannelCount, 1); 20 mMeta->setInt32(kKeySampleRate, mIsWide ? 16000 : 8000); 21 22 off64_t offset = mIsWide ? 9 : 6; 23 off64_t streamSize; 24 size_t frameSize, numFrames = 0; 25 int64_t duration = 0; 26 27 if (mDataSource->getSize(&streamSize) == OK) { 28 while (offset < streamSize) { 29 /*计算每一frame的数据的大小*/ 30 if (getFrameSizeByOffset(source, offset, mIsWide, &frameSize) != OK) { 31 return; 32 } 33 34 if ((numFrames % 50 == 0) && (numFrames / 50 < OFFSET_TABLE_LEN)) { 35 CHECK_EQ(mOffsetTableLength, numFrames / 50); 36 mOffsetTable[mOffsetTableLength] = offset - (mIsWide ? 9: 6); 37 mOffsetTableLength ++; 38 } 39 40 offset += frameSize; 41 /*每一帧数据播放20ms*/ 42 duration += 20000; // Each frame is 20ms 43 numFrames ++; 44 } 45 46 mMeta->setInt64(kKeyDuration, duration); 47 } 48 49 mInitCheck = OK; 50 }