У кого-нибудь есть MediaRecorder, работающий с ParcelFileDescriptor и createPipe()?

Я пытаюсь разработать пример записи звука, с приложением, а не с хранилищем данных. MediaRecorder, Варианты использования включают хранение записи во внутреннем хранилище или шифрование записи.

В принципе, это должно работать с использованием трубы, созданной createPipe() на ParcelFileDescriptor, но я получаю искаженный вывод.

Во-первых, вот пример проекта, который записывает "естественно", используя MediaRecorder, с MediaRecorder запись непосредственно в выходной файл на внешнем хранилище. Это приложение работает просто отлично, и вывод может быть воспроизведен либо устройством Android, записавшим его, либо VLC на моем компьютере с Linux.

Вот мой createPipe() Вариация этого проекта. С точки зрения общего MediaRecorder конфигурация (например, setOutputFormat()), он такой же, как и первый, так что код предположительно правильный.

Тем не менее, я поставляю вывод через:

  recorder.setOutputFile(getStreamFd());

куда getStreamFd() использования createPipe(), порождает фоновый поток для чтения из канала и возвращает конец записи для использования 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 это классика java.io подпрограмма копирования из потока в поток, дополненная смарт-кодами для очистки и синхронизации выходного файла:

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

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

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

Какие-либо предложения?

Заранее спасибо!

1 ответ

Решение

Я предполагаю, что это связано с моим ответом на ваш другой вопрос. У кого-нибудь есть MediaPlayer, работающий с ParcelFileDescriptor и createPipe()?

Возможно, когда MediaRecorder попытается записать информацию заголовка, канал будет закрыт.

Если вы используете:

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

Запись работает нормально, потому что она не будет иметь информацию заголовка, только сырой звук.

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