I am testing the concept of an Android application that allows you to stream Bluetooth over RFCOMM (from PC to phone). I am able to transfer audio from my computer to the phone no problem and start streaming the audio.
The problem is that the audio begins to stutter and I get a buffer underrun error message from the AudioTrack
. Reading from the socket is what is taking the most time. When I timed it, underruns occurred when it takes >= 1000
milliseconds for the read to return, when on average it takes a few hundred to return. Here is my code below:
public ConnectedThread(BluetoothSocket socket) {
this.setPriority(MAX_PRIORITY);
mmSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
// Get the input and output streams; using temp objects because
// member streams are final.
try {
tmpIn = socket.getInputStream();
} catch (IOException e) {
Log.e(TAG, "Error occurred when creating input stream", e);
}
try {
tmpOut = socket.getOutputStream();
} catch (IOException e) {
Log.e(TAG, "Error occurred when creating output stream", e);
}
minBuffSize = AudioTrack.getMinBufferSize(48000, CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT);
m_audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, 48000, CHANNEL_OUT_STEREO,
AudioFormat.ENCODING_PCM_16BIT, minBuffSize /* 1 second buffer */,
AudioTrack.MODE_STREAM);
mmBuffer = new byte[minBuffSize * 2];
mmInStream = tmpIn;
mmOutStream = tmpOut;
// distream = new DataInputStream(new BufferedInputStream(mmInStream, 1000000));
distream = new DataInputStream(mmInStream);
}
public void run() {
int numBytes = 0; // bytes returned from read()
// Keep listening to the InputStream until an exception occurs.
boolean firstRun = true;
while (true) {
try {
final long startTime = System.currentTimeMillis();
distream.readFully(mmBuffer);
final long endTime = System.currentTimeMillis();
int temp = m_audioTrack.write(mmBuffer, 0, mmBuffer.length);
System.out.println("Total execution time: " + (endTime - startTime) );
if (firstRun) {
m_audioTrack.play();
firstRun = false;
}
} catch (IOException e) {
Log.d(TAG, "Input stream was disconnected", e);
break;
}
}
Any suggestions on how I can speed up the reads from the socket or prevent the underruns in general?
Let's consider this piece of code:
minBuffSize = AudioTrack.getMinBufferSize(48000, CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT);
m_audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, 48000, CHANNEL_OUT_STEREO,
AudioFormat.ENCODING_PCM_16BIT, minBuffSize /* 1 second buffer */,
AudioTrack.MODE_STREAM);
Please, note the inconsistency:
AudioTrack.getMinBufferSize()
method is called with the CHANNEL_OUT_MONO
value.AudioTrack
constructor is called with the CHANNEL_OUT_STEREO
value.Please, consider using the same arguments for the AudioTrack.getMinBufferSize()
method call and, in particular, the CHANNEL_OUT_STEREO
value. Even better, please, consider extracting the appropriate constants or local variables to reuse them for both method calls: sampleRate
, channelConfig
, audioFormat
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With