gpt4 book ai didi

java - Bluetoothsocket 影响播放和录制音频的线程

转载 作者:行者123 更新时间:2023-12-02 00:57:52 25 4
gpt4 key购买 nike

我有一个同时运行 3 个线程的应用程序。一个线程用于在手机和另一个蓝牙设备(Arduino)之间建立蓝牙连接。线程 2 通过蓝牙播放从另一部手机传入的音频。线程 3 录制音频并通过蓝牙将音频发送到另一部手机。

如果手机尝试与 Arduino 建立连接(当线程 1 运行 bluetoothsocket.connect(); 时),音频通信会出现很多故障。但是,当手机未尝试与 Arduino 建立连接或连接已建立并且线程 1 已完成时,则通信良好。

这是线程 1 - arduino 的代码(此代码带有一个类)

public class ConnectThread extends Thread {
private final BluetoothSocket mmSocket;
private final BluetoothDevice mmDevice;

public ConnectThread(BluetoothDevice device) {
// As mmSocket is final, we use a temporary socket variable
BluetoothSocket tmp = null;
mmDevice = device;

// Get a BluetoothSocket to connect with the given BluetoothDevice
try {
// MY_UUID is the app's UUID string, also used by the server code
tmp = device.createRfcommSocketToServiceRecord(UUID);
} catch (IOException e) { }
mmSocket = tmp;
}

public void run() {
android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
// Cancel discovery because it will slow down the connection
mBluetoothAdapter.cancelDiscovery();

try {
// Connect the device through the socket. This will block
// until it succeeds or throws an exception
mmSocket.connect();
} catch (IOException connectException) {
// Unable to connect; close the socket and get out
try {
mmSocket.close();
} catch (IOException closeException) { }
// Send the name of the disconnected device back to the UI Activity
sendDeviceConnectionToActivity(deviceMAC, false);
Log.d("Bluetoot connected -->", "NNNNNNNN" + connectException);
return;
}

// Do work to manage the connection (in a separate thread)
manageConnectedSocket(mmSocket, mmDevice);
// mConnectedThread = new ConnectedThread(mmSocket);
// mConnectedThread.start();
Log.d("Bluetoot connected -->", mmDevice.getName());
}

/** Will cancel an in-progress connection, and close the socket */
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) { }
}
}

线程 2 和 3 中的音频代码(此代码与另一个类一起使用)

public void audioCreate() {
// Audio track object
track = new AudioTrack(AudioManager.STREAM_VOICE_CALL,
16000, AudioFormat.CHANNEL_OUT_MONO,
encoding, minSize, AudioTrack.MODE_STREAM);
// Audio record object
recorder = new AudioRecord(MediaRecorder.AudioSource.VOICE_COMMUNICATION, 16000,
AudioFormat.CHANNEL_IN_MONO, encoding,
bufferSize);
}

public void initiateBluetoothConexion(BluetoothDevice deviceSelected) {
// Toast.makeText(getApplicationContext(), "Service On", Toast.LENGTH_SHORT).show();
deviceMAC = deviceSelected.getAddress();

mBluetoothAdapter.cancelDiscovery();
// Cancel any thread attempting to make a connection
if (mConnectThread != null) {
mConnectThread.cancel();
mConnectThread = null;
}
mConnectThread = new ConnectThread(deviceSelected);
mConnectThread.setPriority(10);
mConnectThread.start();
}

public class ConnectThread extends Thread {
private final BluetoothSocket mmSocket;
private final BluetoothDevice mmDevice;

public ConnectThread(BluetoothDevice device) {
// As mmSocket is final, we use a temporary socket variable
BluetoothSocket tmp = null;
mmDevice = device;

// Get a BluetoothSocket to connect with the given BluetoothDevice
try {
// MY_UUID is the app's UUID string, also used by the server code
tmp = device.createRfcommSocketToServiceRecord(UUID);
} catch (IOException e) { }
mmSocket = tmp;
}

public void run() {
android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_AUDIO);
// Cancel discovery because it will slow down the connection
mBluetoothAdapter.cancelDiscovery();

try {
// Connect the device through the socket. This will block
// until it succeeds or throws an exception
mmSocket.connect();
} catch (IOException connectException) {
// Unable to connect; close the socket and get out
try {
mmSocket.close();
} catch (IOException closeException) { }
// Send the name of the disconnected device back to the UI Activity
sendDeviceConnectionToActivity(deviceMAC, false);
return;
}

// Do work to manage the connection (in a separate thread)
manageConnectedSocket(mmSocket, mmDevice);
// mConnectedThread = new ConnectedThread(mmSocket);
// mConnectedThread.start();
Log.d("Bluetoot connected -->", mmDevice.getName());
}

