@capgo/native-audio 4.0.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/CapgoNativeAudio.podspec +16 -0
- package/LICENSE +21 -0
- package/README.md +394 -0
- package/android/build.gradle +55 -0
- package/android/src/main/AndroidManifest.xml +5 -0
- package/android/src/main/java/ee/forgr/audio/AudioAsset.java +140 -0
- package/android/src/main/java/ee/forgr/audio/AudioDispatcher.java +178 -0
- package/android/src/main/java/ee/forgr/audio/Constant.java +18 -0
- package/android/src/main/java/ee/forgr/audio/NativeAudio.java +471 -0
- package/android/src/main/res/layout/bridge_layout_main.xml +15 -0
- package/android/src/main/res/values/colors.xml +3 -0
- package/android/src/main/res/values/strings.xml +3 -0
- package/android/src/main/res/values/styles.xml +3 -0
- package/dist/docs.json +279 -0
- package/dist/esm/audio-asset.d.ts +4 -0
- package/dist/esm/audio-asset.js +6 -0
- package/dist/esm/audio-asset.js.map +1 -0
- package/dist/esm/definitions.d.ts +53 -0
- package/dist/esm/definitions.js +2 -0
- package/dist/esm/definitions.js.map +1 -0
- package/dist/esm/index.d.ts +4 -0
- package/dist/esm/index.js +7 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/web.d.ts +52 -0
- package/dist/esm/web.js +113 -0
- package/dist/esm/web.js.map +1 -0
- package/dist/plugin.cjs.js +134 -0
- package/dist/plugin.cjs.js.map +1 -0
- package/dist/plugin.js +137 -0
- package/dist/plugin.js.map +1 -0
- package/ios/Plugin/AudioAsset.swift +184 -0
- package/ios/Plugin/Constant.swift +20 -0
- package/ios/Plugin/Info.plist +24 -0
- package/ios/Plugin/Plugin.h +10 -0
- package/ios/Plugin/Plugin.m +19 -0
- package/ios/Plugin/Plugin.swift +276 -0
- package/package.json +91 -0
@@ -0,0 +1,276 @@
|
|
1
|
+
import AVFoundation
|
2
|
+
import Foundation
|
3
|
+
import Capacitor
|
4
|
+
import CoreAudio
|
5
|
+
|
6
|
+
enum MyError: Error {
|
7
|
+
case runtimeError(String)
|
8
|
+
}
|
9
|
+
|
10
|
+
/**
|
11
|
+
* Please read the Capacitor iOS Plugin Development Guide
|
12
|
+
* here: https://capacitor.ionicframework.com/docs/plugins/ios
|
13
|
+
*/
|
14
|
+
@objc(NativeAudio)
|
15
|
+
public class NativeAudio: CAPPlugin {
|
16
|
+
|
17
|
+
var audioList: [String : Any] = [:]
|
18
|
+
var fadeMusic = false
|
19
|
+
var session = AVAudioSession.sharedInstance()
|
20
|
+
|
21
|
+
public override func load() {
|
22
|
+
super.load()
|
23
|
+
|
24
|
+
self.fadeMusic = false
|
25
|
+
|
26
|
+
do {
|
27
|
+
try self.session.setCategory(AVAudioSession.Category.playback)
|
28
|
+
try self.session.setActive(false)
|
29
|
+
} catch {
|
30
|
+
print("Failed to set session category")
|
31
|
+
}
|
32
|
+
}
|
33
|
+
|
34
|
+
@objc func configure(_ call: CAPPluginCall) {
|
35
|
+
if let fade = call.getBool(Constant.FadeKey) {
|
36
|
+
self.fadeMusic = fade
|
37
|
+
}
|
38
|
+
if let focus = call.getBool(Constant.FocusAudio) {
|
39
|
+
do {
|
40
|
+
if focus {
|
41
|
+
try self.session.setCategory(AVAudioSession.Category.playback)
|
42
|
+
} else {
|
43
|
+
try self.session.setCategory(AVAudioSession.Category.ambient)
|
44
|
+
}
|
45
|
+
} catch {
|
46
|
+
print("Failed to set setCategory audio")
|
47
|
+
}
|
48
|
+
}
|
49
|
+
}
|
50
|
+
|
51
|
+
@objc func preload(_ call: CAPPluginCall) {
|
52
|
+
preloadAsset(call, isComplex: true)
|
53
|
+
}
|
54
|
+
|
55
|
+
@objc func play(_ call: CAPPluginCall) {
|
56
|
+
let audioId = call.getString(Constant.AssetIdKey) ?? ""
|
57
|
+
let time = call.getDouble("time") ?? 0
|
58
|
+
if audioId != "" {
|
59
|
+
let queue = DispatchQueue(label: "ee.forgr.audio.complex.queue", qos: .userInitiated)
|
60
|
+
|
61
|
+
queue.async {
|
62
|
+
if self.audioList.count > 0 {
|
63
|
+
let asset = self.audioList[audioId]
|
64
|
+
|
65
|
+
if asset != nil {
|
66
|
+
if asset is AudioAsset {
|
67
|
+
let audioAsset = asset as? AudioAsset
|
68
|
+
|
69
|
+
if self.fadeMusic {
|
70
|
+
audioAsset?.playWithFade(time: time)
|
71
|
+
} else {
|
72
|
+
audioAsset?.play(time: time)
|
73
|
+
}
|
74
|
+
call.resolve()
|
75
|
+
} else if (asset is Int32) {
|
76
|
+
let audioAsset = asset as? NSNumber ?? 0
|
77
|
+
AudioServicesPlaySystemSound(SystemSoundID(audioAsset.intValue ))
|
78
|
+
call.resolve()
|
79
|
+
} else {
|
80
|
+
call.reject(Constant.ErrorAssetNotFound)
|
81
|
+
}
|
82
|
+
}
|
83
|
+
}
|
84
|
+
}
|
85
|
+
}
|
86
|
+
}
|
87
|
+
|
88
|
+
@objc private func getAudioAsset(_ call: CAPPluginCall) -> AudioAsset? {
|
89
|
+
let audioId = call.getString(Constant.AssetIdKey) ?? ""
|
90
|
+
if audioId == "" {
|
91
|
+
call.reject(Constant.ErrorAssetId)
|
92
|
+
return nil
|
93
|
+
}
|
94
|
+
if self.audioList.count > 0 {
|
95
|
+
let asset = self.audioList[audioId]
|
96
|
+
if asset != nil && asset is AudioAsset {
|
97
|
+
return asset as? AudioAsset
|
98
|
+
}
|
99
|
+
}
|
100
|
+
call.reject(Constant.ErrorAssetNotFound + " - " + audioId)
|
101
|
+
return nil
|
102
|
+
}
|
103
|
+
|
104
|
+
|
105
|
+
@objc func getDuration(_ call: CAPPluginCall) {
|
106
|
+
guard let audioAsset: AudioAsset = self.getAudioAsset(call) else {
|
107
|
+
return
|
108
|
+
}
|
109
|
+
|
110
|
+
call.resolve([
|
111
|
+
"duration": audioAsset.getDuration()
|
112
|
+
])
|
113
|
+
}
|
114
|
+
|
115
|
+
@objc func getCurrentTime(_ call: CAPPluginCall) {
|
116
|
+
guard let audioAsset: AudioAsset = self.getAudioAsset(call) else {
|
117
|
+
return
|
118
|
+
}
|
119
|
+
|
120
|
+
call.resolve([
|
121
|
+
"currentTime": audioAsset.getCurrentTime()
|
122
|
+
])
|
123
|
+
}
|
124
|
+
|
125
|
+
@objc func resume(_ call: CAPPluginCall) {
|
126
|
+
guard let audioAsset: AudioAsset = self.getAudioAsset(call) else {
|
127
|
+
return
|
128
|
+
}
|
129
|
+
|
130
|
+
audioAsset.resume()
|
131
|
+
call.resolve()
|
132
|
+
}
|
133
|
+
|
134
|
+
@objc func pause(_ call: CAPPluginCall) {
|
135
|
+
guard let audioAsset: AudioAsset = self.getAudioAsset(call) else {
|
136
|
+
return
|
137
|
+
}
|
138
|
+
|
139
|
+
audioAsset.pause()
|
140
|
+
call.resolve()
|
141
|
+
}
|
142
|
+
|
143
|
+
@objc func stop(_ call: CAPPluginCall) {
|
144
|
+
let audioId = call.getString(Constant.AssetIdKey) ?? ""
|
145
|
+
|
146
|
+
do {
|
147
|
+
try stopAudio(audioId: audioId)
|
148
|
+
} catch {
|
149
|
+
call.reject(Constant.ErrorAssetNotFound)
|
150
|
+
}
|
151
|
+
}
|
152
|
+
|
153
|
+
@objc func loop(_ call: CAPPluginCall) {
|
154
|
+
guard let audioAsset: AudioAsset = self.getAudioAsset(call) else {
|
155
|
+
return
|
156
|
+
}
|
157
|
+
|
158
|
+
audioAsset.loop()
|
159
|
+
call.resolve()
|
160
|
+
}
|
161
|
+
|
162
|
+
@objc func unload(_ call: CAPPluginCall) {
|
163
|
+
let audioId = call.getString(Constant.AssetIdKey) ?? ""
|
164
|
+
if self.audioList.count > 0 {
|
165
|
+
let asset = self.audioList[audioId]
|
166
|
+
if asset != nil && asset is AudioAsset {
|
167
|
+
let audioAsset = asset as! AudioAsset
|
168
|
+
audioAsset.unload();
|
169
|
+
self.audioList[audioId] = nil
|
170
|
+
}
|
171
|
+
}
|
172
|
+
call.resolve()
|
173
|
+
}
|
174
|
+
|
175
|
+
@objc func setVolume(_ call: CAPPluginCall) {
|
176
|
+
guard let audioAsset: AudioAsset = self.getAudioAsset(call) else {
|
177
|
+
return
|
178
|
+
}
|
179
|
+
|
180
|
+
let volume = call.getFloat(Constant.Volume) ?? 1.0
|
181
|
+
|
182
|
+
audioAsset.setVolume(volume: volume as NSNumber)
|
183
|
+
call.resolve()
|
184
|
+
}
|
185
|
+
|
186
|
+
@objc func isPlaying(_ call: CAPPluginCall) {
|
187
|
+
guard let audioAsset: AudioAsset = self.getAudioAsset(call) else {
|
188
|
+
return
|
189
|
+
}
|
190
|
+
|
191
|
+
call.resolve([
|
192
|
+
"isPlaying": audioAsset.isPlaying()
|
193
|
+
])
|
194
|
+
}
|
195
|
+
|
196
|
+
private func preloadAsset(_ call: CAPPluginCall, isComplex complex: Bool) {
|
197
|
+
let audioId = call.getString(Constant.AssetIdKey) ?? ""
|
198
|
+
let channels: NSNumber?
|
199
|
+
let volume: Float?
|
200
|
+
let delay: NSNumber?
|
201
|
+
let isUrl: Bool?
|
202
|
+
|
203
|
+
if audioId != "" {
|
204
|
+
let assetPath: String = call.getString(Constant.AssetPathKey) ?? ""
|
205
|
+
|
206
|
+
if (complex) {
|
207
|
+
volume = call.getFloat("volume") ?? 1.0
|
208
|
+
channels = NSNumber(value: call.getInt("channels") ?? 1)
|
209
|
+
delay = NSNumber(value: call.getInt("delay") ?? 1)
|
210
|
+
isUrl = call.getBool("isUrl") ?? false
|
211
|
+
} else {
|
212
|
+
channels = 0
|
213
|
+
volume = 0
|
214
|
+
delay = 0
|
215
|
+
isUrl = false
|
216
|
+
}
|
217
|
+
|
218
|
+
if audioList.isEmpty {
|
219
|
+
audioList = [:]
|
220
|
+
}
|
221
|
+
|
222
|
+
let asset = audioList[audioId]
|
223
|
+
let queue = DispatchQueue(label: "ee.forgr.audio.simple.queue", qos: .userInitiated)
|
224
|
+
|
225
|
+
queue.async {
|
226
|
+
if asset == nil {
|
227
|
+
var basePath: String?
|
228
|
+
if isUrl == false {
|
229
|
+
let assetPathSplit = assetPath.components(separatedBy: ".")
|
230
|
+
basePath = Bundle.main.path(forResource: assetPathSplit[0], ofType: assetPathSplit[1])
|
231
|
+
} else {
|
232
|
+
let url = URL(string: assetPath)
|
233
|
+
basePath = url!.path
|
234
|
+
}
|
235
|
+
|
236
|
+
if FileManager.default.fileExists(atPath: basePath ?? "") {
|
237
|
+
if !complex {
|
238
|
+
let pathUrl = URL(fileURLWithPath: basePath ?? "")
|
239
|
+
let soundFileUrl: CFURL = CFBridgingRetain(pathUrl) as! CFURL
|
240
|
+
var soundId = SystemSoundID()
|
241
|
+
AudioServicesCreateSystemSoundID(soundFileUrl, &soundId)
|
242
|
+
self.audioList[audioId] = NSNumber(value: Int32(soundId))
|
243
|
+
call.resolve()
|
244
|
+
} else {
|
245
|
+
let audioAsset: AudioAsset = AudioAsset(owner: self, withAssetId: audioId, withPath: basePath, withChannels: channels, withVolume: volume as NSNumber?, withFadeDelay: delay)
|
246
|
+
self.audioList[audioId] = audioAsset
|
247
|
+
call.resolve()
|
248
|
+
}
|
249
|
+
} else {
|
250
|
+
call.reject(Constant.ErrorAssetPath + " - " + assetPath)
|
251
|
+
}
|
252
|
+
}
|
253
|
+
}
|
254
|
+
}
|
255
|
+
}
|
256
|
+
|
257
|
+
private func stopAudio(audioId: String) throws {
|
258
|
+
if self.audioList.count > 0 {
|
259
|
+
let asset = self.audioList[audioId]
|
260
|
+
|
261
|
+
if asset != nil {
|
262
|
+
if asset is AudioAsset {
|
263
|
+
let audioAsset = asset as? AudioAsset
|
264
|
+
|
265
|
+
if self.fadeMusic {
|
266
|
+
audioAsset?.playWithFade(time: audioAsset?.getCurrentTime() ?? 0)
|
267
|
+
} else {
|
268
|
+
audioAsset?.stop()
|
269
|
+
}
|
270
|
+
}
|
271
|
+
} else {
|
272
|
+
throw MyError.runtimeError(Constant.ErrorAssetNotFound)
|
273
|
+
}
|
274
|
+
}
|
275
|
+
}
|
276
|
+
}
|
package/package.json
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
{
|
2
|
+
"name": "@capgo/native-audio",
|
3
|
+
"version": "4.0.0",
|
4
|
+
"description": "A native plugin for native audio engine",
|
5
|
+
"main": "dist/plugin.js",
|
6
|
+
"module": "dist/esm/index.js",
|
7
|
+
"types": "dist/esm/index.d.ts",
|
8
|
+
"unpkg": "dist/plugin.js",
|
9
|
+
"files": [
|
10
|
+
"android/src/main/",
|
11
|
+
"android/build.gradle",
|
12
|
+
"dist/",
|
13
|
+
"ios/Plugin/",
|
14
|
+
"CapgoNativeAudio.podspec"
|
15
|
+
],
|
16
|
+
"keywords": [
|
17
|
+
"capacitor",
|
18
|
+
"plugin",
|
19
|
+
"audio",
|
20
|
+
"media",
|
21
|
+
"native"
|
22
|
+
],
|
23
|
+
"scripts": {
|
24
|
+
"verify": "npm run verify:ios && npm run verify:android && npm run verify:web",
|
25
|
+
"verify:ios": "cd ios && pod install && xcodebuild -workspace Plugin.xcworkspace -scheme Plugin && cd ..",
|
26
|
+
"verify:android": "cd android && ./gradlew clean build test && cd ..",
|
27
|
+
"verify:web": "npm run build",
|
28
|
+
"lint": "npm run eslint && npm run prettier -- --check && npm run swiftlint -- lint",
|
29
|
+
"fmt": "npm run eslint -- --fix && npm run prettier -- --write && npm run swiftlint -- autocorrect --format",
|
30
|
+
"eslint": "eslint . --ext ts",
|
31
|
+
"prettier": "prettier \"**/*.{css,html,ts,js,java}\"",
|
32
|
+
"swiftlint": "node-swiftlint",
|
33
|
+
"docgen": "docgen --api NativeAudio --output-readme README.md --output-json dist/docs.json",
|
34
|
+
"build": "npm run clean && npm run docgen && tsc && rollup -c rollup.config.js",
|
35
|
+
"clean": "rimraf ./dist",
|
36
|
+
"watch": "tsc --watch",
|
37
|
+
"prepublishOnly": "npm run build",
|
38
|
+
"prepare": "husky install"
|
39
|
+
},
|
40
|
+
"author": "Martin Donadieu <martindonadieu@gmail.com>",
|
41
|
+
"license": "MIT",
|
42
|
+
"devDependencies": {
|
43
|
+
"@capacitor/android": "^4.4.0",
|
44
|
+
"@capacitor/cli": "^4.4.0",
|
45
|
+
"@capacitor/core": "^4.4.0",
|
46
|
+
"@capacitor/docgen": "^0.2.0",
|
47
|
+
"@capacitor/ios": "^4.4.0",
|
48
|
+
"@ionic/eslint-config": "^0.3.0",
|
49
|
+
"@ionic/prettier-config": "^2.0.0",
|
50
|
+
"@ionic/swiftlint-config": "^1.1.2",
|
51
|
+
"eslint": "^7.32.0",
|
52
|
+
"husky": "^8.0.1",
|
53
|
+
"prettier": "^2.7.1",
|
54
|
+
"prettier-plugin-java": "^1.6.2",
|
55
|
+
"rimraf": "^3.0.2",
|
56
|
+
"rollup": "^2.79.1",
|
57
|
+
"swiftlint": "^1.0.1",
|
58
|
+
"typescript": "^4.8.4"
|
59
|
+
},
|
60
|
+
"peerDependencies": {
|
61
|
+
"@capacitor/core": "^3.0.0 || ^4.0.0"
|
62
|
+
},
|
63
|
+
"husky": {
|
64
|
+
"hooks": {
|
65
|
+
"pre-commit": "pretty-quick --staged"
|
66
|
+
}
|
67
|
+
},
|
68
|
+
"capacitor": {
|
69
|
+
"ios": {
|
70
|
+
"src": "ios"
|
71
|
+
},
|
72
|
+
"android": {
|
73
|
+
"src": "android"
|
74
|
+
}
|
75
|
+
},
|
76
|
+
"prettier": "@ionic/prettier-config",
|
77
|
+
"swiftlint": "@ionic/swiftlint-config",
|
78
|
+
"eslintConfig": {
|
79
|
+
"extends": "@ionic/eslint-config/recommended"
|
80
|
+
},
|
81
|
+
"repository": {
|
82
|
+
"type": "git",
|
83
|
+
"url": "https://github.com/capacitor-community/native-audio"
|
84
|
+
},
|
85
|
+
"bugs": {
|
86
|
+
"url": "https://github.com/capacitor-community/native-audio/issues"
|
87
|
+
},
|
88
|
+
"publishConfig": {
|
89
|
+
"access": "public"
|
90
|
+
}
|
91
|
+
}
|