java 访问 Android 媒体流以进行音频可视化
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3571814/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Accessing the Android media stream for audio visualization
提问by HenryAdamsJr
Basically, I want to make an audio visualizer. I know it's possible, because my phone came with a few live wallpapers that do it. The problem is, I can't seem to figure out how to do this with the Android API.
基本上,我想做一个音频可视化工具。我知道这是可能的,因为我的手机附带了一些可以做到的动态壁纸。问题是,我似乎无法弄清楚如何使用 Android API 做到这一点。
My app would pick up the currently playing media stream and then depending upon the volume that is playing at that time, it would display more or less bars on the screen.
我的应用程序会选择当前正在播放的媒体流,然后根据当时正在播放的音量,它会在屏幕上显示更多或更少的条。
How can I do this? It looks like I could do something like this using the microphone, but I want to be able to do it for music, podcasts, etc.
我怎样才能做到这一点?看起来我可以使用麦克风做这样的事情,但我希望能够为音乐、播客等做这件事。
采纳答案by adietrich
The MusicVisualization wallpaper sourceis available at the AOSP. It basically seems to involve calling MediaPlayer.snoop(), an undocumented method added in Eclair.
该MusicVisualization墙纸源可在AOSP。它基本上似乎涉及调用MediaPlayer.snoop(),这是 Eclair 中添加的一种未记录的方法。
回答by HaMMeReD
It looks like in 2.3 things have changed here, there is permissions now
看起来在 2.3 中这里发生了变化,现在有权限
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
And there is a AudioCapture helper class in the aosp to help the live wallpapers do it properly. https://android.googlesource.com/platform/packages/wallpapers/MusicVisualization/+/gingerbread-release/src/com/android/musicvis/AudioCapture.java
并且在 aosp 中有一个 AudioCapture helper 类来帮助动态壁纸正确地做。 https://android.googlesource.com/platform/packages/wallpapers/MusicVisualization/+/gingerbread-release/src/com/android/musicvis/AudioCapture.java
Edit:
编辑:
One of the imports in the AOSP doesn't match the public api.import android.media.audiofx.Visualizer;
AOSP 中的其中一项导入与公共 api 不匹配。import android.media.audiofx.Visualizer;
it isimport android.media.Visualizer;
它是import android.media.Visualizer;
if it gives a headache make sure to switch. This is all 2.3 api, it apparently returns a low-resolution audio stream for viz, but not good enough for recording.
如果它让人头疼,请确保切换。这都是 2.3 api,它显然为 viz 返回一个低分辨率的音频流,但不足以录制。
回答by aschyiel
Basically what roskit said except with a minor return value modification from
基本上是 roskit 所说的,除了从
return 0;
to
到
return Integer.parseInt( (m.invoke(c, outData, kind)).toString() );
In other words:
换句话说:
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;
}
}
回答by aschyiel
A slightly faster snoop()would be to call Class.getMethod()once, and then to use a custom parseInt()instead of Integer.parseInt()...
稍微快一点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;
}
}
}
回答by roskit
This is how I did it from my application:
这是我从我的应用程序中做到的:
protected short [] mAudioData = new short[1024];
Then in the loop:
然后在循环中:
int res = snoop(mAudioData, 0);
And here is the function itself:
这是函数本身:
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;
}
}
回答by androidworkz
Look at http://code.google.com/p/moonblink/wiki/Tricorderfor an example.

