@capgo/capacitor-native-audio 8.4.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.
Files changed (46) hide show
  1. package/CapgoCapacitorNativeAudio.podspec +16 -0
  2. package/LICENSE +373 -0
  3. package/Package.swift +31 -0
  4. package/README.md +1229 -0
  5. package/android/build.gradle +89 -0
  6. package/android/src/main/AndroidManifest.xml +3 -0
  7. package/android/src/main/java/ee/forgr/audio/AudioAsset.java +611 -0
  8. package/android/src/main/java/ee/forgr/audio/AudioCompletionListener.java +5 -0
  9. package/android/src/main/java/ee/forgr/audio/AudioDispatcher.java +208 -0
  10. package/android/src/main/java/ee/forgr/audio/Constant.java +36 -0
  11. package/android/src/main/java/ee/forgr/audio/HlsAvailabilityChecker.java +84 -0
  12. package/android/src/main/java/ee/forgr/audio/Logger.java +55 -0
  13. package/android/src/main/java/ee/forgr/audio/NativeAudio.java +2022 -0
  14. package/android/src/main/java/ee/forgr/audio/RemoteAudioAsset.java +886 -0
  15. package/android/src/main/java/ee/forgr/audio/StreamAudioAsset.java +708 -0
  16. package/android/src/main/res/values/colors.xml +3 -0
  17. package/android/src/main/res/values/strings.xml +3 -0
  18. package/android/src/main/res/values/styles.xml +3 -0
  19. package/dist/docs.json +1470 -0
  20. package/dist/esm/audio-asset.d.ts +4 -0
  21. package/dist/esm/audio-asset.js +6 -0
  22. package/dist/esm/audio-asset.js.map +1 -0
  23. package/dist/esm/definitions.d.ts +597 -0
  24. package/dist/esm/definitions.js +2 -0
  25. package/dist/esm/definitions.js.map +1 -0
  26. package/dist/esm/index.d.ts +4 -0
  27. package/dist/esm/index.js +7 -0
  28. package/dist/esm/index.js.map +1 -0
  29. package/dist/esm/web.d.ts +82 -0
  30. package/dist/esm/web.js +553 -0
  31. package/dist/esm/web.js.map +1 -0
  32. package/dist/plugin.cjs.js +571 -0
  33. package/dist/plugin.cjs.js.map +1 -0
  34. package/dist/plugin.js +574 -0
  35. package/dist/plugin.js.map +1 -0
  36. package/ios/Sources/NativeAudioPlugin/AudioAsset+Fade.swift +157 -0
  37. package/ios/Sources/NativeAudioPlugin/AudioAsset.swift +403 -0
  38. package/ios/Sources/NativeAudioPlugin/Constant.swift +52 -0
  39. package/ios/Sources/NativeAudioPlugin/Logger.swift +43 -0
  40. package/ios/Sources/NativeAudioPlugin/Plugin.swift +1786 -0
  41. package/ios/Sources/NativeAudioPlugin/RemoteAudioAsset+Fade.swift +152 -0
  42. package/ios/Sources/NativeAudioPlugin/RemoteAudioAsset.swift +405 -0
  43. package/ios/Tests/NativeAudioPluginTests/PluginTests.swift +648 -0
  44. package/ios/Tests/README.md +39 -0
  45. package/package.json +101 -0
  46. package/scripts/configure-dependencies.js +251 -0
