Accediendo a la transmisión multimedia de Android para visualización de audio

Básicamente, quiero hacer un visualizador de audio. Sé que es posible, porque mi teléfono viene con algunos fondos de pantalla en vivo que lo hacen. El problema es que parece que no puedo entender cómo hacerlo con la API de Android.

Mi aplicación recogía la transmisión multimedia que se estaba reproduciendo y luego, dependiendo del volumen que se estaba reproduciendo en ese momento, mostraba más o menos barras en la pantalla.

¿Cómo puedo hacer esto? Parece que podría hacer algo como esto usando el micrófono, pero quiero poder hacerlo para música, podcasts, etc.

El origen del fondo de pantalla MusicVisualization está disponible en AOSP . Básicamente parece implicar llamar a MediaPlayer.snoop() , un método no documentado agregado en Eclair.

Parece que en 2.3 las cosas han cambiado aquí, ahora hay permisos

   

Y hay una clase de ayuda AudioCapture en el aosp para ayudar a que los fondos de pantalla en vivo lo hagan correctamente. https://android.googlesource.com/platform/packages/wallpapers/MusicVisualization/+/gingerbread-release/src/com/android/musicvis/AudioCapture.java

Editar:

Una de las importaciones en el AOSP no coincide con la API pública.
import android.media.audiofx.Visualizer;

es
import android.media.Visualizer;

si le da dolor de cabeza, asegúrese de cambiar. Esto es todo 2.3 api, aparentemente devuelve un flujo de audio de baja resolución para viz, pero no lo suficientemente bueno para grabar.

Básicamente lo que dijo roskit, excepto con una modificación de valor de retorno menor de

 return 0; 

a

 return Integer.parseInt( (m.invoke(c, outData, kind)).toString() ); 

En otras palabras:

 public static int snoop(short [] outData, int kind){ try { Class c = MediaPlayer.class; Method m = c.getMethod("snoop", outData.getClass(), Integer.TYPE); m.setAccessible(true); return Integer.parseInt( (m.invoke(c, outData, kind)).toString() ); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); return 1; } } 

Un snoop() ligeramente más rápido snoop() sería llamar a Class.getMethod() una vez, y luego usar un parseInt() lugar de Integer.parseInt()

 private static Method mSnoop; //..(http://nadeausoftware.com/node/97).. private static int customParseInt( final String s ) { // Check for a sign. int num = 0; int sign = -1; final int len = s.length( ); final char ch = s.charAt( 0 ); if ( ch == '-' ) sign = 1; else num = '0' - ch; // Build the number. int i = 1; while ( i < len ) num = num*10 + '0' - s.charAt( i++ ); return sign * num; } private static int snoop(short [] outData, int kind) { if ( mSnoop != null ) { try { return customParseInt( (mSnoop.invoke( MediaPlayer.class , outData, kind)).toString() ); } catch ( Exception e ) { Log.e( TAG, "Failed to MediaPlayer.snoop()!", e ); return 1; } } else { try { Class c = MediaPlayer.class; Method m = c.getMethod("snoop", outData.getClass(), Integer.TYPE); m.setAccessible(true); mSnoop = m; return customParseInt( (m.invoke(c, outData, kind)).toString() ); } catch (Exception e) { Log.e( TAG, "Failed to MediaPlayer.snoop()!", e ); return 1; } } } 

Así es como lo hice desde mi aplicación:

 protected short [] mAudioData = new short[1024]; 

Luego en el ciclo:

 int res = snoop(mAudioData, 0); 

Y aquí está la función en sí:

 public static int snoop(short [] outData, int kind){ try { Class c = MediaPlayer.class; Method m = c.getMethod("snoop", outData.getClass(), Integer.TYPE); m.setAccessible(true); m.invoke(c, outData, kind); return 0; } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); return 1; } }