官方介绍:这个插件为android和ios平台提供了简单的记录器和播放器功能。这只支持每个平台的默认文件扩展名。这个插件处理来自远程url的文件。这个插件可以处理本地播放流(通过桥接来同步准确的时间)。
插件网址:https://pub.dev/packages/flutter_sound
在pubspec.yaml
添加依赖
dependencies:
...
flutter_sound: ^1.1.5
接着在控制台运行flutter packages get
获取依赖,最重要一点需要在AndroidManifest.xml
文件中添加,权限请求
期间出现的插件,请自行安装,方法同上
import 'package:flutter/material.dart';
import 'package:intl/intl.dart' show DateFormat;
import 'package:intl/date_symbol_data_local.dart';
import 'dart:io';
import 'dart:async';
import 'package:flutter_sound/flutter_sound.dart';
import 'package:flutter_sound/android_encoder.dart';
import 'dart:convert';
class RecorderPage extends StatelessWidget {
const RecorderPage({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("音频录制页面"),
),
body: RecorderContent(),
);
}
}
class RecorderContent extends StatefulWidget {
RecorderContent({Key key}) : super(key: key);
_RecorderContentState createState() => _RecorderContentState();
}
class _RecorderContentState extends State {
bool _isRecording = false;
bool _isPlaying = false;
StreamSubscription _recorderSubscription;
StreamSubscription _dbPeakSubscription;
StreamSubscription _playerSubscription;
FlutterSound flutterSound;
String _recorderTxt = '00:00:00';
String _playerTxt = '00:00:00';
double _dbLevel;
double slider_current_position = 0.0;
double max_duration = 1.0;
@override
void initState() {
super.initState();
flutterSound = new FlutterSound();
flutterSound.setSubscriptionDuration(0.01);
flutterSound.setDbPeakLevelUpdate(0.8);
flutterSound.setDbLevelEnabled(true);
initializeDateFormatting();
}
void startRecorder() async {
try {
String path = await flutterSound.startRecorder(null);
print("数据$path");
_recorderSubscription = flutterSound.onRecorderStateChanged.listen((e) {
DateTime date = new DateTime.fromMillisecondsSinceEpoch(
e.currentPosition.toInt(),
isUtc: true);
// print("时长$date");
String txt = DateFormat('mm:ss:SS', 'en_GB').format(date);
this.setState(() {
this._recorderTxt = txt.substring(0, 8);
});
});
// _dbPeakSubscription =
// flutterSound.onRecorderDbPeakChanged.listen((value) {
// print("got update -> $value");
// setState(() {
// this._dbLevel = value;
// });
// });
this.setState(() {
this._isRecording = true;
});
} catch (err) {
print('startRecorder error: $err');
}
}
void stopRecorder() async {
try {
String result = await flutterSound.stopRecorder();
print('停止录音返回结果: $result');
if (_recorderSubscription != null) {
_recorderSubscription.cancel();
_recorderSubscription = null;
}
if (_dbPeakSubscription != null) {
_dbPeakSubscription.cancel();
_dbPeakSubscription = null;
}
this.setState(() {
this._isRecording = false;
});
} catch (err) {
print('stopRecorder error: $err');
}
}
void startPlayer() async {
String path = await flutterSound.startPlayer(null);
File file= await new File(path);
List contents = await file.readAsBytesSync();
// return print("file文件:$contents");
await flutterSound.setVolume(1.0);
print('startPlayer: $path');
try {
_playerSubscription = flutterSound.onPlayerStateChanged.listen((e) {
if (e != null) {
slider_current_position = e.currentPosition;
max_duration = e.duration;
DateTime date = new DateTime.fromMillisecondsSinceEpoch(
e.currentPosition.toInt(),
isUtc: true);
String txt = DateFormat('mm:ss:SS', 'en_GB').format(date);
this.setState(() {
this._isPlaying = true;
this._playerTxt = txt.substring(0, 8);
});
}
});
} catch (err) {
print('error: $err');
}
}
void stopPlayer() async {
try {
String result = await flutterSound.stopPlayer();
print('stopPlayer: $result');
if (_playerSubscription != null) {
_playerSubscription.cancel();
_playerSubscription = null;
}
this.setState(() {
this._isPlaying = false;
});
} catch (err) {
print('error: $err');
}
}
void pausePlayer() async {
String result = await flutterSound.pausePlayer();
print('pausePlayer: $result');
}
void resumePlayer() async {
String result = await flutterSound.resumePlayer();
print('resumePlayer: $result');
}
void seekToPlayer(int milliSecs) async {
String result = await flutterSound.seekToPlayer(milliSecs);
print('seekToPlayer: $result');
}
@override
Widget build(BuildContext context) {
return Container(
child: ListView(
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
margin: EdgeInsets.only(top: 24.0, bottom: 16.0),
child: Text(
this._recorderTxt,
style: TextStyle(
fontSize: 48.0,
color: Colors.black,
),
),
),
_isRecording
? LinearProgressIndicator(
value: 100.0 / 160.0 * (this._dbLevel ?? 1) / 100,
valueColor: AlwaysStoppedAnimation(Colors.green),
backgroundColor: Colors.red,
)
: Container()
],
),
Row(
children: [
Container(
width: 56.0,
height: 56.0,
child: ClipOval(
child: FlatButton(
onPressed: () {
if (!this._isRecording) {
return this.startRecorder();
}
this.stopRecorder();
},
padding: EdgeInsets.all(8.0),
child: this._isRecording ? Text("停止") : Text("开始录音")),
),
),
],
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
),
Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
margin: EdgeInsets.only(top: 60.0, bottom: 16.0),
child: Text(
this._playerTxt,
style: TextStyle(
fontSize: 48.0,
color: Colors.black,
),
),
),
],
),
Row(
children: [
Container(
width: 56.0,
height: 56.0,
child: ClipOval(
child: FlatButton(
onPressed: () {
startPlayer();
},
padding: EdgeInsets.all(8.0),
child: Text("开始"),
),
),
),
Container(
width: 56.0,
height: 56.0,
child: ClipOval(
child: FlatButton(
onPressed: () {
pausePlayer();
},
padding: EdgeInsets.all(8.0),
child: Text("暂停"),
),
),
),
Container(
width: 56.0,
height: 56.0,
child: ClipOval(
child: FlatButton(
onPressed: () {
stopPlayer();
},
padding: EdgeInsets.all(8.0),
child: Text("停止"),
),
),
),
],
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
),
Container(
height: 56.0,
child: Slider(
value: slider_current_position,
min: 0.0,
max: max_duration,
onChanged: (double value) async {
await flutterSound.seekToPlayer(value.toInt());
},
divisions: max_duration.toInt()))
],
));
}
}
在出现这个问题的时候,经过一系列的排查,这行代码出现的问题
void startRecorder() async {
try {
String path = await flutterSound.startRecorder(null);
print("数据$path");
_recorderSubscription = flutterSound.onRecorderStateChanged.listen((e) {
DateTime date = new DateTime.fromMillisecondsSinceEpoch(
e.currentPosition.toInt(),
isUtc: true);
// print("时长$date");
String txt = DateFormat('mm:ss:SS', 'en_GB').format(date);
this.setState(() {
this._recorderTxt = txt.substring(0, 8);
});
});
// _dbPeakSubscription =
// flutterSound.onRecorderDbPeakChanged.listen((value) {
// print("got update -> $value");
// setState(() {
// this._dbLevel = value;
// });
// });
this.setState(() {
this._isRecording = true;
});
} catch (err) {
print('startRecorder error: $err');
}
}
通过查看它的的参数源码
Future startRecorder(String uri,
{int sampleRate = 44100, int numChannels = 2, int bitRate,
AndroidEncoder androidEncoder = AndroidEncoder.AAC,
IosQuality iosQuality = IosQuality.LOW
}) async {
try {
...
有一个bitRate的参数,这个要设置,会改变这个录制的音质
我的这个加的320000
String path = await flutterSound.startRecorder(null,bitRate:320000);