@capawesome/capacitor-audio-session 0.0.1

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.
Files changed (35) hide show
  1. package/CapawesomeCapacitorAudioSession.podspec +17 -0
  2. package/LICENSE +21 -0
  3. package/Package.swift +28 -0
  4. package/README.md +389 -0
  5. package/android/build.gradle +58 -0
  6. package/android/src/main/AndroidManifest.xml +2 -0
  7. package/android/src/main/java/io/capawesome/capacitorjs/plugins/audiosession/AudioSessionPlugin.java +35 -0
  8. package/android/src/main/res/.gitkeep +0 -0
  9. package/dist/docs.json +759 -0
  10. package/dist/esm/definitions.d.ts +287 -0
  11. package/dist/esm/definitions.js +19 -0
  12. package/dist/esm/definitions.js.map +1 -0
  13. package/dist/esm/index.d.ts +4 -0
  14. package/dist/esm/index.js +7 -0
  15. package/dist/esm/index.js.map +1 -0
  16. package/dist/esm/web.d.ts +8 -0
  17. package/dist/esm/web.js +16 -0
  18. package/dist/esm/web.js.map +1 -0
  19. package/dist/plugin.cjs.js +49 -0
  20. package/dist/plugin.cjs.js.map +1 -0
  21. package/dist/plugin.js +52 -0
  22. package/dist/plugin.js.map +1 -0
  23. package/ios/Plugin/AudioSession.swift +127 -0
  24. package/ios/Plugin/AudioSessionPlugin.swift +103 -0
  25. package/ios/Plugin/Classes/Events/InterruptionEvent.swift +19 -0
  26. package/ios/Plugin/Classes/Events/RouteChangeEvent.swift +19 -0
  27. package/ios/Plugin/Classes/Options/ConfigureOptions.swift +101 -0
  28. package/ios/Plugin/Classes/Options/OverrideOutputOptions.swift +24 -0
  29. package/ios/Plugin/Classes/Options/SetActiveOptions.swift +27 -0
  30. package/ios/Plugin/Classes/Results/AudioSessionOutput.swift +19 -0
  31. package/ios/Plugin/Classes/Results/GetCurrentOutputsResult.swift +16 -0
  32. package/ios/Plugin/Enums/CustomError.swift +36 -0
  33. package/ios/Plugin/Info.plist +24 -0
  34. package/ios/Plugin/Protocols/Result.swift +5 -0
  35. package/package.json +91 -0
