@@ -3,6 +3,7 @@ import whisper_cpp
3
3
4
4
public class Whisper {
5
5
private let whisperContext : OpaquePointer
6
+ private var unmanagedSelf : Unmanaged < Whisper > ?
6
7
7
8
public var delegate : WhisperDelegate ?
8
9
public var params : WhisperParams
@@ -14,17 +15,13 @@ public class Whisper {
14
15
public init ( fromFileURL fileURL: URL , withParams params: WhisperParams = . default) {
15
16
self . whisperContext = fileURL. relativePath. withCString { whisper_init_from_file ( $0) }
16
17
self . params = params
17
-
18
- prepareCallbacks ( )
19
18
}
20
19
21
20
public init ( fromData data: Data , withParams params: WhisperParams = . default) {
22
21
var copy = data // Need to copy memory so we can gaurentee exclusive ownership over pointer
23
22
24
23
self . whisperContext = copy. withUnsafeMutableBytes { whisper_init_from_buffer ( $0. baseAddress!, data. count) }
25
24
self . params = params
26
-
27
- prepareCallbacks ( )
28
25
}
29
26
30
27
deinit {
@@ -38,8 +35,11 @@ public class Whisper {
38
35
39
36
We can unwrap that and obtain a copy of self inside the callback.
40
37
*/
41
- params. new_segment_callback_user_data = Unmanaged . passRetained ( self ) . toOpaque ( )
42
- params. encoder_begin_callback_user_data = Unmanaged . passRetained ( self ) . toOpaque ( )
38
+ cleanupCallbacks ( )
39
+ let unmanagedSelf = Unmanaged . passRetained ( self )
40
+ self . unmanagedSelf = unmanagedSelf
41
+ params. new_segment_callback_user_data = unmanagedSelf. toOpaque ( )
42
+ params. encoder_begin_callback_user_data = unmanagedSelf. toOpaque ( )
43
43
44
44
// swiftlint:disable line_length
45
45
params. new_segment_callback = { ( ctx: OpaquePointer ? , _: OpaquePointer ? , newSegmentCount: Int32 , userData: UnsafeMutableRawPointer ? ) in
@@ -94,32 +94,45 @@ public class Whisper {
94
94
}
95
95
}
96
96
97
+ private func cleanupCallbacks( ) {
98
+ guard let unmanagedSelf else { return }
99
+
100
+ unmanagedSelf. release ( )
101
+ self . unmanagedSelf = nil
102
+ }
103
+
97
104
public func transcribe( audioFrames: [ Float ] , completionHandler: @escaping ( Result < [ Segment ] , Error > ) -> Void ) {
105
+ prepareCallbacks ( )
106
+
107
+ let wrappedCompletionHandler : ( Result < [ Segment ] , Error > ) -> Void = { result in
108
+ self . cleanupCallbacks ( )
109
+ completionHandler ( result)
110
+ }
111
+
98
112
guard !inProgress else {
99
- completionHandler ( . failure( WhisperError . instanceBusy) )
113
+ wrappedCompletionHandler ( . failure( WhisperError . instanceBusy) )
100
114
return
101
115
}
102
116
guard audioFrames. count > 0 else {
103
- completionHandler ( . failure( WhisperError . invalidFrames) )
117
+ wrappedCompletionHandler ( . failure( WhisperError . invalidFrames) )
104
118
return
105
119
}
106
120
107
121
inProgress = true
108
122
frameCount = audioFrames. count
109
123
110
- DispatchQueue . global ( qos: . userInitiated) . async { [ unowned self] in
111
-
112
- whisper_full ( whisperContext, params. whisperParams, audioFrames, Int32 ( audioFrames. count) )
124
+ DispatchQueue . global ( qos: . userInitiated) . async {
125
+ whisper_full ( self . whisperContext, self . params. whisperParams, audioFrames, Int32 ( audioFrames. count) )
113
126
114
- let segmentCount = whisper_full_n_segments ( whisperContext)
127
+ let segmentCount = whisper_full_n_segments ( self . whisperContext)
115
128
116
129
var segments : [ Segment ] = [ ]
117
130
segments. reserveCapacity ( Int ( segmentCount) )
118
131
119
132
for index in 0 ..< segmentCount {
120
- guard let text = whisper_full_get_segment_text ( whisperContext, index) else { continue }
121
- let startTime = whisper_full_get_segment_t0 ( whisperContext, index)
122
- let endTime = whisper_full_get_segment_t1 ( whisperContext, index)
133
+ guard let text = whisper_full_get_segment_text ( self . whisperContext, index) else { continue }
134
+ let startTime = whisper_full_get_segment_t0 ( self . whisperContext, index)
135
+ let endTime = whisper_full_get_segment_t1 ( self . whisperContext, index)
123
136
124
137
segments. append (
125
138
. init(
@@ -130,20 +143,20 @@ public class Whisper {
130
143
)
131
144
}
132
145
133
- if let cancelCallback {
146
+ if let cancelCallback = self . cancelCallback {
134
147
DispatchQueue . main. async {
135
148
// Should cancel callback be called after delegate and completionHandler?
136
149
cancelCallback ( )
137
150
138
151
let error = WhisperError . cancelled
139
152
140
153
self . delegate? . whisper ( self , didErrorWith: error)
141
- completionHandler ( . failure( error) )
154
+ wrappedCompletionHandler ( . failure( error) )
142
155
}
143
156
} else {
144
157
DispatchQueue . main. async {
145
158
self . delegate? . whisper ( self , didCompleteWithSegments: segments)
146
- completionHandler ( . success( segments) )
159
+ wrappedCompletionHandler ( . success( segments) )
147
160
}
148
161
}
149
162
0 commit comments