Merge pull request #7 from brarcher/improve-audio

Improve audio
This commit is contained in:
brarcher
2016-01-01 02:30:27 -05:00
4 changed files with 45 additions and 118 deletions

View File

@@ -1,67 +0,0 @@
/**
* This file is part of the Protect Baby Monitor.
*
* Protect Baby Monitor is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Protect Baby Monitor is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Protect Baby Monitor. If not, see <http://www.gnu.org/licenses/>.
*/
package protect.babymonitor;
import java.util.concurrent.BlockingQueue;
import android.media.AudioTrack;
import android.util.Log;
public class AudioPlayer implements Runnable
{
final String TAG = "BabyMonitor";
private final AudioTrack _audioTrack;
private final BlockingQueue<byte[]> _queue;
public AudioPlayer(AudioTrack audioTrack, BlockingQueue<byte[]> queue)
{
_audioTrack = audioTrack;
_queue = queue;
}
@Override
public void run()
{
Log.i(TAG, "Audio player thread started");
android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO);
_audioTrack.play();
try
{
while(Thread.currentThread().isInterrupted() == false)
{
byte [] data = _queue.take();
int written = _audioTrack.write(data, 0, data.length);
if(written != data.length)
{
Log.i(TAG, "Did not write bytes: " + (data.length - written));
}
}
}
catch (InterruptedException e)
{
}
Log.i(TAG, "Audio player thread stopping");
_audioTrack.stop();
}
}

View File

@@ -82,9 +82,9 @@ public class DiscoverActivity extends Activity
public void onItemClick(AdapterView<?> parent, View view, public void onItemClick(AdapterView<?> parent, View view,
int position, long id) int position, long id)
{ {
ServiceInfoWrapper info = (ServiceInfoWrapper) parent.getItemAtPosition(position); final ServiceInfoWrapper info = (ServiceInfoWrapper) parent.getItemAtPosition(position);
Intent i = new Intent(getApplicationContext(), ListenActivity.class); final Intent i = new Intent(getApplicationContext(), ListenActivity.class);
Bundle b = new Bundle(); final Bundle b = new Bundle();
b.putString("address", info.getAddress()); b.putString("address", info.getAddress());
b.putInt("port", info.getPort()); b.putInt("port", info.getPort());
b.putString("name", info.getName()); b.putString("name", info.getName());
@@ -206,8 +206,13 @@ class ServiceInfoWrapper
// If there is more than one service on the network, it will // If there is more than one service on the network, it will
// have a number at the end, but will appear as the following: // have a number at the end, but will appear as the following:
// "ProtectBabyMonitor\\032(number) // "ProtectBabyMonitor\\032(number)
// Replace \\032 with a "" // or
return _info.getServiceName().replace("\\\\032", " "); // "ProtectBabyMonitor\032(number)
// Replace \\032 and \032 with a " "
String serviceName = _info.getServiceName();
serviceName = serviceName.replace("\\\\032", " ");
serviceName = serviceName.replace("\\032", " ");
return serviceName;
} }
@Override @Override

View File

