Audio笔记之MediaPlayerService:setDataSource
//下面是一个典型的播放序列:
MediaPlayer player=new MediaPlayer()
player->setDataSource(url,header);
player->prepare();
player->start();
...
//使用MediaPlayerServcie的Client对象设置数据源
status_t MediaPlayer::setDataSource(
const char *url, const KeyedVector<String8, String8> *headers)
{
ALOGV("setDataSource(%s)", url);
status_t err = BAD_VALUE;
if (url != NULL) {
//1、获得MediaPlayerService
const sp<IMediaPlayerService>& service(getMediaPlayerService());
if (service != 0) {
//2、返回MediaPlayerService的Client对象player,并保存在Service的数组对象中,
//后续使用该Client将向MediaPlayer提供服务,因此每个MediaPlayer都对应一个Client
sp<IMediaPlayer> player(service->create(this, mAudioSessionId));
//3、选择正确的播放器,并设置播放器的数据源
if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
(NO_ERROR != player->setDataSource(url, headers))) {
player.clear();
}
//4、保存最新的Client对象,断开之前Client对象
err = attachNewPlayer(player);
}
}
return err;
}
1、获取MeidaPlayerSercie
/*static*/const sp<IMediaPlayerService>&
IMediaDeathNotifier::getMediaPlayerService()
{
ALOGV("getMediaPlayerService");
Mutex::Autolock _l(sServiceLock);
if (sMediaPlayerService == 0) {
//获得BpServiceManager对象
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder;
do {
binder = sm->getService(String16("media.player"));
if (binder != 0) {
break;
}
ALOGW("Media player service not published, waiting...");
usleep(500000); // 0.5 s
} while (true); if (sDeathNotifier == NULL) {
sDeathNotifier = new DeathNotifier();
}
//通过Bind获取BpMediaPlayerService对象
binder->linkToDeath(sDeathNotifier);
sMediaPlayerService = interface_cast<IMediaPlayerService>(binder);
}
ALOGE_IF(sMediaPlayerService == 0, "no media player service!?");
return sMediaPlayerService;
}
2、构造MediaPlayerService的Client对象
sp<IMediaPlayer> MediaPlayerService::create(const sp<IMediaPlayerClient>& client,
int audioSessionId)
{
pid_t pid = IPCThreadState::self()->getCallingPid();
int32_t connId = android_atomic_inc(&mNextConnId); sp<Client> c = new Client(
this, pid, connId, client, audioSessionId,
IPCThreadState::self()->getCallingUid()); ALOGV("Create new client(%d) from pid %d, uid %d, ", connId, pid,
IPCThreadState::self()->getCallingUid()); wp<Client> w = c;
{
Mutex::Autolock lock(mLock);
mClients.add(w);
}
return c;
}
//保存Client端的AudioSessionId等信息
MediaPlayerService::Client::Client(
const sp<MediaPlayerService>& service, pid_t pid,
int32_t connId, const sp<IMediaPlayerClient>& client,
int audioSessionId, uid_t uid)
{
ALOGV("Client(%d) constructor", connId);
mPid = pid;
mConnId = connId;
mService = service;
mClient = client;
mLoop = false;
mStatus = NO_INIT;
mAudioSessionId = audioSessionId;
mUID = uid;
mRetransmitEndpointValid = false; #if CALLBACK_ANTAGONIZER
ALOGD("create Antagonizer");
mAntagonizer = new Antagonizer(notify, this);
#endif
}
//通过url获取对应的播放器,然后保存该播放器,并设置播放器的数据源
status_t MediaPlayerService::Client::setDataSource(
const char *url, const KeyedVector<String8, String8> *headers)
{
ALOGV("setDataSource(%s)", url);
if (url == NULL)
return UNKNOWN_ERROR; if ((strncmp(url, "http://", 7) == 0) ||
(strncmp(url, "https://", 8) == 0) ||
(strncmp(url, "rtsp://", 7) == 0)) {
if (!checkPermission("android.permission.INTERNET")) {
return PERMISSION_DENIED;
}
} if (strncmp(url, "content://", 10) == 0) {
// get a filedescriptor for the content Uri and
// pass it to the setDataSource(fd) method String16 url16(url);
int fd = android::openContentProviderFile(url16);
if (fd < 0)
{
ALOGE("Couldn't open fd for %s", url);
return UNKNOWN_ERROR;
}
setDataSource(fd, 0, 0x7fffffffffLL); // this sets mStatus
close(fd);
return mStatus;
} else {
//通过url获取对应的播放器
player_type playerType = MediaPlayerFactory::getPlayerType(this, url);
sp<MediaPlayerBase> p = setDataSource_pre(playerType);
if (p == NULL) {
return NO_INIT;
} setDataSource_post(p, p->setDataSource(url, headers));
return mStatus;
}
}
//通过播放器工厂的scoreFactory函数判断该播放器是否合适,选择播放器类型
#define GET_PLAYER_TYPE_IMPL(a...) \
Mutex::Autolock lock_(&sLock); \
\
player_type ret = STAGEFRIGHT_PLAYER; \
float bestScore = 0.0; \
\
for (size_t i = 0; i < sFactoryMap.size(); ++i) { \
\
IFactory* v = sFactoryMap.valueAt(i); \
float thisScore; \
CHECK(v != NULL); \
thisScore = v->scoreFactory(a, bestScore); \
if (thisScore > bestScore) { \
ret = sFactoryMap.keyAt(i); \
bestScore = thisScore; \
} \
} \
\
if (0.0 == bestScore) { \
ret = getDefaultPlayerType(); \
} \
\
return ret; player_type MediaPlayerFactory::getPlayerType(const sp<IMediaPlayer>& client,
const char* url) {
GET_PLAYER_TYPE_IMPL(client, url);
}
//这里如果所有播放器都不合适,则选择默认播放器这里流程是,
//从播放器仓库中选取最佳播放器,通过scoreFactory来确定
player_type MediaPlayerFactory::getDefaultPlayerType() {
char value[PROPERTY_VALUE_MAX];
if (property_get("media.stagefright.use-nuplayer", value, NULL)
&& (!strcmp("1", value) || !strcasecmp("true", value))) {
return NU_PLAYER;
} return STAGEFRIGHT_PLAYER;
}
sp<MediaPlayerBase> MediaPlayerService::Client::setDataSource_pre(
player_type playerType)
{
ALOGV("player type = %d", playerType); // create the right type of player
sp<MediaPlayerBase> p = createPlayer(playerType);
if (p == NULL) {
return p;
}
//根据AudioSessionId设置播放器的输出端
if (!p->hardwareOutput()) {
mAudioOutput = new AudioOutput(mAudioSessionId);
static_cast<MediaPlayerInterface*>(p.get())->setAudioSink(mAudioOutput);
} return p;
}
sp<MediaPlayerBase> MediaPlayerService::Client::createPlayer(player_type playerType)
{
// determine if we have the right player type
sp<MediaPlayerBase> p = mPlayer;
if ((p != NULL) && (p->playerType() != playerType)) {
ALOGV("delete player");
p.clear();
}
if (p == NULL) {
p = MediaPlayerFactory::createPlayer(playerType, this, notify);
} if (p != NULL) {
p->setUID(mUID);
} return p;
}
//主要是创建播放器 //上面看具体StagefrightPlayerFactory 实现的时候,代码中实现了createPlayer,此处就是调用的此方法 //因此等价于return (new StagefrightPlayer()) ;
void MediaPlayerService::Client::setDataSource_post(
const sp<MediaPlayerBase>& p,
status_t status)
{
ALOGV(" setDataSource");
mStatus = status;
if (mStatus != OK) {
ALOGE(" error: %d", mStatus);
return;
} // Set the re-transmission endpoint if one was chosen.
if (mRetransmitEndpointValid) {
mStatus = p->setRetransmitEndpoint(&mRetransmitEndpoint);
if (mStatus != NO_ERROR) {
ALOGE("setRetransmitEndpoint error: %d", mStatus);
}
} if (mStatus == OK) {
mPlayer = p;
}
}
//setDataSource_post(p, p->setDataSource(source))
//设置播放器的数据源,因为实际的视屏播放是由该播放器完成
status_t StagefrightPlayer::setDataSource(
const char *url, const KeyedVector<String8, String8> *headers) {
return mPlayer->setDataSource(url, headers);
}
status_t AwesomePlayer::setDataSource(
const char *uri, const KeyedVector<String8, String8> *headers) {
Mutex::Autolock autoLock(mLock);
return setDataSource_l(uri, headers);
}
status_t AwesomePlayer::setDataSource_l(
const char *uri, const KeyedVector<String8, String8> *headers) {
reset_l(); mUri = uri; if (headers) {
mUriHeaders = *headers; ssize_t index = mUriHeaders.indexOfKey(String8("x-hide-urls-from-log"));
if (index >= 0) {
// Browser is in "incognito" mode, suppress logging URLs. // This isn't something that should be passed to the server.
mUriHeaders.removeItemsAt(index); modifyFlags(INCOGNITO, SET);
}
} ALOGI("setDataSource_l(URL suppressed)"); // The actual work will be done during preparation in the call to
// ::finishSetDataSource_l to avoid blocking the calling thread in
// setDataSource for any significant time. {
Mutex::Autolock autoLock(mStatsLock);
mStats.mFd = -1;
mStats.mURI = mUri;
} return OK;
}
//4、保存新的MediaPlayerService的Client对象,并断开之前的Client和Service
status_t MediaPlayer::attachNewPlayer(const sp<IMediaPlayer>& player)
{
status_t err = UNKNOWN_ERROR;
sp<IMediaPlayer> p;
{ // scope for the lock
Mutex::Autolock _l(mLock); if ( !( (mCurrentState & MEDIA_PLAYER_IDLE) ||
(mCurrentState == MEDIA_PLAYER_STATE_ERROR ) ) ) {
ALOGE("attachNewPlayer called in state %d", mCurrentState);
return INVALID_OPERATION;
}
//重置相关参数
clear_l();
p = mPlayer;
mPlayer = player;//更新Client属性
if (player != 0) {
mCurrentState = MEDIA_PLAYER_INITIALIZED;
err = NO_ERROR;
} else {
ALOGE("Unable to create media player");
}
}
//断开之前的Client
if (p != 0) {
p->disconnect();
} return err;
}
// always call with lock held
void MediaPlayer::clear_l()
{
mCurrentPosition = -1;
mSeekPosition = -1;
mVideoWidth = mVideoHeight = 0;
mRetransmitEndpointValid = false;
}
void MediaPlayerService::Client::disconnect()
{
ALOGV("disconnect(%d) from pid %d", mConnId, mPid);
// grab local reference and clear main reference to prevent future
// access to object
sp<MediaPlayerBase> p;
{
Mutex::Autolock l(mLock);
p = mPlayer;//播放器对象,如StagefrightPlayer
mClient.clear();//MdediaPlayer对象
} mPlayer.clear(); // clear the notification to prevent callbacks to dead client
// and reset the player. We assume the player will serialize
// access to itself if necessary.
if (p != 0) {
p->setNotifyCallback(0, 0);
#if CALLBACK_ANTAGONIZER
ALOGD("kill Antagonizer");
mAntagonizer->kill();
#endif
p->reset();//调用具体播放器的reset函数,如
} disconnectNativeWindow(); IPCThreadState::self()->flushCommands();
}
void MediaPlayerService::Client::disconnectNativeWindow() {
if (mConnectedWindow != NULL) {
status_t err = native_window_api_disconnect(mConnectedWindow.get(),
NATIVE_WINDOW_API_MEDIA); if (err != OK) {
ALOGW("native_window_api_disconnect returned an error: %s (%d)",
strerror(-err), err);
}
}
mConnectedWindow.clear();
}
status_t StagefrightPlayer::reset() {
ALOGV("reset"); mPlayer->reset(); return OK;
}
//具体的reset操作,不同的播放器有不同的实现
void AwesomePlayer::reset_l() {
mVideoRenderingStarted = false;
mActiveAudioTrackIndex = -1;
mDisplayWidth = 0;
mDisplayHeight = 0; if (mDecryptHandle != NULL) {
mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
Playback::STOP, 0);
mDecryptHandle = NULL;
mDrmManagerClient = NULL;
} if (mFlags & PLAYING) {
uint32_t params = IMediaPlayerService::kBatteryDataTrackDecoder;
if ((mAudioSource != NULL) && (mAudioSource != mAudioTrack)) {
params |= IMediaPlayerService::kBatteryDataTrackAudio;
}
if (mVideoSource != NULL) {
params |= IMediaPlayerService::kBatteryDataTrackVideo;
}
addBatteryData(params);
} if (mFlags & PREPARING) {
modifyFlags(PREPARE_CANCELLED, SET);
if (mConnectingDataSource != NULL) {
ALOGI("interrupting the connection process");
mConnectingDataSource->disconnect();
} if (mFlags & PREPARING_CONNECTED) {
// We are basically done preparing, we're just buffering
// enough data to start playback, we can safely interrupt that.
finishAsyncPrepare_l();
}
} while (mFlags & PREPARING) {
mPreparedCondition.wait(mLock);
} cancelPlayerEvents(); mWVMExtractor.clear();
mCachedSource.clear();
mAudioTrack.clear();
mVideoTrack.clear();
mExtractor.clear(); // Shutdown audio first, so that the respone to the reset request
// appears to happen instantaneously as far as the user is concerned
// If we did this later, audio would continue playing while we
// shutdown the video-related resources and the player appear to
// not be as responsive to a reset request.
if ((mAudioPlayer == NULL || !(mFlags & AUDIOPLAYER_STARTED))
&& mAudioSource != NULL) {
// If we had an audio player, it would have effectively
// taken possession of the audio source and stopped it when
// _it_ is stopped. Otherwise this is still our responsibility.
mAudioSource->stop();
}
mAudioSource.clear(); mTimeSource = NULL; delete mAudioPlayer;
mAudioPlayer = NULL; if (mTextDriver != NULL) {
delete mTextDriver;
mTextDriver = NULL;
} mVideoRenderer.clear(); if (mVideoSource != NULL) {
shutdownVideoDecoder_l();
} mDurationUs = -1;
modifyFlags(0, ASSIGN);
mExtractorFlags = 0;
mTimeSourceDeltaUs = 0;
mVideoTimeUs = 0; mSeeking = NO_SEEK;
mSeekNotificationSent = true;
mSeekTimeUs = 0; mUri.setTo("");
mUriHeaders.clear(); mFileSource.clear(); mBitrate = -1;
mLastVideoTimeUs = -1; {
Mutex::Autolock autoLock(mStatsLock);
mStats.mFd = -1;
mStats.mURI = String8();
mStats.mBitrate = -1;
mStats.mAudioTrackIndex = -1;
mStats.mVideoTrackIndex = -1;
mStats.mNumVideoFramesDecoded = 0;
mStats.mNumVideoFramesDropped = 0;
mStats.mVideoWidth = -1;
mStats.mVideoHeight = -1;
mStats.mFlags = 0;
mStats.mTracks.clear();
} mWatchForAudioSeekComplete = false;
mWatchForAudioEOS = false;
}
以上调用流程:
MediaPlayer(JAVA层)->MediaPlayer(C层)->Client->MediaPlayService->StagefrightPlayer->AwesomePlayer
最终所有对应具体文件的操作都需要AwesomePlayer落实,如:
prepare
play
pause
总结下几种播放器的区别
StagefrightPlayer: 默认播放器,本地文件基本都使用其播放
NuPlayerDriver:主要用于播放网络视频,http https rtsp等
SonivoxPlayer:用于播放midi等类型的音乐
Audio笔记之MediaPlayerService:setDataSource的更多相关文章
- 高仿Android网易云音乐OkHttp+Retrofit+RxJava+Glide+MVC+MVVM
简介 这是一个使用Java(以后还会推出Kotlin版本)语言,从0开发一个Android平台,接近企业级的项目(我的云音乐),包含了基础内容,高级内容,项目封装,项目重构等知识:主要是使用系统功能, ...
- HTML5项目笔记4:使用Audio API设计绚丽的HTML5音乐播放器
HTML5 有两个很炫的元素,就是Audio和 Video,可以用他们在页面上创建音频播放器和视频播放器,制作一些效果很不错的应用. 无论是视屏还是音频,都是一个容器文件,包含了一些音频轨道,视频轨道 ...
- html5学习笔记(audio)
来源于<HTML5高级程序设计> audio api <audio controls> controls告诉浏览器显示播放控件 不指定 type 浏览器自解 oggMP3 ty ...
- 《The challenge of realistic music generation: modelling raw audio at scale》论文阅读笔记
The challenge of realistic music generation: modelling raw audio at scale 作者:Deep mind三位大神 出处:NIPS ...
- web前端学习(二)html学习笔记部分(4)--audio和video文件播放
1.2.10 html5音频 1.2.10.1 HTML5音频播放 本课主要讲解HTML5播放音频 <!--<button onclick="clickA"> ...
- Audio 的一些小笔记
1.在做项目的过程中,对于volume 我们有一个volume curve,就是 0~63 step,每个step对应一个dB值,例如0step对应-90dB, 63 step对应0dB.关于这个0d ...
- Android Media (Audio) Framework 多媒体系统框架
http://blog.csdn.net/lskshz/article/details/17264113 原址:http://blog.csdn.net/myzhzygh/article/detail ...
- <Node入门经典>读书笔记
最近在读<Node入门经典>, 之前没有做笔记, 今天开始把看过自己又写了的代码放这里以免忘记. express var express = require('express') var ...
- html5学习笔记一
HTML5学习笔记 <video>标记:定义视频,Ogg.MPEG4.WebM三种格式 <video src=”movie.ogg” controls=”controls”> ...
随机推荐
- Jquery:Jquery中的DOM操作<二>
由于昨天晚上回来的晚,写的有点匆忙,所以昨天的学习笔记中出现了多处错误的地方,幸好有各位园友帮忙指出,在这里谢过各位了!今天继续学习关于Jquery中DOM的操作,其实是昨天随笔的延续,求围观!!! ...
- StartService与BindService
效果图 MainActivity.java package com.wangzhen.servicedemo; import com.lidroid.xutils.ViewUtils; import ...
- 在App中混合HTML5开发App如何实现的。在App中使用HTML5的优缺点是什么?
参考答案: 在iOS中,通常是通常UIWebView来实现,当然在iOS8以后可以使用WKWebView来实现.有以下几种实现方法: 通过实现UIWebView的代理方法来拦截,判断scheme是否是 ...
- c#使用Dictionary统计字符串中出现次数最多字符
最近在找工作,遇到这样一道面试题: 对于给定的一个字符串,统计出该串中各个字符出现的次数,并打印出出现次数最多的那个字符 因为本人是个菜鸟,所以当时写的思路是用递归 /*str 字符串, strA 第 ...
- 1、发布C++实现的TCP网络框架Khala
1.Khala简介 Khala(卡拉)是用C++实现的TCP网络框架.底层采用muduo网络库作为网络IO+线程模型,并封装实现了网络实现与业务逻辑分离的多线程网络框架,具有超时退出.多设备多事件注册 ...
- C++深层复制解决指针悬挂
代码: #include <iostream> #include <cstring> using namespace std; class mystring{ public: ...
- GacLib使用方法(一)
GacLib使用方法 这是vczh大神的GacLib库新手入门,为自己做点笔记,详细的信息可以参考网页.下面简单说说怎么在自己的程序中使用GacLib库,本文只是前述网址中新手教程的一点体验,使用的环 ...
- DOM 节点实例操作
涉及知识点包括节点的所有知识 目的: 自动为文档创建一个目录表 自动创建目录
- JavaScript 作用域和闭包
作用域的嵌套将形成作用域链,函数的嵌套将形成闭包.闭包与作用域链是 JavaScript 区别于其它语言的重要特性之一. 作用域 JavaScript 中有两种作用域:函数作用域和全局作用域. 在一个 ...
- mongodb3 权限认证问题总结
mongodb3 权限认证问题总结 标签(空格分隔): mongodb 权限 数据库 认证 ubuntu用户安装最新版本mongodb 添加key sudo apt-key adv --keyserv ...