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; // 导入Bundle类用于保存实例状态
import android.os.Handler; // 导入Handler类用于线程间通信
import android.os.Looper; // 导入Looper类用于消息循环
import android.os.Message; // 导入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; // 导入AppCompatActivity基类
import androidx.core.app.ActivityCompat; // 导入兼容库中的Activity权限请求类
import androidx.core.content.ContextCompat; // 导入兼容库中的Context权限检查类
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; // 导入原子布尔值类
public class MainActivity extends AppCompatActivity implements TextToSpeech.OnInitListener { // 主活动类继承自AppCompatActivity并实现TTS初始化监听器
private static final String TAG = "AudioRecorder"; // 日志标签,用于调试输出 private Button startRecordButton, stopRecordButton; // 录音开始和停止按钮 private Button playSoundButton, pauseSoundButton, stopSoundButton, resumeSoundButton, clearSoundsButton; // 播放控制按钮 private AudioRecord audioRecord; // 音频录制对象 private static final int SAMPLE_RATE = 16000; // 音频采样率定义为16kHz private static final int BUFFER_SIZE; // 缓冲区大小定义 static { int minBufferSize = AudioRecord.getMinBufferSize( // 获取最小缓冲区大小 SAMPLE_RATE, // 使用预设的采样率 AudioFormat.CHANNEL_IN_MONO, // 单声道输入 AudioFormat.ENCODING_PCM_16BIT // 16位PCM编码 ); BUFFER_SIZE = Math.max(minBufferSize, 4096); // 设置缓冲区大小为计算出的最小值或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数据写入器 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(); // 同步锁用于保护audioTrack资源 private final Object playbackQueueLock = new Object(); // 同步锁用于保护播放队列 private final Object recordingQueueLock = new Object(); // 同步锁用于保护录音队列 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(); // 显示Toast通知 break; case 0x12: // 开始录音事件 Toast.makeText(MainActivity.this, "开始录音", Toast.LENGTH_SHORT).show(); // 显示开始录音提示 sendJsonPacket("startRecorder", null); // 发送JSON消息通知客户端 playTts("开始录音"); // 使用TTS播报开始录音 break; case 0x14: // 停止录音事件 Toast.makeText(MainActivity.this, "停止录音", Toast.LENGTH_SHORT).show(); // 显示停止录音提示 sendJsonPacket("stopRecorder", null); // 发送JSON消息通知客户端 playTts("停止录音"); // 使用TTS播报停止录音 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; } } }; @Override protected void onCreate(Bundle savedInstanceState) { // Activity创建方法 super.onCreate(savedInstanceState); // 调用父类onCreate方法 setContentView(R.layout.activity_main); // 设置界面布局文件 ttsEngine = new TextToSpeech(this, this); // 初始化TTS引擎 initViews(); // 初始化视图组件 setupClickListeners(); // 设置点击事件监听器 checkPermissions(); // 检查应用所需权限 startServer(30000); // 启动服务器监听在30000端口 startSocketListener(); // 启动Socket监听器 } private void initViews() { // 初始化UI组件 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 -> playNextInQueue()); pauseSoundButton.setOnClickListener(v -> pausePlayback()); stopSoundButton.setOnClickListener(v -> stopPlayback()); resumeSoundButton.setOnClickListener(v -> resumePlayback()); clearSoundsButton.setOnClickListener(v -> { clearPlaybackQueue(); handler.sendEmptyMessage(0x19); }); } // ==================== 录音功能实现 ==================== private void startRecording() { // 开始录音方法 if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) // 检查录音权限 != PackageManager.PERMISSION_GRANTED) { sendErrorMessage("没有录音权限"); // 如果没有权限发送错误消息 return; } if (isRecording.get()) { // 如果已经在录音则释放现有资源 releaseAudioResources(); } try { audioRecord = new AudioRecord( // 创建新的AudioRecord实例 MediaRecorder.AudioSource.MIC, // 使用麦克风作为音频源 SAMPLE_RATE, // 设置采样率为16kHz AudioFormat.CHANNEL_IN_MONO, // 设置单声道输入 AudioFormat.ENCODING_PCM_16BIT, // 设置16位PCM编码 BUFFER_SIZE // 使用预先计算好的缓冲区大小 ); if (audioRecord.getState() != AudioRecord.STATE_INITIALIZED) { // 检查是否初始化成功 throw new IllegalStateException("AudioRecord 初始化失败"); } audioRecord.startRecording(); // 开始录音 isRecording.set(true); // 设置录音状态为true 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); // 设置录音状态为false releaseAudioResources(); // 释放音频资源 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); // 数据进行Base64编码 sendJsonPacket("recording", base64Data); // 发送JSON数据包 } } catch (Exception e) { Log.e(TAG, "音频采集失败", e); // 记录异常日志 } } // ==================== 录音功能结束 ==================== // ==================== 辅助方法 ==================== 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); // 设置清除按钮是否可用 }); } private void playTts(String text) { // 播放TTS文本 if (isTtsInitialized) { // 如果TTS已初始化 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; // 设置为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; // 设置为null } } } private void sendJsonPacket(String type, Object data) { // 发送JSON数据包 if (clientSocket == null || clientSocket.isClosed() || socketWriter == null) { // 如果Socket无效 return; // 直接返回 } try { JSONObject packet = new JSONObject(); // 创建JSON对象 packet.put("type", type); // 添加类型字段 if (data != null) { // 如果有数据 packet.put("data", data); // 添加数据字段 } synchronized (this) { // 加锁确保线程安全 if (socketWriter != null) { // 如果写入器有效 socketWriter.write(packet.toString()); // 写入JSON字符串 socketWriter.write("\n\n"); // 写入换行符作为分隔符 socketWriter.flush(); // 刷新缓冲区 } } } catch (Exception e) { Log.e(TAG, "发送数据包失败: " + type, e); // 记录异常日志 } } 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); // 请求码 } } private void startServer(int port) { // 启动服务器 executorService.execute(() -> { // 异步执行 try { serverSocket = new ServerSocket(port); // 创建服务器Socket Log.i(TAG, "服务器启动: " + port); // 记录启动日志 while (isServerRunning) { // 循环等待连接 try { Socket socket = serverSocket.accept(); // 接受连接 clientSocket = socket; // 保存客户端Socket synchronized (this) { // 加锁同步 socketWriter = new BufferedWriter( // 创建缓冲写入器 new OutputStreamWriter(socket.getOutputStream(), "UTF-8")); // 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, // 在主线程显示Toast "服务器启动失败: " + e.getMessage(), Toast.LENGTH_LONG).show()); } finally { closeServerSocket(); // 关闭服务器Socket } }); } private void startSocketListener() { // 启动Socket监听 executorService.execute(() -> { // 异步执行 while (true) { // 持续监听 if (clientSocket != null && !clientSocket.isClosed()) { // 如果有客户端连接 try { BufferedReader reader = new BufferedReader( // 创建缓冲读取器 new InputStreamReader(clientSocket.getInputStream(), "UTF-8")); // 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); // 解析JSON String type = command.getString("type"); // 获取类型 switch (type) { case "playSound": String base64Sound = command.optString("data"); if (base64Sound != null && !base64Sound.isEmpty()) { byte[] soundData = Base64.decode(base64Sound, Base64.DEFAULT); addSoundToQueue(soundData); handler.sendEmptyMessage(0x18); } break; case "pauseSound": pausePlayback(); break; case "stopSound": stopPlayback(); break; case "resumeSound": resumePlayback(); break; case "clearSounds": clearPlaybackQueue(); handler.sendEmptyMessage(0x19); break; } } 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); // 如果没有连接休眠500毫秒 } catch (InterruptedException e) { Thread.currentThread().interrupt(); // 中断线程 break; } } } }); } private void clearPlaybackQueue() { synchronized (playbackQueueLock) { playbackQueue.clear(); } } private void addSoundToQueue(byte[] soundData) { synchronized (playbackQueueLock) { playbackQueue.offer(soundData); } if (!isPlaying.get() && !isPlaybackThreadActive) { handler.post(this::playNextInQueue); } } private void playNextInQueue() { if (isPlaybackThreadActive) { return; } isPlaybackThreadActive = true; new Thread(() -> { try { while (!playbackQueue.isEmpty() && !isPaused.get()) { byte[] soundData; synchronized (playbackQueueLock) { soundData = playbackQueue.poll(); } if (soundData != null) { playSoundDirectly(soundData); } } if (!isPaused.get()) { isPlaying.set(false); isPlaybackThreadActive = false; handler.sendEmptyMessage(0x17); } } catch (Exception e) { Log.e(TAG, "播放队列处理失败", e); sendErrorMessage("播放失败: " + e.getMessage()); } }).start(); } private void playSoundDirectly(byte[] soundData) { if (soundData == null || soundData.length == 0) { return; } try { isPlaying.set(true); isPaused.set(false); synchronized (audioTrackLock) { int bufferSize = AudioTrack.getMinBufferSize( SAMPLE_RATE, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT ); if (audioTrack != null) { audioTrack.release(); } audioTrack = new AudioTrack( AudioManager.STREAM_MUSIC, SAMPLE_RATE, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT, bufferSize, AudioTrack.MODE_STREAM ); if (audioTrack.getState() != AudioTrack.STATE_INITIALIZED) { throw new IllegalStateException("AudioTrack 初始化失败"); } audioTrack.play(); ByteArrayInputStream inputStream = new ByteArrayInputStream(soundData); byte[] buffer = new byte[bufferSize]; int bytesRead; while ((bytesRead = inputStream.read(buffer)) != -1 && !isPaused.get()) { audioTrack.write(buffer, 0, bytesRead); } audioTrack.stop(); audioTrack.release(); audioTrack = null; if (!isPaused.get()) { runOnUiThread(() -> { updatePlayButtonsState(); }); } } } catch (Exception e) { Log.e(TAG, "音频播放失败", e); sendErrorMessage("播放失败: " + e.getMessage()); } } private void pausePlayback() { if (!isPlaying.get() || isPaused.get()) { return; } isPaused.set(true); synchronized (audioTrackLock) { if (audioTrack != null) { audioTrack.pause(); } } // 将当前播放的数据移到暂停队列 byte[] currentData = null; synchronized (playbackQueueLock) { if (!playbackQueue.isEmpty()) { currentData = playbackQueue.poll(); } } if (currentData != null) { synchronized (playbackQueueLock) { pausedQueue.offer(currentData); } } updatePlayButtonsState(); } private void resumePlayback() { if (!isPaused.get()) { return; } isPaused.set(false); // 将暂停的数据移回播放队列 byte[] pausedData = null; synchronized (playbackQueueLock) { if (!pausedQueue.isEmpty()) { pausedData = pausedQueue.poll(); } } if (pausedData != null) { synchronized (playbackQueueLock) { playbackQueue.offer(pausedData); } } synchronized (audioTrackLock) { if (audioTrack != null && audioTrack.getPlayState() == AudioTrack.PLAYSTATE_PAUSED) { audioTrack.play(); } } if (!isPlaybackThreadActive) { new Thread(() -> { isPlaybackThreadActive = true; try { while (!playbackQueue.isEmpty() && !isPaused.get()) { byte[] soundData; synchronized (playbackQueueLock) { soundData = playbackQueue.poll(); } if (soundData != null) { playSoundDirectly(soundData); } } if (!isPaused.get()) { isPlaying.set(false); isPlaybackThreadActive = false; handler.sendEmptyMessage(0x17); } } catch (Exception e) { Log.e(TAG, "恢复播放失败", e); sendErrorMessage("恢复播放失败: " + e.getMessage()); } }).start(); } updatePlayButtonsState(); } private void stopPlayback() { if (!isPlaying.get() && !isPaused.get()) { return; } isPlaying.set(false); isPaused.set(false); synchronized (playbackQueueLock) { playbackQueue.clear(); if (!pausedQueue.isEmpty()) { pausedQueue.clear(); } } synchronized (audioTrackLock) { if (audioTrack != null) { try { audioTrack.stop(); audioTrack.release(); } catch (Exception e) { Log.e(TAG, "停止音频播放失败", e); } finally { audioTrack = null; } } } updatePlayButtonsState(); handler.sendEmptyMessage(0x19); } private void closeServerSocket() { // 关闭服务器Socket try { if (serverSocket != null && !serverSocket.isClosed()) { // 如果Socket有效 serverSocket.close(); // 关闭Socket } } catch (IOException e) { Log.w(TAG, "关闭ServerSocket失败", e); // 记录异常日志 } } @Override public void onInit(int status) { // TTS初始化回调 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() { // Activity销毁方法 super.onDestroy(); // 调用父类方法 isServerRunning = false; // 设置服务器不再运行 if (ttsEngine != null) { // 如果TTS引擎存在 ttsEngine.stop(); // 停止TTS ttsEngine.shutdown(); // 关闭TTS } closeServerSocket(); // 关闭服务器Socket closeSocket(clientSocket); // 关闭客户端Socket stopRecording(); // 停止录音 executorService.shutdown(); // 关闭线程池 try { if (!executorService.awaitTermination(800, TimeUnit.MILLISECONDS)) { // 等待关闭 executorService.shutdownNow(); // 立即关闭 } } catch (InterruptedException e) { executorService.shutdownNow(); // 立即关闭 Thread.currentThread().interrupt(); // 中断当前线程 } releaseAudioResources(); // 释放音频资源 } private void closeSocket(Socket socket) { // 关闭Socket try { if (socket != null && !socket.isClosed()) { // 如果Socket有效 socket.close(); // 关闭Socket } } catch (IOException e) { Log.w(TAG, "关闭Socket失败", e); // 记录异常日志 } if (socket == clientSocket) { // 如果是客户端Socket clientSocket = null; // 设置为null synchronized (this) { socketWriter = null; // 设置写入器为null } } }
}
生成python脚本
最新发布