Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android: Streaming audio over TCP Sockets

Tags:

For my app, I need to record audio from MIC on an Android phone, and send it over TCP to the other android phone, where it needs to be played.

I am using AudioRecord and AudioTrack class. This works great with a file - write audio to the file using DataOutputStream, and read from it using DataInputStream.

However, if I obtain the same stream from a socket instead of a File, and try writing to it, I get an exception.

I am at a loss to understand what could possibly be going wrong. Any help would be greatly appreciated.

EDIT: The problem is same even if I try with larger buffer sizes (65535 bytes, 160000 bytes).

This is the code:

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

The DataOutputStream above is obtained as:

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

Could you please have a look, and let me know what is it that I could be doing wrong here?

Thanks,

like image 933
Chaitanya Avatar asked May 01 '10 07:05

Chaitanya


2 Answers

I got this working, with some help, and only partially.

I started off with the code at http://emeadev.blogspot.com/2009/09/raw-audio-manipulation-in-android.html, changed File's streams to Socket's streams, and changed the isAvailable() to if(inputStream.read(byteArray) != -1).

Live streaming of audio over TCP is happening now.

However,

All I hear at the other end is noise, and I am now hunting for correct set of parameters for AudioRecorder and AudioTrack - the frequency, channel config and encoding, audio source etc.

If you have any idea about this, please let me know.

Thanks,

EDIT: It was a stupid error on my part. In addition to all I have said above, use inputStream on player side and outputStream on recorder side, and byte arrays instead of shorts and it will work. :)

like image 77
Chaitanya Avatar answered Oct 04 '22 00:10

Chaitanya


The problem is lying here:

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

You read bufferRead worth of bytes but you attempt to write whole buffer to the output stream.

To improve the recording process, you may consider following points:

  1. Enable NoiseSuppressor (since API 16)
  2. Enable AcousticEchoCanceler (since API 16)
  3. Increase initial buffersize and should read a chunk of bytes smaller than initial buffersize for smoother audiostream
  4. Switch to UDP. Streaming is UDP job.

Here is my setup for my previous android app:

// 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);
}
like image 42
Mạnh Quyết Nguyễn Avatar answered Oct 03 '22 23:10

Mạnh Quyết Nguyễn