Доступ к медиа-потоку Android для аудио-визуализации

По сути, я хочу сделать аудио-визуализатор. Я знаю, что это возможно, потому что мой телефон поставляется с несколькими живыми обоями, которые делают это. Проблема в том, что я не могу понять, как это сделать с помощью Android API.

Мое приложение получило бы воспроизводимый в данный момент поток мультимедиа, а затем, в зависимости от громкости, воспроизводимой в это время, оно отображало бы более или менее полосы на экране.

Как я могу это сделать? Похоже, что я мог бы сделать что-то подобное с помощью микрофона, но я хочу быть в состоянии сделать это для музыки, подкастов и т. Д.

6 ответов

Решение

Источник обоев MusicVisualization доступен в AOSP. Похоже, это связано с MediaPlayer.snoop() недокументированный метод добавлен в Eclair.

Похоже, что в 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, он, очевидно, возвращает аудиопоток с низким разрешением, а не достаточно хорошо для записи.

В основном то, что сказал Роскит, за исключением незначительного изменения возвращаемого значения из

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

Вот как я это сделал из своего приложения:

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

Немного быстрее 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;
        }
    }
}

Посмотрите http://code.google.com/p/moonblink/wiki/Tricorder для примера.

Другие вопросы по тегам