The RecorderPlaybackController widget provides a means to co-ordinate a SoundRecorderUI and SoundPlayerUI so that a user can record and playback via a single UI.
The RecorderPlaybackController is an InheritedWidget which allows the SoundRecorderUI and SoundPlayerUI to find and attach to it.
SoundRecorderUI and SoundPlayerUI widgets will automatically search for and attach to the nearest RecorderPlaybackController above them in the widget tree.
Due to the automated nature of the linkage you need to be careful where you place a RecorderPlaybackController in your widget tree to avoid unintentional connections. Keep the RecorderPlaybackController as close to the other two widgets as possible.
The RecorderPlaybackController MUST be above SoundPlayerUI and the SoundRecorderUI widgets in the Widget tree.
Example:
This example is from the example app. It demonstrates how to create a Recorder SoundRecorderUI linked to a SoundPlayerUI.
The example demonstrates how to build a UI which allows a user to record audio and then immediately play it back.
The example also uses requestPermissions to display an explanatory dialog to the user before the OS displays its standard permission dialog.
The RecorderPlaybackController is responsible for coordinating the recording and playback so that only one can occur at a time.
import'dart:async';import'dart:core';import'package:flutter/material.dart';import'package:sounds/sounds.dart';import'package:permission_handler/permission_handler.dart';voidmain() {var recordingPath =Track.tempFile(MediaFormat.aacADTS);runApp(SoundExampleApp._internal(recordingPath));}classSoundExampleAppextendsStatelessWidget {finalTrack _track;//SoundExampleApp._internal(String recordingPath): _track =Track.fromFile(recordingPath, mediaFormat:MediaFormat.aacADTS);@overrideWidgetbuild(BuildContext context) {returnMaterialApp( title:'Welcome to Flutter', home:Scaffold( appBar:AppBar( title:Text('Welcome to Flutter'), ), body:buildBody(), ), ); }WidgetbuildBody() {// link the recorder and player so you can record// and then playback the message.// Note: the recorder and player MUST share the same track.returnRecorderPlaybackController( child:Column( children: [/// Add the recorderSoundRecorderUI(/// the track to record into. _track,/// callback for when recording needs permissions requestPermissions: requestPermissions, ),Padding( padding:constEdgeInsets.all(10),// add the player child:SoundPlayerUI.fromTrack(_track), ) ], )); }/// Callback for when the recorder needs permissions to record /// to the [track].Future<bool> requestPermissions(BuildContext context, Track track) async {var granted =false;/// change this to true if the track doesn't use /// external storage on android.var usingExternalStorage =false;// Request Microphone permission if neededprint('storage: ${await Permission.microphone.status}');var microphoneRequired =!awaitPermission.microphone.isGranted;var storageRequired =false;if (usingExternalStorage) {/// only required if track is on external storageif (Permission.storage.status ==PermissionStatus.undetermined) {print('You are probably missing the storage permission ''in your manifest.'); } storageRequired = usingExternalStorage &&!awaitPermission.storage.isGranted; }/// build the 'reason' why and what we are asking permissions for.if (microphoneRequired || storageRequired) {var both =false;if (microphoneRequired && storageRequired) { both =true; }var reason ="To record a message we need permission ";if (microphoneRequired) { reason +="to access your microphone"; }if (both) { reason +=" and "; }if (storageRequired) { reason +="to store a file on your phone"; } reason +=".";if (both) { reason +=" \n\nWhen prompted click the 'Allow' button on ""each of the following prompts."; } else { reason +=" \n\nWhen prompted click the 'Allow' button."; }/// tell the user we are about to ask for permissions.if (awaitshowAlertDialog(context, reason)) {var permissions =<Permission>[];if (microphoneRequired) permissions.add(Permission.microphone);if (storageRequired) permissions.add(Permission.storage);/// ask for the permissions.await permissions.request();/// check the user gave us the permissions. granted =awaitPermission.microphone.isGranted &&awaitPermission.storage.isGranted;if (!granted) grantFailed(context); } else { granted =false;grantFailed(context); } } else { granted =true; }// we already have the required permissions.return granted; }/// Display a snackbar saying that we can't record due to lack of permissions.voidgrantFailed(BuildContext context) {var snackBar =SnackBar( content:Text('Recording cannot start as you did not allow ''the required permissions'));// Find the Scaffold in the widget tree and use it to show a SnackBar.Scaffold.of(context).showSnackBar(snackBar); }///Future<bool> showAlertDialog(BuildContext context, String prompt) {// set up the buttonsWidget cancelButton =TextButton( child:Text("Cancel"), onPressed: () =>Navigator.of(context).pop(false), );Widget continueButton =TextButton( child:Text("Continue"), onPressed: () =>Navigator.of(context).pop(true), );// set up the AlertDialogvar alert =AlertDialog( title:Text("Recording Permissions"), content:Text(prompt), actions: [ cancelButton, continueButton, ], );// show the dialogreturnshowDialog<bool>( context: context, builder: (context) {return alert; }, ); }}