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

Last updated Jul 24, 2021

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

android:requestLegacyExternalStorage="true"

 

 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

var recorder = FlutterAudioRecorder("file_path.mp4"); // .wav .aac .m4a
await recorder.initialized;

 

 

To Start the Recording

await recorder.start();
var recording = await recorder.current(channel: 0);

 

 

Save the Recorded Audio file

Once we done with our recording, we just stop the recording by

var result = await recorder.stop();

 

 

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(() {});
  });
});

 

Audio recording Flutter

 

 

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.

 

 

Related Tutorials & Resources