Android 原生播放器MediaPlayer

記得剛學(xué)Android開(kāi)發(fā)的時(shí)候在2011年敦锌,那個(gè)時(shí)候除了hello world馒疹,第一個(gè)接觸的組件就是這個(gè),這也是目前Android手機(jī)運(yùn)用到最多的組件乙墙,有人說(shuō)沒(méi)怎么使用過(guò)颖变,目前的各類(lèi)播放器,短視頻听想,都屬于多媒體播放腥刹,作為Android的多媒體開(kāi)始鼻祖當(dāng)屬M(fèi)ediaPlayer了。

回顧下官方的API接口

以官方貼圖為切入點(diǎn)汉买,API地址


從上圖開(kāi)始我們每一次播放的時(shí)候都要按照這樣的狀態(tài)去執(zhí)行衔峰,這就是一個(gè)典型的狀態(tài)機(jī)。
reset->Idle這個(gè)狀態(tài)就是起始狀態(tài)蛙粘,可以繼續(xù)執(zhí)行也可以隨時(shí)終止->release->End垫卤,也可以繼續(xù)執(zhí)行,我們俗稱(chēng)Idle為起始態(tài)也可以稱(chēng)之為空閑態(tài)出牧,它是伴隨播放器創(chuàng)建后首先走到的地方穴肘。若是需要播放,就要先執(zhí)行將播放需要的路徑傳進(jìn)來(lái)setDataSorece舔痕,目前這個(gè)setDataSorece的重載擴(kuò)展了很多评抚。這里繼續(xù)溫故下重載(overload),重載的基本原則:

  • 被重載的方法必須改變參數(shù)列表赵讯;
  • 被重載的方法可以改變返回類(lèi)型盈咳;
  • 被重載的方法可以改變?cè)L問(wèn)修飾符耿眉;
  • 被重載的方法可以聲明新的或更廣的檢查異常边翼;
  • 方法能夠在同一個(gè)類(lèi)中或者在一個(gè)子類(lèi)中被重載
    那么如果返回類(lèi)型不一樣算是重載嗎?答案是:不是的

setDataSorece

下面常用方法中鸣剪,列出不同重載后的方法组底。這時(shí)播放器接收到媒體資源后準(zhǔn)備進(jìn)入初始狀態(tài)。這里需要注意的是筐骇,這個(gè)順序不能改變债鸡,setDataSourece一定是播放器處于空閑態(tài)的時(shí)候調(diào)用的,否則就會(huì)出錯(cuò)铛纬。具體我們用代碼來(lái)分析:

 public void setDataSource(FileDescriptor fd, long offset, long length)
            throws IOException, IllegalArgumentException, IllegalStateException {
        try (ParcelFileDescriptor modernFd = FileUtils.convertToModernFd(fd)) {
            if (modernFd == null) {
                _setDataSource(fd, offset, length);
            } else {
                _setDataSource(modernFd.getFileDescriptor(), offset, length);
            }
        } catch (IOException e) {
            Log.w(TAG, "Ignoring IO error while setting data source", e);
        }
    }

非Idle調(diào)用會(huì)拋出IllegalStateException異常厌均,剩下兩個(gè)是在重載的時(shí)候拋出的。至于上面的異常告唆,官方給出注釋了

Sets the data source (MediaDataSource) to use.
Params:
dataSource – the MediaDataSource for the media you want to play
Throws:
IllegalStateException – if it is called in an invalid state
IllegalArgumentException – if dataSource is not a valid MediaDataSource

看下底層的代碼是如何實(shí)現(xiàn)的棺弊,路徑:framework/av/media/mediaplayer.cpp
看起重載后的其中一個(gè)方法:

status_t MediaPlayer::setDataSource(const sp<IDataSource> &source)
{
    ALOGV("setDataSource(IDataSource)");
    status_t err = UNKNOWN_ERROR;
    const sp<IMediaPlayerService> service(getMediaPlayerService());
    if (service != 0) {
        sp<IMediaPlayer> player(service->create(this, mAudioSessionId, mOpPackageName));
        if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
            (NO_ERROR != player->setDataSource(source))) {
            player.clear();
        }
        err = attachNewPlayer(player);
    }
    return err;
}

這里關(guān)注幾個(gè)點(diǎn)就可以
需要獲取mediaplayer的服務(wù)也就是getMediaPlayerService晶密,這里就要來(lái)到經(jīng)常提起的binder機(jī)制了,其實(shí)就是一個(gè)典型的CS模型

  • Server端
    BnMediaPlayerService 為MediaPlayerService在server端的具體實(shí)現(xiàn)模她;
  • Client端
    BpMediaPlayerService為MediaPlayerService在client端的具體代理稻艰;
    通過(guò)BpMediaPlayerService,可以享用MediaPlayerService所提供的服務(wù)
    通過(guò)BpMediaPlayerService可以獲取到IMediaRecorder侈净、IMediaMetadataRetriever尊勿、IMediaPlayer、IOMX在client端的代理類(lèi)BpXXX(IMediaRecorder畜侦、IMediaMetadataRetriever元扔、IMediaPlayer、IOMX旋膳,這些皆是Bp和Bn的共同接口摇展,和MediaPlayerService一樣,都有Bp和Bn構(gòu)成)
    引用鏈接
