Android: потоковое аудио через TCP-сокеты - PullRequest
21 голосов
/ 01 мая 2010

Для моего приложения мне нужно записать звук с MIC на телефон Android и отправить его по TCP на другой телефон Android, где его необходимо воспроизвести.

Я использую AudioRecord и AudioTrack класс. Это прекрасно работает с файлом - записывайте аудио в файл, используя DataOutputStream, и читайте из него, используя DataInputStream.

Однако, если я получаю тот же поток из сокета, а не из файла, и пытаюсь записать в него, я получаю исключение.

Я затрудняюсь понять, что может быть не так. Любая помощь будет принята с благодарностью.

РЕДАКТИРОВАТЬ: проблема та же, даже если я пытаюсь с большим размером буфера (65535 байт, 160000 байт).

Это код:

Recorder:

int bufferSize = AudioRecord.getMinBufferSize(11025, , AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT); 

AudioRecord recordInstance = new AudioRecord(MediaRecorder.AudioSource.MIC, 11025, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, bufferSize);

byte[] tempBuffer = new byte[bufferSize];

recordInstance.startRecording();

while (/*isRecording*/) {
      bufferRead = recordInstance.read(tempBuffer, 0, bufferSize);
      dataOutputStreamInstance.write(tempBuffer);
}

DataOutputStream выше получается как:

BufferedOutputStream buff = new BufferedOutputStream(out1); //out1 is the socket's outputStream
DataOutputStream dataOutputStreamInstance = new DataOutputStream (buff);

Не могли бы вы взглянуть и дать мне знать, что я могу здесь делать неправильно?

Спасибо

Ответы [ 3 ]

8 голосов
/ 02 мая 2010

Я получил это с некоторой помощью, и только частично.

Я начал с кода на http://emeadev.blogspot.com/2009/09/raw-audio-manipulation-in-android.html,, изменил потоки Файла на потоки Сокета и изменил isAvailable () на if (inputStream.read (byteArray)! = -1).

Сейчас происходит потоковая передача аудио по TCP.

Тем не менее,

Все, что я слышу на другом конце, это шум, и теперь я ищу правильный набор параметров для AudioRecorder и AudioTrack - частоты, конфигурации и кодирования канала, источника звука и т. Д.

Если у вас есть идеи по этому поводу, пожалуйста, дайте мне знать.

Спасибо

EDIT: Это была глупая ошибка с моей стороны. В дополнение ко всему, что я сказал выше, используйте inputStream на стороне плеера и outputStream на стороне рекордера, и байтовые массивы вместо шортов, и это будет работать. :)

2 голосов
/ 07 августа 2018

Проблема лежит здесь:

  bufferRead = recordInstance.read(tempBuffer, 0, bufferSize);
  dataOutputStreamInstance.write(tempBuffer);

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

Чтобы улучшить процесс записи, вы можете рассмотреть следующие моменты:

  1. Включить NoiseSuppressor (начиная с API 16)
  2. Включить AcousticEchoCanceler (начиная с API 16)
  3. Увеличьте начальный размер буфера и должны прочитать кусок байтов меньший , чем начальный размер буфера для более плавного аудиопотока
  4. Переключиться на UDP. Потоковая передача - задание UDP.

Вот мои настройки для моего предыдущего приложения для Android:

// Calculate minimum buffer size
int minBufferSize = AudioRecord.getMinBufferSize(44100, AudioFormat.CHANNEL_IN_MONO,
                                                 AudioFormat.ENCODING_PCM_16BIT);
// Initialize AudioRecord for getting audio from device
AudioRecord recorder = new AudioRecord(MediaRecorder.AudioSource.MIC, 44100,
                                            AudioFormat.CHANNEL_IN_MONO,
                                            AudioFormat.ENCODING_PCM_16BIT, minBufferSize * 4);

if (API > API 16) {
    if (NoiseSuppressor.isAvailable()) {
        NoiseSuppressor.create(recorder.getAudioSessionId()).setEnabled(true);
    }
    if (AcousticEchoCanceler.isAvailable()) {
        AcousticEchoCanceler.create(recorder.getAudioSessionId()).setEnabled(true);
    }
}

....

byte[] tempBuffer = new byte[minBufferSize];
while (/*isRecording*/) {
      bufferRead = recordInstance.read(tempBuffer, 0, minBufferSize);
      dataOutputStreamInstance.write(tempBuffer, 0, bufferRead);
}
1 голос
/ 02 мая 2010

Не зная, какое именно исключение вы получаете, трудно точно понять, в чем дело. Это также поможет увидеть код, который вы используете для создания out1 (то есть код вашего сокета).

Что-то, на что вы могли бы обратить внимание, это количество данных, прочитанных с recordInstance.read(); вы можете не получить из него целый массив данных bufferSize, поэтому вам нужно только позаботиться о записи байтов 0 - bufferRead-1 в выходной сокет.

...