2016-03-01 12 views
6

Sto riscontrando uno strano problema durante il tentativo di implementare la riproduzione audio in streaming a bassa latenza su un Nexus 6 con Android 6.0.1 che utilizza OpenSL ES.Android con Nexus 6 - come evitare una diminuzione della priorità del thread audio OpenSL relativa all'app focus?

Il mio tentativo iniziale sembrava essere affetto da problemi di inedia, quindi ho aggiunto alcuni parametri di riferimento temporali di base nella funzione di callback di completamento del buffer. Quello che ho trovato è che l'audio viene riprodotto correttamente se tocco continuamente lo schermo mentre la mia app è aperta, ma se la lascio in pace per qualche secondo, la callback inizia a richiedere molto più tempo. Sono in grado di riprodurre questo comportamento in modo coerente. Un paio di cose da notare:

  • "pochi secondi" ~ = 3-5 secondi, non abbastanza a lungo per innescare un cambio di pagina
  • dell'attività di mio applicazione imposta FLAG_KEEP_SCREEN_ON, quindi nessun cambiamento schermo dovrebbe avvenire comunque
  • Non ho intrapreso alcuna azione per provare ad aumentare la priorità del thread di callback audio, poiché avevo l'impressione che Android riservasse un'alta priorità per questi thread già
  • Il comportamento si verifica sul mio Nexus 6 (Android 6.0.1), ma Non ho un Galaxy S6 disponibile (Android 5.1.1).

I sintomi che sto vedendo sembrano davvero come il sistema operativo diminuisce la priorità del thread audio dopo alcuni secondi di non interazione con il telefono. È giusto? C'è un modo per evitare questo comportamento?

+0

Inoltre non si verifica su un Nexus 5 con Android 4.4.2. –

+0

La priorità del thread di registrazione durante la riproduzione sembra mostrare che la priorità del thread non cambia effettivamente quando si tocca lo schermo. Forse l'evento tattile sta provocando un'interruzione che mette in crisi ciò a cui è probabile che ritorni lo scheduler? –

+0

Sto riscontrando lo stesso problema nelle mie app. Finché interagisco con lo schermo, tutto scorre liscio come dovrebbe. Non appena smetto di toccare lo schermo, inizia con enormi cadute dopo alcuni (circa 3-5 secondi). Quando ricomincio a interagire con lo schermo, si ritorna al funzionamento regolare. Non importa se l'interazione dello schermo fa qualcosa di reale, né se il dito si innesca con uno specifico controllo/pulsante. Non appena un dito si muove sullo schermo, tutto l'audio scorre liscio. Non succede su Android 5.x, è appena iniziato con 6.0, ed è anche il caso su Android N. – gal

risposta

3

Mentre guardavo l'ultima presentazione audio di Google I/O 2016, ho finalmente trovato la causa e la (brutta) soluzione per questo problema.

solo guardare il circa un minuto di questo si clip di tubo (a partire da 8m56s): https://youtu.be/F2ZDp-eNrh4?t=8m56s

Questo spiega perché questo sta accadendo e come si può sbarazzarsi di esso.

Infatti, Android rallenta la CPU dopo alcuni secondi di inattività tocco per ridurre l'utilizzo della batteria. Il ragazzo nel video promette una soluzione adeguata per questo presto, ma per ora l'unico modo per liberarsene è di inviare dei tocchi finti (questa è la raccomandazione ufficiale).

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

Ripetere l'operazione con un timer ogni 1,5 secondi e il problema scompare.

Lo so, questo è un brutto trucco, e potrebbe avere brutti effetti collaterali che devono essere gestiti. Ma per ora, è semplicemente l'unica soluzione.

Aggiornamento: Per quanto riguarda il tuo ultimo commento ... ecco la mia soluzione. Sto utilizzando un normale MotionEvent.ACTION_DOWN in una posizione esterna ai limiti dello schermo. Tutto il resto ha interferito in modo indesiderato con l'interfaccia utente. Per evitare SecurityException, inizializzare il timer nel gestore onStart() dell'attività principale e terminarlo nel gestore onStop(). Ci sono ancora situazioni in cui l'app passa in secondo piano (a seconda del carico della CPU) in cui è possibile imbattersi in un SecurityException, pertanto è necessario circondare la chiamata tocco falso con un blocco catch try.

