package com.example.demoapplication;
import android.Manifest; // 权限相关
import android.content.pm.PackageManager; // 包管理相关
import android.media.AudioFormat; // 音频格式定义
import android.media.AudioManager; // 音频管理
import android.media.AudioRecord; // 音频录制
import android.media.AudioTrack; // 音频播放
import android.media.MediaRecorder; // 媒体录制
import android.os.Bundle; // 数据存储
import android.os.Handler; // 消息处理
import android.os.Looper; // 主线程消息循环
import android.os.Message; // 消息对象
import android.speech.tts.TextToSpeech; // 文字转语音
import android.util.Base64; // Base64编码解码
import android.util.Log; // 日志工具
import android.widget.Button; // 按钮控件
import android.widget.Toast; // 短时提示
import androidx.annotation.NonNull; // 非空注解
import androidx.appcompat.app.AppCompatActivity; // 主活动基类
import androidx.core.app.ActivityCompat; // 权限兼容处理
import androidx.core.content.ContextCompat; // 上下文工具
import org.json.JSONException; // JSON异常
import org.json.JSONObject; // JSON对象
import java.io.BufferedReader;
import java.io.BufferedWriter; // 缓冲写入
import java.io.ByteArrayInputStream;
import java.io.IOException; // IO异常
import java.io.InputStreamReader;
import java.io.OutputStreamWriter; // 输出流写入
import java.net.ServerSocket; // 服务器Socket
import java.net.Socket; // 客户端Socket
import java.util.LinkedList; // 链表结构
import java.util.Locale; // 地区信息
import java.util.Queue; // 队列结构
import java.util.concurrent.ExecutorService; // 线程池服务
import java.util.concurrent.Executors; // 线程池工厂
import java.util.concurrent.ScheduledExecutorService; // 定时任务执行器
import java.util.concurrent.TimeUnit; // 时间单位
import java.util.concurrent.atomic.AtomicBoolean; // 原子布尔值
/**
* 主活动类,实现录音、播放、网络通信和TTS功能
*/
public class MainActivity extends AppCompatActivity implements TextToSpeech.OnInitListener {
// 日志标签
private static final String TAG = "AudioRecorder";
// UI控件
private Button startRecordButton, stopRecordButton;
private Button playSoundButton, pauseSoundButton, stopSoundButton, resumeSoundButton, clearSoundsButton;
private AudioRecord audioRecord; // 音频录制对象
// 音频配置常量
private static final int SAMPLE_RATE = 16000; // 采样率
private static final int BUFFER_SIZE; // 缓冲区大小
// 静态代码块计算缓冲区大小
static {
int minBufferSize = AudioRecord.getMinBufferSize(
SAMPLE_RATE,
AudioFormat.CHANNEL_IN_MONO,
AudioFormat.ENCODING_PCM_16BIT
);
BUFFER_SIZE = Math.max(minBufferSize, 4096);
}
// 线程和状态管理
private ScheduledExecutorService scheduler; // 定时任务执行器
private AtomicBoolean isRecording = new AtomicBoolean(false); // 录音状态
private static final int PERMISSION_REQUEST_CODE = 1; // 权限请求码
private final ExecutorService executorService = Executors.newCachedThreadPool(); // 线程池
// 网络通信相关变量
private ServerSocket serverSocket; // 服务器Socket
private volatile boolean isServerRunning = true; // 服务器运行状态
private volatile Socket clientSocket; // 客户端Socket
private volatile BufferedWriter socketWriter; // Socket写入流
// TTS和音频播放控制
private TextToSpeech ttsEngine; // 文字转语音引擎
private boolean isTtsInitialized = false; // TTS初始化状态
private AudioTrack audioTrack; // 音频播放轨道
// 队列用于存储录音数据
private final Queue<byte[]> recordingQueue = new LinkedList<>(); // 正常录音队列
private final Queue<byte[]> pausedQueue = new LinkedList<>(); // 暂停队列
private final Queue<byte[]> playbackQueue = new LinkedList<>(); // 播放队列
// 原子变量确保线程安全的状态管理
private final AtomicBoolean isPlaying = new AtomicBoolean(false); // 播放状态
private final AtomicBoolean isPaused = new AtomicBoolean(false); // 暂停状态
private volatile boolean isPlaybackThreadActive = false; // 播放线程活跃状态
// 锁对象用于同步访问共享资源
private final Object audioTrackLock = new Object(); // 音频轨道锁
private final Object playbackQueueLock = new Object(); // 播放队列锁
private final Object recordingQueueLock = new Object(); // 录音队列锁
// 主线程Handler用于更新UI
private final Handler handler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(@NonNull Message msg) {
switch (msg.what) {
case 0x11: // 客户端连接
Toast.makeText(MainActivity.this, "客户端已连接", Toast.LENGTH_SHORT).show();
break;
case 0x12: // 开始录音
Toast.makeText(MainActivity.this, "开始录音", Toast.LENGTH_SHORT).show();
sendJsonPacket("startRecorder", null);
playTts("开始录音");
break;
case 0x14: // 停止录音
Toast.makeText(MainActivity.this, "停止录音", Toast.LENGTH_SHORT).show();
sendJsonPacket("stopRecorder", null);
playTts("停止录音");
break;
case 0x16: // 错误
Toast.makeText(MainActivity.this, "错误: " + msg.obj, Toast.LENGTH_LONG).show();
break;
case 0x17: // 播放完成
Toast.makeText(MainActivity.this, "播放完成", Toast.LENGTH_SHORT).show();
isPlaying.set(false);
isPlaybackThreadActive = false;
updatePlayButtonsState();
break;
case 0x18: // 播放队列已添加
Toast.makeText(MainActivity.this, "已添加到播放队列", Toast.LENGTH_SHORT).show();
break;
case 0x19: // 播放状态更新
updatePlayButtonsState();
break;
case 0x20: // 播放暂停
sendJsonPacket("pauseSound", null);
playTts("播放暂停");
break;
case 0x21: // 播放停止
sendJsonPacket("stopSound", null);
playTts("播放停止");
break;
case 0x22: // 播放恢复
sendJsonPacket("resumeSound", null);
playTts("继续播放");
break;
case 0x23: // 清空声音
sendJsonPacket("clearSounds", null);
playTts("清空所有录音");
break;
case 0x24: // 接收到新的播放指令
String base64Data = (String) msg.obj;
try {
byte[] decodedData = Base64.decode(base64Data, Base64.DEFAULT);
addBase64ToPlaybackQueue(decodedData);
} catch (IllegalArgumentException e) {
Log.e(TAG, "Base64解码失败", e);
sendErrorMessage("无效的Base64数据");
}
break;
}
}
};
/**
* Activity创建方法
* @param savedInstanceState 保存的状态
*/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 初始化TTS引擎
ttsEngine = new TextToSpeech(this, this);
initViews();
setupClickListeners();
checkPermissions();
startServer(30000);
startSocketListener(); // 启动Socket监听
}
/**
* 初始化视图组件
*/
private void initViews() {
// 绑定按钮
startRecordButton = findViewById(R.id.startRecordButton);
stopRecordButton = findViewById(R.id.stopRecordButton);
playSoundButton = findViewById(R.id.playSoundButton);
pauseSoundButton = findViewById(R.id.pauseSoundButton);
stopSoundButton = findViewById(R.id.stopSoundButton);
resumeSoundButton = findViewById(R.id.resumeSoundButton);
clearSoundsButton = findViewById(R.id.clearSoundsButton);
// 初始按钮状态设置
stopRecordButton.setEnabled(false);
pauseSoundButton.setEnabled(false);
stopSoundButton.setEnabled(false);
resumeSoundButton.setEnabled(false);
}
/**
* 设置按钮点击监听器
*/
private void setupClickListeners() {
startRecordButton.setOnClickListener(v -> startRecording());
stopRecordButton.setOnClickListener(v -> stopRecording());
playSoundButton.setOnClickListener(v -> addToPlaybackQueue());
pauseSoundButton.setOnClickListener(v -> {
pausePlayback();
handler.sendEmptyMessage(0x20);
});
stopSoundButton.setOnClickListener(v -> {
stopPlayback();
handler.sendEmptyMessage(0x21);
});
resumeSoundButton.setOnClickListener(v -> {
if (isPaused.get() && !playbackQueue.isEmpty()) {
resumePlayback();
handler.sendEmptyMessage(0x22);
}
});
clearSoundsButton.setOnClickListener(v -> {
clearAllRecordings();
handler.sendEmptyMessage(0x23);
});
}
// ==================== 录音功能实现 ====================
/**
* 开始录音
*/
private void startRecording() {
// 检查录音权限
if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO)
!= PackageManager.PERMISSION_GRANTED) {
sendErrorMessage("没有录音权限");
return;
}
// 如果已经在录音,先释放资源
if (isRecording.get()) {
releaseAudioResources();
}
try {
// 初始化录音器
audioRecord = new AudioRecord(
MediaRecorder.AudioSource.MIC,
SAMPLE_RATE,
AudioFormat.CHANNEL_IN_MONO,
AudioFormat.ENCODING_PCM_16BIT,
BUFFER_SIZE
);
if (audioRecord.getState() != AudioRecord.STATE_INITIALIZED) {
throw new IllegalStateException("AudioRecord 初始化失败");
}
// 开始录音
audioRecord.startRecording();
isRecording.set(true);
// 清空之前的录音数据
synchronized (recordingQueueLock) {
recordingQueue.clear();
}
pausedQueue.clear();
// 更新UI状态
startRecordButton.setEnabled(false);
stopRecordButton.setEnabled(true);
updatePlayButtonsState();
// 启动录音数据采集线程
if (scheduler != null && !scheduler.isShutdown()) {
scheduler.shutdownNow();
}
scheduler = Executors.newSingleThreadScheduledExecutor();
scheduler.scheduleAtFixedRate(this::captureAudioData, 0, 100, TimeUnit.MILLISECONDS);
// 发送开始录音通知
handler.sendEmptyMessage(0x12);
} catch (Exception e) {
Log.e(TAG, "录音启动失败", e);
sendErrorMessage("录音启动失败: " + e.getMessage());
releaseAudioResources();
}
}
/**
* 停止录音
*/
private void stopRecording() {
if (!isRecording.get()) return;
isRecording.set(false);
releaseAudioResources();
// 更新UI状态
stopRecordButton.setEnabled(false);
startRecordButton.setEnabled(true);
updatePlayButtonsState();
// 发送停止录音通知
handler.sendEmptyMessage(0x14);
}
/**
* 采集音频数据并保存到队列
*/
private void captureAudioData() {
if (!isRecording.get() || audioRecord == null) return;
byte[] buffer = new byte[BUFFER_SIZE];
try {
int bytesRead = audioRecord.read(buffer, 0, BUFFER_SIZE);
if (bytesRead > 0) {
// 将录制的音频数据保存到队列
synchronized (recordingQueueLock) {
recordingQueue.offer(buffer.clone());
}
// 发送录音数据包
String base64Data = Base64.encodeToString(buffer, Base64.DEFAULT);
sendJsonPacket("recording", base64Data);
}
} catch (Exception e) {
Log.e(TAG, "音频采集失败", e);
}
}
// ==================== 录音功能结束 ====================
// ==================== 播放功能实现 ====================
/**
* 添加当前录音到播放队列
*/
private void addToPlaybackQueue() {
if (recordingQueue.isEmpty()) {
Toast.makeText(this, "没有可播放的录音", Toast.LENGTH_SHORT).show();
return;
}
// 创建录音数据副本
Queue<byte[]> recordingCopy = new LinkedList<>();
synchronized (recordingQueueLock) {
for (byte[] data : recordingQueue) {
recordingCopy.offer(data.clone());
}
}
// 添加到播放队列
synchronized (playbackQueueLock) {
playbackQueue.addAll(recordingCopy);
}
// 如果当前没有播放,立即开始播放
if (!isPlaybackThreadActive && !isPlaying.get()) {
executorService.execute(this::playRecordingQueue);
} else {
handler.sendEmptyMessage(0x18);
}
}
/**
* 将Base64编码的音频数据添加到播放队列
* @param decodedData 解码后的音频数据
*/
private void addBase64ToPlaybackQueue(byte[] decodedData) {
if (decodedData == null || decodedData.length == 0) {
Log.w(TAG, "无效的音频数据");
return;
}
ByteArrayInputStream inputStream = new ByteArrayInputStream(decodedData);
byte[] buffer;
int bytesRead;
// 使用固定大小的缓冲区读取数据
buffer = new byte[4096]; // 使用固定的缓冲区大小
try {
while ((bytesRead = inputStream.read(buffer)) != -1) {
if (bytesRead > 0) {
byte[] dataChunk = new byte[bytesRead];
System.arraycopy(buffer, 0, dataChunk, 0, bytesRead);
synchronized (playbackQueueLock) {
playbackQueue.offer(dataChunk);
}
}
}
} catch (IOException e) {
Log.e(TAG, "读取音频数据失败", e);
} finally {
try {
inputStream.close();
} catch (IOException e) {
Log.e(TAG, "关闭输入流失败", e);
}
}
// 如果当前没有播放,立即开始播放
if (!isPlaybackThreadActive && !isPlaying.get()) {
executorService.execute(this::playRecordingQueue);
} else {
handler.sendEmptyMessage(0x18); // 提示已添加到播放队列
}
}
/**
* 播放录音队列
*/
private void playRecordingQueue() {
isPlaybackThreadActive = true;
isPlaying.set(true);
isPaused.set(false);
handler.sendEmptyMessage(0x19); // 更新按钮状态
// 配置音频播放器
int bufferSize = AudioTrack.getMinBufferSize(
SAMPLE_RATE,
AudioFormat.CHANNEL_OUT_MONO,
AudioFormat.ENCODING_PCM_16BIT
);
// 创建新的AudioTrack
synchronized (audioTrackLock) {
if (audioTrack != null) {
try {
audioTrack.stop();
audioTrack.release();
} catch (Exception e) {
Log.e(TAG, "释放AudioTrack失败", e);
}
}
try {
audioTrack = new AudioTrack(
AudioManager.STREAM_MUSIC,
SAMPLE_RATE,
AudioFormat.CHANNEL_OUT_MONO,
AudioFormat.ENCODING_PCM_16BIT,
bufferSize,
AudioTrack.MODE_STREAM
);
audioTrack.play();
} catch (IllegalStateException e) {
Log.e(TAG, "创建AudioTrack失败", e);
stopPlayback();
return;
}
}
// 播放队列中的所有录音数据
while (isPlaying.get() && !playbackQueue.isEmpty()) {
if (isPaused.get()) {
// 暂停状态,等待恢复
try {
Thread.sleep(100);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
continue;
}
byte[] audioData;
synchronized (playbackQueueLock) {
audioData = playbackQueue.poll();
}
if (audioData != null) {
synchronized (audioTrackLock) {
if (audioTrack != null && audioTrack.getState() == AudioTrack.STATE_INITIALIZED) {
try {
audioTrack.write(audioData, 0, audioData.length);
} catch (IllegalStateException e) {
Log.e(TAG, "音频写入失败: " + e.getMessage());
break;
}
} else {
Log.w(TAG, "AudioTrack不可用,停止播放");
break;
}
}
}
}
// 确保播放完成时正确释放资源
try {
synchronized (audioTrackLock) {
if (audioTrack != null) {
if (audioTrack.getPlayState() == AudioTrack.PLAYSTATE_PLAYING) {
audioTrack.stop();
}
audioTrack.release();
audioTrack = null;
}
}
} catch (Exception e) {
Log.e(TAG, "播放完成后释放资源失败", e);
}
// 播放完成
stopPlayback();
handler.sendEmptyMessage(0x17);
}
/**
* 暂停播放
*/
private void pausePlayback() {
if (!isPlaying.get() || isPaused.get()) return;
isPaused.set(true);
// 保存当前播放位置
synchronized (playbackQueueLock) {
pausedQueue.clear();
pausedQueue.addAll(playbackQueue);
playbackQueue.clear();
}
// 暂停音频播放
synchronized (audioTrackLock) {
if (audioTrack != null && audioTrack.getPlayState() == AudioTrack.PLAYSTATE_PLAYING) {
try {
audioTrack.pause();
} catch (IllegalStateException e) {
Log.e(TAG, "暂停播放失败: " + e.getMessage());
}
}
}
handler.sendEmptyMessage(0x19); // 更新按钮状态
runOnUiThread(() ->
Toast.makeText(MainActivity.this, "播放已暂停", Toast.LENGTH_SHORT).show()
);
}
/**
* 继续播放
*/
private void resumePlayback() {
if (!isPaused.get() || pausedQueue.isEmpty()) {
return;
}
isPaused.set(false);
isPlaying.set(true);
// 恢复播放位置
synchronized (playbackQueueLock) {
playbackQueue.clear();
playbackQueue.addAll(pausedQueue);
pausedQueue.clear();
}
// 恢复音频播放
synchronized (audioTrackLock) {
if (audioTrack != null && audioTrack.getPlayState() == AudioTrack.PLAYSTATE_PAUSED) {
try {
audioTrack.play();
} catch (IllegalStateException e) {
Log.e(TAG, "恢复播放失败: " + e.getMessage());
}
}
}
handler.sendEmptyMessage(0x19); // 更新按钮状态
runOnUiThread(() ->
Toast.makeText(MainActivity.this, "继续播放", Toast.LENGTH_SHORT).show()
);
}
/**
* 停止播放
*/
private void stopPlayback() {
isPlaying.set(false);
isPaused.set(false);
synchronized (audioTrackLock) {
if (audioTrack != null) {
try {
if (audioTrack.getPlayState() == AudioTrack.PLAYSTATE_PLAYING ||
audioTrack.getPlayState() == AudioTrack.PLAYSTATE_PAUSED) {
audioTrack.stop();
}
audioTrack.release();
} catch (IllegalStateException e) {
Log.e(TAG, "停止播放失败: " + e.getMessage());
} finally {
audioTrack = null;
}
}
}
synchronized (playbackQueueLock) {
playbackQueue.clear();
}
pausedQueue.clear();
runOnUiThread(() ->
{
handler.sendEmptyMessage(0x19); // 更新按钮状态
Toast.makeText(MainActivity.this, "播放已停止", Toast.LENGTH_SHORT).show();
}
);
}
private void clearAllRecordings() {
stopPlayback();
synchronized (recordingQueueLock) {
recordingQueue.clear();
}
pausedQueue.clear();
synchronized (playbackQueueLock) {
playbackQueue.clear();
}
handler.sendEmptyMessage(0x19); // 更新按钮状态
runOnUiThread(() ->
Toast.makeText(MainActivity.this, "所有录音已清除", Toast.LENGTH_SHORT).show()
);
}
// ==================== 播放功能结束 ====================
// ==================== 辅助方法 ====================
/**
* 更新播放按钮状态
*/
private void updatePlayButtonsState() {
runOnUiThread(() -> {
boolean hasRecordings = !recordingQueue.isEmpty() || !pausedQueue.isEmpty();
boolean isPlayingState = isPlaying.get() && !isPaused.get();
playSoundButton.setEnabled(hasRecordings && !isPlayingState);
pauseSoundButton.setEnabled(isPlayingState);
stopSoundButton.setEnabled(isPlaying.get() || isPaused.get());
resumeSoundButton.setEnabled(!playbackQueue.isEmpty() && isPaused.get());
clearSoundsButton.setEnabled(hasRecordings);
});
}
/**
* 播放TTS语音
* @param text 要播放的文本
*/
private void playTts(String text) {
if (isTtsInitialized) {
ttsEngine.speak(text, TextToSpeech.QUEUE_FLUSH, null);
}
}
/**
* 释放音频资源
*/
private void releaseAudioResources() {
if (audioRecord != null) {
try {
if (audioRecord.getRecordingState() == AudioRecord.RECORDSTATE_RECORDING) {
audioRecord.stop();
}
audioRecord.release();
} catch (IllegalStateException e) {
Log.e(TAG, "停止录音失败", e);
} finally {
audioRecord = null;
}
}
if (scheduler != null) {
try {
scheduler.shutdownNow();
if (!scheduler.awaitTermination(500, TimeUnit.MILLISECONDS)) {
Log.w(TAG, "录音线程池未正常关闭");
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
scheduler = null;
}
}
}
/**
* 发送JSON格式的数据包
* @param type 数据包类型
* @param data 数据内容(可以为null)
*/
private void sendJsonPacket(String type, Object data) {
if (clientSocket == null || clientSocket.isClosed() || socketWriter == null) {
return;
}
try {
JSONObject packet = new JSONObject();
packet.put("type", type);
if (data != null) {
packet.put("data", data);
}
synchronized (this) {
if (socketWriter != null) {
socketWriter.write(packet.toString());
socketWriter.write("\n\n");
socketWriter.flush();
}
}
} catch (Exception e) {
Log.e(TAG, "发送数据包失败: " + type, e);
}
}
/**
* 发送错误消息
* @param message 错误信息
*/
private void sendErrorMessage(String message) {
handler.obtainMessage(0x16, message).sendToTarget();
}
/**
* 检查权限
*/
private void checkPermissions() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.RECORD_AUDIO},
PERMISSION_REQUEST_CODE);
}
}
/**
* 启动服务器
* @param port 监听端口
*/
private void startServer(int port) {
executorService.execute(() -> {
try {
serverSocket = new ServerSocket(port);
Log.i(TAG, "服务器启动: " + port);
while (isServerRunning) {
try {
Socket socket = serverSocket.accept();
clientSocket = socket;
synchronized (this) {
socketWriter = new BufferedWriter(
new OutputStreamWriter(socket.getOutputStream(), "UTF-8"));
}
handler.sendEmptyMessage(0x11);
} catch (IOException e) {
if (isServerRunning) Log.e(TAG, "接受连接失败", e);
}
}
} catch (IOException e) {
Log.e(TAG, "服务器启动失败", e);
runOnUiThread(() -> Toast.makeText(this,
"服务器启动失败: " + e.getMessage(), Toast.LENGTH_LONG).show());
} finally {
closeServerSocket();
}
});
}
/**
* 启动Socket监听
*/
private void startSocketListener() {
executorService.execute(() -> {
while (true) {
if (clientSocket != null && !clientSocket.isClosed()) {
try {
BufferedReader reader = new BufferedReader(
new InputStreamReader(clientSocket.getInputStream(), "UTF-8"));
StringBuilder packetBuilder = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
if (line.isEmpty()) {
// 收到两个换行符,表示一个数据包结束
if (packetBuilder.length() > 0) {
String packet = packetBuilder.toString();
Log.d(TAG, "收到数据包: " + packet);
try {
JSONObject command = new JSONObject(packet);
String type = command.getString("type");
switch (type) {
case "playSound":
String base64Data = command.getString("data");
Message msg = handler.obtainMessage(0x24, base64Data);
handler.sendMessage(msg);
break;
case "pauseSound":
handler.sendEmptyMessage(0x20);
break;
case "stopSound":
handler.sendEmptyMessage(0x21);
break;
case "resumeSound":
handler.sendEmptyMessage(0x22);
break;
case "clearSounds":
handler.sendEmptyMessage(0x23);
break;
default:
Log.w(TAG, "未知指令类型: " + type);
}
} catch (JSONException e) {
Log.e(TAG, "JSON解析失败", e);
}
// 重置包构建器
packetBuilder.setLength(0);
}
} else {
// 添加数据到当前包
packetBuilder.append(line);
}
}
} catch (IOException e) {
Log.e(TAG, "Socket读取失败", e);
}
} else {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
}
}
});
}
/**
* 关闭服务器Socket
*/
private void closeServerSocket() {
try {
if (serverSocket != null && !serverSocket.isClosed()) {
serverSocket.close();
}
} catch (IOException e) {
Log.w(TAG, "关闭ServerSocket失败", e);
}
}
/**
* TTS初始化回调
* @param status 初始化状态
*/
@Override
public void onInit(int status) {
if (status == TextToSpeech.SUCCESS) {
int result = ttsEngine.setLanguage(Locale.CHINESE);
if (result == TextToSpeech.LANG_MISSING_DATA || result == TextToSpeech.LANG_NOT_SUPPORTED) {
Log.e(TAG, "TTS语言不支持中文");
} else {
isTtsInitialized = true;
}
}
}
/**
* 活动销毁时调用
*/
@Override
protected void onDestroy() {
super.onDestroy();
isServerRunning = false;
if (ttsEngine != null) {
ttsEngine.stop();
ttsEngine.shutdown();
}
closeServerSocket();
closeSocket(clientSocket);
// 停止所有录音和播放
stopRecording();
stopPlayback();
// 优雅关闭线程池
executorService.shutdown();
try {
if (!executorService.awaitTermination(800, TimeUnit.MILLISECONDS)) {
executorService.shutdownNow();
}
} catch (InterruptedException e) {
executorService.shutdownNow();
Thread.currentThread().interrupt();
}
// 确保所有资源释放
releaseAudioResources();
}
/**
* 关闭Socket
* @param socket 要关闭的Socket
*/
private void closeSocket(Socket socket) {
try {
if (socket != null && !socket.isClosed()) {
socket.close();
}
} catch (IOException e) {
Log.w(TAG, "关闭Socket失败", e);
}
if (socket == clientSocket) {
clientSocket = null;
synchronized (this) {
socketWriter = null;
}
}
}
}
生成python脚本
最新发布