@@ -20,9 +20,6 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.net.Socket; import java.net.Socket;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import android.app.Activity; import android.app.Activity;
import android.media.AudioFormat; import android.media.AudioFormat;
@@ -42,14 +39,15 @@ public class ListenActivity extends Activity
String _name; String _name;
Thread _listenThread; Thread _listenThread;
private void streamAudio(Socket socket) throws IllegalArgumentException, IllegalStateException, IOException private void streamAudio(final Socket socket) throws IllegalArgumentException, IllegalStateException, IOException
{ {
Log.i(TAG, "Setting up stream"); Log.i(TAG, "Setting up stream");
int frequency = 11025; final int frequency = 11025;
int channelConfiguration = AudioFormat.CHANNEL_OUT_MONO; final int channelConfiguration = AudioFormat.CHANNEL_OUT_MONO;
int audioEncoding = AudioFormat.ENCODING_PCM_16BIT; final int audioEncoding = AudioFormat.ENCODING_PCM_16BIT;
int bufferSize = AudioTrack.getMinBufferSize(frequency, channelConfiguration, audioEncoding); final int bufferSize = AudioTrack.getMinBufferSize(frequency, channelConfiguration, audioEncoding);
final int byteBufferSize = bufferSize*2;
final AudioTrack audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, final AudioTrack audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
frequency, frequency,
@@ -58,42 +56,32 @@ public class ListenActivity extends Activity
bufferSize, bufferSize,
AudioTrack.MODE_STREAM); AudioTrack.MODE_STREAM);
final BlockingQueue<byte[]> queue = new LinkedBlockingQueue<byte[]>(1 /*max samples queued*/);
AudioPlayer audioPlayer = new AudioPlayer(audioTrack, queue);
Thread playThread = new Thread(audioPlayer);
playThread.start();
setVolumeControlStream(AudioManager.STREAM_MUSIC); setVolumeControlStream(AudioManager.STREAM_MUSIC);
InputStream is = socket.getInputStream(); final InputStream is = socket.getInputStream();
int read = 0; int read = 0;
while(socket.isConnected() && read != -1 && Thread.currentThread().isInterrupted() == false) audioTrack.play();
try
{ {
byte [] buffer = new byte[bufferSize*2]; final byte [] buffer = new byte[byteBufferSize];
read = is.read(buffer);
if(read > 0) while(socket.isConnected() && read != -1 && Thread.currentThread().isInterrupted() == false)
{ {
if(read < buffer.length) read = is.read(buffer);
{
buffer = Arrays.copyOf(buffer, read);
}
try if(read > 0)
{ {
queue.add(buffer); audioTrack.write(buffer, 0, read);
}
catch(IllegalStateException e)
{
Log.i(TAG, "Buffer full, dropping data");
} }
} }
} }
finally
playThread.interrupt(); {
socket.close(); audioTrack.stop();
socket.close();
}
} }
@Override @Override
@@ -101,7 +89,7 @@ public class ListenActivity extends Activity
{ {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
Bundle b = getIntent().getExtras(); final Bundle b = getIntent().getExtras();
_address = b.getString("address"); _address = b.getString("address");
_port = b.getInt("port"); _port = b.getInt("port");
_name = b.getString("name"); _name = b.getString("name");
@@ -128,7 +116,7 @@ public class ListenActivity extends Activity
{ {
try try
{ {
Socket socket = new Socket(_address, _port); final Socket socket = new Socket(_address, _port);
streamAudio(socket); streamAudio(socket);
} }
catch (UnknownHostException e) catch (UnknownHostException e)

View File

@@ -56,29 +56,30 @@ public class MonitorActivity extends Activity
} }
}); });
int frequency = 11025; final int frequency = 11025;
int channelConfiguration = AudioFormat.CHANNEL_IN_MONO; final int channelConfiguration = AudioFormat.CHANNEL_IN_MONO;
int audioEncoding = AudioFormat.ENCODING_PCM_16BIT; final int audioEncoding = AudioFormat.ENCODING_PCM_16BIT;
int bufferSize = AudioRecord.getMinBufferSize(frequency, channelConfiguration, audioEncoding); final int bufferSize = AudioRecord.getMinBufferSize(frequency, channelConfiguration, audioEncoding);
AudioRecord audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, final AudioRecord audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC,
frequency, channelConfiguration, frequency, channelConfiguration,
audioEncoding, bufferSize); audioEncoding, bufferSize);
byte[] buffer = new byte[bufferSize*2]; final int byteBufferSize = bufferSize*2;
final byte[] buffer = new byte[byteBufferSize];
try try
{ {
audioRecord.startRecording(); audioRecord.startRecording();
OutputStream out = socket.getOutputStream(); final OutputStream out = socket.getOutputStream();
socket.setSendBufferSize(bufferSize); socket.setSendBufferSize(byteBufferSize);
Log.d(TAG, "Socket send buffer size: " + socket.getSendBufferSize()); Log.d(TAG, "Socket send buffer size: " + socket.getSendBufferSize());
while (socket.isConnected() && Thread.currentThread().isInterrupted() == false) while (socket.isConnected() && Thread.currentThread().isInterrupted() == false)
{ {
int read = audioRecord.read(buffer, 0, bufferSize); final int read = audioRecord.read(buffer, 0, bufferSize);
out.write(buffer, 0, read); out.write(buffer, 0, read);
} }
} }
@@ -113,7 +114,7 @@ public class MonitorActivity extends Activity
serverSocket = new ServerSocket(0); serverSocket = new ServerSocket(0);
// Store the chosen port. // Store the chosen port.
int localPort = serverSocket.getLocalPort(); final int localPort = serverSocket.getLocalPort();
// Register the service so that parent devices can // Register the service so that parent devices can
// locate the child device // locate the child device
@@ -201,9 +202,9 @@ public class MonitorActivity extends Activity
return super.onOptionsItemSelected(item); return super.onOptionsItemSelected(item);
} }
private void registerService(int port) private void registerService(final int port)
{ {
NsdServiceInfo serviceInfo = new NsdServiceInfo(); final NsdServiceInfo serviceInfo = new NsdServiceInfo();
serviceInfo.setServiceName("ProtectBabyMonitor"); serviceInfo.setServiceName("ProtectBabyMonitor");
serviceInfo.setServiceType("_babymonitor._tcp."); serviceInfo.setServiceType("_babymonitor._tcp.");
serviceInfo.setPort(port); serviceInfo.setPort(port);