Как записать звук Android, воспроизводимый в гарнитуре

Класс MediaRecorder в Android используется для записи звука с микрофона, может ли кто-нибудь сказать мне, как мы можем записывать звук, который на самом деле воспроизводится на гарнитуре. Звучит технологично, но да, это то, что я изучаю. Мне сказали, что класс «Визуализатор» может записывать системный звук, но, согласно документации, его можно использовать только для визуализации звука, и мы не можем поместить туда интерфейс рекордера.

Подробнее: http://developer.android.com/reference/android/media/audiofx/Visualizer.html

Кто-нибудь снизу будет служить цели?

int CAMCORDER
int DEFAULT
int MIC
int REMOTE_SUBMIX
int VOICE_CALL
int VOICE_COMMUNICAITON
int vOICE_DOWNLINK
int VOICE_RECOGNITION
int VOICE_UPLINK

Кто-нибудь работал на OpenSLES? Слышал, что это тоже служит цели этого

Если вы сталкивались с API Android или сторонними API, не стесняйтесь делиться информацией. Несколько блогов также говорят, что это можно сделать на уровне NDK. Если кто-то работал над этим или имеет примеры кода, пожалуйста, сообщите

Спасибо

Пример кода для демонстрации Майкла:

public class VisualizerView extends View {
  private static final String TAG = "VisualizerView";

  private byte[] mBytes;
  private byte[] mFFTBytes;
  private Rect mRect = new Rect();
  private Visualizer mVisualizer;

  private Set<Renderer> mRenderers;

  private Paint mFlashPaint = new Paint();
  private Paint mFadePaint = new Paint();
  private ByteArrayOutputStream buffer;

  public VisualizerView(Context context, AttributeSet attrs, int defStyle)
  {
    super(context, attrs);
    init();
  }

  public VisualizerView(Context context, AttributeSet attrs)
  {
    this(context, attrs, 0);
  }

  public VisualizerView(Context context)
  {
    this(context, null, 0);
  }

  private void init() {
    mBytes = null;
    mFFTBytes = null;

    mFlashPaint.setColor(Color.argb(122, 255, 255, 255));
    mFadePaint.setColor(Color.argb(238, 255, 255, 255)); // Adjust alpha to change how quickly the image fades
    mFadePaint.setXfermode(new PorterDuffXfermode(Mode.MULTIPLY));

    mRenderers = new HashSet<Renderer>();
  }

