Flutter语音录制插件flutter_voice_recorder的使用
Flutter语音录制插件flutter_voice_recorder的使用
flutter_voice_recorder
是一个支持 Record
、Pause
、Resume
和 Stop
功能的 Flutter 插件,并且提供了音频级别表征属性 average power
和 peak power
的访问。
功能支持
该插件适用于 Android
和 iOS
平台。
安装
在 pubspec.yaml
文件中添加 flutter_voice_recorder
依赖:
dependencies:
flutter_voice_recorder: ^版本号
然后运行 flutter pub get
来安装依赖。
iOS权限配置
-
在
Info.plist
文件中添加麦克风使用描述:<key>NSMicrophoneUsageDescription</key> <string>Can We Use Your Microphone Please</string>
-
使用
hasPermission
API 请求用户授权:bool hasPermission = await FlutterVoiceRecorder.hasPermissions;
Android权限配置
-
在
AndroidManifest.xml
文件中添加录音和存储权限:<uses-permission android:name="android.permission.RECORD_AUDIO"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
-
使用
hasPermission
API 请求用户授权:bool hasPermission = await FlutterVoiceRecorder.hasPermissions;
配置
iOS
iOS 部署目标应为 8.0 或更高版本。
Android
- 使用最新版本(
0.5.x
)的 AndroidX。 - 使用旧版本(
0.4.9
)的 Legacy Android。
使用方法
推荐的API使用顺序:hasPermission
=> init
=> start
-> (pause
<-> resume
) * n -> stop
。每次开始新的录制前,应再次调用 init
方法。
检查权限
首先检查权限,如果权限尚未设置为 true
或 false
,则会请求权限;否则,将返回录制权限的结果。
bool hasPermission = await FlutterVoiceRecorder.hasPermissions;
初始化
在开始录制之前,运行初始化代码,以检查给定名称的文件是否已存在。
var recorder = FlutterVoiceRecorder("file_path.mp4"); // .wav .aac .m4a
await recorder.initialized;
或者指定音频格式:
var recorder = FlutterVoiceRecorder("file_path", audioFormat: AudioFormat.AAC); // or AudioFormat.WAV
await recorder.initialized;
也可以指定采样率:
var recorder = FlutterVoiceRecorder("file_path", audioFormat: AudioFormat.AAC, sampleRate: 22000); // sampleRate 默认为 16000
await recorder.initialized;
开始录制
await recorder.start();
var recording = await recorder.current(channel: 0);
获取录制详情
可以使用定时器每50毫秒访问一次录制详情(录制完成后取消定时器):
new Timer.periodic(tick, (Timer t) async {
var current = await recording.current(channel: 0);
// print(current.status);
setState(() {
});
});
录制对象的属性
Recording 类
名称 | 描述 |
---|---|
path | String |
extension | String |
duration | Duration |
audioFormat | AudioFormat |
metering | AudioMetering |
status | RecordingStatus |
Recording.metering 类
名称 | 描述 |
---|---|
peakPower | double |
averagePower | double |
isMeteringEnabled | bool |
Recording.status 类
Unset
Initialized
Recording
Paused
Stopped
暂停录制
await recorder.pause();
恢复录制
await recorder.resume();
停止录制
停止后,需要重新调用 init
方法来创建新的录制:
var result = await recorder.stop();
File file = widget.localFileSystem.file(result.path);
示例代码
以下是一个完整的示例代码,展示了如何使用 flutter_voice_recorder
插件进行语音录制。
// ignore_for_file: library_private_types_in_public_api, avoid_print, use_build_context_synchronously, depend_on_referenced_packages
import 'dart:async';
import 'dart:io' as io;
import 'package:audioplayers/audioplayers.dart';
import 'package:file/file.dart';
import 'package:file/local.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_voice_recorder/flutter_voice_recorder.dart';
import 'package:path_provider/path_provider.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: [
SystemUiOverlay.bottom,
SystemUiOverlay.top,
]);
return runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
[@override](/user/override)
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
[@override](/user/override)
Widget build(BuildContext context) {
return const MaterialApp(
home: Scaffold(
body: SafeArea(
child: RecorderExample(),
),
),
);
}
}
class RecorderExample extends StatefulWidget {
final LocalFileSystem localFileSystem;
const RecorderExample({super.key, localFileSystem})
: localFileSystem = localFileSystem ?? const LocalFileSystem();
[@override](/user/override)
State<StatefulWidget> createState() => RecorderExampleState();
}
class RecorderExampleState extends State<RecorderExample> {
FlutterVoiceRecorder? _recorder;
Recording? _current;
RecordingStatus _currentStatus = RecordingStatus.Unset;
[@override](/user/override)
void initState() {
super.initState();
_init();
}
[@override](/user/override)
Widget build(BuildContext context) {
return Center(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: TextButton(
onPressed: () {
switch (_currentStatus) {
case RecordingStatus.Initialized:
{
_start();
break;
}
case RecordingStatus.Recording:
{
_pause();
break;
}
case RecordingStatus.Paused:
{
_resume();
break;
}
case RecordingStatus.Stopped:
{
_init();
break;
}
default:
break;
}
},
style: ButtonStyle(
backgroundColor: WidgetStateProperty.all<Color>(
Colors.lightBlue,
)),
child: _buildText(_currentStatus),
),
),
TextButton(
onPressed:
_currentStatus != RecordingStatus.Unset ? _stop : null,
style: ButtonStyle(
backgroundColor: WidgetStateProperty.all<Color>(
Colors.blueAccent.withOpacity(0.5),
)),
child: const Text("Stop",
style: TextStyle(color: Colors.white)),
),
const SizedBox(
width: 8,
),
TextButton(
onPressed: onPlayAudio,
style: ButtonStyle(
backgroundColor: WidgetStateProperty.all<Color>(
Colors.blueAccent.withOpacity(0.5),
)),
child: const Text("Play",
style: TextStyle(color: Colors.white)),
),
],
),
Text("Status : $_currentStatus"),
Text('Avg Power: ${_current?.metering?.averagePower}'),
Text('Peak Power: ${_current?.metering?.peakPower}'),
Text("File path of the record: ${_current?.path}"),
Text("Format: ${_current?.audioFormat}"),
Text(
"isMeteringEnabled: ${_current?.metering?.isMeteringEnabled}"),
Text("Extension : ${_current?.extension}"),
Text(
"Audio recording duration : ${_current?.duration.toString()}")
]),
),
);
}
_init() async {
try {
bool hasPermission = await FlutterVoiceRecorder.hasPermissions ?? false;
if (hasPermission) {
String customPath = '/flutter_audio_recorder_';
io.Directory appDocDirectory;
// io.Directory appDocDirectory = await getApplicationDocumentsDirectory();
if (io.Platform.isIOS) {
appDocDirectory = await getApplicationDocumentsDirectory();
} else {
appDocDirectory = (await getExternalStorageDirectory())!;
}
// 可以添加扩展名如 ".mp4" ".wav" ".m4a" ".aac"
customPath = appDocDirectory.path +
customPath +
DateTime.now().millisecondsSinceEpoch.toString();
// .wav <---> AudioFormat.WAV
// .mp4 .m4a .aac <---> AudioFormat.AAC
// AudioFormat 是可选的,如果给定了值,将会覆盖路径扩展名。
_recorder =
FlutterVoiceRecorder(customPath, audioFormat: AudioFormat.WAV);
await _recorder!.initialized;
// 初始化后
var current = await _recorder!.current(channel: 0);
print(current);
// 应该是 "Initialized",如果一切正常
setState(() {
_current = current;
_currentStatus = current!.status!;
print(_currentStatus);
});
} else {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text("You must accept permissions")));
}
} catch (e) {
print(e);
}
}
_start() async {
try {
await _recorder!.start();
var recording = await _recorder!.current(channel: 0);
setState(() {
_current = recording;
});
const tick = Duration(milliseconds: 50);
Timer.periodic(tick, (Timer t) async {
if (_currentStatus == RecordingStatus.Stopped) {
t.cancel();
}
var current = await _recorder!.current(channel: 0);
// print(current.status);
setState(() {
_current = current;
_currentStatus = _current!.status!;
});
});
} catch (e) {
print(e);
}
}
_resume() async {
await _recorder!.resume();
setState(() {});
}
_pause() async {
await _recorder!.pause();
setState(() {});
}
_stop() async {
var result = await _recorder!.stop();
print("Stop recording: ${result!.path}");
print("Stop recording: ${result.duration}");
File file = widget.localFileSystem.file(result.path);
print("File length: ${await file.length()}");
setState(() {
_current = result;
_currentStatus = _current!.status!;
});
}
Widget _buildText(RecordingStatus status) {
var text = "";
switch (_currentStatus) {
case RecordingStatus.Initialized:
{
text = 'Start';
break;
}
case RecordingStatus.Recording:
{
text = 'Pause';
break;
}
case RecordingStatus.Paused:
{
text = 'Resume';
break;
}
case RecordingStatus.Stopped:
{
text = 'Init';
break;
}
default:
break;
}
return Text(text, style: const TextStyle(color: Colors.white));
}
void onPlayAudio() async {
AudioPlayer audioPlayer = AudioPlayer();
await audioPlayer.setSourceAsset(_current!.path.toString());
}
}
更多关于Flutter语音录制插件flutter_voice_recorder的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html