Audio播放流程(三)---NuPlayer流程之setAudioStreamType以及prepare
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相关推荐
- Android7.1 audio 播放流程(三十五)
android audio 生产者与消费者 简介 全面接触生产者/消费者问题是在操作系统原理中,并发性原理讨论的问题 生产者/消费者问题.最近的工作偏向音频,接着上一篇文章,用生产者,消费者模型来理解 ...
- Android Audio播放流程详解
本文涉及的所有代码都是AOSP源码 目录 1. AudioTrack 2.创建AudioTrack对象 1. AudioTrack AudioTrack用于播放PCM流格式的音频数据.播放器会在fra ...
- Anbox之server端audio播放流程(十二)
Anbox是一个免费的开源兼容层,旨在允许为Android开发的移动应用程序和移动游戏在GNU / Linux发行版上运行. 使用LXC执行Android运行时环境,将Android的目录结构重新创建 ...
- activiti自己定义流程之Spring整合activiti-modeler5.16实例(四):部署流程定义
注:(1)环境搭建:activiti自己定义流程之Spring整合activiti-modeler5.16实例(一):环境搭建 (2)创建流程模型:activiti自己定义流程之Spr ...
- activiti自定义流程之Spring整合activiti-modeler5.16实例(四):部署流程定义
注:(1)环境搭建:activiti自定义流程之Spring整合activiti-modeler5.16实例(一):环境搭建 (2)创建流程模型:activiti自定义流程之Sprin ...
- [原创]FOCUS处理系统流程之:流程批量生成(个人专用懒人版)
根据标准流程生成整个工区流程文件 (1)可按按目录生成 (2)可替换其中的关键字 标准流程准确,则生成的流程将一点到底,所剩的操作变成鼠标的操作,懒之产物. 界面如下: ☆其它物探处理原创软件相关☆ ...
- 视频直播APP源码开发iOS音频播放流程
视频直播APP源码开发iOS音频播放流程 概览 随着移动互联网的发展,如今的手机早已不是打电话.发短信那么简单了,播放音乐.视频.录音.拍照等都是很常用的功能.在iOS中对于多媒体的支持是非常强大的, ...
- Audio播放音频 --- 建立播放通道
Audio播放音频 - 建立播放通道 简介 虽然文章标题是<建立播放通道>,其实播放通道早在AudioPolicyManager解析configuration配置文件时,openoutpu ...
- (连载)Android系统源码分析--Android系统启动流程之Linux内核
> **这是一个连载的博文系列,我将持续为大家提供尽可能透彻的Android源码分析 [github连载地址](https://github.com/foxleezh/AOSP/issues/3 ...
- (连载)Android 8.0 : 系统启动流程之Linux内核
这是一个连载的博文系列,我将持续为大家提供尽可能透彻的Android源码分析 github连载地址 前言 Android本质上就是一个基于Linux内核的操作系统,与Ubuntu Linux.Fedo ...
最新文章
- BZOJ 3175 最大独立集
- 从大学入门到研究生拿大厂offer,必须看的数据结构与算法书籍推荐,不好不推荐!
- SGU 269. Rooks(DP)
- UOJ #164 【清华集训2015】V (线段树)
- 《Linux》解决Linux端口被占用
- 谷歌联合 Adobe 发布 Noto 字体【免费下载】
- 网络服务器最基本的是文件,你可能想知道的15个网络常用基础知识
- m5310模组数据上传至onenet_基于Semtech SX1276RF1KAS SPI模组及ATMEGA328架构下之烟雾气体感测方案...
- visio网络拓扑图_人才测评模型是什么?5步了解好看模型图
- 管理学生信息android,Android 学生信息管理系统-Go语言中文社区
- 比特币与莱特币的区别
- 计算机操作题如何打分,Excel操作题也能自动评分
- 菜鸟Java远程连接腾讯云服务器上面的数据库
- 渗透测试工程师可以写进简历的技能介绍部分
- 如何将DVD的vob视频格式转换成mp4格式
- 超简单的QFN封装芯片的手工焊接方法,先收藏
- ios 获取相机胶卷_电影胶片相机的工作原理
- java使用itextpdf生成PDF批量打印荣誉证书(指定位置输出文字)
- TypeScript Essential Notes 2 - ES6 Language Features
- android仿微信发送位置,Android仿微信发送位置-百度地图
热门文章
- HDU1176:免费馅饼(dp,数字三角形的应用)
- 获取点击按钮的元素_怎么按顺序自动点击网页所有链接
- vue router name命名规范_关于Vue项目微前端的实现
- ]flume高并发优化——(1)load_balance
- Linux下comm命令比较两个文件的异同
- 一道容易栽坑的有趣的面试题(关于js,定时器,闭包等)
- iis6 服务器做301跳转返回状态码200解决方法。
- 清除浮动的七种方式方法(实例代码讲解)
- ubuntu和ok6410开发板之间架设nfs
- jsp页面什么时候用 .do 和 .jsp