  /**
   * Links the visualizer to a player
   * @param player - MediaPlayer instance to link to
   */
  public void link(MediaPlayer player)
  {
    if(player == null)
    {
      throw new NullPointerException("Cannot link to null MediaPlayer");
    }

    // Create the Visualizer object and attach it to our media player.
    mVisualizer = new Visualizer(player.getAudioSessionId());
    mVisualizer.setCaptureSize(Visualizer.getCaptureSizeRange()[1]);

    // Pass through Visualizer data to VisualizerView
    Visualizer.OnDataCaptureListener captureListener = new Visualizer.OnDataCaptureListener()
    {
      @Override
      public void onWaveFormDataCapture(Visualizer visualizer, byte[] bytes,
          int samplingRate)
      {
        updateVisualizer(bytes);
        //Record
        if (bytes.length>-1)
        buffer.write(bytes, 0, bytes.length);
        //Record ends
      }

      @Override
      public void onFftDataCapture(Visualizer visualizer, byte[] bytes,
          int samplingRate)
      {
        updateVisualizerFFT(bytes);
      }
    };

    mVisualizer.setDataCaptureListener(captureListener,
        Visualizer.getMaxCaptureRate() / 2, true, true);

    // Enabled Visualizer and disable when we're done with the stream
    mVisualizer.setEnabled(true);
    player.setOnCompletionListener(new MediaPlayer.OnCompletionListener()
    {
      @Override
      public void onCompletion(MediaPlayer mediaPlayer)
      {
        mVisualizer.setEnabled(false);

        //Save File
        try {
            buffer.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
        mBytes = buffer.toByteArray();
        try {
            buffer.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        mVisualizer.release();

        File file = new File(Environment.getExternalStorageDirectory(), "music1.wav");
        FileOutputStream fos;

        try {
            fos = new FileOutputStream(file);
            fos.write(mBytes);
            fos.flush();
            fos.close();
        } catch (FileNotFoundException e) {
            // handle exception
        } catch (IOException e) {
            // handle exception
        }
        //Save File ends

      }
    });
  }

  public void addRenderer(Renderer renderer)
  {
    if(renderer != null)
    {
      mRenderers.add(renderer);
    }
  }

  public void clearRenderers()
  {
    mRenderers.clear();
  }

  /**
   * Call to release the resources used by VisualizerView. Like with the
   * MediaPlayer it is good practice to call this method
   */
  public void release()
  {
    mVisualizer.release();
  }

  /**
   * Pass data to the visualizer. Typically this will be obtained from the
   * Android Visualizer.OnDataCaptureListener call back. See
   * {@link Visualizer.OnDataCaptureListener#onWaveFormDataCapture }
   * @param bytes
   */
  public void updateVisualizer(byte[] bytes) {
    mBytes = bytes;
    invalidate();
  }

  /**
   * Pass FFT data to the visualizer. Typically this will be obtained from the
   * Android Visualizer.OnDataCaptureListener call back. See
   * {@link Visualizer.OnDataCaptureListener#onFftDataCapture }
   * @param bytes
   */
  public void updateVisualizerFFT(byte[] bytes) {
    mFFTBytes = bytes;
    invalidate();
  }

  boolean mFlash = false;

  /**
   * Call this to make the visualizer flash. Useful for flashing at the start
   * of a song/loop etc...
   */
  public void flash() {
    mFlash = true;
    invalidate();
  }

  Bitmap mCanvasBitmap;
  Canvas mCanvas;


  @Override
  protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);

    // Create canvas once we're ready to draw
    mRect.set(0, 0, getWidth(), getHeight());

    if(mCanvasBitmap == null)
    {
      mCanvasBitmap = Bitmap.createBitmap(canvas.getWidth(), canvas.getHeight(), Config.ARGB_8888);
    }
    if(mCanvas == null)
    {
      mCanvas = new Canvas(mCanvasBitmap);
    }

    if (mBytes != null) {
      // Render all audio renderers
      AudioData audioData = new AudioData(mBytes);
      for(Renderer r : mRenderers)
      {
        r.render(mCanvas, audioData, mRect);
      }
    }

    if (mFFTBytes != null) {
      // Render all FFT renderers
      FFTData fftData = new FFTData(mFFTBytes);
      for(Renderer r : mRenderers)
      {
        r.render(mCanvas, fftData, mRect);
      }
    }

    // Fade out old contents
    mCanvas.drawPaint(mFadePaint);

    if(mFlash)
    {
      mFlash = false;
      mCanvas.drawPaint(mFlashPaint);
    }

    canvas.drawBitmap(mCanvasBitmap, new Matrix(), null);
  }
}

person user45678    schedule 17.09.2014    source источник


Ответы (1)


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

Вы не можете, так как в Android API нет официальной поддержки для этого. Неважно, используете ли вы Java API или нативные API, включенные в NDK.
Могут быть хаки, которые работают на определенных устройствах, если у вас есть root-доступ и т. д., но я не собираюсь покрыть тех. Если вам интересно, вы можете попробовать поискать и посмотреть, что вы можете придумать.


Мне сказали, что класс «Визуализатор» может записывать системный звук, но, согласно документации, его можно использовать только для визуализации звука, и мы не можем поместить туда интерфейс рекордера.

Visualizer имеет этот метод:

public int getWaveForm (byte[] waveform)

Возвращает захват формы волны воспроизводимого в данный момент аудиоконтента. Захват состоит из ряда последовательных 8-битных (беззнаковых) моно выборок PCM, равных размеру захвата, возвращаемому getCaptureSize().

Таким образом, вы можете записывать воспроизводимый в данный момент звук с помощью файла Visualizer. Но, как упоминалось в описании выше, вы получите только аудиоданные низкого качества, потому что целью этого метода является получение аудиоданных, которые вы можете использовать для целей визуализации, а не для общих целей записи.

person Michael    schedule 17.09.2014
comment
Спасибо, Майкл, может ли класс Visualizer также идентифицировать аудиоконтент, воспроизводимый с YouTube или из какого-либо другого потокового контента, у меня есть пример того, как Visualizer API делает это, когда они передают mp3 из необработанной папки. Вы можете проверить здесь: github.com/felixpalmer/android-visualizer - person user45678; 17.09.2014
comment
Зависит от того, что вы подразумеваете под идентифицировать. Если вы имеете в виду что-то вроде TrackID, то этап распознавания — это то, что вы собираетесь реализовать самостоятельно или использовать стороннюю библиотеку. Если вы просто имеете в виду возможность захвата аудиовыхода, то да, не имеет значения, исходит ли звук из YouTube или какого-либо другого приложения. Но, как я уже говорил, вы получите низкокачественный звук только из Visualizer. Так что это не подходит для чего-то вроде приложения для загрузки музыки с YouTube. - person Michael; 17.09.2014