Android de programación de audio pesadilla – soundpool, audiotrack arrghh?

He creado una sencilla aplicación de secuenciador de música para Android que reproduce varios archivos de audio.

Originalmente yo estaba usando SoundPool para reproducir archivos mp3 y funcionó perfectamente en 2.3.4 con un viejo HTC Droid Incredible. Luego lo probé en un Galaxy Nexus corriendo 4.3 y el rendimiento fue horrendo. La sincronización de audio en todo el lugar y hubo fallos / clics / pops.

Así que pasé varios días haciendo un jugador usando AudioTrack incluyendo un decodificador de mp3 y lo consiguió trabajando perfectamente en el Galaxy y el HTC. Ahora lo he probado en un Nexus 4 (corriendo 4.3) y el rendimiento es terrible – el momento es todo el lugar. SoundPool incluso ofrece un mejor rendimiento en este dispositivo.

Estoy realmente frustrado y no sé qué hacer para terminar mi aplicación por lo que realmente apreciaría si alguien me podría ayudar. He puesto algunos ejemplos de código de mi reproductor de audio a continuación. He intentado todo lo que puedo pensar incluyendo el cambio del tamaño del almacenador intermediario, usando AudioTrack.MODE_STATIC etc. AudioTrack.MODE_STATIC Los nuevos dispositivos de Google tienen audio bajo de la latencia así que es muy extraño cómo todo trabaja la manera mejor en mi viejo droid!

