# flutter_sound
This plugin provides simple recorder and player functionalities for both `android` and `ios` platforms. This only supports default file extension for each platform.
This plugin handles file from remote url.
This plugin can handle playback stream from native (To sync exact time with bridging).
## Free Read
[Medium Blog](https://medium.com/@dooboolab/flutter-sound-plugin-audio-recorder-player-e5a455a8beaf)
## Getting Started
For help getting started with Flutter, view our online
[documentation](https://flutter.io/).
## Install
Add ```flutter_sound``` as a dependency in pubspec.yaml
For help on adding as a dependency, view the [documentation](https://flutter.io/using-packages/).
## Post Installation
On *iOS* you need to add a usage description to `info.plist`:
```xml
NSMicrophoneUsageDescription
This sample uses the microphone to record your speech and convert it to text.
UIBackgroundModes
audio
```
On *Android* you need to add a permission to `AndroidManifest.xml`:
```xml
```
## Methods
| Func | Param | Return | Description |
| :------------ |:---------------:| :---------------:| :-----|
| setSubscriptionDuration | `double sec` | `String` message | Set subscription timer in seconds. Default is `0.01` if not using this method.|
| startRecorder | `String uri`, `int sampleRate`, `int numChannels` | `String` uri | Start recording. This will return uri used. |
| stopRecorder | | `String` message | Stop recording. |
| startPlayer | `String uri` | `String` message | Start playing. |
| stopPlayer | | `String` message | Stop playing. |
| pausePlayer | | `String` message | Pause playing. |
| resumePlayer | | `String` message | Resume playing. |
| seekToPlayer | `int milliSecs` position to goTo | `String` message | Seek audio to selected position in seconds. Parameter should be less than audio duration to correctly placed. |
## Subscriptions
| Subscription | Return | Description |
| :------------ |:---------------:| :---------------:|
| onRecorderStateChanged | `` | Able to listen to subscription when recorder starts. |
| onPlayerStateChanged | `` | Able to listen to subscription when player starts. |
## Default uri path
When uri path is not set during the `function call` in `startRecorder` or `startPlayer`, they are saved in below path depending on the platform.
+ Default path for android
* `sdcard/sound.aac`.
+ Default path for ios
* `sound.aac`.
## Usage
#### Creating instance.
In your view/page/dialog widget's State class, create an instance of FlutterSound.
```dart
FlutterSound flutterSound = new FlutterSound();
```
#### Starting recorder with listener.
```dart
Future result = await flutterSound.startRecorder(null);
result.then(path) {
print('startRecorder: $path');
_recorderSubscription = flutterSound.onRecorderStateChanged.listen((e) {
DateTime date = new DateTime.fromMillisecondsSinceEpoch(e.currentPosition.toInt());
String txt = DateFormat('mm:ss:SS', 'en_US').format(date);
});
}
```
If you want to take your own path specify it like below.
```
String path = await flutterSound.startRecorder(Platform.isIOS ? 'ios.aac' : 'android.aac');
```
#### Stop recorder
```dart
Future result = await flutterSound.stopRecorder();
result.then(value) {
print('stopRecorder: $value');
if (_recorderSubscription != null) {
_recorderSubscription.cancel();
_recorderSubscription = null;
}
}
```
You MUST ensure that the recorder has been stopped when your widget is detached from the ui.
Overload your widget's dispose() method to stop the recorder when your widget is disposed.
```dart
@override
void dispose() {
flutterSound.stopRecorder();
super.dispose();
}
```
#### Start player
To start playback of a recording call startPlayer.
You must wait for the return value to complete before attempting to add any listeners
to ensure that the player has fully initialised.
```dart
Future result = await flutterSound.startPlayer(null);
result.then(path) {
print('startPlayer: $path');
_playerSubscription = flutterSound.onPlayerStateChanged.listen((e) {
if (e != null) {
DateTime date = new DateTime.fromMillisecondsSinceEpoch(e.currentPosition.toInt());
String txt = DateFormat('mm:ss:SS', 'en_US').format(date);
this.setState(() {
this._isPlaying = true;
this._playerTxt = txt.substring(0, 8);
});
}
});
}
```
#### Stop player
```dart
Future result = await flutterSound.stopPlayer();
result.then(value) {
print('stopPlayer: $result');
if (_playerSubscription != null) {
_playerSubscription.cancel();
_playerSubscription = null;
}
}
```
You MUST ensure that the player has been stopped when your widget is detached from the ui.
Overload your widget's dispose() method to stop the player when your widget is disposed.
```dart
@override
void dispose() {
flutterSound.stopPlayer();
super.dispose();
}
```
#### Pause player
```dart
Future result = await flutterSound.pausePlayer();
```
#### Resume player
```dart
Future result = await flutterSound.resumePlayer();
```
#### Seek player
To seek to a new location the player must already be playing.
```dart
String Future = await flutterSound.seekToPlayer(miliSecs);
```
#### Setting subscription duration (Optional). 0.01 is default value when not set.
```dart
/// 0.01 is default
flutterSound.setSubscriptionDuration(0.01);
```
#### Setting volume.
```dart
/// 1.0 is default
/// Currently, volume can be changed when player is running. Try manage this right after player starts.
String path = await flutterSound.startPlayer(null);
await flutterSound.setVolume(0.1);
```
#### Using the amplitude meter
The amplitude meter allows displaying a basic representation of the input sound.
When enabled, it returns values ranging 0-120dB.
```dart
//// By default this option is disabled, you can enable it by calling
setDbLevelEnabled(true);
```
```dart
//// You can tweak the frequency of updates by calling this function (unit is seconds)
updateDbPeakProgress(0.8);
```
```dart
//// You need to subscribe in order to receive the value updates
_dbPeakSubscription = flutterSound.onRecorderDbPeakChanged.listen((value) {
setState(() {
this._dbLevel = value;
});
});
```
### TODO
- [ ] Seeking example in `Example` project
- [x] Volume Control
- [x] Sync timing for recorder callback handler
### DEBUG
When you face below error,
```
* What went wrong:
A problem occurred evaluating project ':app'.
> versionCode not found. Define flutter.versionCode in the local.properties file.
```
Please add below to your `example/android/local.properties` file.
```
flutter.versionName=1.0.0
flutter.versionCode=1
flutter.buildMode=debug
```
## Help Maintenance
I've been maintaining quite many repos these days and burning out slowly. If you could help me cheer up, buying me a cup of coffee will make my life really happy and get much energy out of it.
[![Paypal](https://www.paypalobjects.com/webstatic/mktg/Logo/pp-logo-100px.png)](https://paypal.me/dooboolab)