@@ -0,0 +1,103 @@
1
+ import Foundation
2
+ import Capacitor
3
+
4
+ @objc(AudioSessionPlugin)
5
+ public class AudioSessionPlugin: CAPPlugin, CAPBridgedPlugin {
6
+ public let identifier = "AudioSessionPlugin"
7
+ public let jsName = "AudioSession"
8
+ public let pluginMethods: [CAPPluginMethod] = [
9
+ CAPPluginMethod(name: "configure", returnType: CAPPluginReturnPromise),
10
+ CAPPluginMethod(name: "getCurrentOutputs", returnType: CAPPluginReturnPromise),
11
+ CAPPluginMethod(name: "overrideOutput", returnType: CAPPluginReturnPromise),
12
+ CAPPluginMethod(name: "setActive", returnType: CAPPluginReturnPromise)
13
+ ]
14
+ public static let eventInterruption = "interruption"
15
+ public static let eventRouteChange = "routeChange"
16
+ public static let tag = "AudioSessionPlugin"
17
+
18
+ private var implementation: AudioSession?
19
+
20
+ override public func load() {
21
+ self.implementation = AudioSession(plugin: self)
22
+ }
23
+
24
+ @objc func configure(_ call: CAPPluginCall) {
25
+ do {
26
+ let options = try ConfigureOptions(call)
27
+ implementation?.configure(options) { error in
28
+ if let error = error {
29
+ self.rejectCall(call, error)
30
+ return
31
+ }
32
+ self.resolveCall(call)
33
+ }
34
+ } catch {
35
+ rejectCall(call, error)
36
+ }
37
+ }
38
+
39
+ @objc func getCurrentOutputs(_ call: CAPPluginCall) {
40
+ implementation?.getCurrentOutputs { result, error in
41
+ if let error = error {
42
+ self.rejectCall(call, error)
43
+ return
44
+ }
45
+ self.resolveCall(call, result)
46
+ }
47
+ }
48
+
49
+ @objc public func notifyInterruptionListeners(_ event: InterruptionEvent) {
50
+ self.notifyListeners(Self.eventInterruption, data: event.toJSObject() as? [String: Any])
51
+ }
52
+
53
+ @objc public func notifyRouteChangeListeners(_ event: RouteChangeEvent) {
54
+ self.notifyListeners(Self.eventRouteChange, data: event.toJSObject() as? [String: Any])
55
+ }
56
+
57
+ @objc func overrideOutput(_ call: CAPPluginCall) {
58
+ let options = OverrideOutputOptions(call)
59
+ implementation?.overrideOutput(options) { error in
60
+ if let error = error {
61
+ self.rejectCall(call, error)
62
+ return
63
+ }
64
+ self.resolveCall(call)
65
+ }
66
+ }
67
+
68
+ @objc func setActive(_ call: CAPPluginCall) {
69
+ do {
70
+ let options = try SetActiveOptions(call)
71
+ implementation?.setActive(options) { error in
72
+ if let error = error {
73
+ self.rejectCall(call, error)
74
+ return
75
+ }
76
+ self.resolveCall(call)
77
+ }
78
+ } catch {
79
+ rejectCall(call, error)
80
+ }
81
+ }
82
+
83
+ private func rejectCall(_ call: CAPPluginCall, _ error: Error) {
84
+ CAPLog.print("[", AudioSessionPlugin.tag, "] ", error)
85
+ if let customError = error as? CustomError {
86
+ call.reject(customError.localizedDescription, customError.code)
87
+ } else {
88
+ call.reject(error.localizedDescription)
89
+ }
90
+ }
91
+
92
+ private func resolveCall(_ call: CAPPluginCall) {
93
+ call.resolve()
94
+ }
95
+
96
+ private func resolveCall(_ call: CAPPluginCall, _ result: Result?) {
97
+ if let result = result?.toJSObject() as? JSObject {
98
+ call.resolve(result)
99
+ } else {
100
+ call.resolve()
101
+ }
102
+ }
103
+ }
@@ -0,0 +1,19 @@
1
+ import Foundation
2
+ import Capacitor
3
+
4
+ @objc public class InterruptionEvent: NSObject, Result {
5
+ private let shouldResume: Bool
6
+ private let type: String
7
+
8
+ init(type: String, shouldResume: Bool) {
9
+ self.type = type
10
+ self.shouldResume = shouldResume
11
+ }
12
+
13
+ @objc public func toJSObject() -> AnyObject {
14
+ var result = JSObject()
15
+ result["type"] = type
16
+ result["shouldResume"] = shouldResume
17
+ return result as AnyObject
18
+ }
19
+ }
@@ -0,0 +1,19 @@
1
+ import Foundation
2
+ import Capacitor
3
+
4
+ @objc public class RouteChangeEvent: NSObject, Result {
5
+ private let outputs: [AudioSessionOutput]
6
+ private let reason: String
7
+
8
+ init(reason: String, outputs: [AudioSessionOutput]) {
9
+ self.reason = reason
10
+ self.outputs = outputs
11
+ }
12
+
13
+ @objc public func toJSObject() -> AnyObject {
14
+ var result = JSObject()
15
+ result["reason"] = reason
16
+ result["outputs"] = outputs.map { $0.toJSObject() }
17
+ return result as AnyObject
18
+ }
19
+ }
@@ -0,0 +1,101 @@
1
+ import Foundation
2
+ import AVFoundation
3
+ import Capacitor
4
+
5
+ @objc public class ConfigureOptions: NSObject {
6
+ private let category: AVAudioSession.Category
7
+ private let categoryOptions: AVAudioSession.CategoryOptions
8
+ private let mode: AVAudioSession.Mode
9
+
10
+ init(_ call: CAPPluginCall) throws {
11
+ self.category = try ConfigureOptions.getCategoryFromCall(call)
12
+ self.mode = ConfigureOptions.getModeFromCall(call)
13
+ self.categoryOptions = ConfigureOptions.getCategoryOptionsFromCall(call)
14
+ }
15
+
16
+ public func getCategory() -> AVAudioSession.Category {
17
+ return category
18
+ }
19
+
20
+ public func getCategoryOptions() -> AVAudioSession.CategoryOptions {
21
+ return categoryOptions
22
+ }
23
+
24
+ public func getMode() -> AVAudioSession.Mode {
25
+ return mode
26
+ }
27
+
28
+ private static func getCategoryFromCall(_ call: CAPPluginCall) throws -> AVAudioSession.Category {
29
+ guard let category = call.getString("category") else {
30
+ throw CustomError.categoryMissing
31
+ }
32
+ switch category {
33
+ case "ambient":
34
+ return .ambient
35
+ case "multiRoute":
36
+ return .multiRoute
37
+ case "playAndRecord":
38
+ return .playAndRecord
39
+ case "playback":
40
+ return .playback
41
+ case "record":
42
+ return .record
43
+ case "soloAmbient":
44
+ return .soloAmbient
45
+ default:
46
+ throw CustomError.categoryMissing
47
+ }
48
+ }
49
+
50
+ private static func getCategoryOptionsFromCall(_ call: CAPPluginCall) -> AVAudioSession.CategoryOptions {
51
+ guard let options = call.getObject("options") else {
52
+ return []
53
+ }
54
+ var categoryOptions: AVAudioSession.CategoryOptions = []
55
+ if options["mixWithOthers"] as? Bool == true {
56
+ categoryOptions.insert(.mixWithOthers)
57
+ }
58
+ if options["duckOthers"] as? Bool == true {
59
+ categoryOptions.insert(.duckOthers)
60
+ }
61
+ if options["interruptSpokenAudioAndMixWithOthers"] as? Bool == true {
62
+ categoryOptions.insert(.interruptSpokenAudioAndMixWithOthers)
63
+ }
64
+ if options["allowBluetooth"] as? Bool == true {
65
+ categoryOptions.insert(.allowBluetooth)
66
+ }
67
+ if options["allowBluetoothA2DP"] as? Bool == true {
68
+ categoryOptions.insert(.allowBluetoothA2DP)
69
+ }
70
+ if options["allowAirPlay"] as? Bool == true {
71
+ categoryOptions.insert(.allowAirPlay)
72
+ }
73
+ if options["defaultToSpeaker"] as? Bool == true {
74
+ categoryOptions.insert(.defaultToSpeaker)
75
+ }
76
+ return categoryOptions
77
+ }
78
+
79
+ private static func getModeFromCall(_ call: CAPPluginCall) -> AVAudioSession.Mode {
80
+ switch call.getString("mode") {
81
+ case "gameChat":
82
+ return .gameChat
83
+ case "measurement":
84
+ return .measurement
85
+ case "moviePlayback":
86
+ return .moviePlayback
87
+ case "spokenAudio":
88
+ return .spokenAudio
89
+ case "videoChat":
90
+ return .videoChat
91
+ case "videoRecording":
92
+ return .videoRecording
93
+ case "voiceChat":
94
+ return .voiceChat
95
+ case "voicePrompt":
96
+ return .voicePrompt
97
+ default:
98
+ return .default
99
+ }
100
+ }
101
+ }
@@ -0,0 +1,24 @@
1
+ import Foundation
2
+ import AVFoundation
3
+ import Capacitor
4
+
5
+ @objc public class OverrideOutputOptions: NSObject {
6
+ private let portOverride: AVAudioSession.PortOverride
7
+
8
+ init(_ call: CAPPluginCall) {
9
+ self.portOverride = OverrideOutputOptions.getPortOverrideFromCall(call)
10
+ }
11
+
12
+ public func getPortOverride() -> AVAudioSession.PortOverride {
13
+ return portOverride
14
+ }
15
+
16
+ private static func getPortOverrideFromCall(_ call: CAPPluginCall) -> AVAudioSession.PortOverride {
17
+ switch call.getString("type") {
18
+ case "speaker":
19
+ return .speaker
20
+ default:
21
+ return .none
22
+ }
23
+ }
24
+ }
@@ -0,0 +1,27 @@
1
+ import Foundation
2
+ import Capacitor
3
+
4
+ @objc public class SetActiveOptions: NSObject {
5
+ private let active: Bool
6
+ private let notifyOthersOnDeactivation: Bool
7
+
8
+ init(_ call: CAPPluginCall) throws {
9
+ self.active = try SetActiveOptions.getActiveFromCall(call)
10
+ self.notifyOthersOnDeactivation = call.getBool("notifyOthersOnDeactivation") ?? true
11
+ }
12
+
13
+ public func getActive() -> Bool {
14
+ return active
15
+ }
16
+
17
+ public func getNotifyOthersOnDeactivation() -> Bool {
18
+ return notifyOthersOnDeactivation
19
+ }
20
+
21
+ private static func getActiveFromCall(_ call: CAPPluginCall) throws -> Bool {
22
+ guard let active = call.getBool("active") else {
23
+ throw CustomError.activeMissing
24
+ }
25
+ return active
26
+ }
27
+ }
@@ -0,0 +1,19 @@
1
+ import Foundation
2
+ import Capacitor
3
+
4
+ @objc public class AudioSessionOutput: NSObject, Result {
5
+ private let portName: String
6
+ private let portType: String
7
+
8
+ init(portType: String, portName: String) {
9
+ self.portType = portType
10
+ self.portName = portName
11
+ }
12
+
13
+ @objc public func toJSObject() -> AnyObject {
14
+ var result = JSObject()
15
+ result["portType"] = portType
16
+ result["portName"] = portName
17
+ return result as AnyObject
18
+ }
19
+ }
@@ -0,0 +1,16 @@
1
+ import Foundation
2
+ import Capacitor
3
+
4
+ @objc public class GetCurrentOutputsResult: NSObject, Result {
5
+ private let outputs: [AudioSessionOutput]
6
+
7
+ init(outputs: [AudioSessionOutput]) {
8
+ self.outputs = outputs
9
+ }
10
+
11
+ @objc public func toJSObject() -> AnyObject {
12
+ var result = JSObject()
13
+ result["outputs"] = outputs.map { $0.toJSObject() }
14
+ return result as AnyObject
15
+ }
16
+ }
@@ -0,0 +1,36 @@
1
+ import Foundation
2
+
3
+ public enum CustomError: Error {
4
+ case activationFailed
5
+ case activeMissing
6
+ case categoryMissing
7
+ case configurationFailed
8
+
9
+ var code: String? {
10
+ switch self {
11
+ case .activationFailed:
12
+ return "ACTIVATION_FAILED"
13
+ case .activeMissing:
14
+ return nil
15
+ case .categoryMissing:
16
+ return nil
17
+ case .configurationFailed:
18
+ return "CONFIGURATION_FAILED"
19
+ }
20
+ }
21
+ }
22
+
23
+ extension CustomError: LocalizedError {
24
+ public var errorDescription: String? {
25
+ switch self {
26
+ case .activationFailed:
27
+ return NSLocalizedString("The audio session could not be activated or deactivated.", comment: "activationFailed")
28
+ case .activeMissing:
29
+ return NSLocalizedString("active must be provided.", comment: "activeMissing")
30
+ case .categoryMissing:
31
+ return NSLocalizedString("category must be provided.", comment: "categoryMissing")
32
+ case .configurationFailed:
33
+ return NSLocalizedString("The audio session could not be configured.", comment: "configurationFailed")
34
+ }
35
+ }
36
+ }
@@ -0,0 +1,24 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>CFBundleDevelopmentRegion</key>
6
+ <string>$(DEVELOPMENT_LANGUAGE)</string>
7
+ <key>CFBundleExecutable</key>
8
+ <string>$(EXECUTABLE_NAME)</string>
9
+ <key>CFBundleIdentifier</key>
10
+ <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
11
+ <key>CFBundleInfoDictionaryVersion</key>
12
+ <string>6.0</string>
13
+ <key>CFBundleName</key>
14
+ <string>$(PRODUCT_NAME)</string>
15
+ <key>CFBundlePackageType</key>
16
+ <string>FMWK</string>
17
+ <key>CFBundleShortVersionString</key>
18
+ <string>1.0</string>
19
+ <key>CFBundleVersion</key>
20
+ <string>$(CURRENT_PROJECT_VERSION)</string>
21
+ <key>NSPrincipalClass</key>
22
+ <string></string>
23
+ </dict>
24
+ </plist>
@@ -0,0 +1,5 @@
1
+ import Capacitor
2
+
3
+ @objc public protocol Result {
4
+ @objc func toJSObject() -> AnyObject
5
+ }
package/package.json ADDED
@@ -0,0 +1,91 @@
1
+ {
2
+ "name": "@capawesome/capacitor-audio-session",
3
+ "version": "0.0.1",
4
+ "description": "Capacitor plugin to configure and observe the iOS audio session.",
5
+ "main": "dist/plugin.cjs.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
+ "CapawesomeCapacitorAudioSession.podspec",
15
+ "Package.swift"
16
+ ],
17
+ "author": "Robin Genz <mail@robingenz.dev>",
18
+ "license": "MIT",
19
+ "repository": {
20
+ "type": "git",
21
+ "url": "git+https://github.com/capawesome-team/capacitor-plugins.git"
22
+ },
23
+ "bugs": {
24
+ "url": "https://github.com/capawesome-team/capacitor-plugins/issues"
25
+ },
26
+ "funding": [
27
+ {
28
+ "type": "github",
29
+ "url": "https://github.com/sponsors/capawesome-team/"
30
+ },
31
+ {
32
+ "type": "opencollective",
33
+ "url": "https://opencollective.com/capawesome"
34
+ }
35
+ ],
36
+ "homepage": "https://capawesome.io/docs/plugins/audio-session/",
37
+ "keywords": [
38
+ "capacitor",
39
+ "plugin",
40
+ "native"
41
+ ],
42
+ "scripts": {
43
+ "verify": "npm run verify:ios && npm run verify:android && npm run verify:web",
44
+ "verify:ios": "cd ios && pod install && xcodebuild -workspace Plugin.xcworkspace -scheme Plugin -destination generic/platform=iOS && cd ..",
45
+ "verify:android": "cd android && ./gradlew clean build test && cd ..",
46
+ "verify:web": "npm run build",
47
+ "lint": "npm run eslint && npm run prettier -- --check && npm run swiftlint -- lint",
48
+ "fmt": "npm run eslint -- --fix && npm run prettier -- --write && npm run swiftlint -- --fix --format",
49
+ "eslint": "eslint . --ext ts",
50
+ "prettier": "prettier \"**/*.{css,html,ts,js,java}\"",
51
+ "swiftlint": "node-swiftlint",
52
+ "docgen": "docgen --api AudioSessionPlugin --output-readme README.md --output-json dist/docs.json",
53
+ "build": "npm run clean && npm run docgen && tsc && rollup -c rollup.config.mjs",
54
+ "clean": "rimraf ./dist",
55
+ "watch": "tsc --watch",
56
+ "ios:pod:install": "cd ios && pod install --repo-update && cd ..",
57
+ "ios:spm:install": "cd ios && swift package resolve && cd ..",
58
+ "prepublishOnly": "npm run build"
59
+ },
60
+ "devDependencies": {
61
+ "@capacitor/android": "8.0.0",
62
+ "@capacitor/cli": "8.0.0",
63
+ "@capacitor/core": "8.0.0",
64
+ "@capacitor/docgen": "0.3.1",
65
+ "@capacitor/ios": "8.0.0",
66
+ "@ionic/eslint-config": "0.4.0",
67
+ "eslint": "8.57.0",
68
+ "prettier-plugin-java": "2.6.7",
69
+ "rimraf": "6.1.2",
70
+ "rollup": "4.53.3",
71
+ "swiftlint": "2.0.0",
72
+ "typescript": "5.9.3"
73
+ },
74
+ "peerDependencies": {
75
+ "@capacitor/core": ">=8.0.0"
76
+ },
77
+ "eslintConfig": {
78
+ "extends": "@ionic/eslint-config/recommended"
79
+ },
80
+ "capacitor": {
81
+ "ios": {
82
+ "src": "ios"
83
+ },
84
+ "android": {
85
+ "src": "android"
86
+ }
87
+ },
88
+ "publishConfig": {
89
+ "access": "public"
90
+ }
91
+ }