Gracias por adelantado

 /** * Play note */ public void playNote(String note, float vol) { PlayThread oldThread = threadMap.get(note); if(oldThread != null) { //Cancel timer if(oldThread.timer != null) { oldThread.timer.cancel(); oldThread.timer.purge(); oldThread.timer = null; } //Stop oldThread.requestStop(); threadMap.remove(note); } //Play if within Polyphony if(threadMap.size() < POLYPHONY) { PlayThread thread = new PlayThread(note, vol); thread.start(); threadMap.put(note, thread); } } /** * Stop note */ public void stopNote(String note, int fadeDurationInMs) { PlayThread thread = threadMap.get(note); if(thread != null) { thread.fadeOut(fadeDurationInMs); threadMap.remove(note); } } /** * Stop all */ public void stopAllPlaying(int fadeDurationInMs) { for(PlayThread thread : threadMap.values()) { if(thread != null) { thread.fadeOut(fadeDurationInMs); } } threadMap.clear(); } /** * PlayThread */ private class PlayThread extends Thread { String note; float vol; float fadeVol; boolean stop; AudioTrack audioTrack; Timer timer; /** * Constructor */ public PlayThread(String note, float vol) { super(); this.note = note; this.vol = vol; this.fadeVol = vol; } /** * Run */ public void run() { try { android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO); //Create buffer int bufferSize = AudioTrack.getMinBufferSize(SAMPLE_RATE, CHANNELS, AudioFormat.ENCODING_PCM_16BIT); Log.v(Constants.TAG, "min buffersize = " + bufferSize); bufferSize = bufferSize * 2; byte[] buffer = new byte[bufferSize]; //AudioTrack audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, SAMPLE_RATE, CHANNELS, AudioFormat.ENCODING_PCM_16BIT, bufferSize, AudioTrack.MODE_STREAM); audioTrack.setStereoVolume(vol, vol); audioTrack.play(); //Get byte data byte[] byteData = sampleMap.get(note); //Convert to input stream InputStream input = new ByteArrayInputStream(byteData); //Write to audioTrack int bytesRead = 0; while(!stop && (bytesRead = input.read(buffer)) != -1) { audioTrack.write(buffer, 0, bytesRead); } //When finished... audioTrack.stop(); audioTrack.release(); input.close(); killThread(this); } catch(Exception e) {} } /** * Set volume */ private synchronized void setVol(float newVol) { audioTrack.setStereoVolume(newVol, newVol); } /** * Update volume */ private synchronized void lowerVol() { fadeVol -= 0.01; if(fadeVol < 0) vol = 0; audioTrack.setStereoVolume(fadeVol, fadeVol); } /** * Fade out */ public synchronized void fadeOut(int fadeDurationInMs) { //Start decreasing volume if(fadeDurationInMs > 0) { timer = new Timer(true); TimerTask timerTask = new TimerTask() { @Override public void run() { //If thread killed while running try { //Lower volume lowerVol(); } catch (Exception e) {} //Stop when volume reaches 0 if(fadeVol <= 0) { if(timer != null) { timer.cancel(); timer.purge(); } stop = true; } } }; //Calculate delay, set to 1 if zero int delay = (int) (fadeDurationInMs / (vol * 100)); if(delay == 0) delay = 1; timer.schedule(timerTask, delay, delay); } } /** * Request stop */ public synchronized void requestStop() { //Stop click/pop when stopping sample setVol(0.01f); setVol(0.005f); stop = true; } /** * Kill Thread */ private synchronized void killThread(Thread theThread) { if(theThread != null) { theThread = null; } } } 

3 Solutions collect form web for “Android de programación de audio pesadilla – soundpool, audiotrack arrghh?”

Como el usuario harikris sugiere, recomiendo encarecidamente que mueva todo su audio de reproducción y el código de procesamiento de Android NDK utilizando la biblioteca OpenSL ES para el mejor rendimiento.

Según entiendo, la API de AudioTrack se construye encima del jugador audio de la cola de almacenador intermediario de OpenSL ES. Así que probablemente podría mejorar el rendimiento trabajando directamente con el NDK, escribiendo el código C que se llama desde su capa de Java / Android para trabajar con el sonido.

El ejemplo de audio nativo mencionado anteriormente contiene código que le mostrará cómo reproducir un archivo de sonido directamente desde un URI. En mi experiencia, los resultados de este método son mejores que AudioTrack en modo estático.

Soundpool está generalmente reservado para sonidos muy cortos que se pueden reproducir desde la memoria y no es una solución escalable para su secuenciador, especialmente si introduce archivos grandes.

Aquí hay algunos enlaces que me han ayudado con mis aplicaciones: -Información general sobre OpenSL ES para Android: http://mobilepearls.com/labs/native-android-api/opensles/

-Un blog de audio para Android con un gran código de ejemplo: http://audioprograming.wordpress.com

Editar: El vínculo móvil de perlas de edad parece estar abajo. Aquí hay un trabajo: http://mobilepearls.com/labs/native-android-api/ndk/docs/opensles/index.html

Yo recomendaría hacer todo su captura de audio y el tiempo de procesamiento sensible en código nativo y el uso de JNI para interactuar entre el SDK y NDK componentes.

Puede encontrar código de ejemplo de proyecto de audio nativo en la distribución de NDK de Android que le muestra cómo hacer audio en C / C ++

En la sesión de audio de alto rendimiento en Google I / O 2013 (introducido por Ian Ni-Lewis, que comentó sobre el post original. Estoy sorprendido de que no lo entendió), hablan sobre el Nexus 4. En el video De la presentación, saltar a 27:25.

A diferencia de muchos otros dispositivos que usan una frecuencia de muestreo nativa de 44.1kHz, el Nexus 4 utiliza 48kHz. Si está enviando datos a 44.1kHz, tendrá que pasar por el resampler que está en el camino lento. Otra diferencia es que el tamaño del búfer en el Nexus 4 es 240 cuadros que pueden causar un jitter regular en su devolución de llamada. Todo esto se explica en el video enlazado.

  • Compilador de Java erróneo al incluir un módulo de Java como dependencia en Android Studio
  • ¿Cómo comprobar FileLock sin truncar el archivo?
  • Error al inflacionar la clase android.support.design.widget.TabLayout
  • Uso de colores de color.xml en código java
  • Formato de moneda en Android utilizando separador decimal incorrecto
  • Cómo establecer los valores de la interfaz de usuario en fragmento
  • ArrayList que contiene objetos arbitrarios
  • Galería personalizada de Android para desactivar el desplazamiento
  • Rutinas de cifrado y descifrado de PHP y JAVA
  • TextToSpeech setLanguage no funciona?
  • ¿Cuál es la forma más fácil de dibujar textura con OpenGL ES?
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.