/** Will cancel an in-progress connection, and close the socket */
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) { }
}
}

private void manageConnectedSocket(BluetoothSocket mmSocket, BluetoothDevice mmDevice) {
// Cancel the thread that completed the connection
// if (mConnectThread != null) {
// mConnectThread.cancel();
// mConnectThread = null;
// }
// Cancel any thread currently running a connection
if (mConnectedThread != null) {
mConnectedThread.cancel();
mConnectedThread = null;
}
// Start the thread to manage the connection and perform transmissions
mConnectedThread = new ConnectedThread(mmSocket);
mConnectedThread.setPriority(10);
mConnectedThread.start();
// Send the name of the connected device back to the UI Activity
Log.d(TAG, "Connected to " + mmDevice.getName());
sendDeviceConnectionToActivity(mmDevice.getAddress(), true);
// setState(STATE_CONNECTED);
}

public class ConnectedThread extends Thread {
private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final OutputStream mmOutStream;
private byte buffer[] = null;
private byte playBuffer[] = null;
private boolean intercomm = false;

public ConnectedThread(BluetoothSocket socket) {
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);
}

mmInStream = tmpIn;
mmOutStream = tmpOut;
intercomm = true;
}

public void run() {
android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_AUDIO);
playBuffer = new byte[minSize];
// Playback received audio
track.play();

startRecording();

// receive recording until an exception occurs.
while (intercomm) {
try {
if (mmInStream.available() == 0) {
//Do nothing
} else {
mmInStream.read(playBuffer);
track.write(playBuffer, 0, playBuffer.length);
}
} catch (IOException e) {
Log.d("AUDIO", "Error when receiving recording");
sendDeviceConnectionToActivity(deviceMAC, false);
break;
}
}
}

// Record Audio
public void startRecording() {
Log.d("AUDIO", "Assigning recorder");
buffer = new byte[bufferSize];

// Start Recording
recorder.startRecording();
Log.d("startRecording", "passed");
// Start a thread
recordingThread = new Thread(new Runnable() {
@Override
public void run() {
android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_AUDIO);
Log.d("startRecording", "sendRecording");
sendRecording();
}
}, "AudioRecorder Thread");
recordingThread.setPriority(10);
recordingThread.start();
}
// Method for sending Audio
public void sendRecording() {
// Infinite loop until microphone button is released
while (intercomm) {
try {
recorder.read(buffer, 0, bufferSize);
mmOutStream.write(buffer);
} catch (IOException e) {
Log.d("AUDIO", "Error when sending recording");
sendErrorsToActivity("Error sending audio");
}
}
}

// Call this method from the main activity to shut down the connection.
public void cancel() {
intercomm = false;
stopPlaying();
stopRecording();
destroyProcesses();
try {
mmSocket.close();
} catch (IOException e) {
Log.e(TAG, "Could not close the connect socket", e);
}
}

// Stop playing and free up resources
public void stopPlaying() {
if (track != null) {
track.stop();
track.flush();
}
}

// Stop Recording and free up resources
public void stopRecording() {
if (recorder != null) {
recorder.stop();
}
}

public void destroyProcesses() {
//Release resources for audio objects
track.release();
recorder.release();
}
}


我在八核 android oreo 中测试了代码。然而,当我在手机 sdk 23 中执行此操作时,情况最糟糕。

最佳答案

您的 AudioTrack 正在饥饿,因为它没有足够快地从 arduino 接收数据。这很可能是由于 BT 连接过程中网络争用增加所致。

您似乎正在使用尽可能小的播放缓冲区配置您的 AudioTrack。在大多数设备上,这只是几毫秒的音频,因此如果 AudioTrack 没有每隔几毫秒提供更多数据,它就会匮乏,并且您会听到故障。

一种解决方案是增加 AudioTrack 的 缓冲区大小(可能达到 8000 个样本左右或更多)。

此外,您还没有检查 mmInStream.read() 的返回值,这意味着您可能正在尝试“播放”仅部分存在的 playBuffer已满。

像您一样改变线程优先级不太可能产生质的变化。

关于java - Bluetoothsocket 影响播放和录制音频的线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57796256/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com