2016-03-01 49 views
6

我在使用OpenSL ES運行Android 6.0.1的Nexus 6上嘗試實現低延遲流音頻播放時遇到了一個奇怪的問題。Android與Nexus 6 - 如何避免與應用程序重點相關的OpenSL音頻線程優先級降低?

我最初的嘗試似乎遭受飢餓問題,所以我在緩衝區完成回調函數中添加了一些基本的時序基準。我發現,如果我在應用程序打開時不斷點擊屏幕,則音頻播放效果會很好,但如果我將它放置幾秒鐘,則回調開始花費更長時間。我能夠始終如一地重現此行爲。一對夫婦的注意事項:

  • 「幾秒鐘」〜= 3-5秒,不夠長觸發畫面切換
  • 我的應用程序的活動設置FLAG_KEEP_SCREEN_ON,所以沒有屏幕的變化應該發生反正
  • 我沒有采取任何行動來嘗試增加音頻回調線程的優先級,因爲我的印象是Android已經爲這些線程保留了高優先級
  • 行爲發生在我的Nexus 6(Android 6.0.1)上,但不在Galaxy S6上我也有可用的(Android 5.1.1)。

我看到的症狀確實看起來像是操作系統在與手機非交互的幾秒鐘後開啓音頻線程優先級。這是正確的嗎?有什麼辦法可以避免這種行爲?

+0

在運行Android 4.4.2的Nexus 5上也不會發生這種情況。 –

+0

回放期間記錄線程優先級似乎表明線程優先級在點擊屏幕時並未真正改變。也許觸摸事件觸發了一箇中斷,這會擾亂調度程序可能返回的內容? –

+0

我在我的應用程序中遇到同樣的問題。只要我與屏幕互動,所有的運行都應該順利進行。一旦我停止觸摸屏幕,它會在幾秒鐘後(約3-5秒)開始大量丟失。當我再次開始與屏幕交互時,它會恢復平穩運行。不管屏幕交互是否真實,也不管手指是否用特定的控制/按鈕觸發。只要手指在屏幕上移動,所有音頻運行平穩。它不會在Android 5.x上發生,它只是從6.0開始,在Android上也是這樣。N – gal

回答

3

在觀看最新的Google I/O 2016音頻演示文稿時,我終於找到了導致此問題的原因和(醜陋的)解決方案。

剛纔看這個,你管剪輯的一分鐘左右(在8m56s開始): https://youtu.be/F2ZDp-eNrh4?t=8m56s

它解釋了爲什麼這種情況正在發生以及如何擺脫它。

實際上,Android會在觸摸不活動幾秒鐘後降低CPU速度以減少電池使用量。視頻中的傢伙承諾很快就會有適當的解決方案,但現在唯一能擺脫它的方法就是發送虛假的觸摸(這是官方的建議)。

Instrumentation instr = new Instrumentation(); 
instr.sendKeyDownUpSync(KeyEvent.KEYCODE_BACKSLASH); // or whatever event you prefer 

每1.5秒鐘重複一次這個計時器,問題就會消失。

我知道,這是一個醜陋的黑客,它可能有醜陋的副作用,必須處理。但現在,它只是唯一的解決方案。

更新: 關於您最新的評論...這是我的解決方案。 我在屏幕邊界外的位置使用常規MotionEvent.ACTION_DOWN。其他一切都以不希望的方式干擾了UI。要避免SecurityException,請在主活動的onStart()處理程序中初始化計時器,並在onStop()處理程序中終止它。當應用程序轉到後臺(取決於CPU負載)時,您仍然有可能遇到SecurityException,因此您必須使用try catch塊來包圍假觸摸調用。

請注意,我使用自己的計時器框架,因此您必須轉換代碼以使用任何想要使用的計時器。

此外,我還不能確保代碼是100%防彈。我的應用程序已經應用了該應用程序,但目前處於測試狀態,因此如果此功能在所有設備和Android版本上正常運行,我無法給您任何保證。

