Flutter Audio Recording Example

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.

 

 


Article Contributed By :
https://www.rrtutors.com/site_assets/profile/assets/img/avataaars.svg

8063 Views

Subscribe For Daily Updates

Flutter Questions
Android Questions