1.setAudioStreamType的过程

frameworks\av\media\libmediaplayerservice\MediaPlayerService.cpp

status_t MediaPlayerService::Client::setAudioStreamType(audio_stream_type_t type)
{ALOGE("[%d] setAudioStreamType(%d)", mConnId, type);// TODO: for hardware output, call player insteadMutex::Autolock l(mLock);if (mAudioOutput != 0) mAudioOutput->setAudioStreamType(type);return NO_ERROR;
}

这里的mAudioOutput是在Audio播放流程(二)—MediaPlayerService流程之setDataSource中创建的。

setDataSource_premAudioOutput = new AudioOutput(...)将AudioOutput设置为NuPlayer的Sink端static_cast<MediaPlayerInterface*>(p.get())->setAudioSink(mAudioOutput);

继续

void MediaPlayerService::AudioOutput::setAudioStreamType(audio_stream_type_t streamType)
{Mutex::Autolock lock(mLock);// do not allow direct stream type modification if attributes have been setif (mAttributes == NULL) {mStreamType = streamType;// No attributes are set, for mediaPlayer playback, force populate attributes// This is done to ensure that we qualify for a direct outputmAttributes = (audio_attributes_t *) calloc(1, sizeof(audio_attributes_t));if (mAttributes != NULL) {stream_type_to_audio_attributes(mStreamType, mAttributes);}}
}
...
static void stream_type_to_audio_attributes(audio_stream_type_t streamType,audio_attributes_t *attr) {memset(attr, 0, sizeof(audio_attributes_t));switch (streamType) {case AUDIO_STREAM_DEFAULT:case AUDIO_STREAM_MUSIC:attr->content_type = AUDIO_CONTENT_TYPE_MUSIC;attr->usage = AUDIO_USAGE_MEDIA;break;case AUDIO_STREAM_VOICE_CALL:attr->content_type = AUDIO_CONTENT_TYPE_SPEECH;attr->usage = AUDIO_USAGE_VOICE_COMMUNICATION;break;case AUDIO_STREAM_ENFORCED_AUDIBLE:attr->flags  |= AUDIO_FLAG_AUDIBILITY_ENFORCED;// intended fall through, attributes in common with STREAM_SYSTEMcase AUDIO_STREAM_SYSTEM:attr->content_type = AUDIO_CONTENT_TYPE_SONIFICATION;attr->usage = AUDIO_USAGE_ASSISTANCE_SONIFICATION;break;case AUDIO_STREAM_RING:attr->content_type = AUDIO_CONTENT_TYPE_SONIFICATION;attr->usage = AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE;break;case AUDIO_STREAM_ALARM:attr->content_type = AUDIO_CONTENT_TYPE_SONIFICATION;attr->usage = AUDIO_USAGE_ALARM;break;case AUDIO_STREAM_NOTIFICATION:attr->content_type = AUDIO_CONTENT_TYPE_SONIFICATION;attr->usage = AUDIO_USAGE_NOTIFICATION;break;case AUDIO_STREAM_BLUETOOTH_SCO:attr->content_type = AUDIO_CONTENT_TYPE_SPEECH;attr->usage = AUDIO_USAGE_VOICE_COMMUNICATION;attr->flags |= AUDIO_FLAG_SCO;break;case AUDIO_STREAM_DTMF:attr->content_type = AUDIO_CONTENT_TYPE_SONIFICATION;attr->usage = AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING;break;case AUDIO_STREAM_TTS:attr->content_type = AUDIO_CONTENT_TYPE_SPEECH;attr->usage = AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY;break;default:ALOGE("invalid stream type %d when converting to attributes", streamType);}
}

这个API还是很简单的,就是设置音频的属性,例如:

case AUDIO_STREAM_MUSIC:attr->content_type = AUDIO_CONTENT_TYPE_MUSIC;attr->usage = AUDIO_USAGE_MEDIA;

2.prepareAsync的调用流程

frameworks\av\media\libmediaplayerservice\MediaPlayerService.cpp

status_t MediaPlayerService::Client::prepareAsync()
{ALOGE("[%d] prepareAsync", mConnId);sp<MediaPlayerBase> p = getPlayer();if (p == 0) return UNKNOWN_ERROR;status_t ret = p->prepareAsync();
#if CALLBACK_ANTAGONIZERALOGD("start Antagonizer");if (ret == NO_ERROR) mAntagonizer->start();
#endifreturn ret;
}

frameworks\av\media\libmediaplayerservice\nuplayer\NuPlayerDriver.cpp

status_t NuPlayerDriver::prepareAsync() {ALOGV("prepareAsync(%p)", this);Mutex::Autolock autoLock(mLock);switch (mState) {case STATE_UNPREPARED:mState = STATE_PREPARING;mIsAsyncPrepare = true;mPlayer->prepareAsync();return OK;case STATE_STOPPED:// this is really just paused. handle as seek to startmAtEOS = false;mState = STATE_STOPPED_AND_PREPARING;mIsAsyncPrepare = true;mPlayer->seekToAsync(0, true /* needNotify */);return OK;default:return INVALID_OPERATION;};
}

frameworks\av\media\libmediaplayerservice\nuplayer\NuPlayer.cpp

void NuPlayer::prepareAsync() {(new AMessage(kWhatPrepare, this))->post();
}

这里使用了Native的Handle机制,这个机制原理上和JAVA端的是一致的。
先看处理这个handle的线程是在什么地方创建的,如下

frameworks\av\media\libmediaplayerservice\nuplayer\NuPlayerDriver.cpp

NuPlayerDriver::NuPlayerDriver(pid_t pid): mState(STATE_IDLE),mIsAsyncPrepare(false),mAsyncResult(UNKNOWN_ERROR),mSetSurfaceInProgress(false),mDurationUs(-1),mPositionUs(-1),mSeekInProgress(false),mLooper(new ALooper),mPlayerFlags(0),mAtEOS(false),mLooping(false),mAutoLoop(false) {ALOGV("NuPlayerDriver(%p)", this);mLooper->setName("NuPlayerDriver Looper");//开启线程mLooper->start(false, /* runOnCallingThread */true,  /* canCallJava */PRIORITY_AUDIO);mPlayer = AVNuFactory::get()->createNuPlayer(pid);mLooper->registerHandler(mPlayer);mPlayer->setDriver(this);
}

如上,Looper会创建一个名为"NuPlayerDriver Looper"的线程,随后调用mLooper->start开启这个线程,之后循环等待是否有事件需要处理;

mLooper->registerHandler(mPlayer);

上面是为Looper设置handle(mPlayer继承自AHandler),之后AMessage将消息发送到Looper线程,随后线程回调AHandler的onMessageReceived方法去处理。这里需要注意的是onMessageReceived有可能会被AHandler的派生类重载。

AHandler的理论讲完了,回到NuPlayer::prepareAsync(),这里面通过AMessage将消息kWhatPrepare发送到了NuPlayer的onMessageReceived方法:

void NuPlayer::onMessageReceived(const sp<AMessage> &msg) {...case kWhatPrepare:{mSource->prepareAsync();break;}...
}

这里的mSource在上一步kWhatSetDataSource消息的处理中已经完成赋值了
这里的mSource指向的是GenericSource对象,因此prepareAsync会走向

frameworks\av\media\libmediaplayerservice\nuplayer\GenericSource.cpp

void NuPlayer::GenericSource::prepareAsync() {if (mLooper == NULL) {mLooper = new ALooper;mLooper->setName("generic");mLooper->start();mLooper->registerHandler(this);}sp<AMessage> msg = new AMessage(kWhatPrepareAsync, this);msg->post();
}

如上GenericSource内部又开启了一个线程(“generic”),这个线程处理来自GenericSource的消息,因此,这条消息会继续发往GenericSource的onMessageReceived

void NuPlayer::GenericSource::onMessageReceived(const sp<AMessage> &msg) {switch (msg->what()) {case kWhatPrepareAsync:{onPrepareAsync();break;}...
}
...
void NuPlayer::GenericSource::onPrepareAsync() {...创建DataSourcemDataSource = new FileSource(mFd, mOffset, mLength);...//进行多媒体文件的格式探测和解析status_t err = initFromDataSource();// 上报流状态notifyFlagsChanged((mIsSecure ? FLAG_SECURE : 0)| (mDecryptHandle != NULL ? FLAG_PROTECTED : 0)| FLAG_CAN_PAUSE| FLAG_CAN_SEEK_BACKWARD| FLAG_CAN_SEEK_FORWARD| FLAG_CAN_SEEK);...//上报调用完成finishPrepareAsync();...
}  

我们重点关注initFromDataSource中的多媒体文件探测和解析

status_t NuPlayer::GenericSource::initFromDataSource() {...//创建多媒体探测器,这里会通过binder调度到MediaExtractor获取对应的解析器,例如MP3会使用MP3Extractorextractor = MediaExtractor::Create(mDataSource,mimeType.isEmpty() ? NULL : mimeType.string(),mIsStreaming ? 0 : AVNuUtils::get()->getFlags());//获取多媒体文件的元数据           mFileMeta = extractor->getMetaData();   //获取多媒体文件总共有多少个tracksize_t numtracks = extractor->countTracks();       for (size_t i = 0; i < numtracks; ++i) {//获取每一个tracksp<IMediaSource> track = extractor->getTrack(i);//获取当前track的meta数据sp<MetaData> meta = extractor->getTrackMetaData(i);const char *mime;//从当前track的meta信息中得到,多媒体是audio还是videoCHECK(meta->findCString(kKeyMIMEType, &mime));if (!strncasecmp(mime, "audio/", 6)) {if (mAudioTrack.mSource == NULL) {mAudioTrack.mIndex = i;mAudioTrack.mSource = track;mAudioTrack.mPackets =new AnotherPacketSource(mAudioTrack.mSource->getFormat());if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) {mAudioIsVorbis = true;} else {mAudioIsVorbis = false;}if (AVNuUtils::get()->isByteStreamModeEnabled(meta)) {mIsByteMode = true;}}} else if (!strncasecmp(mime, "video/", 6)) {....}}//获取时长if (meta->findInt64(kKeyDuration, &durationUs)) {if (durationUs > mDurationUs) {mDurationUs = durationUs;}}    ...

一般对于音频的文件而言,track只有一个,如下:

size_t MP3Extractor::countTracks() {return mInitCheck != OK ? 0 : 1;
}

参考文章:
NuPlayer播放框架之GenericSource源码分析

Audio播放流程(三)---NuPlayer流程之setAudioStreamType以及prepare相关推荐

  1. Android7.1 audio 播放流程(三十五)

    android audio 生产者与消费者 简介 全面接触生产者/消费者问题是在操作系统原理中,并发性原理讨论的问题 生产者/消费者问题.最近的工作偏向音频,接着上一篇文章,用生产者,消费者模型来理解 ...

  2. Android Audio播放流程详解

    本文涉及的所有代码都是AOSP源码 目录 1. AudioTrack 2.创建AudioTrack对象 1. AudioTrack AudioTrack用于播放PCM流格式的音频数据.播放器会在fra ...

  3. Anbox之server端audio播放流程(十二)

    Anbox是一个免费的开源兼容层,旨在允许为Android开发的移动应用程序和移动游戏在GNU / Linux发行版上运行. 使用LXC执行Android运行时环境,将Android的目录结构重新创建 ...

  4. activiti自己定义流程之Spring整合activiti-modeler5.16实例(四):部署流程定义

    注:(1)环境搭建:activiti自己定义流程之Spring整合activiti-modeler5.16实例(一):环境搭建         (2)创建流程模型:activiti自己定义流程之Spr ...

  5. activiti自定义流程之Spring整合activiti-modeler5.16实例(四):部署流程定义

    注:(1)环境搭建:activiti自定义流程之Spring整合activiti-modeler5.16实例(一):环境搭建         (2)创建流程模型:activiti自定义流程之Sprin ...

  6. [原创]FOCUS处理系统流程之:流程批量生成(个人专用懒人版)

    根据标准流程生成整个工区流程文件 (1)可按按目录生成 (2)可替换其中的关键字 标准流程准确,则生成的流程将一点到底,所剩的操作变成鼠标的操作,懒之产物. 界面如下:  ☆其它物探处理原创软件相关☆ ...

  7. 视频直播APP源码开发iOS音频播放流程

    视频直播APP源码开发iOS音频播放流程 概览 随着移动互联网的发展,如今的手机早已不是打电话.发短信那么简单了,播放音乐.视频.录音.拍照等都是很常用的功能.在iOS中对于多媒体的支持是非常强大的, ...

  8. Audio播放音频 --- 建立播放通道

    Audio播放音频 - 建立播放通道 简介 虽然文章标题是<建立播放通道>,其实播放通道早在AudioPolicyManager解析configuration配置文件时,openoutpu ...

  9. (连载)Android系统源码分析--Android系统启动流程之Linux内核

    > **这是一个连载的博文系列,我将持续为大家提供尽可能透彻的Android源码分析 [github连载地址](https://github.com/foxleezh/AOSP/issues/3 ...

  10. (连载)Android 8.0 : 系统启动流程之Linux内核

    这是一个连载的博文系列,我将持续为大家提供尽可能透彻的Android源码分析 github连载地址 前言 Android本质上就是一个基于Linux内核的操作系统,与Ubuntu Linux.Fedo ...

最新文章

  1. BZOJ 3175 最大独立集
  2. 从大学入门到研究生拿大厂offer,必须看的数据结构与算法书籍推荐,不好不推荐!
  3. SGU 269. Rooks(DP)
  4. UOJ #164 【清华集训2015】V (线段树)
  5. 《Linux》解决Linux端口被占用
  6. 谷歌联合 Adobe 发布 Noto 字体【免费下载】
  7. 网络服务器最基本的是文件,你可能想知道的15个网络常用基础知识
  8. m5310模组数据上传至onenet_基于Semtech SX1276RF1KAS SPI模组及ATMEGA328架构下之烟雾气体感测方案...
  9. visio网络拓扑图_人才测评模型是什么?5步了解好看模型图
  10. 管理学生信息android,Android 学生信息管理系统-Go语言中文社区
  11. 比特币与莱特币的区别
  12. 计算机操作题如何打分,Excel操作题也能自动评分
  13. 菜鸟Java远程连接腾讯云服务器上面的数据库
  14. 渗透测试工程师可以写进简历的技能介绍部分
  15. 如何将DVD的vob视频格式转换成mp4格式
  16. 超简单的QFN封装芯片的手工焊接方法,先收藏
  17. ios 获取相机胶卷_电影胶片相机的工作原理
  18. java使用itextpdf生成PDF批量打印荣誉证书(指定位置输出文字)
  19. TypeScript Essential Notes 2 - ES6 Language Features
  20. android仿微信发送位置,Android仿微信发送位置-百度地图

热门文章

  1. HDU1176:免费馅饼(dp,数字三角形的应用)
  2. 获取点击按钮的元素_怎么按顺序自动点击网页所有链接
  3. vue router name命名规范_关于Vue项目微前端的实现
  4. ]flume高并发优化——(1)load_balance
  5. Linux下comm命令比较两个文件的异同
  6. 一道容易栽坑的有趣的面试题(关于js,定时器,闭包等)
  7. iis6 服务器做301跳转返回状态码200解决方法。
  8. 清除浮动的七种方式方法(实例代码讲解)
  9. ubuntu和ok6410开发板之间架设nfs
  10. jsp页面什么时候用 .do 和 .jsp