【六】Android MediaPlayer整体架构源码分析 -【start请求播放处理流程】【Part 2】

承接上一章节分析:【六】Android MediaPlayer整体架构源码分析 -【start请求播放处理流程】【Part 1】
本系列文章分析的安卓源码版本:【Android 10.0 版本】

【此章节小节编号就接着上一章节排列】
5、canOffloadStream(audioMeta, hasVideo, mSource->isStreaming(), streamType)实现分析:
先分析mSource->isStreaming()实现:
其实返回是 mIsStreaming 是否是网络数据源流媒体数据源标识值,前面章节分析过。非网络数据源时返回false。

// [frameworks/av/media/libmediaplayerservice/nuplayer/GenericSource.cpp]
bool NuPlayer::GenericSource::isStreaming() const {
    Mutex::Autolock _l(mLock);
    return mIsStreaming;
}

canOffloadStream() 方法实现:

// [frameworks/av/media/libstagefright/Utils.cpp]
bool canOffloadStream(const sp<MetaData>& meta, bool hasVideo,
                      bool isStreaming, audio_stream_type_t streamType)
{
    // AUDIO_INFO_INITIALIZER默认值:定义在 system/media/audio/include/system/audio.h
    // 见5.1小节分析
    audio_offload_info_t info = AUDIO_INFO_INITIALIZER;
    // 获取音频offload模式信息
    // 见5.2小节分析
    if (OK != getAudioOffloadInfo(meta, hasVideo, isStreaming, streamType, &info)) {
        return false;
    }
    // Check if offload is possible for given format, stream type, sample rate,
    // bit rate, duration, video and streaming
    // 检查是否支持offload音频播放模式
    // 见5.3小节分析
    return AudioSystem::isOffloadSupported(info);
}

5.1、audio_offload_info_t声明和默认值定义:
均在 [system/media/audio/include/system/audio.h] 该文件中。
由下面的英文注释其实已经可以明确知晓该类包含的信息,都是音频流配置相关信息,主要是用于offload模式音频硬解码器解码播放。不详细分析。

/* Additional information about compressed streams offloaded to
 * hardware playback
 * The version and size fields must be initialized by the caller by using
 * one of the constants defined here.
 * Must be aligned to transmit as raw memory through Binder.
 */
typedef struct {
    uint16_t version;                   // version of the info structure
    uint16_t size;                      // total size of the structure including version and size
    uint32_t sample_rate;               // sample rate in Hz
    audio_channel_mask_t channel_mask;  // channel mask
    audio_format_t format;              // audio format
    audio_stream_type_t stream_type;    // stream type
    uint32_t bit_rate;                  // bit rate in bits per second
    int64_t duration_us;                // duration in microseconds, -1 if unknown
    bool has_video;                     // true if stream is tied to a video stream
    bool is_streaming;                  // true if streaming, false if local playback
    uint32_t bit_width;                 // 位宽即每一个音频采样像素占用多少bit
    uint32_t offload_buffer_size;       // offload fragment size
    audio_usage_t usage;
} __attribute__((aligned(8))) audio_offload_info_t;

#define AUDIO_MAKE_OFFLOAD_INFO_VERSION(maj,min) \
            ((((maj) & 0xff) << 8) | ((min) & 0xff))

#define AUDIO_OFFLOAD_INFO_VERSION_0_1 AUDIO_MAKE_OFFLOAD_INFO_VERSION(0, 1)
#define AUDIO_OFFLOAD_INFO_VERSION_CURRENT AUDIO_OFFLOAD_INFO_VERSION_0_1

// 此为默认初始化器值
static const audio_offload_info_t AUDIO_INFO_INITIALIZER = {
    /* .version = */ AUDIO_OFFLOAD_INFO_VERSION_CURRENT,
    /* .size = */ sizeof(audio_offload_info_t),
    /* .sample_rate = */ 0,
    /* .channel_mask = */ 0,
    /* .format = */ AUDIO_FORMAT_DEFAULT,
    /* .stream_type = */ AUDIO_STREAM_VOICE_CALL,
    /* .bit_rate = */ 0,
    /* .duration_us = */ 0,
    /* .has_video = */ false,
    /* .is_streaming = */ false,
    /* .bit_width = */ 16,
    /* .offload_buffer_size = */ 0,
    /* .usage = */ AUDIO_USAGE_UNKNOWN
};

5.2、getAudioOffloadInfo()实现分析:
获取音频offload模式信息