Timer fakeTouchTimer = null; 
Instrumentation instr; 
void initFakeTouchTimer() 
{ 
    if (this.fakeTouchTimer != null) 
    { 
     if (this.instr == null) 
     { 
      this.instr = new Instrumentation(); 
     } 
     this.fakeTouchTimer.restart(); 
    } 
    else 
    { 
     if (this.instr == null) 
     { 
      this.instr = new Instrumentation(); 
     } 
     this.fakeTouchTimer = new Timer(1500, Thread.MIN_PRIORITY, new TimerTask() 
     { 
      @Override 
      public void execute() 
      { 
       if (instr != null && fakeTouchTimer != null && hasWindowFocus()) 
       { 
        try 
        { 
         long downTime = SystemClock.uptimeMillis(); 

         MotionEvent event = MotionEvent.obtain(downTime, downTime, MotionEvent.ACTION_DOWN, -100, -100, 0); 
         instr.sendPointerSync(event); 
         event.recycle(); 
        } 
        catch (Exception e) 
        { 
        } 
       } 
      } 
     }, true/*isInfinite*/); 
    } 
} 
void killFakeTouchTimer() 
{ 
    if (this.fakeTouchTimer != null) 
    { 
     this.fakeTouchTimer.interupt(); 
     this.fakeTouchTimer = null; 
     this.instr = null; 
    } 
} 

@Override 
protected void onStop() 
{ 
    killFakeTouchTimer(); 
    super.onStop(); 

    ..... 
} 

@Override 
protected void onStart() 
{ 
    initFakeTouchTimer(); 
    super.onStart(); 

    ..... 
} 
+0

感謝您的回答;這絕對看起來像是我想要深入的核心問題。我已經用他們建議的解決方法更新了我的應用程序,但看起來不幸的是比預期的更加惡意。特別是,如果在模擬觸摸事件期間出現音量警告(無跨應用程序化觸摸事件),它可能會因安全異常而崩潰。你有沒有機會自己實現一個更強大的版本? –

+1

這就是我的意思與醜陋的副作用。 SecurityException只是其中之一。我用我的最終解決方案更新了我的答案。 – gal

+1

我剛剛注意到,我沒有照顧到目前爲止的音量警告(或其他性質相同的情況)。我更新瞭解決方案以涵蓋所有這些情況。 – gal

1

衆所周知,the audio pipeline in Android 6 has been completely rewritten。儘管在大多數情況下這種改進的與延遲相關的問題,但並不是不可能產生許多不良的副作用,而這種大規模變化通常就是這種情況。

當您的問題似乎並沒有是一個普遍的,有你也許可以嘗試的幾件事情:

  • 增加音頻線程優先級。 Android中音頻線程的默認優先級爲-16,最大值爲-20,通常僅適用於系統服務。雖然您無法將此值分配給音頻線程,但您可以在設置線程優先級時使用ANDROID_PRIORITY_URGENT_AUDIO標誌分配下一個最好的東西:-19

  • 增加緩衝區的數量以防止任何類型的抖動或延遲(甚至可以增加到16)。但是在某些設備上the callback to fill a new buffer isn’t always called when it should

  • This SO post有幾個建議可以改善Anrdoid上的音頻延遲。特別感興趣的是接受答案中的第3,4和5點。

  • 檢查當前的Android系統是否是通過查詢啓用低延遲,無論hasSystemFeature(FEATURE_AUDIO_LOW_LATENCY)hasSystemFeature(FEATURE_AUDIO_PRO)


此外,this academic paper討論了改進的Android/OpenSL音頻延遲相關的問題,包括buffer-和回調間隔有關的方法策略。

+0

謝謝你的回答。不幸的是,我已經閱讀了所有這些(非常有用)的資源並應用了其中建議的技術。我運行在本機設備採樣率和設備本地緩衝區大小的設備上,聲稱支持低延遲音頻(實際上,我相信Nexus 6時鐘處於最小的本機緩衝區,但仍然在192幀 - 48kHz處4ms)。增加緩衝區數量並不有助於您鏈接的heatvst.com文章中描述的原因。我的問題特別是關於UI交互似乎影響音頻播放的原因。 –

+0

您是否安裝了任何第三方應用程序,可能會在幾秒鐘的非交互後在後臺獲得焦點? – Pickle

+1

如何讓音頻線程「ANDROID_PRIORITY_URGENT_AUDIO」優先? –

-1

強制重新採樣到本地設備的採樣率上的Android 6.

使用48000例如設備的本機的採樣率:

SLDataFormat_PCM DATAFORMAT;

dataFormat.samplesPerSec = 48000;