У кого-нибудь есть 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);

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