// 定义包名,对应项目结构中的包路径
package com.example.demoapplication;
// 导入Android系统权限相关类
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; // 媒体录制配置
// 导入Android基础组件类
import android.os.Bundle; // 用于保存和恢复Activity状态
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; // 短时提示信息
// 导入AndroidX注解支持
import androidx.annotation.NonNull; // 表示非空注解
// 导入权限兼容处理工具类
import androidx.appcompat.app.AppCompatActivity; // 兼容Activity基类
import androidx.core.app.ActivityCompat; // 兼容权限请求
import androidx.core.content.ContextCompat; // 权限状态检查
// 导入JSON解析库
import org.json.JSONException; // JSON异常
import org.json.JSONObject; // JSON对象操作
// 导入IO流相关类
import java.io.BufferedReader; // 缓冲字符输入流
import java.io.BufferedWriter; // 缓冲字符输出流
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; // 原子布尔值
// 主Activity类,继承自AppCompatActivity并实现TTS初始化监听器
public class MainActivity extends AppCompatActivity implements TextToSpeech.OnInitListener {
// 日志标签和UI组件定义
private static final String TAG = "AudioRecorder"; // 日志标签
private Button startRecordButton, stopRecordButton; // 录音控制按钮
private AudioRecord audioRecord; // 音频录制实例
// 音频采样率和缓冲区大小配置
private static final int SAMPLE_RATE = 16000; // 采样率(Hz)
private static final int BUFFER_SIZE; // 缓冲区大小
// 静态代码块用于初始化缓冲区大小
static {
// 计算最小缓冲区大小并确保不小于4096字节
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; // TTS引擎实例
private boolean isTtsInitialized = false; // TTS初始化状态
private AudioTrack audioTrack; // 音频播放轨道
// 控制是否已发送开始/结束提示
private boolean isStartMessageSent = false; // 开始消息发送状态
private boolean isStopMessageSent = false; // 停止消息发送状态
private boolean isTransmitStarted = false; // 传输开始状态
private boolean isStopTransmitSent = false; // 停止传输发送状态
// 新增音频播放状态和控制字段
private boolean isPaused = false; // 是否处于暂停状态
private byte[] pausedAudioData; // 暂停时的音频数据
private int pausedPosition; // 暂停位置
// TTS音频队列和播放状态
private final Queue<byte[]> ttsQueue = new LinkedList<>(); // TTS音频队列
private boolean isTtsPlaying = false; // TTS播放状态
// 主线程消息处理器
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();
isStartMessageSent = true;
isStopMessageSent = false;
sendControlPacket("startRecorder");
playTts("开始录音");
break;
case 0x13: // 数据发送
break;
case 0x14: // 停止录音
Toast.makeText(MainActivity.this, "停止录音", Toast.LENGTH_SHORT).show();
isStopMessageSent = true;
isStartMessageSent = false;
sendControlPacket("stopRecorder");
playTts("停止录音");
break;
case 0x15: // 控制指令
Toast.makeText(MainActivity.this, "收到指令: " + msg.obj, Toast.LENGTH_SHORT).show();
break;
case 0x16: // 错误
Toast.makeText(MainActivity.this, "错误: " + msg.obj, Toast.LENGTH_LONG).show();
break;
case 0x18: // TTS音频
handleTtsAudio((String) msg.obj);
break;
case 0x19: // 聊天开始
Toast.makeText(MainActivity.this, "聊天开始: " + msg.obj, Toast.LENGTH_SHORT).show();
break;
case 0x20: // 聊天回复
Toast.makeText(MainActivity.this, "回复: " + msg.obj, Toast.LENGTH_LONG).show();
break;
case 0x21: // 播放完成
Toast.makeText(MainActivity.this, "播放完成", Toast.LENGTH_SHORT).show();
// 播放下一段音频
playNextTtsAudio();
break;
case 0x22: // 暂停播放
Toast.makeText(MainActivity.this, "播放已暂停", Toast.LENGTH_SHORT).show();
pauseCurrentPlayback();
break;
case 0x23: // 继续播放
Toast.makeText(MainActivity.this, "继续播放", Toast.LENGTH_SHORT).show();
resumeCurrentPlayback();
break;
case 0x24: // 清除队列
Toast.makeText(MainActivity.this, "队列已清除", Toast.LENGTH_SHORT).show();
clearTtsQueue();
break;
}
}
};
@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);
}
private void initViews() {
startRecordButton = findViewById(R.id.startRecordButton); // 绑定开始录音按钮
stopRecordButton = findViewById(R.id.stopRecordButton); // 绑定停止录音按钮
stopRecordButton.setEnabled(false); // 默认禁用停止按钮
}
private void setupClickListeners() {
startRecordButton.setOnClickListener(v -> startRecording()); // 设置开始录音点击事件
stopRecordButton.setOnClickListener(v -> stopRecording()); // 设置停止录音点击事件
}
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 startRecording() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO)
!= PackageManager.PERMISSION_GRANTED) {
sendErrorMessage("没有录音权限");
return;
}
if (isRecording.get()) {
releaseAudioResources();
}
if (clientSocket == null || clientSocket.isClosed() || socketWriter == null) {
sendErrorMessage("客户端未连接");
return;
}
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);
startRecordButton.setEnabled(false);
stopRecordButton.setEnabled(true);
if (scheduler != null) {
scheduler.shutdownNow();
}
scheduler = Executors.newSingleThreadScheduledExecutor();
scheduler.scheduleAtFixedRate(this::uploadAudioData, 0, 100, TimeUnit.MILLISECONDS);
handler.sendEmptyMessage(0x12);
sendControlPacket("startRecorder");
playTts("开始录音");
} catch (Exception e) {
Log.e(TAG, "录音启动失败", e);
sendErrorMessage("录音启动失败: " + e.getMessage());
releaseAudioResources();
}
}
private void stopRecording() {
if (!isRecording.get()) return;
isRecording.set(false);
releaseAudioResources();
stopRecordButton.setEnabled(false);
startRecordButton.setEnabled(true);
isStopMessageSent = false;
isStartMessageSent = false;
handler.sendEmptyMessage(0x14);
sendControlPacket("stopRecorder");
playTts("停止录音");
}
private void playTts(String text) {
if (isTtsInitialized) {
ttsEngine.speak(text, TextToSpeech.QUEUE_FLUSH, null);
Log.i(TAG, "播放TTS: " + text);
}
}
private void releaseAudioResources() {
if (audioRecord != null) {
try {
if (audioRecord.getRecordingState() == AudioRecord.RECORDSTATE_RECORDING) {
audioRecord.stop();
}
} catch (IllegalStateException e) {
Log.e(TAG, "停止录音失败", e);
}
audioRecord.release();
audioRecord = null;
}
if (scheduler != null) {
scheduler.shutdownNow();
scheduler = null;
}
}
private void uploadAudioData() {
if (!isRecording.get() || clientSocket == null || clientSocket.isClosed() || socketWriter == null) {
return;
}
byte[] buffer = new byte[BUFFER_SIZE];
try {
int bytesRead = audioRecord.read(buffer, 0, BUFFER_SIZE);
if (bytesRead > 0) {
if (audioRecord.getRecordingState() == AudioRecord.RECORDSTATE_RECORDING && !isTransmitStarted) {
sendControlPacket("startTransmit");
playTts("开始传输");
audioRecord.startRecording();
isTransmitStarted = true;
}
if (bytesRead < BUFFER_SIZE / 2 && isTransmitStarted) {
sendControlPacket("stopTransmit");
playTts("停止传输");
isTransmitStarted = false;
}
JSONObject json = new JSONObject();
json.put("type", "recording");
json.put("data", Base64.encodeToString(buffer, 0, bytesRead, Base64.NO_WRAP));
synchronized (this) {
if (socketWriter != null) {
socketWriter.write(json.toString());
socketWriter.write("\n\n");
socketWriter.flush();
}
}
}
} catch (Exception e) {
Log.e(TAG, "发送音频数据失败", e);
sendErrorMessage("发送音频数据失败: " + e.getMessage());
}
}
@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;
}
}
}
private void sendControlPacket(String type) {
if (clientSocket == null || clientSocket.isClosed() || socketWriter == null) {
return;
}
try {
JSONObject packet = new JSONObject();
packet.put("type", type);
synchronized (this) {
if (socketWriter != null) {
socketWriter.write(packet.toString());
socketWriter.write("\n\n");
socketWriter.flush();
}
}
} catch (Exception e) {
Log.e(TAG, "发送控制指令失败", e);
}
}
private void sendErrorMessage(String message) {
handler.obtainMessage(0x16, message).sendToTarget();
}
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);
executorService.execute(() -> startCommunication(socket));
} 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();
}
});
}
private void startCommunication(Socket socket) {
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(socket.getInputStream(), "UTF-8"))) {
StringBuilder packetBuilder = new StringBuilder();
int c;
while ((c = reader.read()) != -1 && isServerRunning) {
char ch = (char) c;
packetBuilder.append(ch);
if (packetBuilder.length() >= 2 &&
packetBuilder.charAt(packetBuilder.length() - 2) == '\n' &&
packetBuilder.charAt(packetBuilder.length() - 1) == '\n') {
String packet = packetBuilder.toString().trim();
packetBuilder.setLength(0);
if (!packet.isEmpty()) {
try {
JSONObject jsonObject = new JSONObject(packet);
handleReceivedPacket(jsonObject);
} catch (JSONException e) {
Log.w(TAG, "JSON解析失败: " + packet, e);
}
}
}
}
} catch (IOException e) {
if (isServerRunning) {
Log.e(TAG, "通信中断", e);
}
} finally {
closeSocket(socket);
}
}
/**
* 处理接收到的JSON数据包
* @param jsonObject 接收到的JSON对象
*/
private void handleReceivedPacket(JSONObject jsonObject) {
try {
// 获取数据包类型字段
String type = jsonObject.getString("type");
// 获取可选的数据字段(可能不存在)
Object data = jsonObject.opt("data");
Message msg;
// 根据数据包类型进行处理
switch (type) {
case "tts_audio": // TTS音频数据
// 创建带数据的消息并发送到主线程
msg = handler.obtainMessage(0x18, data.toString());
handler.sendMessage(msg);
break;
case "chat_start": // 聊天开始事件
// 解析查询内容并发送消息
msg = handler.obtainMessage(0x19, jsonObject.getJSONObject("data").getString("query"));
handler.sendMessage(msg);
break;
case "chat_reply": // 聊天回复事件
// 解析回复内容并发送消息
msg = handler.obtainMessage(0x20, jsonObject.getJSONObject("data").getString("reply"));
handler.sendMessage(msg);
break;
case "play_complete": // 播放完成通知
// 发送空消息触发下一段播放
handler.sendEmptyMessage(0x21);
break;
case "playSound": // 播放指定音频
// 添加到播放队列
addTtsAudioToQueue(Base64.decode(data.toString(), Base64.DEFAULT));
break;
case "pauseSound": // 暂停播放
handler.sendEmptyMessage(0x22);
break;
case "resumeSound": // 继续播放
handler.sendEmptyMessage(0x23);
break;
case "stopSound": // 停止播放
handler.sendEmptyMessage(0x24);
break;
case "clearSound": // 清除队列
// 清空播放队列
handler.sendEmptyMessage(0x24);
break;
default: // 其他未知类型
// 发送通用处理消息
msg = handler.obtainMessage(0x15, type + ": " + data);
handler.sendMessage(msg);
break;
}
} catch (JSONException e) {
// 记录JSON处理异常日志
Log.e(TAG, "处理数据包失败", e);
}
}
/**
* 处理TTS音频数据 - 将Base64数据解码后加入播放队列
* @param base64Data Base64编码的PCM音频数据
*/
private void handleTtsAudio(String base64Data) {
// 解码Base64数据为字节数组
byte[] pcmData = Base64.decode(base64Data, Base64.DEFAULT);
// 添加到音频播放队列
addTtsAudioToQueue(pcmData);
}
/**
* 将PCM音频数据添加到播放队列
* @param pcmData 要添加的PCM音频数据
*/
private void addTtsAudioToQueue(byte[] pcmData) {
synchronized (ttsQueue) {
// 如果不是暂停状态,则直接加入队列
if (!isPaused) {
// 将音频数据加入队列尾部
ttsQueue.offer(pcmData);
// 如果当前没有正在播放,则立即开始播放
if (!isTtsPlaying) {
playNextTtsAudio();
}
} else {
// 替换当前暂停的音频数据
pausedAudioData = pcmData;
pausedPosition = 0;
}
}
}
/**
* 播放队列中的下一段音频
*/
private void playNextTtsAudio() {
synchronized (ttsQueue) {
// 如果队列为空,标记播放结束
if (ttsQueue.isEmpty()) {
isTtsPlaying = false;
return;
}
// 取出队列头部的音频数据
byte[] pcmData = ttsQueue.poll();
// 开始播放该段音频
playPcm(pcmData);
// 标记为正在播放状态
isTtsPlaying = true;
}
}
/**
* 播放PCM格式的音频数据,并设置播放完成监听
* @param pcmData PCM音频数据字节数组
*/
private void playPcm(byte[] pcmData) {
// 停止任何正在进行的音频播放
stopAudioPlayback();
// 设置音频参数
int sampleRate = 16000; // 采样率
int channelConfig = AudioFormat.CHANNEL_OUT_MONO; // 单声道输出
int audioFormat = AudioFormat.ENCODING_PCM_16BIT; // 16位PCM编码
// 计算最小缓冲区大小
int bufferSize = AudioTrack.getMinBufferSize(sampleRate, channelConfig, audioFormat);
// 创建音频播放器实例
audioTrack = new AudioTrack(
AudioManager.STREAM_MUSIC, // 音频流类型
sampleRate, // 采样率
channelConfig, // 声道配置
audioFormat, // 音频格式
bufferSize, // 缓冲区大小
AudioTrack.MODE_STREAM); // 播放模式
// 设置播放位置监听器
audioTrack.setPlaybackPositionUpdateListener(new AudioTrack.OnPlaybackPositionUpdateListener() {
@Override
public void onMarkerReached(AudioTrack track) {
// 播放完成后发送通知
handler.sendEmptyMessage(0x21);
}
@Override
public void onPeriodicNotification(AudioTrack track) {
// 周期性通知,不需要实现
}
});
// 计算帧数(单声道,16位,所以每帧2字节)
int frameCount = pcmData.length / 2;
// 设置标记位置(在最后一帧)
audioTrack.setNotificationMarkerPosition(frameCount);
audioTrack.play();
audioTrack.write(pcmData, 0, pcmData.length);
}
// 停止音频播放(添加状态重置)
private void stopAudioPlayback() {
if (audioTrack != null) {
if (audioTrack.getPlayState() == AudioTrack.PLAYSTATE_PLAYING) {
audioTrack.stop();
}
// 移除监听器,防止回调时使用已释放的对象
audioTrack.setPlaybackPositionUpdateListener(null);
audioTrack.release();
audioTrack = null;
}
// 重置播放状态
synchronized (ttsQueue) {
ttsQueue.clear();
isTtsPlaying = false;
}
}
// 暂停当前播放
private void pauseCurrentPlayback() {
if (audioTrack != null && audioTrack.getPlayState() == AudioTrack.PLAYSTATE_PLAYING) {
audioTrack.pause();
isPaused = true;
// 保存当前音频数据和播放位置
if (audioTrack != null && audioTrack.getPlayState() == AudioTrack.PLAYSTATE_PAUSED) {
int position = audioTrack.getPlaybackHeadPosition();
if (position > 0) {
pausedPosition = position * 2; // 转换为字节位置
if (pausedPosition < audioTrack.getBufferSizeInFrames() * 2) {
int remaining = audioTrack.getBufferSizeInFrames() * 2 - pausedPosition;
byte[] remainingData = new byte[remaining];
System.arraycopy(pausedAudioData, pausedPosition, remainingData, 0, remaining);
pausedAudioData = remainingData;
}
}
}
}
}
// 继续当前播放
private void resumeCurrentPlayback() {
if (isPaused && pausedAudioData != null) {
// 从暂停位置继续播放
playPcmFromPosition(pausedAudioData, pausedPosition);
isPaused = false;
} else if (audioTrack != null && audioTrack.getPlayState() == AudioTrack.PLAYSTATE_PAUSED) {
audioTrack.play();
} else {
// 没有暂停的音频,播放队列中的下一段
playNextTtsAudio();
}
}
// 从指定位置播放PCM音频数据
private void playPcmFromPosition(byte[] pcmData, int startPosition) {
// 停止任何正在进行的音频播放
stopAudioPlayback();
// 设置音频参数
int sampleRate = 16000; // 采样率
int channelConfig = AudioFormat.CHANNEL_OUT_MONO; // 单声道输出
int audioFormat = AudioFormat.ENCODING_PCM_16BIT; // 16位PCM编码
// 计算最小缓冲区大小
int bufferSize = AudioTrack.getMinBufferSize(sampleRate, channelConfig, audioFormat);
// 创建音频播放器实例
audioTrack = new AudioTrack(
AudioManager.STREAM_MUSIC, // 音频流类型
sampleRate, // 采样率
channelConfig, // 声道配置
audioFormat, // 音频格式
bufferSize, // 缓冲区大小
AudioTrack.MODE_STREAM); // 播放模式
// 设置播放位置监听器
audioTrack.setPlaybackPositionUpdateListener(new AudioTrack.OnPlaybackPositionUpdateListener() {
@Override
public void onMarkerReached(AudioTrack track) {
// 播放完成后发送通知
handler.sendEmptyMessage(0x21);
}
@Override
public void onPeriodicNotification(AudioTrack track) {
// 周期性通知,不需要实现
}
});
// 计算剩余数据长度
int remainingLength = pcmData.length - startPosition;
// 创建新数组存储从指定位置开始的数据
byte[] remainingData = new byte[remainingLength];
System.arraycopy(pcmData, startPosition, remainingData, 0, remainingLength);
// 计算帧数(单声道,16位,所以每帧2字节)
int frameCount = remainingLength / 2;
// 设置标记位置(在最后一帧)
audioTrack.setNotificationMarkerPosition(frameCount);
audioTrack.play();
audioTrack.write(remainingData, 0, remainingLength);
}
// 清空TTS播放队列
private void clearTtsQueue() {
synchronized (ttsQueue) {
ttsQueue.clear();
// 停止当前播放并重置状态
if (audioTrack != null) {
if (audioTrack.getPlayState() == AudioTrack.PLAYSTATE_PLAYING) {
audioTrack.stop();
}
audioTrack.release();
audioTrack = null;
}
isTtsPlaying = false;
isPaused = false;
pausedAudioData = null;
pausedPosition = 0;
}
}
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;
}
}
}
private void closeServerSocket() {
try {
if (serverSocket != null && !serverSocket.isClosed()) {
serverSocket.close();
}
} catch (IOException e) {
Log.w(TAG, "关闭ServerSocket失败", e);
}
}
@Override
protected void onDestroy() {
super.onDestroy();
isServerRunning = false;
if (ttsEngine != null) {
ttsEngine.stop();
ttsEngine.shutdown();
}
closeServerSocket();
closeSocket(clientSocket);
executorService.shutdownNow();
releaseAudioResources();
stopAudioPlayback();
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
@NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == PERMISSION_REQUEST_CODE) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this, "录音权限已授予", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "录音权限被拒绝", Toast.LENGTH_SHORT).show();
}
}
}
public boolean isStopTransmitSent() {
return isStopTransmitSent;
}
public void setStopTransmitSent(boolean stopTransmitSent) {
isStopTransmitSent = stopTransmitSent;
}
public boolean isStartMessageSent() {
return isStartMessageSent;
}
public void setStartMessageSent(boolean startMessageSent) {
isStartMessageSent = startMessageSent;
}
public boolean isStopMessageSent() {
return isStopMessageSent;
}
public void setStopMessageSent(boolean stopMessageSent) {
isStopMessageSent = stopMessageSent;
}
}
生成JAVa在ider用的后台接收代码
最新发布