Skip to content

Commit 5dba64e

Browse files
🐛 Fix extractor requires audio player to be initialised
1 parent a16c9a8 commit 5dba64e

File tree

5 files changed

+80
-66
lines changed

5 files changed

+80
-66
lines changed

android/src/main/kotlin/com/simform/audio_waveforms/AudioPlayer.kt

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -24,36 +24,6 @@ class AudioPlayer(
2424
private var isPlayerPrepared: Boolean = false
2525
private var finishMode = FinishMode.Stop
2626
private var key = playerKey
27-
private var waveformExtractor: WaveformExtractor? = null
28-
private var noOfSamples = 100
29-
30-
fun extractWaveform(
31-
result: MethodChannel.Result,
32-
path: String?,
33-
noOfSamples: Int?,
34-
) {
35-
if (path != null) {
36-
this.noOfSamples = noOfSamples ?: 100
37-
waveformExtractor = WaveformExtractor(
38-
path = path,
39-
expectedPoints = this.noOfSamples,
40-
key = key,
41-
methodChannel = methodChannel,
42-
context = appContext,
43-
result = result,
44-
extractorCallBack = object : ExtractorCallBack {
45-
override fun onProgress(value: Float) {
46-
if (value == 1.0F) {
47-
result.success(waveformExtractor?.sampleData)
48-
}
49-
}
50-
}
51-
)
52-
waveformExtractor?.startDecode()
53-
waveformExtractor?.stop()
54-
55-
}
56-
}
5727

5828
fun preparePlayer(
5929
result: MethodChannel.Result,

android/src/main/kotlin/com/simform/audio_waveforms/AudioWaveformsPlugin.kt

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,8 @@ class AudioWaveformsPlugin : FlutterPlugin, MethodCallHandler, ActivityAware {
3333
private var sampleRate: Int = 44100
3434
private var bitRate: Int? = null
3535
private lateinit var applicationContext: Context
36-
37-
//Todo: bitrate
3836
private var audioPlayers = mutableMapOf<String, AudioPlayer?>()
37+
private var extractors = mutableMapOf<String, WaveformExtractor?>()
3938

4039
override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
4140
channel = MethodChannel(flutterPluginBinding.binaryMessenger, Constants.methodChannelName)
@@ -144,7 +143,12 @@ class AudioWaveformsPlugin : FlutterPlugin, MethodCallHandler, ActivityAware {
144143
val path = call.argument(Constants.path) as String?
145144
val noOfSample = call.argument(Constants.noOfSamples) as Int?
146145
if (key != null) {
147-
audioPlayers[key]?.extractWaveform(result, path, noOfSample)
146+
createOrUpdateExtractor(
147+
playerKey = key,
148+
result = result,
149+
path = path,
150+
noOfSamples = noOfSample ?: 100,
151+
)
148152
} else {
149153
result.error(Constants.LOG_TAG, "Player key can't be null", "")
150154
}
@@ -217,6 +221,36 @@ class AudioWaveformsPlugin : FlutterPlugin, MethodCallHandler, ActivityAware {
217221
return
218222
}
219223

224+
private fun createOrUpdateExtractor(
225+
playerKey: String,
226+
noOfSamples: Int,
227+
path: String?,
228+
result: Result,
229+
) {
230+
if (path == null) {
231+
result.error(Constants.LOG_TAG, "Path cant be null", "")
232+
return
233+
}
234+
extractors[playerKey] = WaveformExtractor(
235+
context = applicationContext,
236+
methodChannel = channel,
237+
expectedPoints = noOfSamples,
238+
key = playerKey,
239+
path = path,
240+
result = result,
241+
extractorCallBack = object : ExtractorCallBack {
242+
override fun onProgress(value: Float) {
243+
if (value == 1.0F) {
244+
result.success(extractors[playerKey]?.sampleData)
245+
}
246+
}
247+
248+
}
249+
)
250+
extractors[playerKey]?.startDecode()
251+
extractors[playerKey]?.stop()
252+
}
253+
220254
override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) {
221255
channel.setMethodCallHandler(null)
222256
}
@@ -236,6 +270,8 @@ class AudioWaveformsPlugin : FlutterPlugin, MethodCallHandler, ActivityAware {
236270
override fun onDetachedFromActivity() {
237271
recorder?.release()
238272
recorder = null
273+
audioPlayers.clear()
274+
extractors.clear()
239275
activity = null
240276
}
241277
}

android/src/main/kotlin/com/simform/audio_waveforms/WaveformExtractor.kt

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@ import android.media.MediaExtractor
77
import android.media.MediaFormat
88
import android.net.Uri
99
import android.os.Build
10-
import android.os.Handler
11-
import android.os.Looper
1210
import io.flutter.plugin.common.MethodChannel
1311
import java.nio.ByteBuffer
1412
import java.util.concurrent.CountDownLatch
@@ -23,8 +21,7 @@ class WaveformExtractor(
2321
private val result: MethodChannel.Result,
2422
private val extractorCallBack: ExtractorCallBack,
2523
private val context: Context,
26-
) {
27-
private val handler = Handler(Looper.getMainLooper())
24+
) {
2825
private var decoder: MediaCodec? = null
2926
private var extractor: MediaExtractor? = null
3027
private var duration = 0L
@@ -45,7 +42,7 @@ class WaveformExtractor(
4542
val mediaExtractor = MediaExtractor()
4643
this.extractor = mediaExtractor
4744
val uri = Uri.parse(path)
48-
mediaExtractor.setDataSource(context,uri,null)
45+
mediaExtractor.setDataSource(context, uri, null)
4946
val trackCount = mediaExtractor.trackCount
5047
repeat(trackCount) {
5148
val format = mediaExtractor.getTrackFormat(it)
@@ -169,6 +166,13 @@ class WaveformExtractor(
169166
if (sampleCount == perSamplePoints) {
170167
currentProgress++
171168
progress = currentProgress / expectedPoints
169+
170+
// Discard redundant values and release resources
171+
if (progress > 1.0F) {
172+
stop()
173+
return
174+
}
175+
172176
val rms = sqrt(sampleSum / perSamplePoints)
173177
sampleData.add(rms.toFloat())
174178
extractorCallBack.onProgress(progress)

ios/Classes/AudioPlayer.swift

Lines changed: 1 addition & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -11,38 +11,13 @@ class AudioPlayer: NSObject, AVAudioPlayerDelegate {
1111
var plugin: SwiftAudioWaveformsPlugin
1212
var playerKey: String
1313
var flutterChannel: FlutterMethodChannel
14-
private var waveformExtractor: WaveformExtractor?
14+
1515
init(plugin: SwiftAudioWaveformsPlugin, playerKey: String, channel: FlutterMethodChannel) {
1616
self.plugin = plugin
1717
self.playerKey = playerKey
1818
flutterChannel = channel
1919
}
2020

21-
func extractWaveformData(path: String?, result: @escaping FlutterResult, noOfSamples: Int?) {
22-
if(!(path ?? "").isEmpty) {
23-
do {
24-
let audioUrl = URL.init(string: path!)
25-
if(audioUrl == nil){
26-
result(FlutterError(code: Constants.audioWaveforms, message: "Failed to initialise Url from provided audio file", details: "If path contains `file://` try removing it"))
27-
return
28-
}
29-
waveformExtractor = try WaveformExtractor(url: audioUrl!, flutterResult: result, channel: flutterChannel)
30-
if(waveformExtractor != nil) {
31-
let data = waveformExtractor!.extractWaveform(samplesPerPixel: noOfSamples, playerKey: playerKey)
32-
waveformExtractor!.cancel()
33-
if(waveformExtractor!.progress == 1.0) {
34-
let waveformData = waveformExtractor!.getChannelMean(data: data!)
35-
result(waveformData)
36-
}
37-
}
38-
} catch {
39-
result(FlutterError(code: Constants.audioWaveforms, message: "Failed to decode audio file", details: nil))
40-
}
41-
} else {
42-
result(FlutterError(code: Constants.audioWaveforms, message: "Audio file path can't be empty or null", details: nil))
43-
}
44-
}
45-
4621
func preparePlayer(path: String?, volume: Double?, result: @escaping FlutterResult) {
4722
if(!(path ?? "").isEmpty) {
4823
let audioUrl = URL.init(string: path!)

ios/Classes/SwiftAudioWaveformsPlugin.swift

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,18 @@ public class SwiftAudioWaveformsPlugin: NSObject, FlutterPlugin {
55

66
final var audioRecorder = AudioRecorder()
77
var audioPlayers = [String: AudioPlayer]()
8+
var extractors = [String: WaveformExtractor]()
89
var flutterChannel: FlutterMethodChannel
910

1011
init(registrar: FlutterPluginRegistrar, flutterChannel: FlutterMethodChannel) {
1112
self.flutterChannel = flutterChannel
1213
super.init()
1314
}
1415

16+
deinit {
17+
audioPlayers.removeAll()
18+
extractors.removeAll()
19+
}
1520
public static func register(with registrar: FlutterPluginRegistrar) {
1621
let channel = FlutterMethodChannel(name: Constants.methodChannelName, binaryMessenger: registrar.messenger())
1722
let instance = SwiftAudioWaveformsPlugin(registrar: registrar, flutterChannel: channel)
@@ -113,8 +118,8 @@ public class SwiftAudioWaveformsPlugin: NSObject, FlutterPlugin {
113118
let key = args?[Constants.playerKey] as? String
114119
let path = args?[Constants.path] as? String
115120
let noOfSamples = args?[Constants.noOfSamples] as? Int
116-
if(key != nil){
117-
audioPlayers[key!]?.extractWaveformData(path: path, result: result,noOfSamples: noOfSamples)
121+
if(key != nil) {
122+
createOrUpdateExtractor(playerKey: key!, result: result, path: path, noOfSamples: noOfSamples)
118123
} else {
119124
result(FlutterError(code: Constants.audioWaveforms, message: "Can not get waveform data", details: "Player key is null"))
120125
}
@@ -130,4 +135,28 @@ public class SwiftAudioWaveformsPlugin: NSObject, FlutterPlugin {
130135
audioPlayers[playerKey] = newPlayer
131136
}
132137
}
138+
139+
func createOrUpdateExtractor(playerKey: String, result: @escaping FlutterResult,path: String?, noOfSamples: Int?) {
140+
if(!(path ?? "").isEmpty) {
141+
do {
142+
let audioUrl = URL.init(string: path!)
143+
if(audioUrl == nil){
144+
result(FlutterError(code: Constants.audioWaveforms, message: "Failed to initialise Url from provided audio file", details: "If path contains `file://` try removing it"))
145+
return
146+
}
147+
var newExtractor = try WaveformExtractor(url: audioUrl!, flutterResult: result, channel: flutterChannel)
148+
extractors[playerKey] = newExtractor
149+
let data = newExtractor.extractWaveform(samplesPerPixel: noOfSamples, playerKey: playerKey)
150+
newExtractor.cancel()
151+
if(newExtractor.progress == 1.0) {
152+
let waveformData = newExtractor.getChannelMean(data: data!)
153+
result(waveformData)
154+
}
155+
} catch {
156+
result(FlutterError(code: Constants.audioWaveforms, message: "Failed to decode audio file", details: nil))
157+
}
158+
} else {
159+
result(FlutterError(code: Constants.audioWaveforms, message: "Audio file path can't be empty or null", details: nil))
160+
}
161+
}
133162
}

0 commit comments

Comments
 (0)