From 03495665a0b63fdeee64bdfc648def0740407ef3 Mon Sep 17 00:00:00 2001 From: liwei1dao Date: Fri, 24 Jan 2025 08:14:57 +0800 Subject: [PATCH] s --- lib/scenes/SoundRecordScene.dart | 203 ++++++++++++++++++++++++++----- 1 file changed, 170 insertions(+), 33 deletions(-) diff --git a/lib/scenes/SoundRecordScene.dart b/lib/scenes/SoundRecordScene.dart index 3774d05..1df8d33 100644 --- a/lib/scenes/SoundRecordScene.dart +++ b/lib/scenes/SoundRecordScene.dart @@ -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 { 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 _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 { ), ), ), - // 按钮区域 - 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; // 高音量 + } + } }