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;
import android.util.Log;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.ScaleAnimation;
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;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.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;
private volatile boolean isServerRunning = true;
private volatile Socket clientSocket;
private volatile BufferedWriter socketWriter;
// TTS和音频播放控制
private TextToSpeech ttsEngine;
private boolean isTtsInitialized = false;
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();
// 动画资源
private Animation buttonPressAnim;
// 主线程Handler用于更新UI
private final Handler handler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(@NonNull Message msg) {
switch (msg.what) {
case 0x11:
showAnimatedToast("客户端已连接", Toast.LENGTH_SHORT);
break;
case 0x12:
showAnimatedToast("开始录音", Toast.LENGTH_SHORT);
sendJsonPacket("startRecorder", null);
playTts("开始录音");
startButtonPulseAnimation(startRecordButton);
break;
case 0x14:
showAnimatedToast("停止录音", Toast.LENGTH_SHORT);
sendJsonPacket("stopRecorder", null);
playTts("停止录音");
stopButtonPulseAnimation(startRecordButton);
break;
case 0x16:
showAnimatedToast("错误: " + msg.obj, Toast.LENGTH_LONG);
break;
case 0x17:
showAnimatedToast("播放完成", Toast.LENGTH_SHORT);
isPlaying.set(false);
isPlaybackThreadActive = false;
updatePlayButtonsState();
stopPlaybackAnimations();
break;
case 0x18:
showAnimatedToast("已添加到播放队列", Toast.LENGTH_SHORT);
break;
case 0x19:
updatePlayButtonsState();
break;
case 0x20:
sendJsonPacket("pauseSound", null);
playTts("播放暂停");
pausePlaybackAnimations();
break;
case 0x21:
sendJsonPacket("stopSound", null);
playTts("播放停止");
stopPlaybackAnimations();
break;
case 0x22:
sendJsonPacket("resumeSound", null);
playTts("继续播放");
resumePlaybackAnimations();
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);
// 初始化按钮脉冲动画
initButtonAnimations();
// 初始化TTS引擎
ttsEngine = new TextToSpeech(this, this);
initViews();
setupClickListeners();
checkPermissions();
startServer(30000);
startSocketListener();
}
/**
* 初始化按钮动画
*/
private void initButtonAnimations() {
// 创建按钮点击动画
buttonPressAnim = new ScaleAnimation(
1.0f, 0.9f, 1.0f, 0.9f,
Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f
);
buttonPressAnim.setDuration(150);
buttonPressAnim.setRepeatCount(0);
buttonPressAnim.setFillAfter(false);
}
/**
* 初始化视图组件
*/
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 -> {
animateButtonClick(v);
startRecording();
});
stopRecordButton.setOnClickListener(v -> {
animateButtonClick(v);
stopRecording();
});
playSoundButton.setOnClickListener(v -> {
animateButtonClick(v);
addToPlaybackQueue();
});
pauseSoundButton.setOnClickListener(v -> {
animateButtonClick(v);
pausePlayback();
handler.sendEmptyMessage(0x20);
});
stopSoundButton.setOnClickListener(v -> {
animateButtonClick(v);
stopPlayback();
handler.sendEmptyMessage(0x21);
});
resumeSoundButton.setOnClickListener(v -> {
animateButtonClick(v);
if (isPaused.get() && !playbackQueue.isEmpty()) {
resumePlayback();
handler.sendEmptyMessage(0x22);
}
});
clearSoundsButton.setOnClickListener(v -> {
animateButtonClick(v);
clearAllRecordings();
handler.sendEmptyMessage(0x23);
});
}
/**
* 按钮点击动画
*/
private void animateButtonClick(View view) {
view.startAnimation(buttonPressAnim);
}
/**
* 开始录音时启动脉冲动画
*/
private void startButtonPulseAnimation(Button button) {
stopButtonPulseAnimation(button); // 先停止之前的动画
Animation pulseAnim = new ScaleAnimation(
1.0f, 1.1f, 1.0f, 1.1f,
Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f
);
pulseAnim.setDuration(500);
pulseAnim.setRepeatCount(Animation.INFINITE);
pulseAnim.setRepeatMode(Animation.REVERSE);
button.startAnimation(pulseAnim);
}
/**
* 停止录音时停止脉冲动画
*/
private void stopButtonPulseAnimation(Button button) {
button.clearAnimation();
}
/**
* 播放暂停时的动画效果
*/
private void pausePlaybackAnimations() {
stopButtonPulseAnimation(playSoundButton);
stopButtonPulseAnimation(resumeSoundButton);
}
/**
* 播放恢复时的动画效果
*/
private void resumePlaybackAnimations() {
startButtonPulseAnimation(resumeSoundButton);
}
/**
* 播放停止时的动画效果
*/
private void stopPlaybackAnimations() {
stopButtonPulseAnimation(playSoundButton);
stopButtonPulseAnimation(resumeSoundButton);
}
/**
* 显示带缩放动画的Toast
*/
private void showAnimatedToast(String message, int duration) {
Toast toast = Toast.makeText(this, message, duration);
View view = toast.getView();
Animation anim = new ScaleAnimation(
0.0f, 1.0f, 0.0f, 1.0f,
Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f
);
anim.setDuration(300);
view.startAnimation(anim);
toast.show();
}
// ==================== 录音功能实现 ====================
/**
* 开始录音
*/
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);
// 更新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()) {
showAnimatedToast("没有可播放的录音", Toast.LENGTH_SHORT);
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);
startButtonPulseAnimation(playSoundButton);
} 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);
startButtonPulseAnimation(playSoundButton);
} 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(() ->
showAnimatedToast("播放已暂停", Toast.LENGTH_SHORT)
);
}
/**
* 继续播放
*/
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(() ->
showAnimatedToast("继续播放", Toast.LENGTH_SHORT)
);
}
/**
* 停止播放
*/
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);
showAnimatedToast("播放已停止", Toast.LENGTH_SHORT);
});
}
private void clearAllRecordings() {
stopPlayback();
synchronized (recordingQueueLock) {
recordingQueue.clear();
}
pausedQueue.clear();
synchronized (playbackQueueLock) {
playbackQueue.clear();
}
handler.sendEmptyMessage(0x19);
runOnUiThread(() ->
showAnimatedToast("所有录音已清除", Toast.LENGTH_SHORT)
);
}
// ==================== 播放功能结束 ====================
// ==================== 辅助方法 ====================
/**
* 更新播放按钮状态
*/
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初始化回调
*/
@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;
}
}
}
}
在这个页面添加点样式。录音时候带些波浪回馈,美化页面 然后把完整的安卓代码给我
最新发布