Мгновенный ввод и вывод звука Android

В моем приложении для Android я хотел бы взять немного звука с микрофона смартфона и сразу же воспроизвести его, вживую, как микрофон, без задержек. В настоящее время я думаю об использовании классов AudioRecord и AudioTrack (из того, что я прочитал), но я не совсем уверен, как действовать дальше.

Я проверил некоторые другие вопросы о переполнении стека, но они точно не отвечают на то, что я хотел бы сделать. И большинство из них с 2012 года.

Итак, как я могу использовать эти классы для одновременного ввода и вывода звука?

ТАКЖЕ: я просмотрел MediaRecorder API, но из того, что я прочитал, требуется, чтобы вы сохраняли звук в файл, чего я не хочу делать. Можно ли его настроить под мои требования? Или мне лучше просто использовать AudioRecord?

Спасибо

ИЗМЕНИТЬ:

Вот мой обновленный код ниже, как предложил @Pradip Pramanick:

final Thread record = new Thread(new Runnable() {
        @Override
        public void run() {
            while (!Thread.interrupted()) {
                MediaRecorder microphone = new MediaRecorder();
                microphone.setAudioSource(MediaRecorder.AudioSource.MIC);
                    microphone.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
                microphone.setOutputFile(filename);
                microphone.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
                try {
                    microphone.prepare();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                microphone.start();
            }
        }
    });

    final Thread play = new Thread(new Runnable() {
        @Override
        public void run() {
            while (!Thread.interrupted()) {
                player = new MediaPlayer();
                try {
                    player.setDataSource(filename);
                    player.prepare();
                    player.start();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    });

Я получаю Illegal State Exception | Start failed: -38. Но я звоню microphone.start после microphone.prepare... В чем проблема? Я искал другие темы, в которых говорилось, что могут быть другие фоновые приложения, использующие микрофон. Я искал свое устройство: Moto X Play (3-го поколения) и ничего не нашел. (Я даже отключил распознавание голоса «Окей, Google», но ошибка продолжала появляться).

ЖУРНАЛ ОШИБОК:

Вот log-cat, показывающий самые последние ошибки:

01-31 09:37:21.064 344-3339/? E/MediaPlayerService: offset error
01-31 09:37:21.065 1835-1922/com.synerflow.testapp E/MediaPlayer: Unable to create media player

01-31 09:37:21.065 1835-1922/com.synerflow.testapp I/Player: player.prepare() has failed
01-31 09:37:21.065 1835-1922/com.synerflow.testapp W/System.err: java.io.IOException: setDataSourceFD failed.: status=0x80000000

Исключение ввода-вывода похоже на player.setDataSource(filename), переменная имени файла представляет собой строку: Environment.getExternalStorageDirectory().getAbsolutePath() + "\voice.3gp"


person Adifyr    schedule 28.12.2015    source источник
comment
Должна просто иметь возможность передавать потоки примерно так: Android, как записать аудиопоток mp3-радио"> stackoverflow.com/questions/5381969/. Может и с маленьким буфером тоже. Просто интересно, почему на самом деле - и не пострадаете ли вы от звуковой обратной связи, если бы вы это сделали.   -  person ste-fu    schedule 26.01.2016
comment
Да, проблема связана с тем, что плеер и рекордер пытаются читать и записывать один и тот же файл. Используйте небольшой буфер, который может хранить, скажем, 1 мс аудио. Затем используйте два синхронизированных потока: поток записи помещает данные в буфер и устанавливает флаг. Тред игрока о проверке флага начинает играть. Обратитесь к классической проблеме производитель-потребитель.   -  person 0x5050    schedule 01.02.2016


Ответы (4)


Вы можете попробовать Google Гобой.

Oboe — это библиотека C++, которая упрощает создание высокопроизводительных аудиоприложений для Android.

У Oboe уже есть пример для Immediate Audio Input & Output Android

Пример живого эффекта

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

https://github.com/google/oboe/tree/master/samples/LiveEffect

person Konrad Nowicki    schedule 23.01.2020

Насколько я понимаю, это можно сделать очень просто. Я не пробовал, но ты попробуй. Я думаю, это сработает:

Создайте два потока, один для записи, другой для воспроизведения. Скажем, это потоки TRecord и TPlay.

В методе запуска TRecord сделайте следующее:

public void run(){
        MediaRecorder mRecorder = null;
        mRecorder = new MediaRecorder();
        mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
        mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
        mRecorder.setOutputFile(mFileName);
        mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);

        try {
            mRecorder.prepare();
        } catch (IOException e) {
            //todo
        }

        mRecorder.start();
}

И метод запуска TPlay делает это:

public void run() {
MediaPlayer   mPlayer = null;
mPlayer = new MediaPlayer();
        try {
            mPlayer.setDataSource(mFileName);
            mPlayer.prepare();
            mPlayer.start();
        } catch (IOException e) {
            //todo
        }
}

Теперь в mainactivity просто создайте два потока. Сначала запустите поток TRecord, затем Tplay. Попробуй.

вот код расширения файла:

mFileName = Environment.getExternalStorageDirectory().getAbsolutePath();
 mFileName += "/audiorecordtest.3gp";
person 0x5050    schedule 26.01.2016
comment
Привет, что такое mFileName в этом случае? Это предопределенный файл? Кроме того, я хотел бы избавиться от файла после того, как закончу говорить. Как это может быть сделано? - person Adifyr; 27.01.2016
comment
И какое в этом случае должно быть расширение файла? Не могли бы вы включить код, который настраивает выходной файл/источник данных? - person Adifyr; 27.01.2016
comment
Привет, выдает ошибку: Start Failed: -38 | IllegalStateException. Но я звоню начать после подготовки. В чем проблема? - person Adifyr; 28.01.2016
comment
Оказывается, вы не можете использовать MediaRecorder, когда какой-либо другой сервис использует микрофон. Ознакомьтесь с этим . Проверьте, не происходит ли чего-то подобного. В противном случае используйте другой класс, например AudioRecord. - person 0x5050; 28.01.2016
comment
Вы также можете попробовать выполнить любую из задач (запись/воспроизведение) с помощью AsynkTask и проверить, соответствует ли она вашим требованиям к задержке. - person 0x5050; 28.01.2016
comment
Я поместил код в AsyncTasks. Он не дает никаких ошибок (изначально, после того, как я останавливаюсь и снова запускаю, он дает IOException), но он все еще не работает. - person Adifyr; 28.01.2016
comment
Было бы лучше, если бы вы предоставили некоторые детали, такие как logcat. Я думаю, что исключение ввода-вывода вызвано проблемами синхронизации, потому что в конечном итоге вы читаете и пишете из одного и того же потока. Попробуйте использовать буфер. Для потоков существует решение Producer-Consumer. Проверьте это - person 0x5050; 29.01.2016

Это на самом деле очень сложно на Android. У самих Google есть очень хорошее (но немного длинное) видео, объясняющее проблемы .

У них также есть страница, объясняющая их методы тестирования задержки и эталонные показатели для различных устройств.

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

person Kas Hunt    schedule 27.01.2016

попробуй это. Я не запускал это.

      recorder = new AudioRecord(MediaRecorder.AudioSource.MIC,
      RECORDER_SAMPLERATE, RECORDER_CHANNELS,
      RECORDER_AUDIO_ENCODING, bufferSize * BytesPerElement);

    recorder.startRecording();

    isRecording = true;

    recordingThread = new Thread(new Runnable() {

     public void run() {

      try {
          int intSize = android.media.AudioTrack.getMinBufferSize(RECORDER_SAMPLERATE,AudioFormat.CHANNEL_OUT_MONO , RECORDER_AUDIO_ENCODING);
          byte[] sData = new byte[bufferSize];
          AudioTrack at = new AudioTrack(AudioManager.STREAM_MUSIC, RECORDER_SAMPLERATE, AudioFormat.CHANNEL_OUT_MONO, RECORDER_AUDIO_ENCODING, intSize, AudioTrack.MODE_STREAM);
          while(isRecording){
          recorder.read(sData, 0, bufferSize);  //isRecording = false; onStop button

          if (at!=null) { 
              at.play();
              // Write the byte array to the track
              at.write(sData, 0, sData.length); 
              at.stop();
              at.release();
          }
          }
    } catch (IOException e) {
        e.printStackTrace();
    }
 }
  }, "AudioRecorder Thread");
    recordingThread.start();
person kAmol    schedule 28.01.2016
comment
Его часть одного из моих проектов ранее, и работает нормально. Вам нужно правильно собрать его и инициализировать переменные, такие как частота дискретизации 44100 и т. Д. :) - person kAmol; 28.01.2016
comment
Итак, это работает. Но голос очень хриплый и очень странный. Любая причина, по которой это может происходить? Кроме того, сколько стоит BytesPerElement? - person Adifyr; 28.01.2016
comment
Попробуйте частоту дискретизации 44100 и RECORDER_AUDIO_ENCODING = AudioFormat.ENCODING_PCM_16BIT . Я надеюсь, вы рассмотрели buffersize = AudioRecord.getMinBufferSize(RECORDER_SAMPLERATE, RECORDER_CHANNELS, RECORDER_AUDIO_ENCODING) Если это работает, не забудьте отметить как ответ. :) - person kAmol; 28.01.2016
comment
Привет, у меня именно такие параметры как частота дискретизации и кодировка. Он по-прежнему издает хриплый звук. Что такое BytesPerElement и каково значение? Также мой канал CHANNEL_IN_MONO. Это правильно? - person Adifyr; 28.01.2016
comment
bytesperelement=2 канал правильный. Вы можете обратиться к веб-сайту разработчика Android для получения дополнительных опций. - person kAmol; 28.01.2016
comment
качество голоса и задержка по-прежнему ужасны. - person Adifyr; 28.01.2016
comment
Затем нужно попробовать с разными частотами дискретизации и режимами. - person kAmol; 28.01.2016