// [frameworks/av/media/libstagefright/Utils.cpp]
status_t getAudioOffloadInfo(const sp<MetaData>& meta, bool hasVideo,
        bool isStreaming, audio_stream_type_t streamType, audio_offload_info_t *info)
{
    const char *mime;
    if (meta == NULL) {
        return BAD_VALUE;
    }
    // 获取MIME文件类型
    CHECK(meta->findCString(kKeyMIMEType, &mime));

    // 初始化为默认值
    (*info) = AUDIO_INFO_INITIALIZER;

	// format初始化为无效值
    info->format = AUDIO_FORMAT_INVALID;
    // 通过mime类型(字符串)匹配转换为audio format格式(枚举类型)
    // 见5.2.1小节分析
    if (mapMimeToAudioFormat(info->format, mime) != OK) {
        ALOGE(" Couldn't map mime type \"%s\" to a valid AudioSystem::audio_format !", mime);
        return BAD_VALUE;
    } else {
        ALOGV("Mime type \"%s\" mapped to audio_format %d", mime, info->format);
    }

// __NO_AVEXTENSIONS__ 该宏定义默认是没有定义的,因此若厂商(如高通)没有自己私有库【libavenhancements.so】实现的解码器,
// 将会加载AVUtils.cpp的默认实现,也就是空实现。
// 备注:高通有实现该私有库,也就是用于支持高通自己实现的qcom高通软硬音频解码器。
#ifndef __NO_AVEXTENSIONS__
    info->format  = AVUtils::get()->updateAudioFormat(info->format, meta);
#endif
	// 若audio format为无效,则不支持offload模式音频解码
    if (AUDIO_FORMAT_INVALID == info->format) {
        // can't offload if we don't know what the source format is
        ALOGE("mime type \"%s\" not a known audio format", mime);
        return BAD_VALUE;
    }

#ifndef __NO_AVEXTENSIONS__
	// 同上分析,默认实现为空实现并返回true
    if (AVUtils::get()->canOffloadStream(meta) != true) {
        return false;
    }
#endif

    // 如英文注释:根据aac配置级别重新定义aac音频格式,offload模式支持情况主要取决于audio DSP能力(DSP也就是音频解码器芯片)
    // Redefine aac format according to its profile
    // Offloading depends on audio DSP capabilities.
    int32_t aacaot = -1;
    // 从音频track信息的媒体元数据中获取该值
    if (meta->findInt32(kKeyAACAOT, &aacaot)) {
    	// 获取该值成功时
        bool isADTSSupported = false;
#ifndef __NO_AVEXTENSIONS__
		// 默认返回false
		// 其实此处就是获取高通私有库实现的该方法,作用就是AAC配置级别和audio format的映射关系匹配
        isADTSSupported = AVUtils::get()->mapAACProfileToAudioFormat(meta, info->format,
                                    (OMX_AUDIO_AACPROFILETYPE) aacaot);
#endif
        if (!isADTSSupported) {
        	// 若上面私有库实现失败,则执行本地实现匹配
        	// AAC配置级别和audio format的映射关系匹配,来再次获取具体的AAC具体版本类型值。
        	// 见5.2.2小节分析
            mapAACProfileToAudioFormat(info->format,(OMX_AUDIO_AACPROFILETYPE) aacaot);
        }
    }

    // 获取音频采样率
    int32_t srate = -1;
    if (!meta->findInt32(kKeySampleRate, &srate)) {
    	// 若为空则可能是该音频类型track没有在文件中写入该信息
        ALOGV("track of type '%s' does not publish sample rate", mime);
    }
    info->sample_rate = srate;

	// 获取音频通道(掩码)数信息
    int32_t cmask = 0;
    if (!meta->findInt32(kKeyChannelMask, &cmask) || cmask == CHANNEL_MASK_USE_CHANNEL_ORDER) {
        ALOGV("track of type '%s' does not publish channel mask", mime);

        // 上面获取失败时尝试获取通道数配置信息元数据
        // Try a channel count instead
        int32_t channelCount;
        if (!meta->findInt32(kKeyChannelCount, &channelCount)) {
            ALOGV("track of type '%s' does not publish channel count", mime);
        } else {
        	// 获取成功则转换成音频通道输出掩码类型值
        	// 见5.2.3小节分析
            cmask = audio_channel_out_mask_from_count(channelCount);
        }
        ALOGW("track of type '%s' does not publish channel mask, channel count %d",
              mime, channelCount);
    }
    // 缓存
    info->channel_mask = cmask;

    // 获取音频track的音频时长,默认0
    int64_t duration = 0;
    if (!meta->findInt64(kKeyDuration, &duration)) {
        ALOGV("track of type '%s' does not publish duration", mime);
    }
    info->duration_us = duration;

    // 获取音频码率,默认-1
    int32_t brate = -1;
    if (!meta->findInt32(kKeyBitRate, &brate)) {
        ALOGV("track of type '%s' does not publish bitrate", mime);
    }
    info->bit_rate = brate;


    // 缓存值
    info->stream_type = streamType;
    info->has_video = hasVideo;
    info->is_streaming = isStreaming;
    return OK;
}

