访问Android媒体流以进行音频可视化

时间:2010-08-26 03:16:55

标签: java android audio

基本上,我想制作一个音频可视化工具。我知道这是可能的,因为我的手机附带了一些动态壁纸。问题是,我似乎无法弄清楚如何使用Android API。

我的应用会选择当前播放的媒体流,然后根据当时正在播放的音量,它会在屏幕上显示更多或更少的小节。

我该怎么做?看起来我可以使用麦克风做这样的事情,但我希望能够用于音乐,播客等。

6 个答案:

答案 0 :(得分:7)

看起来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,它显然返回了一个低分辨率的音频流,但不足以录音。

答案 1 :(得分:5)

MusicVisualization wallpaper source位于AOSP。它基本上似乎涉及调用MediaPlayer.snoop(),这是Eclair中添加的一个未记录的方法。

答案 2 :(得分:3)

除了从

修改一个小的返回值之外,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;
           }
    }

答案 3 :(得分:2)

这就是我从我的申请中做到的:

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

答案 4 :(得分:2)

稍微快一点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;
        }
    }
}

答案 5 :(得分:0)