访问 Android 媒体流以实现音频可视化

问题描述 投票:0回答:6

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

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

我该怎么做?看起来我可以使用麦克风做类似的事情,但我希望能够为音乐、播客等做到这一点。

java android audio
6个回答
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,它显然返回一个低分辨率的音频流用于可视化,但不足以用于录制。


5
投票

MusicVisualization 壁纸源可在AOSP获取。它基本上似乎涉及调用

MediaPlayer.snoop()
,这是 Eclair 中添加的一个未记录的方法。


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

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

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

© www.soinside.com 2019 - 2024. All rights reserved.