基本上,我想制作一个音频可视化工具。我知道这是可能的,因为我的手机附带了一些可以做到这一点的动态壁纸。问题是,我似乎不知道如何使用 Android API 来做到这一点。
我的应用程序会拾取当前正在播放的媒体流,然后根据当时播放的音量,它会在屏幕上显示更多或更少的条。
我该怎么做?看起来我可以使用麦克风做类似的事情,但我希望能够为音乐、播客等做到这一点。
看起来2.3中的事情已经改变了,现在有权限了
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
并且 aosp 中有一个 AudioCapture 辅助类来帮助动态壁纸正确完成此操作。 https://android.googlesource.com/platform/packages/wallpapers/MusicVisualization/+/gingerbread-release/src/com/android/musicvis/AudioCapture.java
编辑:
AOSP 中的其中一个导入与公共 api 不匹配。
import android.media.audiofx.Visualizer;
是
import android.media.Visualizer;
如果它让你头疼,请务必更换。这都是 2.3 api,它显然返回一个低分辨率的音频流用于可视化,但不足以用于录制。
MusicVisualization 壁纸源可在AOSP获取。它基本上似乎涉及调用
MediaPlayer.snoop()
,这是 Eclair 中添加的一个未记录的方法。
基本上就是 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);
这是函数本身:
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;
}
}