package/package.json ADDED
@@ -0,0 +1,101 @@
1
+ {
2
+ "name": "@capgo/capacitor-native-audio",
3
+ "version": "8.4.3",
4
+ "description": "A native plugin for native audio engine",
5
+ "license": "MPL-2.0",
6
+ "main": "dist/plugin.cjs.js",
7
+ "module": "dist/esm/index.js",
8
+ "types": "dist/esm/index.d.ts",
9
+ "unpkg": "dist/plugin.js",
10
+ "files": [
11
+ "android/src/main/",
12
+ "android/build.gradle",
13
+ "dist/",
14
+ "ios/Sources",
15
+ "ios/Tests",
16
+ "Package.swift",
17
+ "CapgoCapacitorNativeAudio.podspec",
18
+ "scripts/configure-dependencies.js"
19
+ ],
20
+ "author": "Martin Donadieu",
21
+ "repository": {
22
+ "type": "git",
23
+ "url": "git+https://github.com/Cap-go/capacitor-native-audio.git"
24
+ },
25
+ "bugs": {
26
+ "url": "https://github.com/Cap-go/capacitor-native-audio/native-audio/issues"
27
+ },
28
+ "homepage": "https://capgo.app/docs/plugins/native-audio/",
29
+ "keywords": [
30
+ "capacitor",
31
+ "plugin",
32
+ "audio",
33
+ "media",
34
+ "capgo",
35
+ "native"
36
+ ],
37
+ "scripts": {
38
+ "capacitor:sync:after": "node scripts/configure-dependencies.js",
39
+ "verify": "bun run verify:ios && bun run verify:android && bun run verify:web",
40
+ "verify:ios": "xcodebuild -scheme CapgoCapacitorNativeAudio -destination generic/platform=iOS",
41
+ "verify:android": "cd android && ./gradlew clean build test && cd ..",
42
+ "verify:web": "bun run build",
43
+ "test": "bun run test:ios",
44
+ "test:ios": "cd ios && xcodebuild test -workspace Plugin.xcworkspace -scheme Plugin -destination 'platform=iOS Simulator,name=iPhone 16' && cd ..",
45
+ "lint": "bun run eslint && bun run prettier -- --check && bun run swiftlint -- lint",
46
+ "fmt": "bun run eslint -- --fix && bun run prettier -- --write && bun run swiftlint -- --fix --format",
47
+ "eslint": "eslint . --ext .ts",
48
+ "prettier": "prettier-pretty-check \"**/*.{css,html,ts,js,java}\" --plugin=prettier-plugin-java",
49
+ "swiftlint": "node-swiftlint",
50
+ "docgen": "docgen --api NativeAudio --output-readme README.md --output-json dist/docs.json",
51
+ "build": "bun run clean && bun run docgen && bun run build:scripts && tsc && rollup -c rollup.config.mjs",
52
+ "build:scripts": "tsc -p scripts/tsconfig.json",
53
+ "clean": "rimraf ./dist",
54
+ "watch": "tsc --watch",
55
+ "example:install": "cd example-app && bun install",
56
+ "example:build": "cd example-app && bun run build",
57
+ "example:sync:android": "cd example-app && bun run sync:android",
58
+ "example:sync:ios": "cd example-app && bun run sync:ios",
59
+ "test:e2e:android": "maestro test .maestro/android/basic-features.yaml",
60
+ "test:e2e:ios": "maestro test .maestro/ios/basic-features.yaml",
61
+ "prepublishOnly": "bun run build",
62
+ "check:wiring": "node scripts/check-capacitor-plugin-wiring.mjs"
63
+ },
64
+ "devDependencies": {
65
+ "@capacitor/android": "^8.0.0",
66
+ "@capacitor/cli": "^8.0.0",
67
+ "@capacitor/core": "^8.0.0",
68
+ "@capacitor/docgen": "^0.3.1",
69
+ "@capacitor/ios": "^8.0.0",
70
+ "@ionic/eslint-config": "^0.4.0",
71
+ "@ionic/prettier-config": "^4.0.0",
72
+ "@ionic/swiftlint-config": "^2.0.0",
73
+ "@types/node": "^24.10.1",
74
+ "eslint": "^8.57.1",
75
+ "eslint-plugin-import": "^2.31.0",
76
+ "husky": "^9.1.7",
77
+ "prettier": "^3.6.2",
78
+ "prettier-plugin-java": "^2.7.7",
79
+ "rimraf": "^6.1.0",
80
+ "rollup": "^4.53.2",
81
+ "swiftlint": "^2.0.0",
82
+ "typescript": "^5.9.3",
83
+ "prettier-pretty-check": "^0.2.0"
84
+ },
85
+ "peerDependencies": {
86
+ "@capacitor/core": ">=8.0.0"
87
+ },
88
+ "prettier": "@ionic/prettier-config",
89
+ "swiftlint": "@ionic/swiftlint-config",
90
+ "eslintConfig": {
91
+ "extends": "@ionic/eslint-config/recommended"
92
+ },
93
+ "capacitor": {
94
+ "ios": {
95
+ "src": "ios"
96
+ },
97
+ "android": {
98
+ "src": "android"
99
+ }
100
+ }
101
+ }
@@ -0,0 +1,251 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ /**
4
+ * Capacitor Hook Script: Configure Optional HLS Dependency
5
+ *
6
+ * This script runs during `npx cap sync` and configures whether to include
7
+ * the HLS (m3u8) streaming dependency based on capacitor.config.ts settings.
8
+ *
9
+ * By default, HLS is enabled for backward compatibility.
10
+ * To disable HLS and reduce APK size by ~4MB, set:
11
+ *
12
+ * plugins: {
13
+ * NativeAudio: {
14
+ * hls: false
15
+ * }
16
+ * }
17
+ *
18
+ * Environment variables provided by Capacitor:
19
+ * - CAPACITOR_ROOT_DIR: Root directory of the consuming app
20
+ * - CAPACITOR_CONFIG: JSON stringified config object
21
+ * - CAPACITOR_PLATFORM_NAME: Platform name (android, ios, web)
22
+ * - process.cwd(): Plugin root directory
23
+ */
24
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
25
+ if (k2 === undefined) k2 = k;
26
+ var desc = Object.getOwnPropertyDescriptor(m, k);
27
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
28
+ desc = { enumerable: true, get: function() { return m[k]; } };
29
+ }
30
+ Object.defineProperty(o, k2, desc);
31
+ }) : (function(o, m, k, k2) {
32
+ if (k2 === undefined) k2 = k;
33
+ o[k2] = m[k];
34
+ }));
35
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
36
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
37
+ }) : function(o, v) {
38
+ o["default"] = v;
39
+ });
40
+ var __importStar = (this && this.__importStar) || (function () {
41
+ var ownKeys = function(o) {
42
+ ownKeys = Object.getOwnPropertyNames || function (o) {
43
+ var ar = [];
44
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
45
+ return ar;
46
+ };
47
+ return ownKeys(o);
48
+ };
49
+ return function (mod) {
50
+ if (mod && mod.__esModule) return mod;
51
+ var result = {};
52
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
53
+ __setModuleDefault(result, mod);
54
+ return result;
55
+ };
56
+ })();
57
+ Object.defineProperty(exports, "__esModule", { value: true });
58
+ exports.getConfig = getConfig;
59
+ exports.configureAndroid = configureAndroid;
60
+ exports.configureIOS = configureIOS;
61
+ exports.configureWeb = configureWeb;
62
+ const fs = __importStar(require("fs"));
63
+ const path = __importStar(require("path"));
64
+ // Get environment variables
65
+ const PLUGIN_ROOT = process.cwd();
66
+ const CONFIG_JSON = process.env.CAPACITOR_CONFIG;
67
+ const PLATFORM = process.env.CAPACITOR_PLATFORM_NAME;
68
+ // File paths
69
+ const gradlePropertiesPath = path.join(PLUGIN_ROOT, 'android', 'gradle.properties');
70
+ // ============================================================================
71
+ // Logging Utilities
72
+ // ============================================================================
73
+ const colors = {
74
+ reset: '\x1b[0m',
75
+ bright: '\x1b[1m',
76
+ green: '\x1b[32m',
77
+ red: '\x1b[31m',
78
+ yellow: '\x1b[33m',
79
+ blue: '\x1b[34m',
80
+ cyan: '\x1b[36m',
81
+ gray: '\x1b[90m',
82
+ };
83
+ function log(message, emoji = '', color = '') {
84
+ const emojiPart = emoji ? `${emoji} ` : '';
85
+ const colorCode = color || colors.reset;
86
+ const resetCode = color ? colors.reset : '';
87
+ console.log(`${colorCode}${emojiPart}${message}${resetCode}`);
88
+ }
89
+ function logSuccess(message) {
90
+ log(message, '✔', colors.green);
91
+ }
92
+ function logError(message) {
93
+ log(message, '✖', colors.red);
94
+ }
95
+ function logInfo(message) {
96
+ log(message, 'ℹ', colors.blue);
97
+ }
98
+ function logWarning(message) {
99
+ log(message, '⚠', colors.yellow);
100
+ }
101
+ /**
102
+ * Parse NativeAudio configuration from Capacitor config
103
+ * Default: hls = true (for backward compatibility)
104
+ */
105
+ function getConfig() {
106
+ const defaultConfig = {
107
+ hls: true, // Enabled by default for backward compatibility
108
+ };
109
+ try {
110
+ if (!CONFIG_JSON) {
111
+ logInfo('No CAPACITOR_CONFIG found, using defaults (HLS enabled)');
112
+ return defaultConfig;
113
+ }
114
+ const config = JSON.parse(CONFIG_JSON);
115
+ const nativeAudioConfig = config.plugins?.NativeAudio || {};
116
+ return {
117
+ hls: nativeAudioConfig.hls !== false, // Default to true unless explicitly set to false
118
+ };
119
+ }
120
+ catch (error) {
121
+ logError(`Error parsing config: ${error.message}`);
122
+ return defaultConfig;
123
+ }
124
+ }
125
+ /**
126
+ * Log the current configuration status
127
+ */
128
+ function logConfig(config) {
129
+ log('\nNativeAudio configuration:', '', colors.bright);
130
+ if (config.hls) {
131
+ console.log(` ${colors.green}✔${colors.reset} ${colors.bright}HLS (m3u8)${colors.reset}: ${colors.green}enabled${colors.reset} (includes media3-exoplayer-hls, adds ~4MB to APK)`);
132
+ }
133
+ else {
134
+ console.log(` ${colors.yellow}○${colors.reset} ${colors.bright}HLS (m3u8)${colors.reset}: ${colors.yellow}disabled${colors.reset} (reduces APK size by ~4MB)`);
135
+ }
136
+ console.log('');
137
+ }
138
+ // ============================================================================
139
+ // Android: Gradle Configuration
140
+ // ============================================================================
141
+ /**
142
+ * Write gradle.properties file for Android
143
+ * Injects NativeAudio properties while preserving existing content
144
+ */
145
+ function configureAndroid(config) {
146
+ logInfo('Configuring Android dependencies...');
147
+ try {
148
+ // Read existing gradle.properties if it exists
149
+ let existingContent = '';
150
+ if (fs.existsSync(gradlePropertiesPath)) {
151
+ existingContent = fs.readFileSync(gradlePropertiesPath, 'utf8');
152
+ }
153
+ // Remove existing NativeAudio properties (if any)
154
+ const lines = existingContent.split('\n');
155
+ const filteredLines = [];
156
+ let inNativeAudioSection = false;
157
+ let lastWasEmpty = false;
158
+ for (const line of lines) {
159
+ // Check if this is a NativeAudio property or comment
160
+ if (line.trim().startsWith('# NativeAudio') ||
161
+ line.trim().startsWith('nativeAudio.') ||
162
+ line.trim() === '# Generated by NativeAudio hook script') {
163
+ inNativeAudioSection = true;
164
+ continue; // Skip this line
165
+ }
166
+ // If we were in NativeAudio section and hit a non-empty line, we're done
167
+ if (inNativeAudioSection && line.trim() !== '') {
168
+ inNativeAudioSection = false;
169
+ }
170
+ // Add non-NativeAudio lines, but avoid multiple consecutive empty lines
171
+ if (!inNativeAudioSection) {
172
+ if (line.trim() === '') {
173
+ if (!lastWasEmpty) {
174
+ filteredLines.push(line);
175
+ lastWasEmpty = true;
176
+ }
177
+ }
178
+ else {
179
+ filteredLines.push(line);
180
+ lastWasEmpty = false;
181
+ }
182
+ }
183
+ }
184
+ // Build new NativeAudio properties section
185
+ const nativeAudioProperties = [];
186
+ nativeAudioProperties.push('');
187
+ nativeAudioProperties.push('# NativeAudio Optional Dependencies (auto-generated)');
188
+ nativeAudioProperties.push('# Generated by NativeAudio hook script');
189
+ nativeAudioProperties.push(`nativeAudio.hls.include=${config.hls ? 'true' : 'false'}`);
190
+ // Combine: existing content + new NativeAudio properties
191
+ const newContent = filteredLines.join('\n') + '\n' + nativeAudioProperties.join('\n') + '\n';
192
+ fs.writeFileSync(gradlePropertiesPath, newContent, 'utf8');
193
+ logSuccess('Updated gradle.properties');
194
+ }
195
+ catch (error) {
196
+ logError(`Error updating gradle.properties: ${error.message}`);
197
+ }
198
+ }
199
+ // ============================================================================
200
+ // iOS: No Configuration Needed (yet)
201
+ // ============================================================================
202
+ /**
203
+ * iOS platform - HLS is handled natively by AVPlayer
204
+ */
205
+ function configureIOS() {
206
+ logInfo('iOS uses native AVPlayer for HLS - no additional configuration needed');
207
+ }
208
+ // ============================================================================
209
+ // Web: No Configuration Needed
210
+ // ============================================================================
211
+ /**
212
+ * Web platform doesn't need native dependency configuration
213
+ */
214
+ function configureWeb() {
215
+ logInfo('Web platform - no native dependency configuration needed');
216
+ }
217
+ // ============================================================================
218
+ // Main Execution
219
+ // ============================================================================
220
+ function main() {
221
+ const config = getConfig();
222
+ switch (PLATFORM) {
223
+ case 'android':
224
+ log('Configuring optional dependencies for NativeAudio', '🔧', colors.cyan);
225
+ logConfig(config);
226
+ configureAndroid(config);
227
+ logSuccess('Configuration complete\n');
228
+ break;
229
+ case 'ios':
230
+ log('Configuring NativeAudio for iOS', '🔧', colors.cyan);
231
+ logConfig(config);
232
+ configureIOS();
233
+ logSuccess('Configuration complete\n');
234
+ break;
235
+ case 'web':
236
+ configureWeb();
237
+ break;
238
+ default:
239
+ // If platform is not specified, configure all platforms (backward compatibility)
240
+ log('Configuring optional dependencies for NativeAudio', '🔧', colors.blue);
241
+ logConfig(config);
242
+ logWarning(`Unknown platform: ${PLATFORM || 'undefined'}, configuring Android`);
243
+ configureAndroid(config);
244
+ logSuccess('Configuration complete\n');
245
+ break;
246
+ }
247
+ }
248
+ // Run if executed directly
249
+ if (require.main === module) {
250
+ main();
251
+ }