Accessing the Android media stream for audio visualization

后端 未结 6 1297
谎友^
谎友^ 2020-11-30 20:06

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

相关标签:
6条回答
  • 2020-11-30 20:28

    The MusicVisualization wallpaper source is available at the AOSP. It basically seems to involve calling MediaPlayer.snoop(), an undocumented method added in Eclair.

    0 讨论(0)
  • 2020-11-30 20:28

    It looks like in 2.3 things have changed here, there is permissions now

    <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

    Edit:

    One of the imports in the AOSP doesn't match the public api.
    import android.media.audiofx.Visualizer;

    it is
    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.

    0 讨论(0)
  • 2020-11-30 20:28

    A slightly faster snoop() would be to call Class.getMethod() once, and then to use a custom parseInt() instead of 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;
            }
        }
    }
    
    0 讨论(0)
  • 2020-11-30 20:31

    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;
        }
    }
    
    0 讨论(0)
  • 2020-11-30 20:37

    Look at http://code.google.com/p/moonblink/wiki/Tricorder for an example.

    0 讨论(0)
  • 2020-11-30 20:43

    Basically what roskit said except with a minor return value modification from

    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;
               }
        }
    
    0 讨论(0)
提交回复
热议问题