5.2.1、mapMimeToAudioFormat(info->format, mime)实现分析:
通过mime类型(字符串)匹配转换为audio format格式(枚举类型)

// [frameworks/av/media/libstagefright/Utils.cpp]
status_t mapMimeToAudioFormat( audio_format_t& format, const char* mime )
{
// mimeLookup:是一个mime和音频format映射关系的结构数组
// 见下面的定义
const struct mime_conv_t* p = &mimeLookup[0];
	// while循环匹配相等时则赋值并返回OK
    while (p->mime != NULL) {
        if (0 == strcasecmp(mime, p->mime)) {
            format = p->format;
            return OK;
        }
        ++p;
    }
	
	// 注意:上面 mimeLookup 数组中若都没有找到对应的mime匹配值,那么将会使用AV扩展(so私有)库实现匹配,
	// 这点和此前分析过的解复用模块私有so库的模块插件化实现类似,并且该AVUtils在此前章节中有分析过其加载原理,
	// 也就是同一个扩展库里加载的,因此可以添加自己的解码器模块支持的音频mime和format映射关系来创建自己实现的特有音频format解码器。

// __NO_AVEXTENSIONS__ 该宏定义默认是没有定义的,因此若厂商(如高通)没有自己私有库【libavenhancements.so】实现的解码器,
// 将会加载AVUtils.cpp的默认实现,也就是空实现。
// 备注:高通有实现该私有库,也就是用于支持高通自己实现的qcom高通软硬音频解码器。
#ifndef __NO_AVEXTENSIONS__
    return AVUtils::get()->mapMimeToAudioFormat(format, mime);
#else
    return BAD_VALUE;
#endif
}

mimeLookup:是一个mime和音频format映射关系的结构数组

// [frameworks/av/media/libstagefright/Utils.cpp]

struct mime_conv_t {
    const char* mime;
    audio_format_t format;
};

// mime和format映射关系
// 注意:这里列出来的mime格式并不是当前安卓都支持的格式,如ALAC就不支持。
static const struct mime_conv_t mimeLookup[] = {
    { MEDIA_MIMETYPE_AUDIO_MPEG,        AUDIO_FORMAT_MP3 },
    { MEDIA_MIMETYPE_AUDIO_RAW,         AUDIO_FORMAT_PCM_16_BIT },
    { MEDIA_MIMETYPE_AUDIO_AMR_NB,      AUDIO_FORMAT_AMR_NB },
    { MEDIA_MIMETYPE_AUDIO_AMR_WB,      AUDIO_FORMAT_AMR_WB },
    { MEDIA_MIMETYPE_AUDIO_AAC,         AUDIO_FORMAT_AAC },
    { MEDIA_MIMETYPE_AUDIO_VORBIS,      AUDIO_FORMAT_VORBIS },
    { MEDIA_MIMETYPE_AUDIO_OPUS,        AUDIO_FORMAT_OPUS},
    { MEDIA_MIMETYPE_AUDIO_AC3,         AUDIO_FORMAT_AC3},
    { MEDIA_MIMETYPE_AUDIO_EAC3,        AUDIO_FORMAT_E_AC3},
    { MEDIA_MIMETYPE_AUDIO_EAC3_JOC,    AUDIO_FORMAT_E_AC3_JOC},
    { MEDIA_MIMETYPE_AUDIO_AC4,         AUDIO_FORMAT_AC4},
    { MEDIA_MIMETYPE_AUDIO_FLAC,        AUDIO_FORMAT_FLAC},
    { MEDIA_MIMETYPE_AUDIO_ALAC,        AUDIO_FORMAT_ALAC },
    // 此处mime可知为空时,格式类型为无效值
    { 0, AUDIO_FORMAT_INVALID }
};

5.2.2、mapAACProfileToAudioFormat(info->format,(OMX_AUDIO_AACPROFILETYPE) aacaot)实现分析:
AAC配置级别和audio format的映射关系匹配,来再次获取具体的AAC版本类型值。
注意:此处获取的是修正上面获取的【AUDIO_FORMAT_AAC】该AAC类型值为具体AAC版本编码格式,AAC有多种版本编码格式。

