关于播放模式的选择

转自: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 }
上一篇:把web项目用uni-app打包,导致录音出现问题


下一篇:ffplay分析(从启动到读取线程的操作)