status_t MediaPlayer::setDataSource(
        const sp<IMediaHTTPService> &httpService,
        const char *url, const KeyedVector<String8, String8> *headers)
{
    ALOGV("setDataSource(%s)", url);
    status_t err = BAD_VALUE;
    if (url != NULL) {
        const sp<IMediaPlayerService> service(getMediaPlayerService());
        if (service != 0) {
            sp<IMediaPlayer> player(service->create(this, mAudioSessionId, mOpPackageName));
            if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
                (NO_ERROR != player->setDataSource(httpService, url, headers))) {
                player.clear();
            }
            err = attachNewPlayer(player);
        }
    }
    return err;
}

status_t MediaPlayer::setDataSource(int fd, int64_t offset, int64_t length)
{
    ALOGV("setDataSource(%d, %" PRId64 ", %" PRId64 ")", fd, offset, length);
    status_t err = UNKNOWN_ERROR;
    const sp<IMediaPlayerService> service(getMediaPlayerService());
    if (service != 0) {
        sp<IMediaPlayer> player(service->create(this, mAudioSessionId, mOpPackageName));
        if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
            (NO_ERROR != player->setDataSource(fd, offset, length))) {
            player.clear();
        }
        err = attachNewPlayer(player);
    }
    return err;
}

status_t MediaPlayer::setDataSource(const sp<IDataSource> &source)
{
    ALOGV("setDataSource(IDataSource)");
    status_t err = UNKNOWN_ERROR;
    const sp<IMediaPlayerService> service(getMediaPlayerService());
    if (service != 0) {
        sp<IMediaPlayer> player(service->create(this, mAudioSessionId, mOpPackageName));
        if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
            (NO_ERROR != player->setDataSource(source))) {
            player.clear();
        }
        err = attachNewPlayer(player);
    }
    return err;
}

prepareAsync

status_t MediaPlayer::prepareAsync()
{
    ALOGV("prepareAsync");
    //防止重復(fù)調(diào)用溺忧,它的作用域到函數(shù)結(jié)束
    Mutex::Autolock _l(mLock);
    return prepareAsync_l();
}
// must call with lock held
status_t MediaPlayer::prepareAsync_l()
{
    if ( (mPlayer != 0) && ( mCurrentState & (MEDIA_PLAYER_INITIALIZED | MEDIA_PLAYER_STOPPED) ) ) {
        if (mAudioAttributesParcel != NULL) {
            mPlayer->setParameter(KEY_PARAMETER_AUDIO_ATTRIBUTES, *mAudioAttributesParcel);
        } else {
            mPlayer->setAudioStreamType(mStreamType);
        }
        mCurrentState = MEDIA_PLAYER_PREPARING;
        return mPlayer->prepareAsync();
    }
    ALOGE("prepareAsync called in state %d, mPlayer(%p)", mCurrentState, mPlayer.get());
    return INVALID_OPERATION;
}
  • prepare
  • start
  • pause
  • stop
  • reset
  • seekTo
  • release
  • setDisplay
  • setSurface
  • setVolume
  • getTrackInfo
  • selectTrack
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末咏连,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子鲁森,更是在濱河造成了極大的恐慌祟滴,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,509評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件歌溉,死亡現(xiàn)場(chǎng)離奇詭異垄懂,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)痛垛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門(mén)法梯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人桶错,你說(shuō)我怎么就攤上這事桃移。” “怎么了蹂析?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,875評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵舔示,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我电抚,道長(zhǎng)惕稻,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,441評(píng)論 1 293
  • 正文 為了忘掉前任蝙叛,我火速辦了婚禮俺祠,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己蜘渣,他們只是感情好妓布,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,488評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著宋梧,像睡著了一般匣沼。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上捂龄,一...
    開(kāi)封第一講書(shū)人閱讀 51,365評(píng)論 1 302
  • 那天释涛,我揣著相機(jī)與錄音,去河邊找鬼倦沧。 笑死唇撬,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的展融。 我是一名探鬼主播窖认,決...
    沈念sama閱讀 40,190評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼告希!你這毒婦竟也來(lái)了扑浸?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,062評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤燕偶,失蹤者是張志新(化名)和其女友劉穎喝噪,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體指么,經(jīng)...
    沈念sama閱讀 45,500評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡酝惧,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,706評(píng)論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了伯诬。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片晚唇。...
    茶點(diǎn)故事閱讀 39,834評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖盗似,靈堂內(nèi)的尸體忽然破棺而出哩陕,到底是詐尸還是另有隱情,我是刑警寧澤桥言,帶...
    沈念sama閱讀 35,559評(píng)論 5 345
  • 正文 年R本政府宣布萌踱,位于F島的核電站葵礼,受9級(jí)特大地震影響号阿,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜鸳粉,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,167評(píng)論 3 328
  • 文/蒙蒙 一扔涧、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦枯夜、人聲如沸弯汰。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,779評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)咏闪。三九已至,卻和暖如春摔吏,著一層夾襖步出監(jiān)牢的瞬間鸽嫂,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,912評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工征讲, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留据某,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,958評(píng)論 2 370
  • 正文 我出身青樓诗箍,卻偏偏與公主長(zhǎng)得像癣籽,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子滤祖,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,779評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容