// [frameworks/av/media/libstagefright/Utils.cpp]
void mapAACProfileToAudioFormat( audio_format_t& format, uint64_t eAacProfile)
{
// profileLookup:AAC配置级别和audio format的映射关系匹配数组
// 见下面的分析
const struct aac_format_conv_t* p = &profileLookup[0];
    while (p->eAacProfileType != OMX_AUDIO_AACObjectNull) {
    	// while循环匹配相等时则赋值并返回匹配到的AAC具体版本编码格式
        if (eAacProfile == p->eAacProfileType) {
            format = p->format;
            return;
        }
        ++p;
    }
    // 否则返回默认值,其实也就是对应与aacaot为null值类型时
    format = AUDIO_FORMAT_AAC;
    return;
}

profileLookup:AAC配置级别和audio format的映射关系匹配数组 定义
AAC有多种版本编码格式对应关系。

// [frameworks/av/media/libstagefright/Utils.cpp]

struct aac_format_conv_t {
    OMX_AUDIO_AACPROFILETYPE eAacProfileType;
    audio_format_t format;
};

static const struct aac_format_conv_t profileLookup[] = {
    { OMX_AUDIO_AACObjectMain,        AUDIO_FORMAT_AAC_MAIN},
    { OMX_AUDIO_AACObjectLC,          AUDIO_FORMAT_AAC_LC},
    { OMX_AUDIO_AACObjectSSR,         AUDIO_FORMAT_AAC_SSR},
    { OMX_AUDIO_AACObjectLTP,         AUDIO_FORMAT_AAC_LTP},
    { OMX_AUDIO_AACObjectHE,          AUDIO_FORMAT_AAC_HE_V1},
    { OMX_AUDIO_AACObjectScalable,    AUDIO_FORMAT_AAC_SCALABLE},
    { OMX_AUDIO_AACObjectERLC,        AUDIO_FORMAT_AAC_ERLC},
    { OMX_AUDIO_AACObjectLD,          AUDIO_FORMAT_AAC_LD},
    { OMX_AUDIO_AACObjectHE_PS,       AUDIO_FORMAT_AAC_HE_V2},
    { OMX_AUDIO_AACObjectELD,         AUDIO_FORMAT_AAC_ELD},
    { OMX_AUDIO_AACObjectXHE,         AUDIO_FORMAT_AAC_XHE},
    // 默认值处理,aacaot为null值类型时
    { OMX_AUDIO_AACObjectNull,        AUDIO_FORMAT_AAC},
};

5.2.3、audio_channel_out_mask_from_count(channelCount)实现分析:

 // [system/media/audio/include/system/audio.h]
 
 /* Derive an output channel mask for position assignment from a channel count.
 * This is to be used when the content channel mask is unknown. The 1, 2, 4, 5, 6, 7 and 8 channel
 * cases are mapped to the standard game/home-theater layouts, but note that 4 is mapped to quad,
 * and not stereo + FC + mono surround. A channel count of 3 is arbitrarily mapped to stereo + FC
 * for continuity with stereo.
 * Returns the matching channel mask,
 * or AUDIO_CHANNEL_NONE if the channel count is zero,
 * or AUDIO_CHANNEL_INVALID if the channel count exceeds that of the
 * configurations for which a default output channel mask is defined.
 */
static inline audio_channel_mask_t audio_channel_out_mask_from_count(uint32_t channel_count)
{
	// 其实通过下面的实现可知,实现很简单就是将音频通道数类型值转换成解码器OMX等支持识别的类型
	// 支持音频通道数有:单声道、双声道即立体声、2.1声道即三声道、四声道、5声道、5.1声道、6.1声道、7.1声道。
	// 关于音频声道的定义理解可自行百度下,很简单。
	
    uint32_t bits;
    switch (channel_count) {
    case 0:
    	// 无音频通道
        return AUDIO_CHANNEL_NONE;
    case 1:
        bits = AUDIO_CHANNEL_OUT_MONO;
        break;
    case 2:
        bits = AUDIO_CHANNEL_OUT_STEREO;
        break;
    case 3: // 2.1
        bits = AUDIO_CHANNEL_OUT_STEREO | AUDIO_CHANNEL_OUT_LOW_FREQUENCY;
        break;
    case 4: // 4.0
        bits = AUDIO_CHANNEL_OUT_QUAD;
        break;
    case 5: // 5.0
        bits = AUDIO_CHANNEL_OUT_QUAD | AUDIO_CHANNEL_OUT_FRONT_CENTER;
        break;
    case 6: // 5.1
        bits = AUDIO_CHANNEL_OUT_5POINT1;
        break;
    case 7: // 6.1
        bits = AUDIO_CHANNEL_OUT_5POINT1 | AUDIO_CHANNEL_OUT_BACK_CENTER;
        break;
    case 8:
        bits = AUDIO_CHANNEL_OUT_7POINT1;
        break;
    // FIXME FCC_8
    default:
    	// 无效音频通道数错误码
        return AUDIO_CHANNEL_INVALID;
    }
    //  AUDIO_CHANNEL_REPRESENTATION_POSITION   = 0x0u 即默认为16进制表示的无类型int值
    // 见下面分析
    return audio_channel_mask_from_representation_and_bits(
            AUDIO_CHANNEL_REPRESENTATION_POSITION, bits);
}

