Flutter音频录制插件system_audio_recorder的使用
system_audio_recorder是一个简单的 Flutter 插件,用于录制 Android 系统播放的音频。
功能
requestRecord
此函数用于请求系统权限以录制播放的音频。调用此函数时,系统会显示提示。点击“允许”返回 true
,点击“拒绝”返回 false
。(虽然此函数可以接受参数,但无需传递任何参数)
startRecord
调用此函数开始录制系统播放的音频。在调用此函数之前,必须先调用 requestRecord
请求权限。目前仅支持 PCM16 编码。
参数名 | 类型 | 描述 | 默认值 |
---|---|---|---|
sampleRate | int | 采样率 | 16000 |
bufferSize | int | 缓冲区大小(字节数) | 640 |
toStream | bool | 是否将录制的音频作为流接收 | true |
toFile | bool | 是否将录制的音频保存到文件中 | false |
filePath | String | 录制音频保存的文件路径 | null |
stopRecord
此函数用于停止录制。如果 toFile
为 true
,它返回文件路径;否则返回 ""
示例
权限配置
在 android/app/src/main/AndroidManifest.xml
中添加以下权限:
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application
...
>
<!-- 添加服务开始 -->
<service
android:name="com.foregroundservice.ForegroundService"
android:foregroundServiceType="mediaProjection">
</service>
<!-- 添加服务结束 -->
...
</application>
...
<!-- 添加权限开始 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_INTERNAL_STORAGE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION" />
<!-- 添加权限结束 -->
</manifest>
开始录制
bool isConfirmed = await SystemAudioRecorder.requestRecord(
titleNotification: "titleNotification",
messageNotification: "messageNotification",
);
bool toStream = true;
bool toFile = true;
String? path; // path can not be null when toFile is true
if (isConfirmed) {
audioData.clear();
if (toFile){ // 如果录制到文件,获取文件路径
var tempDir = await getExternalStorageDirectory();
path = '${tempDir?.parent.path}/record.mp3';
var outputFile = File(path);
if (outputFile.existsSync()) {
await outputFile.delete();
}
}
bool isStart = await SystemAudioRecorder.startRecord(toStream: toStream, toFile: toFile, filePath: path);
if (toStream){ // 如果录制到流,设置流监听器
_audioSubscription ??=
SystemAudioRecorder.audioStream.receiveBroadcastStream({}).listen((data) {
audioData.addAll(List<int>.from(data)); // data.length = bufferSize * 2
});
}
}
停止录制
String path = await SystemAudioRecorder.stopRecord();
if (_audioSubscription != null) { // 如果录制到流,停止时取消订阅
_audioSubscription?.cancel();
_audioSubscription = null;
}
完整示例代码
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'dart:async';
import 'package:flutter/services.dart';
import 'package:system_audio_recorder/system_audio_recorder.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:flutter_sound/flutter_sound.dart';
import 'package:path_provider/path_provider.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
[@override](/user/override)
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String _platformVersion = 'Unknown';
final _systemAudioRecorderPlugin = SystemAudioRecorder();
StreamSubscription? _audioSubscription;
List<int> audioData = List.empty(growable: true);
Uint8List? udata;
FlutterSoundPlayer player = FlutterSoundPlayer();
requestPermissions() async {
if (!kIsWeb) {
if (await Permission.storage.request().isDenied) {
await Permission.storage.request();
}
}
}
[@override](/user/override)
void initState() {
super.initState();
requestPermissions();
initPlatformState();
}
// 平台消息异步初始化
Future<void> initPlatformState() async {
String platformVersion;
// 平台消息可能失败,因此使用 try/catch 捕获 PlatformException。
// 我们还处理消息可能返回 null 的情况。
try {
platformVersion = await _systemAudioRecorderPlugin.getPlatformVersion() ?? 'Unknown platform version';
} on PlatformException {
platformVersion = 'Failed to get platform version.';
}
// 如果小部件从树中移除时异步平台消息仍在飞行中,则我们希望丢弃回复而不是调用
// setState 来更新我们的非存在的外观。
if (!mounted) return;
setState(() {
_platformVersion = platformVersion;
});
}
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Plugin example app'),
),
body: Column(children: [
Text('Running on: $_platformVersion\n'),
TextButton(
onPressed: () async {
bool isConfirmed = await SystemAudioRecorder.requestRecord(
titleNotification: "titleNotification",
messageNotification: "messageNotification",
);
bool toStream = true;
bool toFile = true;
String? path; // path can not be null when toFile is true
if (isConfirmed) {
audioData.clear();
if (toFile){
var tempDir = await getExternalStorageDirectory();
path = '${tempDir?.parent.path}/record.mp3';
var outputFile = File(path);
if (outputFile.existsSync()) {
await outputFile.delete();
}
}
bool isStart = await SystemAudioRecorder.startRecord(toStream: toStream, toFile: toFile, filePath: path);
if (toStream){
_audioSubscription ??=
SystemAudioRecorder.audioStream.receiveBroadcastStream({}).listen((data) {
audioData.addAll(List<int>.from(data));
});
}
}
},
child: const Text("开始录制")),
TextButton(
onPressed: () async {
String path = await SystemAudioRecorder.stopRecord();
if (_audioSubscription != null) {
_audioSubscription?.cancel();
_audioSubscription = null;
}
if(path != "") print(path);
},
child: const Text("停止录制")),
TextButton(onPressed: () async {
udata = Uint8List.fromList(audioData);
await player.openPlayer();
await player.startPlayerFromStream(codec: Codec.pcm16, numChannels: 1, sampleRate: 16000);
await player.feedFromStream(udata!);
await player.stopPlayer();
}, child: const Text("开始播放"))
]),
),
);
}
}
更多关于Flutter音频录制插件system_audio_recorder的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
1 回复