我正在尝试为我的一个课程构建一个蓝牙对讲机应用程序,但我似乎无法让它正常工作。我修改了BluetoothChat示例(http://developer.android.com/guide/topics/connectivity/bluetooth.html)以尝试满足我的需求,我可以成功地将录音从一部手机传输到另一部手机,但它非常严重。我正在使用AudioRecord和AudioTrack进行录制和播放。
我有这些全局变量
private static final int RECORDER_SAMPLERATE = 8000;
private static final int RECORDER_CHANNELS = AudioFormat.CHANNEL_IN_STEREO;
private static final int RECORDER_AUDIO_ENCODING = AudioFormat.ENCODING_PCM_16BIT;
private AudioRecord recorder = null;
private AudioTrack audioTrack = null;
private int bufferSize = 0;
private Thread recordingThread = null;
private boolean isRecording = false;
在我的onCreate方法中,我设置了bufferSize并初始化了AudioTrack。
bufferSize = AudioRecord.getMinBufferSize(RECORDER_SAMPLERATE,RECORDER_CHANNELS,RECORDER_AUDIO_ENCODING);
audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
RECORDER_SAMPLERATE, AudioFormat.CHANNEL_OUT_STEREO,
RECORDER_AUDIO_ENCODING, bufferSize, AudioTrack.MODE_STREAM);
按下记录/发送按钮时,这是我的代码(我目前只有记录3秒的数据。)
private void startRecording() {
recorder = new AudioRecord(MediaRecorder.AudioSource.MIC,
RECORDER_SAMPLERATE, RECORDER_CHANNELS,
RECORDER_AUDIO_ENCODING, bufferSize);
int i = recorder.getState();
if (i == 1)
recorder.startRecording();
isRecording = true;
new Timer().schedule(new TimerTask() {
@Override
public void run() {
runOnUiThread(new Runnable() {
@Override
public void run()
{
enableButtons(false);
if(null != recorder){
isRecording = false;
recorder.stop();
recorder.release();
recorder = null;
recordingThread = null;
}
}
});
}
}, 3000);
recordingThread = new Thread(new Runnable() {
@Override
public void run() {
writeOutAudioData();
}
}, "AudioRecorder Thread");
recordingThread.start();
}
private void writeOutAudioData() {
byte data[] = new byte[bufferSize];
int read = 0;
while (isRecording)
{
read = recorder.read(data, 0, bufferSize);
if (AudioRecord.ERROR_INVALID_OPERATION != read)
{
mChatService.write(data);
//TODO
}
}
}
以下是处理所有传入和传出传输的代码
private class ConnectedThread extends Thread {
private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final OutputStream mmOutStream;
public ConnectedThread(BluetoothSocket socket, String socketType) {
Log.d(TAG, "create ConnectedThread: " + socketType);
mmSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
// Get the BluetoothSocket input and output streams
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) {
Log.e(TAG, "temp sockets not created", e);
}
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
public void run() {
Log.i(TAG, "BEGIN mConnectedThread");
byte[] buffer = new byte[1024];
int bytes;
// Keep listening to the InputStream while connected
while (true) {
try {
// Read from the InputStream
bytes = mmInStream.read(buffer);
// Send the obtained bytes to the UI Activity
mHandler.obtainMessage(BluetoothChat.MESSAGE_READ, bytes, -1, buffer)
.sendToTarget();
} catch (IOException e) {
Log.e(TAG, "disconnected", e);
connectionLost();
// Start the service over to restart listening mode
BluetoothChatService.this.start();
break;
}
}
}
/**
* Write to the connected OutStream.
* @param buffer The bytes to write
*/
public void write(byte[] buffer) {
try {
mmOutStream.write(buffer);
// Share the sent message back to the UI Activity
mHandler.obtainMessage(BluetoothChat.MESSAGE_WRITE, -1, -1, buffer).sendToTarget();
} catch (IOException e) {
Log.e(TAG, "Exception during write", e);
}
}
这是我的处理程序的代码,它从BluetoothChatService获取信息
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MESSAGE_STATE_CHANGE:
if (D)
Log.i(TAG, "MESSAGE_STATE_CHANGE: " + msg.arg1);
switch (msg.arg1) {
case BluetoothChatService.STATE_CONNECTED:
setStatus(getString(R.string.title_connected_to,
mConnectedDeviceName));
mConversationArrayAdapter.clear();
break;
case BluetoothChatService.STATE_CONNECTING:
setStatus(R.string.title_connecting);
break;
case BluetoothChatService.STATE_LISTEN:
case BluetoothChatService.STATE_NONE:
setStatus(R.string.title_not_connected);
break;
}
break;
case MESSAGE_WRITE:
//byte[] writeBuf = (byte[]) msg.obj;
break;
case MESSAGE_READ:
final byte[] readBuf = (byte[]) msg.obj;
final byte bytes = (byte) msg.arg1;
Thread audioPlay = new Thread()
{
public void run(){
audioTrack.play();
audioTrack.write(readBuf, 0, readBuf.length);
audioTrack.stop();
}
};
audioPlay.start();
break;
}
}
};
我只是不明白在ConnectedThread类中byte []缓冲区的大小。我应该将其保留在1024或将其更改为其他内容吗?我无法找出正确的方法来读取这些传入的字节并将它们写入AudioTrack进行播放(没有静态)。 我在一部手机上使用Android 4.3,在另一部手机上使用4.2.2。 任何帮助将不胜感激!谢谢!
答案 0 :(得分:0)
我知道它已经有一年了,但我也有这个问题。
您必须确保您发送的内容正是您要发送的内容,并且您写入AudioTrack的内容正是您收到的内容。一个简单的测试是计算发送的字节数并与接收的(感知的接收的)字节进行比较。
我认为关键是使用您的audiotrack参数计算的最小缓冲区大小。
int minsize = AudioTrack.getMinBufferSize(RECORDER_SAMPLERATE, AudioFormat.CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_16BIT);
您可以以您想要的任何块大小发送数据,但您会看到蓝牙套接字通常为1007字节(这是我在测试中看到的)。我怀疑如果你允许套接字为你做块,那么最好的表现是,因为它无论如何都会执行检查,因此你可能想要发送相同的minsize
。
我还建议您将音频格式更改为单声道,除非您的设备有双耳话筒?
我承认我并没有尝试消化你的所有代码,但我认为你在消息中封装数据时会有一些不必要的开销。它是一个数据流,我认为它不需要封装。我建议使用BluetoothSocketServer
和BluetoothSocket
。
最后请注意,因为我正在为遇到此问题的其他人写这篇文章。请注意,除非您将AudioTrack.write()
数据写入其中,否则流模式下的minsize
将会阻塞。虽然在android参考站点上对此进行了解释,但我想强调其重要性,以避免浪费时间调试死锁。