audio_channel_mask_from_representation_and_bits() 实现:
其实际实现就是,使用二进制的bit位不同值来转换表示不同的声道数,也就得到了声道掩码的概念表示。

 // [system/media/audio/include/system/audio.h]
 /* Not part of public API */
static inline audio_channel_mask_t audio_channel_mask_from_representation_and_bits(
        audio_channel_representation_t representation, uint32_t bits)
{
	// AUDIO_CHANNEL_COUNT_MAX                 = 30u
	// 此处representation传入为0,通过将0向左移运算30个bit位,其实就是啥事没做,然后或运算后得到还是bits值本身。
    return (audio_channel_mask_t) ((representation << AUDIO_CHANNEL_COUNT_MAX) | bits);
}

5.3、AudioSystem::isOffloadSupported(info)实现分析:
根据offload配置信息,检查是否支持offload音频播放模式。
其实该方法实现比较简单,也就是获取音频策略服务即AudioPolicyService对象的Binder代理接口对象,通过服务注册中心ServiceManager来获取此前已注册的名称为"media.audio_policy"的该服务对象,然后转换为代理对象供客户端使用。关于Binder机制及其获取服务原理请查看:Android C++底层Binder通信机制原理分析总结【通俗易懂】

// [frameworks/av/media/libaudioclient/AudioSystem.cpp]
bool AudioSystem::isOffloadSupported(const audio_offload_info_t& info)
{
    ALOGV("isOffloadSupported()");
    // 获取音频策略服务即AudioPolicyService对象的Binder代理接口对象即Bp代理端BpAudioPolicyService对象
    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
    if (aps == 0) return false;
    // 然后通过代理对象访问AudioPolicyService对象即Bn实现端的该方法
    return aps->isOffloadSupported(info);
}

aps->isOffloadSupported(info)实现分析:
注意:该方法实现其实不是在AudioPolicyService.cpp文件中,而是在另外的单独文件AudioPolicyInterfaceImpl.cpp实现的,其实该文件就是将AudioPolicyService.h的部分功能实现在此文件中。

// [frameworks/av/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp]
bool AudioPolicyService::isOffloadSupported(const audio_offload_info_t& info)
{
    if (mAudioPolicyManager == NULL) {
        ALOGV("mAudioPolicyManager == NULL");
        return false;
    }
    Mutex::Autolock _l(mLock);
    AutoCallerClear acc;
    // 其实际还是调用了AudioPolicyManager对象的实现
    // 见下面的分析
    return mAudioPolicyManager->isOffloadSupported(info);
}

mAudioPolicyManager->isOffloadSupported(info)实现分析:
根据英文注释可知,该功能其实就是依赖于DSP音频(芯片)硬解码器能力和系统策略管理,得到最终是否支持的情况

// [frameworks/av/services/audiopolicy/managedefult/AudioPolicyManager.cpp]

