ANdroid O MeidiaPlayer 深刻理解(一)

前言

android對於java層的音頻播放器提供了不少api,主要的有 AudioTrack、SoundPool、MediaPlayer(其實AudioPlayer和MediaPlayerAdapter也都是加了AudioFcus後對於MediaPlayer的二次封裝,關於AudioFocus有時間再詳細介紹)。
其中AudioTrack主要是播放pcm流,而soundPool主要播放一些短暫的聲音,好比touch音。MediaPlayer主要播放媒體音頻文件像.mp3文件等。其中SoundPool和MediaPlayer最終都會在native層調用到audioTrack將音頻流寫入到對應devices上。
關於MediaPlayer和AudioTrack的區別,這裏就不細說了,百度一大堆。主要就是MediaPlayer會把.mp3等格式文件最終解析成pcm流輸出給audiotrack。關於MediaPlayer的Java層的各狀態轉化和各方法調用說明,這裏也不一一細說了。度娘全是這玩意。
這裏主要說說MediaPlayer關於native層的東東(本人java出生,對於c/c++等了解的不免疏漏,若有理解錯誤,望各位大神不吝賜教,定虛心改正)。java


MediaPlayer初始化

給你們提供一個免費看源碼的網站(知道請略過)http://androidxref.com/
言歸正傳,就從java層的MediaPlayer提及吧。android

  1. 構造方法

MediaPlayer位於frameworks/base/media/java/android/media/下繼承PlayerBase。
其中PlayerBase的構造方法以下:c++

PlayerBase(@NonNull AudioAttributes attr, int implType) {
        if (attr == null) {
            throw new IllegalArgumentException("Illegal null AudioAttributes");
        }
        mAttributes = attr;
       mImplType = implType;
        mState = AudioPlaybackConfiguration.PLAYER_STATE_IDLE;
   };

MediaPlayer的構造方法:api

public MediaPlayer() {
        super(new AudioAttributes.Builder().build(),
                AudioPlaybackConfiguration.PLAYER_TYPE_JAM_MEDIAPLAYER);

        Looper looper;
        if ((looper = Looper.myLooper()) != null) {
            mEventHandler = new EventHandler(this, looper);
        } else if ((looper = Looper.getMainLooper()) != null) {
            mEventHandler = new EventHandler(this, looper);
        } else {
            mEventHandler = null;
        }

        mTimeProvider = new TimeProvider(this);
        mOpenSubtitleSources = new Vector<InputStream>();

        /* Native setup requires a weak reference to our object.
         * It's easier to create it here than in C++.
         */
        native_setup(new WeakReference<MediaPlayer>(this));

        baseRegisterPlayer();
    }

能夠看咱們在使用時MediaPlayer時,經過new MediaPlayer的方式到實際都作了什麼,着重關注下這幾個點
1.new AudioAttributes.Builder()//這個主要後面的audioPolicy會用到。
2.native_setup
3.baseRegisterPlayer註冊了一個player狀態回調,這塊邏輯,感興趣的能夠本身查下源碼,暫忽略掉,有時間細看再補上這塊吧,今天重點不是他。
重點說2.native_setup,這步直接調用了jni方法,關於jni我瞭解不是不少,我主要作從事App開發的,底層的東東只能略知一二,說的不對的,請多多指教。ide

private native final void native_setup(Object mediaplayer_this);

jni的加載主要經過 System.loadLibrary來實現的:oop

static {
        System.loadLibrary("media_jni");
        native_init();
    }

在/frameworks/base/media/jni/android_media_MediaPlayer.cpp目錄下,這樣就走到了C++部分。
經過JNINativeMethod gMethods[]方法知道native_setup會調到android_media_MediaPlayer_native_setup方法。網站

{"native_setup",        "(Ljava/lang/Object;)V",            (void *)android_media_MediaPlayer_native_setup},

其中:ui

static void
android_media_MediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this)
{
    ALOGV("native_setup");
    sp<MediaPlayer> mp = new MediaPlayer();
    if (mp == NULL) {
        jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
        return;
    }

    // create new listener and give it to MediaPlayer
    sp<JNIMediaPlayerListener> listener = new JNIMediaPlayerListener(env, thiz, weak_this);
    mp->setListener(listener);

    // Stow our new C++ MediaPlayer in an opaque field in the Java object.
    setMediaPlayer(env, thiz, mp);
}

Ok分析下sp<MediaPlayer> mp = new MediaPlayer(); native層的mediaplayer也有了,建立了一個C++的mediaPlayer對象。
繼續:setMediaPlayer(env, thiz, mp)將建立的Native層的MediaPlayer對象保存到Java層。也就是說未來咱們經過getMediaplayer()的時候獲取到的就是這個對象。this


總結

到此MediaPlayer就建立完成了,經過java代碼 new MediaPlayer()開始,一直到native層建立native層的MediaPlayer,並將native層的MediaPlayer返回到java層,供java層調用。
其實整個MediaPlayer在運行的時候,能夠大體上分紅Client和Server兩個部分,它們分別在兩個進程中運行,它們之間使用Binder機制實現IPC通信,但Client端分一個在java層的MediaPlayer和native層的MediaPlayer。
最後感謝百度各位大師提供資料。code

相關文章
相關標籤/搜索