@capgo/native-audio 8.2.12 → 8.2.14

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.
@@ -0,0 +1,110 @@
1
+ import AVFoundation
2
+
3
+ extension RemoteAudioAsset {
4
+
5
+ func fadeIn(player: AVPlayer, fadeInDuration: TimeInterval, targetVolume: Float) {
6
+ cancelFade()
7
+ let steps = Int(fadeInDuration / TimeInterval(fadeDelaySecs))
8
+ guard steps > 0 else { return }
9
+ let fadeStep = targetVolume / Float(steps)
10
+ var currentVolume: Float = 0
11
+
12
+ var task: DispatchWorkItem?
13
+ task = DispatchWorkItem { [weak self] in
14
+ guard let self else { return }
15
+ for _ in 0..<steps {
16
+ guard let task, !task.isCancelled, self.isPlaying(), player.timeControlStatus == .playing else { return }
17
+ currentVolume += fadeStep
18
+ DispatchQueue.main.async {
19
+ player.volume = min(currentVolume, targetVolume)
20
+ }
21
+ Thread.sleep(forTimeInterval: TimeInterval(self.fadeDelaySecs))
22
+ }
23
+ }
24
+ fadeTask = task
25
+ if let task {
26
+ fadeQueue.async(execute: task)
27
+ }
28
+ }
29
+
30
+ func fadeOut(player: AVPlayer, fadeOutDuration: TimeInterval, toPause: Bool = false) {
31
+ cancelFade()
32
+ let steps = Int(fadeOutDuration / TimeInterval(fadeDelaySecs))
33
+ guard steps > 0 else { return }
34
+ let fadeStep = player.volume / Float(steps)
35
+ var currentVolume = player.volume
36
+
37
+ var task: DispatchWorkItem?
38
+ task = DispatchWorkItem { [weak self] in
39
+ guard let self else { return }
40
+ for _ in 0..<steps {
41
+ guard let task, !task.isCancelled, self.isPlaying(), player.timeControlStatus == .playing else { return }
42
+ currentVolume -= fadeStep
43
+ DispatchQueue.main.async {
44
+ player.volume = max(currentVolume, 0)
45
+ }
46
+ Thread.sleep(forTimeInterval: TimeInterval(self.fadeDelaySecs))
47
+ }
48
+ DispatchQueue.main.async { [weak self] in
49
+ guard let self else { return }
50
+ if toPause {
51
+ player.pause()
52
+ } else {
53
+ player.pause()
54
+ player.seek(to: .zero)
55
+ self.owner?.notifyListeners("complete", data: ["assetId": self.assetId as Any])
56
+ self.dispatchedCompleteMap[self.assetId] = true
57
+ }
58
+ }
59
+ }
60
+ fadeTask = task
61
+ if let task {
62
+ fadeQueue.async(execute: task)
63
+ }
64
+ }
65
+
66
+ func fadeTo(player: AVPlayer, fadeOutDuration: TimeInterval, targetVolume: Float) {
67
+ cancelFade()
68
+ let steps = Int(fadeOutDuration / TimeInterval(fadeDelaySecs))
69
+ guard steps > 0 else { return }
70
+
71
+ let minVolume = zeroVolume
72
+ var currentVolume: Float = max(player.volume, minVolume)
73
+ let safeTargetVolume: Float = max(targetVolume, minVolume)
74
+ let ratio = pow(safeTargetVolume / currentVolume, 1.0 / Float(steps))
75
+
76
+ var task: DispatchWorkItem?
77
+ task = DispatchWorkItem { [weak self] in
78
+ guard let self else { return }
79
+ for _ in 0..<steps {
80
+ guard let task, !task.isCancelled, self.isPlaying(), player.timeControlStatus == .playing else { return }
81
+ currentVolume *= ratio
82
+ DispatchQueue.main.async {
83
+ player.volume = min(max(currentVolume, minVolume), self.maxVolume)
84
+ }
85
+ Thread.sleep(forTimeInterval: TimeInterval(self.fadeDelaySecs))
86
+ }
87
+ }
88
+ fadeTask = task
89
+ if let task {
90
+ fadeQueue.async(execute: task)
91
+ }
92
+ }
93
+
94
+ static func clearCache() {
95
+ DispatchQueue.global(qos: .background).sync {
96
+ let urls = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask)
97
+ if let cachePath = urls.first {
98
+ do {
99
+ let fileURLs = try FileManager.default.contentsOfDirectory(at: cachePath, includingPropertiesForKeys: nil)
100
+ let audioExtensions = ["mp3", "wav", "aac", "m4a", "ogg", "mp4", "caf", "aiff"]
101
+ for fileURL in fileURLs where audioExtensions.contains(fileURL.pathExtension.lowercased()) {
102
+ try FileManager.default.removeItem(at: fileURL)
103
+ }
104
+ } catch {
105
+ staticLogger.error("Error clearing audio cache: %@", error.localizedDescription)
106
+ }
107
+ }
108
+ }
109
+ }
110
+ }