// This function checks for the parameters which can be offloaded.
// This can be enhanced depending on the capability of the DSP and policy
// of the system.
bool AudioPolicyManager::isOffloadSupported(const audio_offload_info_t& offloadInfo)
{
    ALOGV("isOffloadSupported: SR=%u, CM=0x%x, Format=0x%x, StreamType=%d,"
     " BitRate=%u, duration=%" PRId64 " us, has_video=%d",
     offloadInfo.sample_rate, offloadInfo.channel_mask,
     offloadInfo.format,
     offloadInfo.stream_type, offloadInfo.bit_rate, offloadInfo.duration_us,
     offloadInfo.has_video);

	// 注意:如果设置了单声道模式则不支持offload
    if (mMasterMono) {
        return false; // no offloading if mono is set.
    }

    // 此处检查该系统属性值是否被设置为true即不启用offload音频播放模式。默认为false
    // Check if offload has been disabled
    if (property_get_bool("audio.offload.disable", false /* default_value */)) {
        ALOGV("offload disabled by audio.offload.disable");
        return false;
    }

    // 目前offload功能只支持music类型音频流
    // Check if stream type is music, then only allow offload as of now.
    if (offloadInfo.stream_type != AUDIO_STREAM_MUSIC)
    {
        ALOGV("isOffloadSupported: stream_type != MUSIC, returning false");
        return false;
    }

    // 该值其实用于检查是否有视频流时支持其音频流offload模式播放,默认为true支持。
    // 但注意:有可能此时传入的has_video信息不准确,因为可能video track此前还没准备好,那么该值将会为false。
    //TODO: enable audio offloading with video when ready
    const bool allowOffloadWithVideo =
            property_get_bool("audio.offload.video", false /* default_value */);
    if (offloadInfo.has_video && !allowOffloadWithVideo) {
        ALOGV("isOffloadSupported: has_video == true, returning false");
        return false;
    }

	// 此处检查音频offload播放模式下支持的最小音频时长,默认系统配置为30秒,该属性值默认配置是在mk文件中。
	// 若音频流时长小于该允许值,则将不支持offload模式播放。
    //If duration is less than minimum value defined in property, return false
    const int min_duration_secs = property_get_int32(
            "audio.offload.min.duration.secs", -1 /* default_value */);
    if (min_duration_secs >= 0) {
        if (offloadInfo.duration_us < min_duration_secs * 1000000LL) {
            ALOGV("Offload denied by duration < audio.offload.min.duration.secs(=%d)",
                    min_duration_secs);
            return false;
        }
    } else if (offloadInfo.duration_us < OFFLOAD_DEFAULT_MIN_DURATION_SECS * 1000000) {
    	// 若上面系统属性值小于0时
    	// OFFLOAD_DEFAULT_MIN_DURATION_SECS值定义为60秒。
    	// 此处判断音频流时长若小于60秒则也将会不支持offload模式播放
        ALOGV("Offload denied by duration < default min(=%u)", OFFLOAD_DEFAULT_MIN_DURATION_SECS);
        return false;
    }

	// 下面的两个处理流程将不分析,主要是是获取音频输出设备的IO输出配置信息

    // Do not allow offloading if one non offloadable effect is enabled. This prevents from
    // creating an offloaded track and tearing it down immediately after start when audioflinger
    // detects there is an active non offloadable effect.
    // FIXME: We should check the audio session here but we do not have it in this context.
    // This may prevent offloading in rare situations where effects are left active by apps
    // in the background.
    if (mEffects.isNonOffloadableEffectEnabled()) {
        return false;
    }

    // See if there is a profile to support this.
    // AUDIO_DEVICE_NONE
    sp<IOProfile> profile = getProfileForOutput(DeviceVector() /*ignore device */,
                                            offloadInfo.sample_rate,
                                            offloadInfo.format,
                                            offloadInfo.channel_mask,
                                            AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD,
                                            true /* directOnly */);
    ALOGV("isOffloadSupported() profile %sfound", profile != 0 ? "" : "NOT ");
    // 不为空则表示支持offload模式播放
    return (profile != 0);
}

6、NuPlayer::Renderer类声明和构造函数实现:
NuPlayer::Renderer类声明【省略其他代码】,其实际实现了AHandler消息机制功能。

// [frameworks/av/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h]
struct NuPlayer::Renderer : public AHandler {}

NuPlayer::Renderer构造函数实现
主要就是初始化赋值各个参数