Si prega di notare che sto usando il mio framework timer, quindi devi trasformare il codice per usare qualsiasi timer tu voglia usare.

Inoltre, non posso ancora garantire che il codice sia al 100% antiproiettile. Le mie app hanno applicato questo hack, ma sono attualmente in stato beta, quindi non posso darti alcuna garanzia se funziona correttamente su tutti i dispositivi e le versioni di 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

Grazie per la risposta; questo sicuramente sembra il problema che stavo cercando di ottenere nel cuore di. Ho aggiornato la mia app con il loro suggerito work-around, ma purtroppo sembra più hacker del previsto. In particolare, può arrestarsi in modo anomalo con un'eccezione di sicurezza se viene visualizzato l'avviso di volume durante l'evento di tocco simulato (nessun evento di tocco programmatico tra app). Hai avuto la possibilità di implementare una versione più robusta di questo te stesso? –

+1

Questo è quello che intendevo con i brutti effetti collaterali. SecurityException è solo uno di questi. Ho aggiornato la mia risposta con la mia soluzione finale. – gal

+1

Ho appena notato che non mi sono occupato di situazioni come l'avviso del volume (o altre situazioni della stessa natura) finora. Ho aggiornato la soluzione per coprire tutte queste situazioni. – gal

1

È noto che the audio pipeline in Android 6 has been completely rewritten. Mentre questo ha migliorato i problemi relativi alla latenza nella maggior parte dei casi, non è impossibile che abbia generato una serie di effetti collaterali indesiderati, come di solito accade con tali cambiamenti su larga scala.

Mentre il problema non sembra essere un comune, ci sono alcune cose che si potrebbe essere in grado di provare:

  • aumentare la priorità filo audio. La priorità predefinita per i thread audio in Android è -16, con il massimo è -20, in genere disponibile solo per i servizi di sistema. Sebbene non sia possibile assegnare questo valore al thread audio, è possibile assegnare la cosa migliore successiva: -19 utilizzando il flag ANDROID_PRIORITY_URGENT_AUDIO quando si imposta la priorità del thread.

  • Aumentare il numero di buffer per impedire qualsiasi tipo di jitter o latenza (è possibile persino arrivare fino a 16). Tuttavia su alcuni dispositivi the callback to fill a new buffer isn’t always called when it should.

  • This SO post ha diversi suggerimenti per migliorare la latenza audio su Anrdoid. Di particolare interesse sono i punti 3, 4 e 5 nella risposta accettata.

  • Controllare se l'attuale sistema Android è a bassa latenza abilitato interrogando se hasSystemFeature(FEATURE_AUDIO_LOW_LATENCY) o hasSystemFeature(FEATURE_AUDIO_PRO).


Inoltre, this academic paper discute strategie per migliorare i problemi audio di latenza legati in Android/OpenSL, tra cui buffer- e callback approcci intervalli correlati.

+0

Grazie per la risposta. Sfortunatamente, ho già letto tutte queste risorse (molto utili) e applicato le tecniche ivi suggerite. Sto utilizzando la frequenza di campionamento del dispositivo nativo e la dimensione del buffer nativo del dispositivo su un dispositivo che sostiene di supportare l'audio a bassa latenza (in effetti, credo che il Nexus 6 abbia un clock con il più piccolo buffer nativo a 192 frame - 4 ms a 48kHz). L'aumento del numero di buffer non ha aiutato per il motivo descritto nell'articolo heatvst.com che hai collegato. La mia domanda riguarda specificamente il motivo per cui l'interazione dell'interfaccia utente sembra influenzare la riproduzione audio. –

+0

Hai installato app di terze parti che potrebbero concentrarsi sullo sfondo dopo un paio di secondi di non interazione? – Pickle

+1

Come si fa la priorità audio 'ANDROID_PRIORITY_URGENT_AUDIO'? –

-1

Forza ricampionamento di frequenza di campionamento dispositivo nativo su Android 6.

Usa frequenza di campionamento nativa del dispositivo di 48000. Ad esempio:

SLDataFormat_PCM dataFormat;

dataFormat.samplesPerSec = 48000;

Problemi correlati