Skip to content

Commit c7e8d06

Browse files
✨ Added recordedDuration to get recorded duration for ios and added onRecordingEnded stream
1 parent 06f327e commit c7e8d06

File tree

5 files changed

+52
-14
lines changed

5 files changed

+52
-14
lines changed

CHANGELOG.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
## 1.0.2 (Unreleased)
1+
## 1.0.2
22

33
- Now, calling `stopAllPlayers` is not mandatory for disposing streams and it will also not dispose controller. With last remaining player they will be disposed (Streams can be re-initialised by creating a new PlayerController).
44
- Added legacy normalization with this fixed [#144](https://github.com/SimformSolutionsPvtLtd/audio_waveforms/issues/144).
55
- Added `onRecorderStateChanged` stream to monitor Recorder state changes.
6-
- Added `onCurrentDuration` stream to get latest recorded audio duration
6+
- Added `onCurrentDuration` stream to get latest recorded audio duration.
7+
- Added `onRecordingEnded` stream to get recorded audio file duration. Fixes [#157](https://github.com/SimformSolutionsPvtLtd/audio_waveforms/issues/157).
78

89
## 1.0.1
910

README.md

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -60,12 +60,13 @@ import 'package:audio_waveforms/audio_waveforms.dart';
6060
### Usage
6161
1. Recording audio
6262
```dart
63-
RecorderController controller = RecorderController(); // Initialise
64-
await controller.record(path: 'path'); // Record (path is optional)
65-
await controller.pause(); // Pause recording
66-
final path = await controller.stop(); // Stop recording and get the path
67-
controller.refresh(); // Refresh waveform to original position
68-
controller.dispose(); // Dispose controller
63+
RecorderController controller = RecorderController(); // Initialise
64+
await controller.record(path: 'path'); // Record (path is optional)
65+
final hasPermission = await controller.checkPermission(); // Check mic permission (also called duration record)
66+
await controller.pause(); // Pause recording
67+
final path = await controller.stop(); // Stop recording and get the path
68+
controller.refresh(); // Refresh waveform to original position
69+
controller.dispose(); // Dispose controller
6970
```
7071

7172
2. Use `AudioWaveforms` widget in widget tree
@@ -101,6 +102,7 @@ controller.sampleRate = 44100; // Updating sam
101102
controller.bitRate = 48000; // Updating bitrate
102103
controller.onRecorderStateChanged.listen((state){}); // Listening to recorder state changes
103104
controller.onCurrentDuration.listen((duration){}); // Listening to current duration updates
105+
controller.onRecordingEnded.listen((duration)); // Listening to audio file duration
104106
controller.recordedDuration; // Get recorded audio duration
105107
controller.currentScrolledDuration; // Current duration position notifier
106108
```

ios/Classes/AudioRecorder.swift

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ public class AudioRecorder: NSObject, AVAudioRecorderDelegate{
66
var path: String?
77
var hasPermission: Bool = false
88
var useLegacyNormalization: Bool = false
9+
var audioUrl: URL?
10+
var recordedDuration: CMTime = CMTime.zero
911

1012
public func startRecording(_ result: @escaping FlutterResult,_ path: String?,_ encoder : Int?,_ sampleRate : Int?,_ bitRate : Int?,_ fileNameFormat: String, _ useLegacy: Bool?){
1113
useLegacyNormalization = useLegacy ?? false
@@ -41,21 +43,44 @@ public class AudioRecorder: NSObject, AVAudioRecorderDelegate{
4143
try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playAndRecord, options: options)
4244
try AVAudioSession.sharedInstance().setActive(true)
4345

44-
let url = URL(string: self.path!) ?? URL(fileURLWithPath: self.path!)
45-
audioRecorder = try AVAudioRecorder(url: url, settings: bitRate != nil ? settingsWithBitrate as [String : Any] : settings as [String : Any])
46+
audioUrl = URL(fileURLWithPath: self.path!)
47+
48+
if(audioUrl == nil){
49+
result(FlutterError(code: Constants.audioWaveforms, message: "Failed to initialise file URL", details: nil))
50+
}
51+
audioRecorder = try AVAudioRecorder(url: audioUrl!, settings: bitRate != nil ? settingsWithBitrate as [String : Any] : settings as [String : Any])
52+
4653
audioRecorder?.delegate = self
4754
audioRecorder?.isMeteringEnabled = true
4855
audioRecorder?.record()
4956
result(true)
5057
} catch {
51-
result(FlutterError(code: "", message: "Failed to start recording", details: nil))
58+
result(FlutterError(code: Constants.audioWaveforms, message: "Failed to start recording", details: nil))
5259
}
5360
}
5461

5562
public func stopRecording(_ result: @escaping FlutterResult) {
5663
audioRecorder?.stop()
64+
if(audioUrl != nil) {
65+
let asset = AVURLAsset(url: audioUrl!)
66+
if #available(iOS 15.0, *) {
67+
Task {
68+
do {
69+
recordedDuration = try await asset.load(.duration)
70+
result([path,Int(recordedDuration.seconds * 1000).description])
71+
} catch let err {
72+
debugPrint(err.localizedDescription)
73+
result([path,CMTime.zero.seconds.description])
74+
}
75+
}
76+
} else {
77+
recordedDuration = asset.duration
78+
result([path,Int(recordedDuration.seconds * 1000).description])
79+
}
80+
} else {
81+
result([path,CMTime.zero.seconds.description])
82+
}
5783
audioRecorder = nil
58-
result(path)
5984
}
6085

6186
public func pauseRecording(_ result: @escaping FlutterResult) {

lib/src/audio_file_waveforms.dart

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,7 @@ class AudioFileWaveforms extends StatefulWidget {
6565
/// Generate waveforms from audio file. You play those audio file using
6666
/// [PlayerController].
6767
///
68-
/// When you play the audio file, another waveform
69-
/// will drawn on top of it to show
68+
/// When you play the audio file, waves change their color according to
7069
/// how much audio has been played and how much is left.
7170
///
7271
/// With seeking gesture enabled, playing audio can be seeked to

lib/src/controllers/recorder_controller.dart

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,11 +96,20 @@ class RecorderController extends ChangeNotifier {
9696
final StreamController<RecorderState> _recorderStateController =
9797
StreamController.broadcast();
9898

99+
final StreamController<Duration> _recordedFileDurationController =
100+
StreamController.broadcast();
101+
99102
/// A Stream to monitor change in RecorderState. Events are emitted whenever
100103
/// there is change in the RecorderState.
101104
Stream<RecorderState> get onRecorderStateChanged =>
102105
_recorderStateController.stream;
103106

107+
/// A stream to get duration of recording when audio recorder has
108+
/// been stopped. Events are only emitted if platform could extract the
109+
/// duration of audio file when recording is ended.
110+
Stream<Duration> get onRecordingEnded =>
111+
_recordedFileDurationController.stream;
112+
104113
/// A class having controls for recording audio and other useful handlers.
105114
///
106115
/// Use [useLegacyNormalization] parameter to use normalization before
@@ -281,6 +290,7 @@ class RecorderController extends ChangeNotifier {
281290
var duration = int.tryParse(audioInfo[1]!);
282291
if (duration != null) {
283292
recordedDuration = Duration(milliseconds: duration);
293+
_recordedFileDurationController.add(recordedDuration);
284294
}
285295
}
286296
elapsedDuration = Duration.zero;
@@ -415,6 +425,7 @@ class RecorderController extends ChangeNotifier {
415425
_currentScrolledDuration.dispose();
416426
_currentDurationController.close();
417427
_recorderStateController.close();
428+
_recordedFileDurationController.close();
418429
_recorderTimer?.cancel();
419430
_timer?.cancel();
420431
_timer = null;

0 commit comments

Comments
 (0)