最近在Android遊戲開發中,需要處理WAV和OGG的播放。其中背景音樂需求爲一路WAV或者OGG。在Android.media Package中。選中了MediaPlayer作爲背景音樂的播放。
0. 簡介:
1. Playback狀態機:
可以將播放文件和流看作狀態機管理。下圖詳細描述了各狀態以及如何在各狀態間轉移。
注:單箭頭表示同步調用。雙箭頭表示異步調用。
現在詳細分析每個狀態以及狀態間轉移。
1.1:Idle狀態:
當MediaPlayer object剛被使用new 創建,或者調用reset()後,此MediaPlayer object處於Idle狀態。
兩種方法進入Idle狀態,有個細小卻重要的區別:當程序在Idle狀態錯誤的調用了類似getCurrentPosition(),GetDuration(),getVideoight(),setAudioStreamType(), setLooping(),setVolume(),pause(),start(),stop(),seekTo(),prepare()等方法。
如果MediaPlayer object剛被new 出來,處於idle狀態。用戶使用OnErrorListener.onError()註冊的callback函數不會被內在palyer Engine調用,且狀態不會發生改變,繼續爲idle.
如果是reset() 後處於idle狀態,則註冊的callback函數被調用。且MediaPlayer object會轉爲Error狀態。
1.2:End狀態:
當MediaPlayer object調用release() 後,它處於End 狀態。
如果MediaPlayer object不再使用時,請立即調用release(),這樣,內部player engine可以釋放掉他們所佔用的資源。 這類資源,不光包括內存資源,還包括Audio,Video硬件解碼設備。
當用戶進入End狀態後,沒有任何渠道去轉回其它狀態。
1.3:Initialized狀態:
當MediaPlayer Object爲Idle狀態時,調用setDataSource(FileDescriptor), or setDataSource(String), or setDataSource(Context, Uri), or setDataSource(FileDescriptor, long, long)轉變其狀態到Initialized狀態。
如果setDataSource()在非Idle狀態調用, IllegalStateException會被拋出。
所以,setDataSource()時必須捕獲IllegalArgumentException and IOException異常。
1.4:Prepared狀態:
MediaPlayer Object 必須首先進入Prepared狀態,之後才能開始start.
有兩種方式進入Prepared狀態:
調用prepare() 則以同步方式進入Prepared狀態。當prepare()返回時,MediaPlayer Object 已經進入Prepared狀態。
調用prepareAsync()則以異步方式進入Prepared狀態。
當在錯誤狀態調用prepare() or prepareAsync() ,則拋出異常IllegalStateException。
1.5: Started狀態:
要播放,則需要調用start(),當start()返回successfully時,MediaPlayer Object則進入Started狀態。
isPlaying()可以測試是否位於Started 狀態。
在MediaPlayer Object處於Started狀態時,調用start()沒有任何效果。
1.6:Paused狀態:
調用pause(),當其返回時,MediaoPlayer Object進入Paused狀態。從started狀態到pasued狀態,Play Engine有缺陷。所以導致isPlaying()...
MediaPlayer進入Paused狀態後,調用start()重新開始播放(Resume).但Position是從剛纔暫停處開始播放,而不是從頭。且狀態變化爲Started。
在Paused狀態,再次調用pause()沒有反應 。
1.7 Stop狀態:
在Started,Paused,Prepared或者PlaybackCompleted狀態,調用stop(),則進入Stopped狀態。
在Stopped狀態,MediaPlayer Object不能再次調用start()去播放,除非調用prepare()或prepareAsync()使其進入Prepared狀態。
在Stopped狀態下再次調用stop.無效。
1.8 PlaybackCompleted狀態:
當Video/Audio播放完畢後,進入PlaybackCompleted模式。
但如果使用setLooping(true),則播放完畢後,立刻重新播放。且狀態繼續爲started.
如果setLooping(false).播放完畢後,MediaPlayer Object進入PlaybackCompleted模式,並調用setOnCompletionListener(OnCompletionListener)註冊的callback函數。
如在 PlaybackCompleted狀態下,調用start(),會進入started模式,並從頭播放。
2. 回調機制:
MediaPlayer使用一些方法來設置回調函數,當發生某種特定情況時,內部palyer Engine會調用之。
使用方法,可以在稍後的例子中看到。
3. 播放指針:
可以調用 seekTo()來調整當前播放指針。
下表列出了各種方法在哪些狀態下調用合法,在哪些狀態下非法以及導致的後果:
Valid and invalid states
Method Name
|
Valid Sates
|
Invalid States
|
Comments
|
attachAuxEffect
|
{Initialized, Prepared, Started, Paused, Stopped, PlaybackCompleted}
|
{Idle, Error}
|
This method must be called after setDataSource. Calling it does not change the object state.
|
getAudioSessionId
|
any
|
{}
|
This method can be called in any state and calling it does not change the object state.
|
getCurrentPosition
|
{Idle, Initialized, Prepared, Started, Paused, Stopped, PlaybackCompleted}
|
{Error}
|
Successful invoke of this method in a valid state does not change the state. Calling this method in an invalid state transfers the object to the Error state.
|
getDuration
|
{Prepared, Started, Paused, Stopped, PlaybackCompleted}
|
{Idle, Initialized, Error}
|
Successful invoke of this method in a valid state does not change the state. Calling this method in an invalid state transfers the object to the Error state.
|
getVideoHeight
|
{Idle, Initialized, Prepared, Started, Paused, Stopped, PlaybackCompleted}
|
{Error}
|
Successful invoke of this method in a valid state does not change the state. Calling this method in an invalid state transfers the object to the Error state.
|
getVideoWidth
|
{Idle, Initialized, Prepared, Started, Paused, Stopped, PlaybackCompleted}
|
{Error}
|
Successful invoke of this method in a valid state does not change the state. Calling this method in an invalid state transfers the object to the Error state.
|
isPlaying
|
{Idle, Initialized, Prepared, Started, Paused, Stopped, PlaybackCompleted}
|
{Error}
|
Successful invoke of this method in a valid state does not change the state. Calling this method in an invalid state transfers the object to the Error state.
|
pause
|
{Started, Paused}
|
{Idle, Initialized, Prepared, Stopped, PlaybackCompleted, Error}
|
Successful invoke of this method in a valid state transfers the object to thePaused state. Calling this method in an invalid state transfers the object to the Error state.
|
prepare
|
{Initialized, Stopped}
|
{Idle, Prepared, Started, Paused, PlaybackCompleted, Error}
|
Successful invoke of this method in a valid state transfers the object to thePrepared state. Calling this method in an invalid state throws an IllegalStateException.
|
prepareAsync
|
{Initialized, Stopped}
|
{Idle, Prepared, Started, Paused, PlaybackCompleted, Error}
|
Successful invoke of this method in a valid state transfers the object to thePreparing state. Calling this method in an invalid state throws an IllegalStateException.
|
release
|
any
|
{}
|
After release() , the object is no longer
available.
|
reset
|
{Idle, Initialized, Prepared, Started, Paused, Stopped, PlaybackCompleted, Error}
|
{}
|
After reset() , the object is like being
just created.
|
seekTo
|
{Prepared, Started, Paused, PlaybackCompleted}
|
{Idle, Initialized, Stopped, Error}
|
Successful invoke of this method in a valid state does not change the state. Calling this method in an invalid state transfers the object to the Error state.
|
setAudioSessionId
|
{Idle}
|
{Initialized, Prepared, Started, Paused, Stopped, PlaybackCompleted, Error}
|
This method must be called in idle state as the audio session ID must be known before calling setDataSource. Calling it does not change the object state.
|
setAudioStreamType
|
{Idle, Initialized, Stopped, Prepared, Started, Paused, PlaybackCompleted}
|
{Error}
|
Successful invoke of this method does not change the state. In order for the target audio stream type to become effective, this method must be called before prepare() or prepareAsync().
|
setAuxEffectSendLevel
|
any
|
{}
|
Calling this method does not change the object state.
|
setDataSource
|
{Idle}
|
{Initialized, Prepared, Started, Paused, Stopped, PlaybackCompleted, Error}
|
Successful invoke of this method in a valid state transfers the object to theInitialized state. Calling this method in an invalid state throws an IllegalStateException.
|
setDisplay
|
any
|
{}
|
This method can be called in any state and calling it does not change the object state.
|
setSurface
|
any
|
{}
|
This method can be called in any state and calling it does not change the object state.
|
setLooping
|
{Idle, Initialized, Stopped, Prepared, Started, Paused, PlaybackCompleted}
|
{Error}
|
Successful invoke of this method in a valid state does not change the state. Calling this method in an invalid state transfers the object to the Error state.
|
isLooping
|
any
|
{}
|
This method can be called in any state and calling it does not change the object state.
|
setOnBufferingUpdateListener
|
any
|
{}
|
This method can be called in any state and calling it does not change the object state.
|
setOnCompletionListener
|
any
|
{}
|
This method can be called in any state and calling it does not change the object state.
|
setOnErrorListener
|
any
|
{}
|
This method can be called in any state and calling it does not change the object state.
|
setOnPreparedListener
|
any
|
{}
|
This method can be called in any state and calling it does not change the object state.
|
setOnSeekCompleteListener
|
any
|
{}
|
This method can be called in any state and calling it does not change the object state.
|
setScreenOnWhilePlaying |
any
|
{}
|
This method can be called in any state and calling it does not change the object state.
|
setVolume
|
{Idle, Initialized, Stopped, Prepared, Started, Paused, PlaybackCompleted}
|
{Error}
|
Successful invoke of this method does not change the state. |
setWakeMode
|
any
|
{}
|
This method can be called in any state and calling it does not change the object state.
|
start
|
{Prepared, Started, Paused, PlaybackCompleted}
|
{Idle, Initialized, Stopped, Error}
|
Successful invoke of this method in a valid state transfers the object to theStarted state. Calling this method in an invalid state transfers the object to the Error state.
|
stop
|
{Prepared, Started, Stopped, Paused, PlaybackCompleted}
|
{Idle, Initialized, Error}
|
Successful invoke of this method in a valid state transfers the object to theStopped state. Calling this method in an invalid state transfers the object to the Error state.
|
例子程序如下:
MediaPlayer所支持格式:
這個問題,看到網上有不少人回答。但個人覺得回答並不正確。
MediaPlayer底層具體實現決定了所支持格式。畢竟JAVA層不太可能直接操作硬件去播放Video/Audio. 它也是通過JNI與底層C打交道播放Audio/Video. 那麼底層的實現纔是決定MediaPlayer支持格式的關鍵。
例如:Sam使用Hi3716C來測試,發現其底層是用HiPlayer來實現,支持WAV,OGG等。
但MTK5502平臺,則只支持WAV.(可能OGG沒來的及加入)