關於OpenSL ES播放音頻數據的一個奇怪的問題html
Author:lihaiping1603@aliyun.comandroid
最近用業餘時間作了一個android平臺的播放器sdk,其中視頻用的opengl es,音頻用的opensl es 作渲染,其中整個播放器在音視頻同步的過程當中,使用的視頻同步到音頻的方式,以音頻做爲主時鐘。函數
今天在測試的過程當中發現一個奇怪的問題,我音頻數據的填充,使用了單獨的音頻線程,這其中的實現,主要參考ijk的實現代碼和方式。測試
整個流程方式:我在音頻播放的過程當中設置的200ms的播放緩衝區給底層隊列,當我把音頻數據緩衝區填滿之後,就wait_timeout(1s),若是在wait的過程當中,底層有回調,就會signal,從而喚醒wait函數,而後再查詢緩衝區大小,是否能夠填充數據,若是能夠填充數據的話,就填充數據進去,同時在填充數據的函數中,經過計算音頻的pts和緩衝區的剩餘數據大小,來更新當前的音頻播放時鐘位置。其中問題就是出在更新音頻時鐘位置的這個地方,咱們計算剩餘緩衝區的數據大小的時候,經過調用這個函數來獲取底層數據的緩衝區延時:spa
經過計算state.count的計數來獲取這個延時時間。線程
那麼如今的問題現象是這樣的,在視頻正常播放的過程當中,我填充了200ms滿的緩衝區音頻數據去播放,在填充數據線程中wait,而後在大概過了120ms以後,底層回調:調試
發送信號喚醒wait函數,而後我去拷貝音頻數據,拷貝完數據以後,計算時鐘,這個時候查詢底層緩衝區數據還剩多少,發現state.count=17,也就是說填滿的時候20,如今獲取還剩17,意思是中間難道只消耗了30ms的音頻數據?不太可能啊,正常播放的狀況下,120ms應該消耗120ms的音頻數據纔對啊,爲啥這個地方只消耗了30ms的數據呢?視頻
通過進一步的排查和分析,發現了問題,若是通過了120ms的播放時間,底層實際消耗的音頻數據是爲120ms,而他開始回調,並連續回調12次。但第一次回調的時候,咱們就喚醒了wait函數,這個時候咱們去拷貝數據,而從喚醒到拷貝數據完成,並從新獲取底層緩衝區大小的的這個過程,由於時間很短,短到他12次的連續回調,實際上只完成了3次回調,這個時候咱們就去獲取了state.count,發現它比以前只少了3次,因此誤認爲這個時間他只消耗了30ms的數據。由於state.count這個底層計數,他回調一次-1,並不會真正的實時反映實際的數據消耗過程。htm
那麼個人代碼和ijk的貌似看上去一致啊,爲啥他的不會出現這個問題?後面思考發現問題所在,ijk在播放填充的數據線程中,經過回調給上層,他在上層的實現中實現了音頻數據的解碼,也就是正是這個解碼函數產生的影響,他的這個耗時,徹底足以讓底層的音頻連續回調,回調完畢,因此再去拿數據之後,就是正確的結果。blog
本人主要是我的對調試的理解和記錄,僅供參考。
轉載請註明出處:https://www.cnblogs.com/lihaiping/p/11739836.html