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等类型的音乐

时间: 2024-11-05 23:34:38

Audio笔记之MediaPlayerService:setDataSource的相关文章

android audio effects笔记

这里的内部跳转链接好像无效--这里会好一点:https://blog.csdn.net/whshiyun/article/details/79806870 #wmd-preview h1 { color: #0077bb } android effects笔记 android sound effect android effects笔记 1 相关类及成员说明 1.1 AudioPolicyService类 1.2 AudioPolicyEffects类 1.3 audioEffect相关 1.3

HTML5项目笔记4:使用Audio API设计绚丽的HTML5音乐播放器

HTML5 有两个很炫的元素,就是Audio和 Video,可以用他们在页面上创建音频播放器和视频播放器,制作一些效果很不错的应用. 无论是视屏还是音频,都是一个容器文件,包含了一些音频轨道,视频轨道和一些元数据,这些是和你的视频或者音频控件绑定到一块的,这样才形成了一个完整的播放组件. 浏览器支持情况: 浏览器 支持情况 编解码器 Chrome 3.0 Theora . Vorbis .Ogg H.264 . AAC .MPEG4 FireFox 3.5 Theora . Vorbis .Og

HTML5学习笔记简明版(4):新元素之video,audio,meter,datalist,keygen,output

video 通过<video>标签,我们可以抛弃最近不怎么讨好的Flash,直接在页面中播放视频文件.视频文件自然是最符合语义化的文件格式,但该元素标签同样支持音频与图片. 过去(及目前),我们通常要使用类似下面这样繁冗丑陋的代码来将视频放置在页面中,但这种方式要求浏览器安装有Flash插件,并支持JavaScript: <object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="4

安卓第十六天笔记-音频与视频播放

安卓第十六天笔记-音频与视频播放 音频与视频播放 1.音频 播放应用资源中的音乐 应用中的音乐一般放在res/raw目录下 /** * 播放应用资源中的音乐 * * @param v */ public void player1(View v) { // 设置播放数据源 MediaPlayer mediaPlayer = MediaPlayer.create(this, R.raw.gm); // 不需要准备,create,创建完成直接可以使用播放 mediaPlayer.start(); }

ijkplayer阅读学习笔记之从代码上看播放流程

看了很久的ijkplayer的视频播放,其实还是没有怎么看懂,只是个人浅浅的笔记 关键部分就是联网获取数据那部分,还没有搞定其实 从用户点击一个已有地址的网络视频开始,从源码分析播放流程. 1.        // init player  加载native底层库 IjkMediaPlayer.loadLibrariesOnce(null); IjkMediaPlayer.native_profileBegin("libijkplayer.so"); 第一句话是加载三个重要的so文件

学习笔记之邮件发送篇

用脚本语言发送邮件是系统管理员必备技能 对系统定期检查或者当服务器受到攻击时生成文档和报表. 发布这些文档最快速有效的方法就是发送邮件. python中email模块使得处理邮件变得比较简单 发送邮件主要用到了smtplib和email两个模块,这里首先就两个模块进行一下简单的介绍: 本段摘录于    http://www.cnblogs.com/xiaowuyi/archive/2012/03/17/2404015.html 1.smtplib模块 smtplib.SMTP([host[, p

播放器制作笔记----MediaStore

在最初的构思中,我使用的是File类递归遍历SD卡中的所有文件,然后筛选出以".mp3"格式结尾的文件,放入一个map.然后将map放入List,让media加载. 但是,发现这样的方法耗时比较长,容易出现"卡住"的现象,然后就想将List永久化存到本地,但是发现如果有几百首歌的话,文件太大了,非常占内存控件.在查阅了一些资料后,发现android手机自身就有一个媒体库,可以直接查询.在多次尝试后,终于成功读取文件.这里做一个笔记. 一,获取ContextResol

Machine Learning第十一周笔记:photo OCR

博客已经迁移至Marcovaldo's blog (http://marcovaldong.github.io/) 刚刚完毕了Cousera上Machine Learning的最后一周课程.这周介绍了machine learning的一个应用:photo OCR(optimal character recognition,光学字符识别),以下将笔记整理在以下. Photo OCR Problem Description and Pipeline 最后几小节介绍机器学习的一个应用--photo O

第二天课堂笔记

##5.0新特性###十大新特性1. 全新Material Design设计风格 * 新的视觉语言,在基本元素的处理上,借鉴了传统的印刷设计,字体版式.网格系统.空间.比例.配色.图像使用等这些基础的平面设计规范2. 支持多种设备3. 全新的通知中心设计4. 支持64位ART虚拟机 * 谷歌承诺所有性能都会比原来提升一倍,Android Lollipop支持更大的寄存器,支持新的指令集,提升了内存寻址空间,未来Android智能手机将支持4GB以上的内存.5. Project Volta电池续航