Flutter Audio Recording Example
Flutter Audio Recording application. Record auido files and save it on device. Fetch all recording from the files folder. Share audio recoridngs with facebook, instagram, email, updated with null safety
In this post we are going to create Flutter Audio Recording application. To record audio we create a class and to play audio file we used audioplayers plugin. We have updated all plugins to null safety
In this example we will cover
- Record Audio
- Save the Recorded Audio file
- Fetch and Display all Recodrings
- Share the recodrings with other applcations
Step 1: Create a Flutter application
Step 2: Add required dependencies
In this Audio recording app we were used below dependencies
rflutter_alert: ^2.0.2
audioplayers: ^0.19.1
path_provider: ^2.0.2
fluttertoast: ^8.0.7
share: ^2.0.4
permission_handler: ^8.1.4+1
|
Step 3: Import flutter_audio_recorder into dart file by
import 'package:flutter_audio_recorder/flutter_audio_recorder.dart';
Step 4: To work with Audio recording feature we need to grant permissions
In Android Manifest file add below permissions
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
To Read External storage permission in Android 10 we need to add
|
under application tag
This Audio recording plugin support below types
AAC | .m4a .aac .mp4 |
WAV | .wav |
Record Audio
To Record Audio we need to create FlutterAudioRecorder instance
|
To Start the Recording
|
Save the Recorded Audio file
Once we done with our recording, we just stop the recording by
|
This result object will return file path what we given on the initializing the FlutterAudioRecord object
"file_path.mp4"
Fetch and Display all Recordings
To fetch the saved recordings we need to pass out file directory path to Directory class .
This will return list of files inside the folder
getExternalStorageDirectory().then((value) {
appDir = value.;
Directory appDirec = Directory("${appDir.path}/Audiorecords/");
appDir = appDirec;
appDir.list().listen((onData) {
records.add(onData.path);
}).onDone(() {
records = records.reversed.toList();
setState(() {});
});
});
|
Share Audio
To share any file or text we used share: ^0.6.5+4 plugin.To share particular audio recording we need to pass its path to
Share.shareFiles(list)
This Share Files will take the List of file paths as parameter.
Directory appDirec =
Directory(widget.records.elementAt(i));
List<String>list=List();
list.add(appDirec.path);
Share.shareFiles(list);
|
Complete Example of Audio Recording Application
home.dart file
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';
import 'list.dart';
import 'view.dart';
class HomePage extends StatefulWidget {
final String _appTitle;
const HomePage({Key? key, required String title})
: assert(title != null),
_appTitle = title,
super(key: key);
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
late Directory? appDir;
late List<String>? records;
@override
void initState() {
super.initState();
records = [];
getExternalStorageDirectory().then((value) {
appDir = value!;
Directory appDirec = Directory("${appDir!.path}/Audiorecords/");
appDir = appDirec;
appDir!.list().listen((onData) {
records!.add(onData.path);
}).onDone(() {
records = records!.reversed.toList();
setState(() {});
});
});
}
@override
void dispose() {
appDir = null;
records = null;
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FloatingActionButton(
onPressed: (){},
child: InkWell(child: Icon(Icons.mic),onTap: (){
show(context);},),
),
appBar: AppBar(
title: Text(
widget._appTitle,
style: TextStyle(color: Colors.white),
),
centerTitle: true,
),
body: Column(
children: [
Expanded(
flex: 2,
child: Records(
records: records!,
),
),
],
),
);
}
_onFinish() {
records!.clear();
print(records!.length.toString());
appDir!.list().listen((onData) {
records!.add(onData.path);
}).onDone(() {
records!.sort();
records = records!.reversed.toList();
setState(() {});
});
}
void show(BuildContext context) {
showModalBottomSheet<void>(
context: context,
builder: (BuildContext context) {
return Container(
height: 200,
color: Colors.white70,
child: Recorder(
save: _onFinish,
),
);
},
);
}
}
|
list.dart file
import 'dart:io';
import 'package:audioplayers/audioplayers.dart';
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:share/share.dart';
class Records extends StatefulWidget {
final List<String> records;
const Records({
Key? key,
required this.records,
}) : super(key: key);
@override
_RecordsState createState() => _RecordsState();
}
class _RecordsState extends State<Records> {
late int _totalTime;
late int _currentTime;
double _percent = 0.0;
int _selected = -1;
bool isPlay=false;
AudioPlayer advancedPlayer = AudioPlayer();
@override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: widget.records.length,
shrinkWrap: true,
reverse: true,
itemBuilder: (BuildContext context, int i) {
return Card(
elevation: 5,
child: ExpansionTile(
title: Text(
'Record ${widget.records.length - i}',
style: TextStyle(color: Colors.black),
),
subtitle: Text(
_getTime(filePath: widget.records.elementAt(i)!),
style: TextStyle(color: Colors.black38),
),
onExpansionChanged: ((newState) {
if (newState) {
setState(() {
_selected = i;
});
}
}),
children: [
Container(
height: 100,
padding: const EdgeInsets.all(10),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
LinearProgressIndicator(
minHeight: 5,
backgroundColor: Colors.black,
valueColor: AlwaysStoppedAnimation<Color>(Colors.green),
value: _selected == i ? _percent : 0,
),
Row(
children: [
(isPlay)? _Presso(
ico: Icons.pause,
onPressed: () {
setState(() {
isPlay=false;
});
advancedPlayer.pause();
}): _Presso(
ico: Icons.play_arrow,
onPressed: () {
setState(() {
isPlay=true;
});
advancedPlayer.play(widget.records.elementAt(i),
isLocal: true);
setState(() {});
setState(() {
_selected = i;
_percent = 0.0;
});
advancedPlayer.onPlayerCompletion.listen((_) {
setState(() {
_percent = 0.0;
});
});
advancedPlayer.onDurationChanged.listen((duration) {
setState(() {
_totalTime = duration.inMicroseconds;
});
});
advancedPlayer.onAudioPositionChanged
.listen((duration) {
setState(() {
_currentTime = duration.inMicroseconds;
_percent = _currentTime.toDouble() /
_totalTime.toDouble();
});
});
}),
_Presso(
ico: Icons.stop,
onPressed: () {
advancedPlayer.stop();
setState(() {
_percent = 0.0;
});
}),
_Presso(
ico: Icons.delete,
onPressed: () {
Directory appDirec =
Directory(widget.records.elementAt(i));
appDirec.delete(recursive: true);
Fluttertoast.showToast(msg: "File Deleted");
setState(() {
widget.records
.remove(widget.records.elementAt(i));
});
}),
_Presso(
ico: Icons.share,
onPressed: () {
Directory appDirec =
Directory(widget.records.elementAt(i));
List<String>list=List.empty(growable: true);
list.add(appDirec.path);
Share.shareFiles(list);
}),
],
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
),
],
),
),
],
),
);
},
);
}
String _getTime({required String filePath}) {
String fromPath = filePath.substring(
filePath.lastIndexOf('/') + 1, filePath.lastIndexOf('.'));
if (fromPath.startsWith("1", 0)) {
DateTime dateTime =
DateTime.fromMillisecondsSinceEpoch(int.parse(fromPath));
int year = dateTime.year;
int month = dateTime.month;
int day = dateTime.day;
int hour = dateTime.hour;
int min = dateTime.minute;
String dato = '$year-$month-$day--$hour:$min';
return dato;
} else {
return "No Date";
}
}
}
class _Presso extends StatelessWidget {
final IconData ico;
final VoidCallback onPressed;
const _Presso({Key? key, required this.ico,required this.onPressed}) : super(key: key);
@override
Widget build(BuildContext context) {
return ButtonTheme(
minWidth: 48.0,
child: RaisedButton(
child: Icon(
ico,
color: Colors.white,
),
onPressed: onPressed),
);
}
}
|
view.dart file
import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart';
import 'audio_recorder.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:path_provider/path_provider.dart';
import 'package:permission_handler/permission_handler.dart';
class Recorder extends StatefulWidget {
final Function save;
const Recorder({Key? key, required this.save}) : super(key: key);
@override
_RecorderState createState() => _RecorderState();
}
class _RecorderState extends State<Recorder> {
IconData _recordIcon = Icons.mic_none;
MaterialColor colo = Colors.orange;
RecordingStatus _currentStatus = RecordingStatus.Unset;
bool stop = false;
Recording? _current;
// Recorder properties
late FlutterAudioRecorder? audioRecorder;
@override
void initState() {
super.initState();
checkPermission();
}
checkPermission()async{
if (await Permission.contacts.request().isGranted) {
// Either the permission was already granted before or the user just granted it.
}
// You can request multiple permissions at once.
Map<Permission, PermissionStatus> statuses = await [
Permission.microphone,
Permission.storage,
].request();
print(statuses[Permission.microphone]);
print(statuses[Permission.storage]);
//bool hasPermission = await FlutterAudioRecorder.hasPermissions ?? false;
if (statuses[Permission.microphone]==PermissionStatus.granted) {
_currentStatus = RecordingStatus.Initialized;
_recordIcon = Icons.mic;
}else
{
}
}
@override
void dispose() {
_currentStatus = RecordingStatus.Unset;
audioRecorder = null;
super.dispose();
}
@override
Widget build(BuildContext context) {
return Stack(
alignment: Alignment.center,
children: [
Column(
children: [
SizedBox(height: 20,),
Text(
(_current==null)?"0:0:0:0":_current!.duration.toString() ?? "0:0:0:0",
style: TextStyle(color: Colors.black, fontSize: 20),
),
SizedBox(height: 20,),
stop == false
? RaisedButton(
color: Colors.orange,
onPressed: () async {
await _onRecordButtonPressed();
setState(() {});
},
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
child: Column(
children: [
Container(
width: 80,
height: 80,
child: Icon(
_recordIcon,
color: Colors.white,
size: 80,
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text("Write Dailry",style: TextStyle(color: Colors.white),),
)
],
),
)
: Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
RaisedButton(
color: colo,
onPressed: () async {
await _onRecordButtonPressed();
setState(() {});
},
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
child: Container(
width: 80,
height: 80,
child: Icon(
_recordIcon,
color: Colors.white,
size: 50,
),
),
),
RaisedButton(
color: Colors.orange,
onPressed: _currentStatus != RecordingStatus.Unset
? _stop
: null,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
child: Container(
width: 80,
height: 80,
child: Icon(
Icons.stop,
color: Colors.white,
size: 50,
),
),
),
],
),
),
],
),
],
);
}
Future<void> _onRecordButtonPressed() async {
switch (_currentStatus) {
case RecordingStatus.Initialized:
{
_recordo();
break;
}
case RecordingStatus.Recording:
{
_pause();
break;
}
case RecordingStatus.Paused:
{
_resume();
break;
}
case RecordingStatus.Stopped:
{
_recordo();
break;
}
default:
break;
}
}
_initial() async {
Directory? appDir = await getExternalStorageDirectory();
String jrecord = 'Audiorecords';
String dato = "${DateTime.now()!.millisecondsSinceEpoch?.toString()}.wav";
Directory appDirec =
Directory("${appDir!.path}/$jrecord/");
if (await appDirec.exists()) {
String patho = "${appDirec.path}$dato";
print("path for file11 ${patho}");
audioRecorder = FlutterAudioRecorder(patho, audioFormat: AudioFormat.WAV);
await audioRecorder!.initialized;
} else {
appDirec.create(recursive: true);
Fluttertoast.showToast(msg: "Start Recording , Press Start");
String patho = "${appDirec.path}$dato";
print("path for file22 ${patho}");
audioRecorder = FlutterAudioRecorder(patho, audioFormat: AudioFormat.WAV);
await audioRecorder!.initialized;
}
}
_start() async {
await audioRecorder!.start();
var recording = await audioRecorder!.current(channel: 0);
setState(() {
_current = recording!;
});
const tick = const Duration(milliseconds: 50);
new Timer.periodic(tick, (Timer t) async {
if (_currentStatus == RecordingStatus.Stopped) {
t.cancel();
}
var current = await audioRecorder!.current(channel: 0);
// print(current.status);
setState(() {
_current = current!;
_currentStatus = _current!.status!;
});
});
}
_resume() async {
await audioRecorder!.resume();
Fluttertoast.showToast(msg: "Resume Recording");
setState(() {
_recordIcon = Icons.pause;
colo = Colors.red;
});
}
_pause() async {
await audioRecorder!.pause();
Fluttertoast.showToast(msg: "Pause Recording");
setState(() {
_recordIcon = Icons.mic;
colo = Colors.green;
});
}
_stop() async {
var result = await audioRecorder!.stop();
Fluttertoast.showToast(msg: "Stop Recording , File Saved");
widget.save();
setState(() {
_current = result!;
_currentStatus = _current!.status!;
_current!.duration = null;
_recordIcon = Icons.mic;
stop = false;
});
}
Future<void> _recordo() async {
Map<Permission, PermissionStatus> statuses = await [
Permission.microphone,
Permission.storage,
].request();
print(statuses[Permission.microphone]);
print(statuses[Permission.storage]);
//bool hasPermission = await FlutterAudioRecorder.hasPermissions ?? false;
if (statuses[Permission.microphone]==PermissionStatus.granted) {
/* }
bool hasPermission = await FlutterAudioRecorder.hasPermissions ?? false;
if (hasPermission) {*/
await _initial();
await _start();
Fluttertoast.showToast(msg: "Start Recording");
setState(() {
_currentStatus = RecordingStatus.Recording;
_recordIcon = Icons.pause;
colo = Colors.red;
stop = true;
});
} else {
Fluttertoast.showToast(msg: "Allow App To Use Mic");
}
}
}
|
main.dart file
import 'package:flutter/material.dart';
import 'package:flutter_audio_record/home.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.pink,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: HomePage(
title: 'Recordings',
),
);
}
}
|
Conclusion: In this Audio recording application we cover how to record audio file in flutter and also learned share files from flutter application.