liwei1dao 3 mesi fa
parent
commit
03495665a0
1 ha cambiato i file con 170 aggiunte e 33 eliminazioni
  1. +170
    -33
      lib/scenes/SoundRecordScene.dart

+ 170
- 33
lib/scenes/SoundRecordScene.dart Vedi File

@@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';
import 'package:flutter_sound/flutter_sound.dart';
import 'package:audioplayers/audioplayers.dart';
import 'package:permission_handler/permission_handler.dart';
@@ -11,65 +12,168 @@ class SoundRecordScene extends StatefulWidget {
class _SoundRecordSceneState extends State<SoundRecordScene> {
FlutterSoundRecorder? _soundRecorder;
AudioPlayer? _audioPlayer;
bool _isRecorderReady = false;
bool _isRecording = false;
bool _isSpeaking = false; // 是否正在说话
String? _audioFilePath;
double _volumeLevel = 0.0; // 当前音量值
DateTime? _lastBelowThresholdTime; // 上次音量低于阈值的时间
ScrollController _scrollController = ScrollController();
List<String> _logs = [];

// 音量阈值
final double _speakingThreshold = -30.0; // 开始说话的阈值
final double _silenceThreshold = -40.0; // 结束说话的阈值
final Duration _silenceDuration = Duration(seconds: 1); // 持续低于阈值的时间

// 采样率和声道数
final int _sampleRate = 16000; // 16kHz 采样率
final int _numChannels = 1; // 单声道

@override
void initState() {
super.initState();
_soundRecorder = FlutterSoundRecorder();
// 监听音量变化
_soundRecorder?.onProgress?.listen((event) {
_log('onProgress 回调触发, 分贝: ${event.decibels}');
if (event.decibels != null) {
setState(() {
_volumeLevel = event.decibels!; // 更新音量值
});
_checkSpeakingStatus(); // 检查说话状态
}
});
_audioPlayer = AudioPlayer();
_requestPermissions();
_initRecorder();
}

// 初始化录音器
void _initRecorder() async {
try {
await _soundRecorder?.openRecorder();
setState(() {
_isRecorderReady = true;
});
_log('录音器初始化成功');
} catch (e) {
_log('初始化录音器失败: $e');
setState(() {
_isRecorderReady = false;
});
}
}

// 请求麦克风权限
void _requestPermissions() async {
try {
await Permission.microphone.request();
if (await Permission.microphone.request().isGranted) {
_log('麦克风权限已授予');
} else {
_log('麦克风权限被拒绝');
setState(() {
_isRecorderReady = false;
});
}
} catch (e) {
_log('播放录音失败: $e');
_log('请求麦克风权限失败: $e');
setState(() {
_isRecorderReady = false;
});
}
}

// 开始录音
void _startRecording() async {
try {
_log('录音开始');
final tempPath =
'/data/user/0/com.example.flutter_app/cache/recorded_audio.aac'; // 可根据需要调整路径
if (!_isRecorderReady) {
_log('录音器未准备好');
return;
}

if (_isRecording) return; // 防止重复调用

final directory = await getTemporaryDirectory();
final tempPath = '${directory.path}/recorded_audio.aac';
_log('录音文件路径: $tempPath');

await _soundRecorder?.startRecorder(
toFile: tempPath,
codec: Codec.aacADTS,
sampleRate: _sampleRate, // 设置采样率
numChannels: _numChannels, // 设置声道数
enableVoiceProcessing: false, // 启用音量监听
);
setState(() {
_audioFilePath = tempPath;
_isRecording = true;
});
_log('录音开始');
} catch (e) {
_log('播放录音失败: $e');
_log('录音开始 异常: $e');
}
}

// 停止录音
void _stopRecording() async {
try {
if (!_isRecording) return; // 防止重复调用
await _soundRecorder?.stopRecorder();
setState(() {
_isRecording = false;
_volumeLevel = 0.0; //重置音量值
});
_log('录音停止');
} catch (e) {
_log('播放录音失败: $e');
_log('录音停止 异常: $e');
}
}

// 播放录音
void _playRecording() async {
if (_audioFilePath != null) {
await _audioPlayer?.play(DeviceFileSource(_audioFilePath!));
_log('播放录音');
try {
if (_audioFilePath != null) {
await _audioPlayer?.play(DeviceFileSource(_audioFilePath!));
_log('播放录音');
}
} catch (e) {
_log('播放录音 异常: $e');
}
}

// 检查说话状态
void _checkSpeakingStatus() {
if (_volumeLevel > _speakingThreshold && !_isSpeaking) {
// 音量高于阈值,表示开始说话
setState(() {
_isSpeaking = true;
});
_log('开始说话');
} else if (_volumeLevel < _silenceThreshold) {
// 音量低于阈值
if (_lastBelowThresholdTime == null) {
// 记录第一次低于阈值的时间
_lastBelowThresholdTime = DateTime.now();
} else if (DateTime.now().difference(_lastBelowThresholdTime!) >
_silenceDuration) {
// 持续低于阈值超过指定时间,表示结束说话
if (_isSpeaking) {
setState(() {
_isSpeaking = false;
});
_log('结束说话');
}
}
} else {
// 音量恢复到阈值以上,重置计时器
_lastBelowThresholdTime = null;
}
}

// 添加日志信息并自动滚动
void _log(String message) {
print("输出日志:${message}");
setState(() {
_logs.add(message); // 从顶部插入新日志
});
@@ -128,31 +232,64 @@ class _SoundRecordSceneState extends State<SoundRecordScene> {
),
),
),
// 按钮区域
GestureDetector(
onTapDown: (details) {
_startRecording(); // 按下时开始录音
},
onTapUp: (details) {
_stopRecording(); // 抬起时停止录音并播放
_playRecording(); // 播放录音
},
child: Container(
margin: EdgeInsets.all(20),
padding: EdgeInsets.all(20),
decoration: BoxDecoration(
color: Colors.blue,
shape: BoxShape.circle,
),
child: Icon(
Icons.mic,
color: Colors.white,
size: 50,
),
),
),

// 底部按钮区域
Padding(
padding: const EdgeInsets.all(20.0),
child:
Row(mainAxisAlignment: MainAxisAlignment.center, children: [
// 音量图标和音量值
Row(
children: [
Icon(
Icons.volume_up,
size: 30,
),
SizedBox(width: 10), // 间距
Text(
'${_volumeLevel.toStringAsFixed(2)} dB', //显示音量值,保留两位小数
style: TextStyle(fontSize: 16),
),
],
),
SizedBox(width: 20), // 间距
// 按钮区域
GestureDetector(
onTapDown: (details) {
_startRecording(); // 按下时开始录音
},
onTapUp: (details) {
_stopRecording(); // 抬起时停止录音并播放
_playRecording(); // 播放录音
},
child: Container(
margin: EdgeInsets.all(20),
padding: EdgeInsets.all(20),
decoration: BoxDecoration(
color: Colors.blue,
shape: BoxShape.circle,
),
child: Icon(
Icons.mic,
color: Colors.white,
size: 50,
),
),
),
]))
],
),
);
}

// 根据音量值动态调整图标颜色
Color _getVolumeColor() {
if (_volumeLevel < -40) {
return Colors.green; // 低音量
} else if (_volumeLevel < -20) {
return Colors.yellow; // 中音量
} else {
return Colors.red; // 高音量
}
}
}

Caricamento…
Annulla
Salva