Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
270 views
in Technique[技术] by (71.8m points)

android - Anyone Have MediaRecorder Working with ParcelFileDescriptor and createPipe()?

I am trying to work out an example of recording audio, with the data storage being handled by the app, not MediaRecorder. Use cases include storing the recording on internal storage or encrypting the recording.

In principle, this should work using a pipe created by createPipe() on ParcelFileDescriptor, but I am getting malformed output.

First, here is a sample project that records "naturally" using MediaRecorder, with MediaRecorder writing directly to an output file on external storage. This app works just fine, and the output can be played either by the Android device the recorded it or VLC on my Linux box.

Here is my createPipe() variation of this project. From the standpoint of general MediaRecorder configuration (e.g., setOutputFormat()), it is the same as the first, so that code is presumably correct.

However, I am supplying the output via:

  recorder.setOutputFile(getStreamFd());

Where getStreamFd() uses createPipe(), spawns a background thread to read from the pipe, and returns the writing end for use by MediaRecorder:

  private FileDescriptor getStreamFd() {
    ParcelFileDescriptor[] pipe=null;

    try {
      pipe=ParcelFileDescriptor.createPipe();

      new TransferThread(new AutoCloseInputStream(pipe[0]),
                       new FileOutputStream(getOutputFile())).start();
    }
    catch (IOException e) {
      Log.e(getClass().getSimpleName(), "Exception opening pipe", e);
    }

    return(pipe[1].getFileDescriptor());
  }

TransferThread is a classic java.io stream-to-stream copy routine, augmented with smarts to flush and sync the output file:

  static class TransferThread extends Thread {
    InputStream in;
    FileOutputStream out;

    TransferThread(InputStream in, FileOutputStream out) {
      this.in=in;
      this.out=out;
    }

    @Override
    public void run() {
      byte[] buf=new byte[8192];
      int len;

      try {
        while ((len=in.read(buf)) > 0) {
          out.write(buf, 0, len);
        }

        in.close();

        out.flush();
        out.getFD().sync();
        out.close();
      }
      catch (IOException e) {
        Log.e(getClass().getSimpleName(),
              "Exception transferring file", e);
      }
    }
  }

When I run the second app, I get an output file that, by crude inspection via a hex editor, seems basically OK. IOW, it's not like it's a zero-byte file, or is filled with unrecognizable gibberish. It is filled with a similar sort of gibberish as is the output from the first app. However, neither Android nor VLC can play it.

If I had to guess, I would presume that I am screwing up something in reading from the pipe, but I am not sure where specifically I am going wrong.

Any suggestions?

Thanks in advance!

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I would guess this is related to my answer to your other question. Anyone Have MediaPlayer Working with ParcelFileDescriptor and createPipe()?

Probably when the MediaRecorder will seek to write the Header information, the pipe is closed.

If you use:

recorder.setOutputFormat(MediaRecorder.OutputFormat.RAW_AMR);
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);

The record works fine, because it will not have a header information, only raw audio.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...