// [frameworks/av/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp]
NuPlayer::Renderer::Renderer(
        const sp<MediaPlayerBase::AudioSink> &sink,
        const sp<MediaClock> &mediaClock,
        const sp<AMessage> &notify,
        uint32_t flags)
    : mAudioSink(sink),
      mUseVirtualAudioSink(false),
      mNotify(notify),
      mFlags(flags),
      // 已写入帧数,默认为0
      mNumFramesWritten(0),
      // 音视频帧数据(消息事件)是否需要加入渲染请求(消息)队列中,即待执行消息队列的该消息事件
      mDrainAudioQueuePending(false),
      mDrainVideoQueuePending(false),
      // 音视频数据(消息事件)加入渲染队列时记录的代数值,
      // 可以在消息得到处理时判断是否应该丢弃该消息事件的处理
      mAudioQueueGeneration(0),
      mVideoQueueGeneration(0),
      // 与上面这组代数值功能相连接,也就是若上面代数值处理流程成功后就开始执行音视频帧的渲染消息事件处理,
      // 这组代数值就是用于判断该消息得到处理时是否应该丢弃本次处理
      mAudioDrainGeneration(0),
      mVideoDrainGeneration(0),
      // 音频EOS(流结束)消息事件代数值,功能作用和上面类似
      mAudioEOSGeneration(0),
      // 音视频同步时钟,见此前相关章节分析
      mMediaClock(mediaClock),
      // 根据前面setDataSource分析第三章节可知,
	  // mPlaybackSettings该信息是播放速率参数,AUDIO_PLAYBACK_RATE_DEFAULT为默认值。
      mPlaybackSettings(AUDIO_PLAYBACK_RATE_DEFAULT),
      // 音频第一次锚点媒体开始播放时间戳,默认-1。
      // 也就是本次播放请求的媒体开始播放时间点,该值将会在渲染器flush流程中重置
      mAudioFirstAnchorTimeMediaUs(-1),
      // 该值锚点是音频当前已播放的媒体时间戳位置,若没有音频该值将不启用
      mAnchorTimeMediaUs(-1),
      // (锚点)记录当前已写入音频帧数,若是offload播放模式该值将不启用
      mAnchorNumFramesWritten(-1),
      // 记录当前视频帧请求渲染时的延迟时长,默认有效帧不能超过40毫秒,否则将不会显示它
      mVideoLateByUs(0LL),
      // 记录将要渲染的下一帧视频媒体时间戳
      mNextVideoTimeMediaUs(-1),
      // 是否有音视频流
      mHasAudio(false),
      mHasVideo(false),
      // 是否向NuPlayer通知音频或视频flush完成事件
      mNotifyCompleteAudio(false),
      mNotifyCompleteVideo(false),
      // 是否同步渲染(即同步将音视频帧加入渲染队列中)
      // 注意:高版本该值都是false了,即目前都已才有异步音视频帧渲染方式处理,已弃用该功能
      mSyncQueues(false),
      // 是否已暂停
      mPaused(false),
      // 暂停状态下允许向AudioTrack模块即AudioFlinger提供数据的时间戳
      // 注意:该值也已弃用,一直是0
      mPauseDrainAudioAllowedUs(0),
      // 是否已接收到将要渲染的视频帧(样本)数据
      mVideoSampleReceived(false),
      // 是否视频渲染已开始,实际用于控制只向NuPlayer及上层播放器发送一次视频渲染已开始该事件消息
      mVideoRenderingStarted(false),
      // 音频或视频渲染已开始代数值,代数值都是用于判断是否应该执行该事件的处理
      mVideoRenderingStartGeneration(0),
      mAudioRenderingStartGeneration(0),
      // 渲染数据是否已交付(提供),
      // 其实际就是控制是否应该向NuPlayer及上层播放器发送一次媒体渲染已开始事件消息,注意和mVideoRenderingStarted的区别。
      mRenderingDataDelivered(false),
      // 下一个音频时钟同步更新媒体基准时间戳【主要就是当前媒体时间加上默认20毫秒的周期性时间】
      // 备注:只有在非offload模式下才启用。
      mNextAudioClockUpdateTimeUs(-1),
      // 该值记录的是音频流EOS时的最后一帧音频媒体时间戳
      // 备注:只有在非offload模式下才启用。
      mLastAudioMediaTimeUs(-1),
      // 音频offload播放模式下暂停超时时间,客户端请求暂停时将会在暂停指定时间(默认3秒)内卸载offload功能模块,
      // 而该值将在超时时即处理该事件流程时判断是否应该丢弃/放弃该处理,比如3秒内用户恢复了播放等,将会改变该值。
      // 该处理流程的作用主要就是节省电。offload播放模式就是用硬解码器提高音频解码速度。
      // 备注:只有在offload模式下才启用。
      mAudioOffloadPauseTimeoutGeneration(0),
      // 判断当前audio处理模块是否已卸载/关闭。
      mAudioTornDown(false),
      // 当前offload模式信息,见前面的分析
      mCurrentOffloadInfo(AUDIO_INFO_INITIALIZER),
      // 当前音频PCM数据的配置信息和上面的mCurrentOffloadInfo信息类似,
      // 不过它是处理非offload模式时的数据,初始化为默认配置。
      // 见6.1小节分析
      mCurrentPcmInfo(AUDIO_PCMINFO_INITIALIZER),
      // 已放入缓冲区队列的音频和视频buffer(帧)的总数
      mTotalBuffersQueued(0),
      // 最后渲染的音频帧buffer(在音频流buffer队列缓冲区中的)索引值
      mLastAudioBufferDrained(0),
      // 是否使用callback音频播放模式
      // 备注:目前只在offload播放模式下时为true,
      // 即AudioFlinger模块通过该回调主动获取解复用音频数据。
      mUseAudioCallback(false),
      // AWakeLock唤醒锁功能实现类,其功能其实际上就是和java层我们自己写的PowerManager来获取屏幕/CPU保持唤醒工作的处理类似,
      // 因此该功能实现就不分析了。
      mWakeLock(new AWakeLock()),
      // 是否视频播放时清除锚点信息即是否清除音视频同步锚点功能,当只有视频无音频时将会设置为true,即独流播放。
      mNeedVideoClearAnchor(false) {
    CHECK(mediaClock != NULL);
    // 由前面的分析可知,该播放设置参数即播放速度默认为1
    mPlaybackRate = mPlaybackSettings.mSpeed;
    // 设置给MediaClock音视频同步时钟缓存处理
    // 见6.2小节分析
    mMediaClock->setPlaybackRate(mPlaybackRate);
}

