@capgo/native-audio 7.1.7 → 7.3.0
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.
- package/README.md +56 -8
- package/android/build.gradle +14 -5
- package/android/src/main/java/ee/forgr/audio/AudioAsset.java +276 -133
- package/android/src/main/java/ee/forgr/audio/AudioCompletionListener.java +1 -1
- package/android/src/main/java/ee/forgr/audio/AudioDispatcher.java +168 -182
- package/android/src/main/java/ee/forgr/audio/Constant.java +20 -21
- package/android/src/main/java/ee/forgr/audio/NativeAudio.java +596 -506
- package/android/src/main/java/ee/forgr/audio/RemoteAudioAsset.java +599 -166
- package/android/src/main/java/ee/forgr/audio/StreamAudioAsset.java +499 -0
- package/dist/docs.json +96 -3
- package/dist/esm/definitions.d.ts +33 -2
- package/dist/esm/definitions.js.map +1 -1
- package/dist/esm/index.d.ts +2 -2
- package/dist/esm/index.js +4 -4
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/web.d.ts +4 -3
- package/dist/esm/web.js +23 -20
- package/dist/esm/web.js.map +1 -1
- package/dist/plugin.cjs.js +22 -19
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +22 -19
- package/dist/plugin.js.map +1 -1
- package/ios/Plugin/AudioAsset.swift +200 -94
- package/ios/Plugin/Plugin.swift +56 -50
- package/ios/Plugin/RemoteAudioAsset.swift +217 -62
- package/package.json +18 -20
@@ -4,115 +4,270 @@ public class RemoteAudioAsset: AudioAsset {
|
|
4
4
|
var playerItems: [AVPlayerItem] = []
|
5
5
|
var players: [AVPlayer] = []
|
6
6
|
var playerObservers: [NSKeyValueObservation] = []
|
7
|
+
var duration: TimeInterval = 0
|
8
|
+
var asset: AVURLAsset?
|
7
9
|
|
8
10
|
override init(owner: NativeAudio, withAssetId assetId: String, withPath path: String!, withChannels channels: Int!, withVolume volume: Float!, withFadeDelay delay: Float!) {
|
9
|
-
super.init(owner: owner, withAssetId: assetId, withPath: path, withChannels: channels, withVolume: volume, withFadeDelay: delay)
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
let
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
11
|
+
super.init(owner: owner, withAssetId: assetId, withPath: path, withChannels: channels ?? 1, withVolume: volume ?? 1.0, withFadeDelay: delay ?? 0.0)
|
12
|
+
|
13
|
+
owner.executeOnAudioQueue { [self] in
|
14
|
+
if let url = URL(string: path) {
|
15
|
+
let asset = AVURLAsset(url: url, options: [AVURLAssetPreferPreciseDurationAndTimingKey: true])
|
16
|
+
self.asset = asset
|
17
|
+
|
18
|
+
for _ in 0..<(channels ?? 1) {
|
19
|
+
let playerItem = AVPlayerItem(asset: asset)
|
20
|
+
let player = AVPlayer(playerItem: playerItem)
|
21
|
+
player.volume = volume ?? 1.0
|
22
|
+
player.rate = 1.0
|
23
|
+
self.playerItems.append(playerItem)
|
24
|
+
self.players.append(player)
|
25
|
+
|
26
|
+
// Add observer for duration
|
27
|
+
let durationObserver = playerItem.observe(\.status) { [weak self] item, _ in
|
28
|
+
self?.owner.executeOnAudioQueue { [self] in
|
29
|
+
if item.status == .readyToPlay {
|
30
|
+
self?.duration = item.duration.seconds
|
31
|
+
}
|
32
|
+
}
|
23
33
|
}
|
34
|
+
self.playerObservers.append(durationObserver)
|
35
|
+
|
36
|
+
// Add observer for playback finished
|
37
|
+
let observer = player.observe(\.timeControlStatus) { [weak self] player, _ in
|
38
|
+
self?.owner.executeOnAudioQueue { [self] in
|
39
|
+
if player.timeControlStatus == .paused && player.currentItem?.currentTime() == player.currentItem?.duration {
|
40
|
+
self?.playerDidFinishPlaying(player: player)
|
41
|
+
}
|
42
|
+
}
|
43
|
+
}
|
44
|
+
self.playerObservers.append(observer)
|
24
45
|
}
|
25
|
-
self.playerObservers.append(observer)
|
26
46
|
}
|
27
47
|
}
|
28
48
|
}
|
29
49
|
|
30
50
|
func playerDidFinishPlaying(player: AVPlayer) {
|
31
|
-
|
32
|
-
"
|
33
|
-
|
51
|
+
owner.executeOnAudioQueue { [self] in
|
52
|
+
self.owner.notifyListeners("complete", data: [
|
53
|
+
"assetId": self.assetId
|
54
|
+
])
|
55
|
+
}
|
34
56
|
}
|
35
57
|
|
36
58
|
override func play(time: TimeInterval, delay: TimeInterval) {
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
59
|
+
owner.executeOnAudioQueue { [self] in
|
60
|
+
guard !players.isEmpty else { return }
|
61
|
+
let player = players[playIndex]
|
62
|
+
if delay > 0 {
|
63
|
+
// Convert delay to CMTime and add to current time
|
64
|
+
let currentTime = player.currentTime()
|
65
|
+
let delayTime = CMTimeMakeWithSeconds(delay, preferredTimescale: currentTime.timescale)
|
66
|
+
let timeToPlay = CMTimeAdd(currentTime, delayTime)
|
67
|
+
player.seek(to: timeToPlay)
|
68
|
+
} else {
|
69
|
+
player.seek(to: CMTimeMakeWithSeconds(time, preferredTimescale: 1))
|
70
|
+
}
|
71
|
+
player.play()
|
72
|
+
playIndex = (playIndex + 1) % players.count
|
73
|
+
NSLog("RemoteAudioAsset: About to start timer updates")
|
74
|
+
startCurrentTimeUpdates()
|
44
75
|
}
|
45
|
-
player.play()
|
46
|
-
playIndex = (playIndex + 1) % players.count
|
47
76
|
}
|
48
77
|
|
49
78
|
override func pause() {
|
50
|
-
|
51
|
-
|
52
|
-
|
79
|
+
owner.executeOnAudioQueue { [self] in
|
80
|
+
guard !players.isEmpty else { return }
|
81
|
+
let player = players[playIndex]
|
82
|
+
player.pause()
|
83
|
+
stopCurrentTimeUpdates()
|
84
|
+
}
|
53
85
|
}
|
54
86
|
|
55
87
|
override func resume() {
|
56
|
-
|
57
|
-
|
58
|
-
|
88
|
+
owner.executeOnAudioQueue { [self] in
|
89
|
+
guard !players.isEmpty else { return }
|
90
|
+
let player = players[playIndex]
|
91
|
+
player.play()
|
92
|
+
NSLog("RemoteAudioAsset Resume: About to start timer updates")
|
93
|
+
startCurrentTimeUpdates() // Add timer start
|
94
|
+
}
|
59
95
|
}
|
60
96
|
|
61
97
|
override func stop() {
|
62
|
-
|
63
|
-
|
64
|
-
player
|
98
|
+
owner.executeOnAudioQueue { [self] in
|
99
|
+
stopCurrentTimeUpdates() // Stop timer first
|
100
|
+
for player in players {
|
101
|
+
// First pause
|
102
|
+
player.pause()
|
103
|
+
// Then reset to beginning
|
104
|
+
player.seek(to: .zero, completionHandler: { _ in
|
105
|
+
// Reset any loop settings
|
106
|
+
player.actionAtItemEnd = .pause
|
107
|
+
})
|
108
|
+
}
|
109
|
+
// Reset playback state
|
110
|
+
playIndex = 0
|
65
111
|
}
|
66
112
|
}
|
67
113
|
|
68
114
|
override func loop() {
|
69
|
-
|
70
|
-
player
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
115
|
+
owner.executeOnAudioQueue { [self] in
|
116
|
+
for player in players {
|
117
|
+
player.actionAtItemEnd = .none
|
118
|
+
NotificationCenter.default.removeObserver(self,
|
119
|
+
name: .AVPlayerItemDidPlayToEndTime,
|
120
|
+
object: player.currentItem)
|
121
|
+
NotificationCenter.default.addObserver(self,
|
122
|
+
selector: #selector(playerItemDidReachEnd(notification:)),
|
123
|
+
name: .AVPlayerItemDidPlayToEndTime,
|
124
|
+
object: player.currentItem)
|
125
|
+
player.seek(to: .zero)
|
126
|
+
player.play()
|
127
|
+
}
|
128
|
+
NSLog("RemoteAudioAsset Loop: About to start timer updates")
|
129
|
+
startCurrentTimeUpdates() // Add timer start
|
76
130
|
}
|
77
131
|
}
|
78
132
|
|
79
133
|
@objc func playerItemDidReachEnd(notification: Notification) {
|
80
|
-
|
81
|
-
|
82
|
-
|
134
|
+
owner.executeOnAudioQueue { [self] in
|
135
|
+
if let playerItem = notification.object as? AVPlayerItem,
|
136
|
+
let player = players.first(where: { $0.currentItem == playerItem }) {
|
137
|
+
player.seek(to: .zero)
|
138
|
+
player.play()
|
139
|
+
}
|
140
|
+
}
|
83
141
|
}
|
84
142
|
|
85
143
|
override func unload() {
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
144
|
+
owner.executeOnAudioQueue { [self] in
|
145
|
+
stopCurrentTimeUpdates()
|
146
|
+
stop()
|
147
|
+
NotificationCenter.default.removeObserver(self)
|
148
|
+
// Remove KVO observers
|
149
|
+
for observer in playerObservers {
|
150
|
+
observer.invalidate()
|
151
|
+
}
|
152
|
+
playerObservers = []
|
153
|
+
players = []
|
154
|
+
playerItems = []
|
91
155
|
}
|
92
|
-
playerObservers = []
|
93
|
-
players = []
|
94
|
-
playerItems = []
|
95
156
|
}
|
96
157
|
|
97
158
|
override func setVolume(volume: NSNumber!) {
|
98
|
-
|
99
|
-
player
|
159
|
+
owner.executeOnAudioQueue { [self] in
|
160
|
+
for player in players {
|
161
|
+
player.volume = volume.floatValue
|
162
|
+
}
|
100
163
|
}
|
101
164
|
}
|
102
165
|
|
103
166
|
override func setRate(rate: NSNumber!) {
|
104
|
-
|
105
|
-
player
|
167
|
+
owner.executeOnAudioQueue { [self] in
|
168
|
+
for player in players {
|
169
|
+
player.rate = rate.floatValue
|
170
|
+
}
|
106
171
|
}
|
107
172
|
}
|
108
173
|
|
109
174
|
override func isPlaying() -> Bool {
|
110
|
-
|
175
|
+
var result = false
|
176
|
+
owner.executeOnAudioQueue { [self] in
|
177
|
+
guard !players.isEmpty else {
|
178
|
+
result = false
|
179
|
+
return
|
180
|
+
}
|
181
|
+
let player = players[playIndex]
|
182
|
+
result = player.timeControlStatus == .playing
|
183
|
+
}
|
184
|
+
return result
|
111
185
|
}
|
112
186
|
|
113
187
|
override func getCurrentTime() -> TimeInterval {
|
114
|
-
|
115
|
-
|
116
|
-
|
188
|
+
var result: TimeInterval = 0
|
189
|
+
owner.executeOnAudioQueue { [self] in
|
190
|
+
guard !players.isEmpty else {
|
191
|
+
result = 0
|
192
|
+
return
|
193
|
+
}
|
194
|
+
let player = players[playIndex]
|
195
|
+
result = player.currentTime().seconds
|
196
|
+
}
|
197
|
+
return result
|
198
|
+
}
|
199
|
+
|
200
|
+
override func getDuration() -> TimeInterval {
|
201
|
+
var result: TimeInterval = 0
|
202
|
+
owner.executeOnAudioQueue { [self] in
|
203
|
+
guard !players.isEmpty else {
|
204
|
+
result = 0
|
205
|
+
return
|
206
|
+
}
|
207
|
+
let player = players[playIndex]
|
208
|
+
if player.currentItem?.duration == CMTime.indefinite {
|
209
|
+
result = 0
|
210
|
+
return
|
211
|
+
}
|
212
|
+
result = player.currentItem?.duration.seconds ?? 0
|
213
|
+
}
|
214
|
+
return result
|
215
|
+
}
|
216
|
+
|
217
|
+
override func playWithFade(time: TimeInterval) {
|
218
|
+
owner.executeOnAudioQueue { [self] in
|
219
|
+
guard !players.isEmpty else { return }
|
220
|
+
let player = players[playIndex]
|
221
|
+
|
222
|
+
if player.timeControlStatus != .playing {
|
223
|
+
player.seek(to: CMTimeMakeWithSeconds(time, preferredTimescale: 1))
|
224
|
+
player.volume = initialVolume
|
225
|
+
player.play()
|
226
|
+
playIndex = (playIndex + 1) % players.count
|
227
|
+
NSLog("RemoteAudioAsset PlayWithFade: About to start timer updates")
|
228
|
+
startCurrentTimeUpdates()
|
229
|
+
} else {
|
230
|
+
if player.volume < initialVolume {
|
231
|
+
player.volume += self.FADESTEP
|
232
|
+
}
|
233
|
+
}
|
234
|
+
}
|
235
|
+
}
|
236
|
+
|
237
|
+
override func stopWithFade() {
|
238
|
+
owner.executeOnAudioQueue { [self] in
|
239
|
+
guard !players.isEmpty else { return }
|
240
|
+
let player = players[playIndex]
|
241
|
+
|
242
|
+
if player.timeControlStatus == .playing {
|
243
|
+
if player.volume > self.FADESTEP {
|
244
|
+
player.volume -= self.FADESTEP
|
245
|
+
// Schedule next fade step
|
246
|
+
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(Int(self.FADEDELAY * 1000))) { [weak self] in
|
247
|
+
self?.stopWithFade()
|
248
|
+
}
|
249
|
+
} else {
|
250
|
+
// Volume is near 0, actually stop
|
251
|
+
player.volume = 0
|
252
|
+
self.stop()
|
253
|
+
}
|
254
|
+
}
|
255
|
+
}
|
256
|
+
}
|
257
|
+
|
258
|
+
static func clearCache() {
|
259
|
+
DispatchQueue.global(qos: .background).sync {
|
260
|
+
let urls = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask)
|
261
|
+
if let cachePath = urls.first {
|
262
|
+
do {
|
263
|
+
let fileURLs = try FileManager.default.contentsOfDirectory(at: cachePath, includingPropertiesForKeys: nil)
|
264
|
+
for fileURL in fileURLs where fileURL.pathExtension == "mp3" || fileURL.pathExtension == "wav" {
|
265
|
+
try FileManager.default.removeItem(at: fileURL)
|
266
|
+
}
|
267
|
+
} catch {
|
268
|
+
print("Error clearing audio cache: \(error)")
|
269
|
+
}
|
270
|
+
}
|
271
|
+
}
|
117
272
|
}
|
118
273
|
}
|
package/package.json
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
{
|
2
2
|
"name": "@capgo/native-audio",
|
3
|
-
"version": "7.
|
3
|
+
"version": "7.3.0",
|
4
4
|
"description": "A native plugin for native audio engine",
|
5
|
-
"
|
5
|
+
"license": "MIT",
|
6
|
+
"main": "dist/plugin.cjs.js",
|
6
7
|
"module": "dist/esm/index.js",
|
7
8
|
"types": "dist/esm/index.d.ts",
|
8
9
|
"unpkg": "dist/plugin.js",
|
@@ -13,11 +14,20 @@
|
|
13
14
|
"ios/Plugin/",
|
14
15
|
"CapgoNativeAudio.podspec"
|
15
16
|
],
|
17
|
+
"author": "Martin Donadieu",
|
18
|
+
"repository": {
|
19
|
+
"type": "git",
|
20
|
+
"url": "git+https://github.com/Cap-go/native-audio.git"
|
21
|
+
},
|
22
|
+
"bugs": {
|
23
|
+
"url": "https://github.com/Cap-go/native-audio/issues"
|
24
|
+
},
|
16
25
|
"keywords": [
|
17
26
|
"capacitor",
|
18
27
|
"plugin",
|
19
28
|
"audio",
|
20
29
|
"media",
|
30
|
+
"capgo",
|
21
31
|
"native"
|
22
32
|
],
|
23
33
|
"scripts": {
|
@@ -28,7 +38,7 @@
|
|
28
38
|
"lint": "npm run eslint && npm run prettier -- --check && npm run swiftlint -- lint",
|
29
39
|
"fmt": "npm run eslint -- --fix && npm run prettier -- --write && npm run swiftlint -- --autocorrect --format",
|
30
40
|
"eslint": "eslint . --ext .ts",
|
31
|
-
"prettier": "prettier
|
41
|
+
"prettier": "prettier \"**/*.{css,html,ts,js,java}\" --plugin=prettier-plugin-java",
|
32
42
|
"swiftlint": "node-swiftlint",
|
33
43
|
"docgen": "docgen --api NativeAudio --output-readme README.md --output-json dist/docs.json",
|
34
44
|
"build": "npm run clean && npm run docgen && tsc && rollup -c rollup.config.mjs",
|
@@ -36,8 +46,6 @@
|
|
36
46
|
"watch": "tsc --watch",
|
37
47
|
"prepublishOnly": "npm run build"
|
38
48
|
},
|
39
|
-
"author": "Martin Donadieu <martin@capgo.app>",
|
40
|
-
"license": "MIT",
|
41
49
|
"devDependencies": {
|
42
50
|
"@capacitor/android": "^7.0.0",
|
43
51
|
"@capacitor/cli": "^7.0.0",
|
@@ -61,6 +69,11 @@
|
|
61
69
|
"peerDependencies": {
|
62
70
|
"@capacitor/core": ">=7.0.0"
|
63
71
|
},
|
72
|
+
"prettier": "@ionic/prettier-config",
|
73
|
+
"swiftlint": "@ionic/swiftlint-config",
|
74
|
+
"eslintConfig": {
|
75
|
+
"extends": "@ionic/eslint-config/recommended"
|
76
|
+
},
|
64
77
|
"capacitor": {
|
65
78
|
"ios": {
|
66
79
|
"src": "ios"
|
@@ -68,20 +81,5 @@
|
|
68
81
|
"android": {
|
69
82
|
"src": "android"
|
70
83
|
}
|
71
|
-
},
|
72
|
-
"eslintConfig": {
|
73
|
-
"extends": "@ionic/eslint-config/recommended"
|
74
|
-
},
|
75
|
-
"prettier": "@ionic/prettier-config",
|
76
|
-
"swiftlint": "@ionic/swiftlint-config",
|
77
|
-
"repository": {
|
78
|
-
"type": "git",
|
79
|
-
"url": "https://github.com/Cap-go/native-audio"
|
80
|
-
},
|
81
|
-
"bugs": {
|
82
|
-
"url": "https://github.com/Cap-go/native-audio/issues"
|
83
|
-
},
|
84
|
-
"publishConfig": {
|
85
|
-
"access": "public"
|
86
84
|
}
|
87
85
|
}
|