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”> ...
随机推荐
- HTTP 错误 404.17 - Not Found 请求的内容似乎是脚本,因而将无法由静态文件处理程序来处理。
异常信息: 解决方案: 检查一下ASP.NET有没有安装: 控制面板>程序和功能>打开或关闭Windows功能 > Internet信息服务 > 万维网服务 &g ...
- 找不到类型“IBatisService.boxManageService”,它在 ServiceHost 指令中提供为 Service 特性值,或在配置元素 system.serviceModel/serviceHostingEnvironment/serviceActivations 中提供。
找不到类型“IBatisService.boxManageService”,它在 ServiceHost 指令中提供为 Service 特性值,或在配置元素 system.serviceModel/s ...
- 关于WinForm/Web如何使用缓存Cach
原文链接:http://www.cnblogs.com/zfanlong1314/archive/2013/03/28/2986403.html Cache 的绝对到期与滑动到期 绝对到期:设置绝对过 ...
- 2、shell命令学习
1.第一个例子 touch test.sh vim test.sh #!/bin/bash echo "hello world" chmod 755 test.sh ./test. ...
- [Mac] 使用Mac时的一些技巧
这篇博客就用来记录自己在使用Mac时学来的一些技巧吧! 1. 如何开启 Sticky key (在屏幕上显示输入的控制键) 就是这个东西啦,就是在视频演示的时候让别人看到自己按了什么控制键. 在s ...
- destoon实现资讯信息前面调用它所属分类的方法
有时候我们需要在一些信息前面添加他所属的分类,让他显示出来,本文介绍的方法虽然有些不具有通用性,但是可以实现这一效果,代码如下,供大家参考: <!--{php null=tag("mo ...
- 如何在word中写出赏心悦目的代码
短学期的VHDL终于结束了,虽然代码并不是很难,但是框框条条的规矩很多,也算折腾了一会,最后要写一个技术手册,结题报告类似物.考虑到word毕竟套主题比较方便,所以也就没有用LaTeX写,但是很快就发 ...
- rlwrap 的安装使用
rlwrap 的安装使用 在Windows操作系统上,当在DOS命令窗口中运行SQL*Plus的时候,可以使用向上,向下键来跳回之前已经执行过的SQL语句.你可以根据需要修改他们,然后按Enter键重 ...
- hdu 3832 Earth Hour
http://acm.hdu.edu.cn/showproblem.php?pid=3832 #include <cstdio> #include <iostream> #in ...
- poj2975--Nim
题意:对于一个给定的取石子游戏,有多少种先手策略获胜? Ans:若无法获胜,则输出0. 若能获胜我们只要找到一堆石子,使得我们能取它的一部分让总和的异或和变为0.我们先将整个游戏的值异或起来为s 则a ...