6.1、mCurrentPcmInfo(AUDIO_PCMINFO_INITIALIZER)实现分析:
可以看到信息记录的是音频PCM数据的相关配置信息

// [frameworks/av/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h]
struct NuPlayer::Renderer : public AHandler {
protected:
    struct PcmInfo {
    	// 如前面已有分析,也就是音频声道类型
        audio_channel_mask_t mChannelMask;
        // 该枚举类型表示的是音频输出标志位类型,用于标记如何输出音频
        // 见下面的分析
        audio_output_flags_t mFlags;
        // 如前面已有分析,也就是音频(编码)格式类型
        audio_format_t mFormat;
        // 音频声道数
        int32_t mNumChannels;
        // 音频采样率
        int32_t mSampleRate;
    };
    PcmInfo mCurrentPcmInfo;
    // 见下面的分析
    static const PcmInfo AUDIO_PCMINFO_INITIALIZER;
}

audio_output_flags_t 实现:

 // [system/media/audio/include/system/audio-base.h]
typedef enum {
    AUDIO_OUTPUT_FLAG_NONE             = 0x0,
    AUDIO_OUTPUT_FLAG_DIRECT           = 0x1,
    AUDIO_OUTPUT_FLAG_PRIMARY          = 0x2,
    AUDIO_OUTPUT_FLAG_FAST             = 0x4,
    // 这个是deep-buffer播放模式,也就是非offload播放模式
    AUDIO_OUTPUT_FLAG_DEEP_BUFFER      = 0x8,
    // 这个就是offload播放模式类型值
    AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD = 0x10,
    AUDIO_OUTPUT_FLAG_NON_BLOCKING     = 0x20,
    AUDIO_OUTPUT_FLAG_HW_AV_SYNC       = 0x40,
    AUDIO_OUTPUT_FLAG_TTS              = 0x80,
    AUDIO_OUTPUT_FLAG_RAW              = 0x100,
    AUDIO_OUTPUT_FLAG_SYNC             = 0x200,
    AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO  = 0x400,
    AUDIO_OUTPUT_FLAG_DIRECT_PCM       = 0x2000,
    AUDIO_OUTPUT_FLAG_MMAP_NOIRQ       = 0x4000,
    AUDIO_OUTPUT_FLAG_VOIP_RX          = 0x8000,
    AUDIO_OUTPUT_FLAG_INCALL_MUSIC     = 0x10000,
    AUDIO_OUTPUT_FLAG_NAVI             = 0x20000,
    AUDIO_OUTPUT_FLAG_UE               = 0x40000,
} audio_output_flags_t;

AUDIO_PCMINFO_INITIALIZER默认实现:
其实都是无效值

// [frameworks/av/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp]
// static
const NuPlayer::Renderer::PcmInfo NuPlayer::Renderer::AUDIO_PCMINFO_INITIALIZER = {
        AUDIO_CHANNEL_NONE,
        AUDIO_OUTPUT_FLAG_NONE,
        AUDIO_FORMAT_INVALID,
        0, // mNumChannels
        0 // mSampleRate
};

6.2、mMediaClock->setPlaybackRate(mPlaybackRate)实现分析:
设置播放速率(默认为1)给MediaClock音视频同步时钟缓存处理。
该播放速率其实是可以用来控制播放速度的即快播或慢播。
由于篇幅长度过长,因此放入下一章节分析,请查看:
【六】Android MediaPlayer整体架构源码分析 -【start请求播放处理流程】【Part 3】

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值