访问Android媒体stream进行audio可视化

基本上,我想制作一个audio可视化器。 我知道这是可能的,因为我的手机带有几个dynamic壁纸。 问题是,我似乎无法弄清楚如何用Android API来做到这一点。

我的应用程序会拿起当前正在播放的媒体stream,然后根据当时正在播放的音量,它会在屏幕上显示更多或更less的条。

我怎样才能做到这一点? 看起来我可以用麦克风做这样的事情,但我希望能够做到这一点,音乐,播客等。

Solutions Collecting From Web of "访问Android媒体stream进行audio可视化"

AOSP提供MusicVisualization壁纸来源 。 它基本上似乎涉及调用MediaPlayer.snoop() ,这是一种在Eclair中添加的未logging方法。

它看起来像2.3在这里改变了,现在有权限

 <uses-permission android:name="android.permission.RECORD_AUDIO"/> <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/> 

并且aosp中有一个AudioCapture助手类来帮助dynamic壁纸正确执行。 https://android.googlesource.com/platform/packages/wallpapers/MusicVisualization/+/gingerbread-release/src/com/android/musicvis/AudioCapture.java

编辑:

AOSP中的一个import与公共API不匹配。
import android.media.audiofx.Visualizer;

它是
import android.media.Visualizer;

如果它让头痛一定要切换。 这是所有2.3 api,它显然返回一个低分辨率的audiostream,即没有足够的logging。

基本上是什么roskit说,除了从微小的返回值修改

 return 0; 

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

换一种说法:

 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; } } 

稍微快一点的snoop()可以调用Class.getMethod()一次,然后使用自定义parseInt()而不是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; } } } 

这是我从我的应用程序中做到的:

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

然后在循环中:

 int res = snoop(mAudioData, 0); 

这里是function本身:

 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; } }