SoundRecorderUI

Overview

The SoundRecorderUI widget provide a simple UI for recording audio.
The audio is recorded to a Track.

permissions

When recording audio you need access to the devices microphone and possibly its storage.
Sounds does not manage permissions for you. You must ensure that the appropriate permissions are obtained.
The package permission_handler provides a convenient set of methods for manageing permissions.
When requesting permissions the OS will display a prompt to the user. I generally recommend that you only prompt the user for the required permissions at the point in time that they require them.
To allow you complete control over the timing of the permission request to the user you can provide a call back to the requestPermission argument which is called when the user clicks the 'record' button. Recording will not start until the callback completes.

onStart

The onStart method is called when recording starts.
1
Widget build(BuildContext context)
2
{
3
return SoundRecorderUI(track, onStart: () => print('recording started'))
4
}
Copied!

onStopped

The onStopped method is called when the recording stops.
1
Widget build(BuildContext context)
2
{
3
return SoundRecorderUI(track, onStop: () => print('recording stopped'))
4
}
Copied!

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.
1
import 'dart:async';
2
import 'dart:core';
3
​
4
import 'package:flutter/material.dart';
5
import 'package:sounds/sounds.dart';
6
import 'package:permission_handler/permission_handler.dart';
7
​
8
void main() {
9
var recordingPath = Track.tempFile(MediaFormat.aacADTS);
10
runApp(SoundExampleApp._internal(recordingPath));
11
}
12
​
13
class SoundExampleApp extends StatelessWidget {
14
final Track _track;
15
​
16
//
17
SoundExampleApp._internal(String recordingPath)
18
: _track = Track.fromFile(recordingPath, mediaFormat: MediaFormat.aacAdts);
19
​
20
@override
21
Widget build(BuildContext context) {
22
return MaterialApp(
23
title: 'Welcome to Flutter',
24
home: Scaffold(
25
appBar: AppBar(
26
title: Text('Welcome to Flutter'),
27
),
28
body: buildBody(),
29
),
30
);
31
}
32
​
33
Widget buildBody() {
34
// link the recorder and player so you can record
35
// and then playback the message.
36
// Note: the recorder and player MUST share the same track.
37
return RecorderPlaybackController(
38
child: Column(
39
children: [
40
/// Add the recorder
41
SoundRecorderUI(
42
/// the track to record into.
43
_track,
44
​
45
/// callback for when recording needs permissions
46
requestPermissions: requestPermissions,
47
),
48
Padding(
49
padding: const EdgeInsets.all(10),
50
// add the player
51
child: SoundPlayerUI.fromTrack(_track),
52
)
53
],
54
));
55
}
56
​
57
/// Callback for when the recorder needs permissions to record
58
/// to the [track].
59
Future<bool> requestPermissions(BuildContext context, Track track) async {
60
var granted = false;
61
​
62
/// change this to true if the track doesn't use
63
/// external storage on android.
64
var usingExternalStorage = false;
65
​
66
// Request Microphone permission if needed
67
print('storage: ${await Permission.microphone.status}');
68
var microphoneRequired = !await Permission.microphone.isGranted;
69
​
70
var storageRequired = false;
71
​
72
if (usingExternalStorage) {
73
/// only required if track is on external storage
74
if (Permission.storage.status == PermissionStatus.undetermined) {
75
print('You are probably missing the storage permission '
76
'in your manifest.');
77
}
78
​
79
storageRequired =
80
usingExternalStorage && !await Permission.storage.isGranted;
81
}
82
​
83
/// build the 'reason' why and what we are asking permissions for.
84
if (microphoneRequired || storageRequired) {
85
var both = false;
86
​
87
if (microphoneRequired && storageRequired) {
88
both = true;
89
}
90
​
91
var reason = "To record a message we need permission ";
92
​
93
if (microphoneRequired) {
94
reason += "to access your microphone";
95
}
96
​
97
if (both) {
98
reason += " and ";
99
}
100
​
101
if (storageRequired) {
102
reason += "to store a file on your phone";
103
}
104
​
105
reason += ".";
106
​
107
if (both) {
108
reason += " \n\nWhen prompted click the 'Allow' button on "
109
"each of the following prompts.";
110
} else {
111
reason += " \n\nWhen prompted click the 'Allow' button.";
112
}
113
​
114
/// tell the user we are about to ask for permissions.
115
if (await showAlertDialog(context, reason)) {
116
var permissions = <Permission>[];
117
if (microphoneRequired) permissions.add(Permission.microphone);
118
if (storageRequired) permissions.add(Permission.storage);
119
​
120
/// ask for the permissions.
121
await permissions.request();
122
​
123
/// check the user gave us the permissions.
124
granted = await Permission.microphone.isGranted &&
125
await Permission.storage.isGranted;
126
if (!granted) grantFailed(context);
127
} else {
128
granted = false;
129
grantFailed(context);
130
}
131
} else {
132
granted = true;
133
}
134
​
135
// we already have the required permissions.
136
return granted;
137
}
138
​
139
/// Display a snackbar saying that we can't record due to lack of permissions.
140
void grantFailed(BuildContext context) {
141
var snackBar = SnackBar(
142
content: Text('Recording cannot start as you did not allow '
143
'the required permissions'));
144
​
145
// Find the Scaffold in the widget tree and use it to show a SnackBar.
146
Scaffold.of(context).showSnackBar(snackBar);
147
}
148
​
149
///
150
Future<bool> showAlertDialog(BuildContext context, String prompt) {
151
// set up the buttons
152
Widget cancelButton = TextButton(
153
child: Text("Cancel"),
154
onPressed: () => Navigator.of(context).pop(false),
155
);
156
Widget continueButton = TextButton(
157
child: Text("Continue"),
158
onPressed: () => Navigator.of(context).pop(true),
159
);
160
​
161
// set up the AlertDialog
162
var alert = AlertDialog(
163
title: Text("Recording Permissions"),
164
content: Text(prompt),
165
actions: [
166
cancelButton,
167
continueButton,
168
],
169
);
170
​
171
// show the dialog
172
return showDialog<bool>(
173
context: context,
174
builder: (context) {
175
return alert;
176
},
177
);
178
}
179
}
Copied!
Last modified 7mo ago