Подтвердить что ты не робот

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

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

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

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

4b9b3361

Ответ 2

Похоже, что в 2.3 здесь все изменилось, теперь есть разрешения

<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>

И есть вспомогательный класс AudioCapture в aosp, чтобы помочь живым обоям сделать это правильно. https://android.googlesource.com/platform/packages/wallpapers/MusicVisualization/+/gingerbread-release/src/com/android/musicvis/AudioCapture.java

Edit:

Один из импорта в AOSP не соответствует публичному api.
import android.media.audiofx.Visualizer;

это
import android.media.Visualizer;

если он дает головную боль, обязательно переключитесь. Это все 2.3 api, он, по-видимому, возвращает аудиопоток низкого разрешения, но не достаточно хорош для записи.

Ответ 3

В основном то, что сказал roskit, за исключением незначительной модификации возвращаемого значения из

return 0;

to

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

Ответ 4

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

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

Ответ 5

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