@capgo/native-audio 7.1.1 → 7.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -11,13 +11,39 @@ enum MyError: Error {
11
11
  /// here: https://capacitor.ionicframework.com/docs/plugins/ios
12
12
  @objc(NativeAudio)
13
13
  public class NativeAudio: CAPPlugin, AVAudioPlayerDelegate {
14
-
15
- var audioList: [String: Any] = [:]
14
+ public let identifier = "NativeAudio"
15
+ public let jsName = "NativeAudio"
16
+ public let pluginMethods: [CAPPluginMethod] = [
17
+ CAPPluginMethod(name: "configure", returnType: CAPPluginReturnPromise),
18
+ CAPPluginMethod(name: "preload", returnType: CAPPluginReturnPromise),
19
+ CAPPluginMethod(name: "isPreloaded", returnType: CAPPluginReturnPromise),
20
+ CAPPluginMethod(name: "play", returnType: CAPPluginReturnPromise),
21
+ CAPPluginMethod(name: "pause", returnType: CAPPluginReturnPromise),
22
+ CAPPluginMethod(name: "stop", returnType: CAPPluginReturnPromise),
23
+ CAPPluginMethod(name: "loop", returnType: CAPPluginReturnPromise),
24
+ CAPPluginMethod(name: "unload", returnType: CAPPluginReturnPromise),
25
+ CAPPluginMethod(name: "setVolume", returnType: CAPPluginReturnPromise),
26
+ CAPPluginMethod(name: "setRate", returnType: CAPPluginReturnPromise),
27
+ CAPPluginMethod(name: "isPlaying", returnType: CAPPluginReturnPromise),
28
+ CAPPluginMethod(name: "getCurrentTime", returnType: CAPPluginReturnPromise),
29
+ CAPPluginMethod(name: "getDuration", returnType: CAPPluginReturnPromise),
30
+ CAPPluginMethod(name: "resume", returnType: CAPPluginReturnPromise),
31
+ CAPPluginMethod(name: "setCurrentTime", returnType: CAPPluginReturnPromise)
32
+ ]
33
+ private let audioQueue = DispatchQueue(label: "ee.forgr.audio.queue", qos: .userInitiated)
34
+ private var audioList: [String: Any] = [:] {
35
+ didSet {
36
+ // Ensure audioList modifications happen on audioQueue
37
+ assert(DispatchQueue.getSpecific(key: queueKey) != nil)
38
+ }
39
+ }
40
+ private let queueKey = DispatchSpecificKey<Bool>()
16
41
  var fadeMusic = false
17
42
  var session = AVAudioSession.sharedInstance()
18
43
 
19
44
  override public func load() {
20
45
  super.load()
46
+ audioQueue.setSpecific(key: queueKey, value: true)
21
47
 
22
48
  self.fadeMusic = false
23
49
 
@@ -102,9 +128,12 @@ public class NativeAudio: CAPPlugin, AVAudioPlayerDelegate {
102
128
  call.reject("Missing assetId")
103
129
  return
104
130
  }
105
- call.resolve([
106
- "found": self.audioList[assetId] != nil
107
- ])
131
+
132
+ audioQueue.sync {
133
+ call.resolve([
134
+ "found": self.audioList[assetId] != nil
135
+ ])
136
+ }
108
137
  }
109
138
 
110
139
  @objc func preload(_ call: CAPPluginCall) {
@@ -135,34 +164,34 @@ public class NativeAudio: CAPPlugin, AVAudioPlayerDelegate {
135
164
  let audioId = call.getString(Constant.AssetIdKey) ?? ""
136
165
  let time = call.getDouble("time") ?? 0
137
166
  let delay = call.getDouble("delay") ?? 0
138
- if audioId == "" {
167
+
168
+ if audioId.isEmpty {
139
169
  call.reject(Constant.ErrorAssetId)
140
170
  return
141
171
  }
142
- if self.audioList.count == 0 {
143
- call.reject("Audio list is empty")
144
- return
145
- }
146
- let queue = DispatchQueue(label: "ee.forgr.audio.complex.queue", qos: .userInitiated)
147
- let asset = self.audioList[audioId]
148
- if asset == nil {
149
- call.reject(Constant.ErrorAssetNotFound)
150
- return
151
- }
152
- queue.async {
153
- if asset is AudioAsset {
154
- let audioAsset = asset as? AudioAsset
172
+
173
+ audioQueue.async {
174
+ guard !self.audioList.isEmpty else {
175
+ call.reject("Audio list is empty")
176
+ return
177
+ }
178
+
179
+ guard let asset = self.audioList[audioId] else {
180
+ call.reject(Constant.ErrorAssetNotFound)
181
+ return
182
+ }
183
+
184
+ if let audioAsset = asset as? AudioAsset {
155
185
  self.activateSession()
156
186
  if self.fadeMusic {
157
- audioAsset?.playWithFade(time: time)
187
+ audioAsset.playWithFade(time: time)
158
188
  } else {
159
- audioAsset?.play(time: time, delay: delay)
189
+ audioAsset.play(time: time, delay: delay)
160
190
  }
161
191
  call.resolve()
162
- } else if asset is Int32 {
163
- let audioAsset = asset as? NSNumber ?? 0
192
+ } else if let audioNumber = asset as? NSNumber {
164
193
  self.activateSession()
165
- AudioServicesPlaySystemSound(SystemSoundID(audioAsset.intValue))
194
+ AudioServicesPlaySystemSound(SystemSoundID(audioNumber.intValue))
166
195
  call.resolve()
167
196
  } else {
168
197
  call.reject(Constant.ErrorAssetNotFound)
@@ -172,143 +201,183 @@ public class NativeAudio: CAPPlugin, AVAudioPlayerDelegate {
172
201
 
173
202
  @objc private func getAudioAsset(_ call: CAPPluginCall) -> AudioAsset? {
174
203
  let audioId = call.getString(Constant.AssetIdKey) ?? ""
175
- if audioId == "" {
204
+ if audioId.isEmpty {
176
205
  call.reject(Constant.ErrorAssetId)
177
206
  return nil
178
207
  }
179
- if self.audioList.count == 0 {
180
- call.reject("Audio list is empty")
181
- return nil
208
+
209
+ var asset: AudioAsset?
210
+ audioQueue.sync {
211
+ if self.audioList.isEmpty {
212
+ call.reject("Audio list is empty")
213
+ return
214
+ }
215
+
216
+ guard let foundAsset = self.audioList[audioId] as? AudioAsset else {
217
+ call.reject(Constant.ErrorAssetNotFound + " - " + audioId)
218
+ return
219
+ }
220
+ asset = foundAsset
182
221
  }
183
- let asset = self.audioList[audioId]
184
- if asset == nil || !(asset is AudioAsset) {
185
- call.reject(Constant.ErrorAssetNotFound + " - " + audioId)
222
+
223
+ if asset == nil {
224
+ call.reject("Failed to get audio asset")
186
225
  return nil
187
226
  }
188
- return asset as? AudioAsset
227
+ return asset
189
228
  }
190
229
 
191
230
  @objc func setCurrentTime(_ call: CAPPluginCall) {
192
- guard let audioAsset: AudioAsset = self.getAudioAsset(call) else {
193
- return
194
- }
231
+ audioQueue.async {
232
+ guard let audioAsset: AudioAsset = self.getAudioAsset(call) else {
233
+ call.reject("Failed to get audio asset")
234
+ return
235
+ }
195
236
 
196
- let time = call.getDouble("time") ?? 0
197
- audioAsset.setCurrentTime(time: time)
198
- call.resolve()
237
+ let time = call.getDouble("time") ?? 0
238
+ audioAsset.setCurrentTime(time: time)
239
+ call.resolve()
240
+ }
199
241
  }
200
242
 
201
243
  @objc func getDuration(_ call: CAPPluginCall) {
202
- guard let audioAsset: AudioAsset = self.getAudioAsset(call) else {
203
- return
204
- }
244
+ audioQueue.async {
245
+ guard let audioAsset: AudioAsset = self.getAudioAsset(call) else {
246
+ call.reject("Failed to get audio asset")
247
+ return
248
+ }
205
249
 
206
- call.resolve([
207
- "duration": audioAsset.getDuration()
208
- ])
250
+ call.resolve([
251
+ "duration": audioAsset.getDuration()
252
+ ])
253
+ }
209
254
  }
210
255
 
211
256
  @objc func getCurrentTime(_ call: CAPPluginCall) {
212
- guard let audioAsset: AudioAsset = self.getAudioAsset(call) else {
213
- return
214
- }
257
+ audioQueue.async {
258
+ guard let audioAsset: AudioAsset = self.getAudioAsset(call) else {
259
+ call.reject("Failed to get audio asset")
260
+ return
261
+ }
215
262
 
216
- call.resolve([
217
- "currentTime": audioAsset.getCurrentTime()
218
- ])
263
+ call.resolve([
264
+ "currentTime": audioAsset.getCurrentTime()
265
+ ])
266
+ }
219
267
  }
220
268
 
221
269
  @objc func resume(_ call: CAPPluginCall) {
222
- guard let audioAsset: AudioAsset = self.getAudioAsset(call) else {
223
- return
270
+ audioQueue.async {
271
+ guard let audioAsset: AudioAsset = self.getAudioAsset(call) else {
272
+ call.reject("Failed to get audio asset")
273
+ return
274
+ }
275
+ self.activateSession()
276
+ audioAsset.resume()
277
+ call.resolve()
224
278
  }
225
- self.activateSession()
226
- audioAsset.resume()
227
- call.resolve()
228
279
  }
229
280
 
230
281
  @objc func pause(_ call: CAPPluginCall) {
231
- guard let audioAsset: AudioAsset = self.getAudioAsset(call) else {
232
- return
233
- }
282
+ audioQueue.async {
283
+ guard let audioAsset: AudioAsset = self.getAudioAsset(call) else {
284
+ call.reject("Failed to get audio asset")
285
+ return
286
+ }
234
287
 
235
- audioAsset.pause()
236
- self.endSession()
237
- call.resolve()
288
+ audioAsset.pause()
289
+ self.endSession()
290
+ call.resolve()
291
+ }
238
292
  }
239
293
 
240
294
  @objc func stop(_ call: CAPPluginCall) {
241
295
  let audioId = call.getString(Constant.AssetIdKey) ?? ""
242
-
243
- if self.audioList.count == 0 {
244
- call.reject("Audio list is empty")
245
- return
246
- }
247
- do {
248
- try stopAudio(audioId: audioId)
249
- self.endSession()
250
- call.resolve()
251
- } catch {
252
- call.reject(Constant.ErrorAssetNotFound)
296
+
297
+ audioQueue.async {
298
+ guard !self.audioList.isEmpty else {
299
+ call.reject("Audio list is empty")
300
+ return
301
+ }
302
+
303
+ do {
304
+ try self.stopAudio(audioId: audioId)
305
+ self.endSession()
306
+ call.resolve()
307
+ } catch {
308
+ call.reject(Constant.ErrorAssetNotFound)
309
+ }
253
310
  }
254
311
  }
255
312
 
256
313
  @objc func loop(_ call: CAPPluginCall) {
257
- guard let audioAsset: AudioAsset = self.getAudioAsset(call) else {
258
- return
259
- }
314
+ audioQueue.async {
315
+ guard let audioAsset: AudioAsset = self.getAudioAsset(call) else {
316
+ call.reject("Failed to get audio asset")
317
+ return
318
+ }
260
319
 
261
- audioAsset.loop()
262
- call.resolve()
320
+ audioAsset.loop()
321
+ call.resolve()
322
+ }
263
323
  }
264
324
 
265
325
  @objc func unload(_ call: CAPPluginCall) {
266
326
  let audioId = call.getString(Constant.AssetIdKey) ?? ""
267
- if self.audioList.count == 0 {
268
- call.reject("Audio list is empty")
269
- return
270
- }
271
- let asset = self.audioList[audioId]
272
- if asset != nil && asset is AudioAsset {
273
- guard let audioAsset = asset as? AudioAsset else {
274
- call.reject("Cannot cast to AudioAsset")
327
+
328
+ audioQueue.async {
329
+ guard !self.audioList.isEmpty else {
330
+ call.reject("Audio list is empty")
275
331
  return
276
332
  }
277
- audioAsset.unload()
278
- self.audioList[audioId] = nil
333
+
334
+ if let asset = self.audioList[audioId] as? AudioAsset {
335
+ asset.unload()
336
+ self.audioList[audioId] = nil
337
+ call.resolve()
338
+ } else {
339
+ call.reject("Cannot cast to AudioAsset")
340
+ }
279
341
  }
280
- call.resolve()
281
342
  }
282
343
 
283
344
  @objc func setVolume(_ call: CAPPluginCall) {
284
- guard let audioAsset: AudioAsset = self.getAudioAsset(call) else {
285
- return
286
- }
287
-
288
- let volume = call.getFloat(Constant.Volume) ?? 1.0
345
+ audioQueue.async {
346
+ guard let audioAsset: AudioAsset = self.getAudioAsset(call) else {
347
+ call.reject("Failed to get audio asset")
348
+ return
349
+ }
289
350
 
290
- audioAsset.setVolume(volume: volume as NSNumber)
291
- call.resolve()
351
+ let volume = call.getFloat(Constant.Volume) ?? 1.0
352
+ audioAsset.setVolume(volume: volume as NSNumber)
353
+ call.resolve()
354
+ }
292
355
  }
293
356
 
294
357
  @objc func setRate(_ call: CAPPluginCall) {
295
- guard let audioAsset: AudioAsset = self.getAudioAsset(call) else {
296
- return
297
- }
358
+ audioQueue.async {
359
+ guard let audioAsset: AudioAsset = self.getAudioAsset(call) else {
360
+ call.reject("Failed to get audio asset")
361
+ return
362
+ }
298
363
 
299
- let rate = call.getFloat(Constant.Rate) ?? 1.0
300
- audioAsset.setRate(rate: rate as NSNumber)
301
- call.resolve()
364
+ let rate = call.getFloat(Constant.Rate) ?? 1.0
365
+ audioAsset.setRate(rate: rate as NSNumber)
366
+ call.resolve()
367
+ }
302
368
  }
303
369
 
304
370
  @objc func isPlaying(_ call: CAPPluginCall) {
305
- guard let audioAsset: AudioAsset = self.getAudioAsset(call) else {
306
- return
307
- }
371
+ audioQueue.async {
372
+ guard let audioAsset: AudioAsset = self.getAudioAsset(call) else {
373
+ call.reject("Failed to get audio asset")
374
+ return
375
+ }
308
376
 
309
- call.resolve([
310
- "isPlaying": audioAsset.isPlaying()
311
- ])
377
+ call.resolve([
378
+ "isPlaying": audioAsset.isPlaying()
379
+ ])
380
+ }
312
381
  }
313
382
 
314
383
  private func preloadAsset(_ call: CAPPluginCall, isComplex complex: Bool) {
@@ -402,20 +471,20 @@ public class NativeAudio: CAPPlugin, AVAudioPlayerDelegate {
402
471
  }
403
472
 
404
473
  private func stopAudio(audioId: String) throws {
405
- let asset = self.audioList[audioId]
406
-
407
- if asset == nil {
408
- throw MyError.runtimeError(Constant.ErrorAssetNotFound)
474
+ var asset: AudioAsset?
475
+
476
+ audioQueue.sync {
477
+ asset = self.audioList[audioId] as? AudioAsset
409
478
  }
410
- if !(asset is AudioAsset) {
479
+
480
+ guard let audioAsset = asset else {
411
481
  throw MyError.runtimeError(Constant.ErrorAssetNotFound)
412
482
  }
413
- let audioAsset = asset as? AudioAsset
414
483
 
415
484
  if self.fadeMusic {
416
- audioAsset?.playWithFade(time: audioAsset?.getCurrentTime() ?? 0)
485
+ audioAsset.playWithFade(time: audioAsset.getCurrentTime())
417
486
  } else {
418
- audioAsset?.stop()
487
+ audioAsset.stop()
419
488
  }
420
489
  }
421
490
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capgo/native-audio",
3
- "version": "7.1.1",
3
+ "version": "7.1.3",
4
4
  "description": "A native plugin for native audio engine",
5
5
  "main": "dist/plugin.js",
6
6
  "module": "dist/esm/index.js",
@@ -49,7 +49,7 @@
49
49
  "@ionic/swiftlint-config": "^2.0.0",
50
50
  "@types/node": "^22.13.1",
51
51
  "eslint": "^8.57.0",
52
- "eslint-plugin-import": "^2.29.1",
52
+ "eslint-plugin-import": "^2.31.0",
53
53
  "husky": "^9.1.7",
54
54
  "prettier": "^3.4.2",
55
55
  "prettier-plugin-java": "^2.6.7",
@@ -1,10 +0,0 @@
1
- #import <UIKit/UIKit.h>
2
-
3
- //! Project version number for Plugin.
4
- FOUNDATION_EXPORT double PluginVersionNumber;
5
-
6
- //! Project version string for Plugin.
7
- FOUNDATION_EXPORT const unsigned char PluginVersionString[];
8
-
9
- // In this header, you should import all the public headers of your framework using statements like #import <Plugin/PublicHeader.h>
10
-
@@ -1,22 +0,0 @@
1
- #import <Foundation/Foundation.h>
2
- #import <Capacitor/Capacitor.h>
3
-
4
- // Define the plugin using the CAP_PLUGIN Macro, and
5
- // each method the plugin supports using the CAP_PLUGIN_METHOD macro.
6
- CAP_PLUGIN(NativeAudio, "NativeAudio",
7
- CAP_PLUGIN_METHOD(configure, CAPPluginReturnPromise);
8
- CAP_PLUGIN_METHOD(preload, CAPPluginReturnPromise);
9
- CAP_PLUGIN_METHOD(isPreloaded, CAPPluginReturnPromise);
10
- CAP_PLUGIN_METHOD(setRate, CAPPluginReturnPromise);
11
- CAP_PLUGIN_METHOD(play, CAPPluginReturnPromise);
12
- CAP_PLUGIN_METHOD(stop, CAPPluginReturnPromise);
13
- CAP_PLUGIN_METHOD(loop, CAPPluginReturnPromise);
14
- CAP_PLUGIN_METHOD(pause, CAPPluginReturnPromise);
15
- CAP_PLUGIN_METHOD(resume, CAPPluginReturnPromise);
16
- CAP_PLUGIN_METHOD(unload, CAPPluginReturnPromise);
17
- CAP_PLUGIN_METHOD(setVolume, CAPPluginReturnPromise);
18
- CAP_PLUGIN_METHOD(setCurrentTime, CAPPluginReturnPromise);
19
- CAP_PLUGIN_METHOD(getCurrentTime, CAPPluginReturnPromise);
20
- CAP_PLUGIN_METHOD(getDuration, CAPPluginReturnPromise);
21
- CAP_PLUGIN_METHOD(isPlaying, CAPPluginReturnPromise);
22
- )