@capgo/capacitor-audio-recorder 7.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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.js","sources":["esm/definitions.js","esm/index.js","esm/web.js"],"sourcesContent":["/**\n * The recording status.\n *\n * @since 1.0.0\n */\nexport var RecordingStatus;\n(function (RecordingStatus) {\n RecordingStatus[\"Inactive\"] = \"INACTIVE\";\n RecordingStatus[\"Recording\"] = \"RECORDING\";\n RecordingStatus[\"Paused\"] = \"PAUSED\";\n})(RecordingStatus || (RecordingStatus = {}));\n/**\n * Audio session category options available on iOS.\n *\n * @since 1.0.0\n */\nexport var AudioSessionCategoryOption;\n(function (AudioSessionCategoryOption) {\n AudioSessionCategoryOption[\"AllowAirPlay\"] = \"ALLOW_AIR_PLAY\";\n AudioSessionCategoryOption[\"AllowBluetooth\"] = \"ALLOW_BLUETOOTH\";\n AudioSessionCategoryOption[\"AllowBluetoothA2DP\"] = \"ALLOW_BLUETOOTH_A2DP\";\n AudioSessionCategoryOption[\"DefaultToSpeaker\"] = \"DEFAULT_TO_SPEAKER\";\n AudioSessionCategoryOption[\"DuckOthers\"] = \"DUCK_OTHERS\";\n AudioSessionCategoryOption[\"InterruptSpokenAudioAndMixWithOthers\"] = \"INTERRUPT_SPOKEN_AUDIO_AND_MIX_WITH_OTHERS\";\n AudioSessionCategoryOption[\"MixWithOthers\"] = \"MIX_WITH_OTHERS\";\n AudioSessionCategoryOption[\"OverrideMutedMicrophoneInterruption\"] = \"OVERRIDE_MUTED_MICROPHONE_INTERRUPTION\";\n})(AudioSessionCategoryOption || (AudioSessionCategoryOption = {}));\n/**\n * Audio session modes available on iOS.\n *\n * @since 1.0.0\n */\nexport var AudioSessionMode;\n(function (AudioSessionMode) {\n AudioSessionMode[\"Default\"] = \"DEFAULT\";\n AudioSessionMode[\"GameChat\"] = \"GAME_CHAT\";\n AudioSessionMode[\"Measurement\"] = \"MEASUREMENT\";\n AudioSessionMode[\"SpokenAudio\"] = \"SPOKEN_AUDIO\";\n AudioSessionMode[\"VideoChat\"] = \"VIDEO_CHAT\";\n AudioSessionMode[\"VideoRecording\"] = \"VIDEO_RECORDING\";\n AudioSessionMode[\"VoiceChat\"] = \"VOICE_CHAT\";\n})(AudioSessionMode || (AudioSessionMode = {}));\n//# sourceMappingURL=definitions.js.map","import { registerPlugin } from '@capacitor/core';\nconst CapacitorAudioRecorder = registerPlugin('CapacitorAudioRecorder', {\n web: () => import('./web').then((m) => new m.CapacitorAudioRecorderWeb()),\n});\nexport * from './definitions';\nexport { CapacitorAudioRecorder };\n//# sourceMappingURL=index.js.map","import { WebPlugin } from '@capacitor/core';\nimport { RecordingStatus, } from './definitions';\nexport class CapacitorAudioRecorderWeb extends WebPlugin {\n constructor() {\n super(...arguments);\n this.mediaRecorder = null;\n this.mediaStream = null;\n this.recordedChunks = [];\n this.status = RecordingStatus.Inactive;\n this.startTimestamp = null;\n this.pausedTimestamp = null;\n this.accumulatedPauseDuration = 0;\n this.stopResolver = null;\n this.stopRejector = null;\n }\n async startRecording(_options) {\n var _a, _b;\n if (this.status === RecordingStatus.Recording || this.status === RecordingStatus.Paused) {\n throw this.unavailable('Recording already in progress.');\n }\n await this.ensurePermission(true);\n try {\n this.mediaStream = await navigator.mediaDevices.getUserMedia({ audio: true });\n }\n catch (error) {\n this.handleError(`Unable to acquire microphone: ${(_a = error === null || error === void 0 ? void 0 : error.message) !== null && _a !== void 0 ? _a : error}`);\n throw error;\n }\n const mimeType = this.pickMimeType();\n try {\n this.mediaRecorder = new MediaRecorder(this.mediaStream, mimeType ? { mimeType } : undefined);\n }\n catch (error) {\n this.cleanupMediaStream();\n this.handleError(`Unable to initialise MediaRecorder: ${(_b = error === null || error === void 0 ? void 0 : error.message) !== null && _b !== void 0 ? _b : error}`);\n throw error;\n }\n this.recordedChunks = [];\n this.startTimestamp = Date.now();\n this.accumulatedPauseDuration = 0;\n this.pausedTimestamp = null;\n this.mediaRecorder.addEventListener('dataavailable', (event) => {\n if (event.data.size > 0) {\n this.recordedChunks.push(event.data);\n }\n });\n this.mediaRecorder.addEventListener('stop', () => {\n const result = this.buildStopResult();\n if (this.stopResolver) {\n this.stopResolver(result);\n }\n this.notifyListeners('recordingStopped', result);\n this.resetStopHandlers();\n this.resetState();\n });\n this.mediaRecorder.addEventListener('error', (event) => {\n var _a, _b;\n const message = (_b = (_a = event === null || event === void 0 ? void 0 : event.error) === null || _a === void 0 ? void 0 : _a.message) !== null && _b !== void 0 ? _b : 'Recording error.';\n this.handleError(message);\n if (this.stopRejector) {\n this.stopRejector(new Error(message));\n }\n this.resetStopHandlers();\n this.resetState();\n });\n this.mediaRecorder.start();\n this.status = RecordingStatus.Recording;\n }\n async pauseRecording() {\n if (!this.mediaRecorder || this.status !== RecordingStatus.Recording) {\n throw this.unavailable('No active recording to pause.');\n }\n if (this.supportsRecorderPause()) {\n this.mediaRecorder.pause();\n this.status = RecordingStatus.Paused;\n this.pausedTimestamp = Date.now();\n this.notifyListeners('recordingPaused', {});\n }\n else {\n throw this.unavailable('Pausing recordings is not supported in this browser.');\n }\n }\n async resumeRecording() {\n if (!this.mediaRecorder || this.status !== RecordingStatus.Paused) {\n throw this.unavailable('No paused recording to resume.');\n }\n if (this.supportsRecorderPause()) {\n this.mediaRecorder.resume();\n if (this.pausedTimestamp) {\n this.accumulatedPauseDuration += Date.now() - this.pausedTimestamp;\n }\n this.pausedTimestamp = null;\n this.status = RecordingStatus.Recording;\n }\n else {\n throw this.unavailable('Resuming recordings is not supported in this browser.');\n }\n }\n async stopRecording() {\n var _a;\n if (!this.mediaRecorder || this.status === RecordingStatus.Inactive) {\n throw this.unavailable('No active recording to stop.');\n }\n if (this.status === RecordingStatus.Paused && this.pausedTimestamp) {\n this.accumulatedPauseDuration += Date.now() - this.pausedTimestamp;\n this.pausedTimestamp = null;\n }\n const stopPromise = new Promise((resolve, reject) => {\n this.stopResolver = resolve;\n this.stopRejector = reject;\n });\n try {\n this.mediaRecorder.stop();\n }\n catch (error) {\n this.resetStopHandlers();\n this.resetState();\n this.handleError(`Unable to stop recorder: ${(_a = error === null || error === void 0 ? void 0 : error.message) !== null && _a !== void 0 ? _a : error}`);\n throw error;\n }\n return stopPromise;\n }\n async cancelRecording() {\n if (!this.mediaRecorder || this.status === RecordingStatus.Inactive) {\n this.resetState();\n return;\n }\n try {\n this.mediaRecorder.stop();\n }\n catch (_a) {\n // Ignored.\n }\n this.resetStopHandlers();\n this.resetState();\n }\n async getRecordingStatus() {\n return { status: this.status };\n }\n async checkPermissions() {\n const state = await this.getPermissionState();\n return { recordAudio: state };\n }\n async requestPermissions() {\n const state = await this.ensurePermission(true);\n return { recordAudio: state };\n }\n async addListener(eventName, listenerFunc) {\n return super.addListener(eventName, listenerFunc);\n }\n async removeAllListeners() {\n await super.removeAllListeners();\n }\n // Helpers\n supportsRecorderPause() {\n return !!this.mediaRecorder && typeof this.mediaRecorder.pause === 'function' && typeof this.mediaRecorder.resume === 'function';\n }\n pickMimeType() {\n const preferred = ['audio/webm;codecs=opus', 'audio/ogg;codecs=opus', 'audio/mp4'];\n for (const type of preferred) {\n if (window.MediaRecorder && MediaRecorder.isTypeSupported && MediaRecorder.isTypeSupported(type)) {\n return type;\n }\n }\n return undefined;\n }\n buildStopResult() {\n const blob = this.recordedChunks.length > 0 ? new Blob(this.recordedChunks, { type: this.pickMimeType() || 'audio/webm' }) : undefined;\n let duration;\n if (this.startTimestamp) {\n duration = Date.now() - this.startTimestamp - this.accumulatedPauseDuration;\n }\n return {\n blob,\n duration,\n };\n }\n resetStopHandlers() {\n this.stopResolver = null;\n this.stopRejector = null;\n }\n resetState() {\n this.status = RecordingStatus.Inactive;\n this.startTimestamp = null;\n this.pausedTimestamp = null;\n this.accumulatedPauseDuration = 0;\n this.recordedChunks = [];\n this.cleanupMediaStream();\n if (this.mediaRecorder) {\n const recorder = this.mediaRecorder;\n recorder.ondataavailable = null;\n recorder.onstop = null;\n recorder.onerror = null;\n }\n this.mediaRecorder = null;\n }\n cleanupMediaStream() {\n if (this.mediaStream) {\n this.mediaStream.getTracks().forEach((track) => track.stop());\n }\n this.mediaStream = null;\n }\n async ensurePermission(request) {\n const currentState = await this.getPermissionState();\n if (currentState === 'granted' || !request) {\n return currentState;\n }\n try {\n const stream = await navigator.mediaDevices.getUserMedia({ audio: true });\n stream.getTracks().forEach((track) => track.stop());\n return 'granted';\n }\n catch (error) {\n return 'denied';\n }\n }\n async getPermissionState() {\n var _a;\n if (!((_a = navigator.permissions) === null || _a === void 0 ? void 0 : _a.query)) {\n return 'prompt';\n }\n try {\n const result = await navigator.permissions.query({ name: 'microphone' });\n switch (result.state) {\n case 'granted':\n return 'granted';\n case 'denied':\n return 'denied';\n default:\n return 'prompt';\n }\n }\n catch (_b) {\n return 'prompt';\n }\n }\n handleError(message) {\n this.status = RecordingStatus.Inactive;\n this.notifyListeners('recordingError', { message });\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["RecordingStatus","AudioSessionCategoryOption","AudioSessionMode","registerPlugin","WebPlugin"],"mappings":";;;IAAA;IACA;IACA;IACA;IACA;AACWA;IACX,CAAC,UAAU,eAAe,EAAE;IAC5B,IAAI,eAAe,CAAC,UAAU,CAAC,GAAG,UAAU;IAC5C,IAAI,eAAe,CAAC,WAAW,CAAC,GAAG,WAAW;IAC9C,IAAI,eAAe,CAAC,QAAQ,CAAC,GAAG,QAAQ;IACxC,CAAC,EAAEA,uBAAe,KAAKA,uBAAe,GAAG,EAAE,CAAC,CAAC;IAC7C;IACA;IACA;IACA;IACA;AACWC;IACX,CAAC,UAAU,0BAA0B,EAAE;IACvC,IAAI,0BAA0B,CAAC,cAAc,CAAC,GAAG,gBAAgB;IACjE,IAAI,0BAA0B,CAAC,gBAAgB,CAAC,GAAG,iBAAiB;IACpE,IAAI,0BAA0B,CAAC,oBAAoB,CAAC,GAAG,sBAAsB;IAC7E,IAAI,0BAA0B,CAAC,kBAAkB,CAAC,GAAG,oBAAoB;IACzE,IAAI,0BAA0B,CAAC,YAAY,CAAC,GAAG,aAAa;IAC5D,IAAI,0BAA0B,CAAC,sCAAsC,CAAC,GAAG,4CAA4C;IACrH,IAAI,0BAA0B,CAAC,eAAe,CAAC,GAAG,iBAAiB;IACnE,IAAI,0BAA0B,CAAC,qCAAqC,CAAC,GAAG,wCAAwC;IAChH,CAAC,EAAEA,kCAA0B,KAAKA,kCAA0B,GAAG,EAAE,CAAC,CAAC;IACnE;IACA;IACA;IACA;IACA;AACWC;IACX,CAAC,UAAU,gBAAgB,EAAE;IAC7B,IAAI,gBAAgB,CAAC,SAAS,CAAC,GAAG,SAAS;IAC3C,IAAI,gBAAgB,CAAC,UAAU,CAAC,GAAG,WAAW;IAC9C,IAAI,gBAAgB,CAAC,aAAa,CAAC,GAAG,aAAa;IACnD,IAAI,gBAAgB,CAAC,aAAa,CAAC,GAAG,cAAc;IACpD,IAAI,gBAAgB,CAAC,WAAW,CAAC,GAAG,YAAY;IAChD,IAAI,gBAAgB,CAAC,gBAAgB,CAAC,GAAG,iBAAiB;IAC1D,IAAI,gBAAgB,CAAC,WAAW,CAAC,GAAG,YAAY;IAChD,CAAC,EAAEA,wBAAgB,KAAKA,wBAAgB,GAAG,EAAE,CAAC,CAAC;;ACxC1C,UAAC,sBAAsB,GAAGC,mBAAc,CAAC,wBAAwB,EAAE;IACxE,IAAI,GAAG,EAAE,MAAM,mDAAe,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,yBAAyB,EAAE,CAAC;IAC7E,CAAC;;ICDM,MAAM,yBAAyB,SAASC,cAAS,CAAC;IACzD,IAAI,WAAW,GAAG;IAClB,QAAQ,KAAK,CAAC,GAAG,SAAS,CAAC;IAC3B,QAAQ,IAAI,CAAC,aAAa,GAAG,IAAI;IACjC,QAAQ,IAAI,CAAC,WAAW,GAAG,IAAI;IAC/B,QAAQ,IAAI,CAAC,cAAc,GAAG,EAAE;IAChC,QAAQ,IAAI,CAAC,MAAM,GAAGJ,uBAAe,CAAC,QAAQ;IAC9C,QAAQ,IAAI,CAAC,cAAc,GAAG,IAAI;IAClC,QAAQ,IAAI,CAAC,eAAe,GAAG,IAAI;IACnC,QAAQ,IAAI,CAAC,wBAAwB,GAAG,CAAC;IACzC,QAAQ,IAAI,CAAC,YAAY,GAAG,IAAI;IAChC,QAAQ,IAAI,CAAC,YAAY,GAAG,IAAI;IAChC,IAAI;IACJ,IAAI,MAAM,cAAc,CAAC,QAAQ,EAAE;IACnC,QAAQ,IAAI,EAAE,EAAE,EAAE;IAClB,QAAQ,IAAI,IAAI,CAAC,MAAM,KAAKA,uBAAe,CAAC,SAAS,IAAI,IAAI,CAAC,MAAM,KAAKA,uBAAe,CAAC,MAAM,EAAE;IACjG,YAAY,MAAM,IAAI,CAAC,WAAW,CAAC,gCAAgC,CAAC;IACpE,QAAQ;IACR,QAAQ,MAAM,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC;IACzC,QAAQ,IAAI;IACZ,YAAY,IAAI,CAAC,WAAW,GAAG,MAAM,SAAS,CAAC,YAAY,CAAC,YAAY,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IACzF,QAAQ;IACR,QAAQ,OAAO,KAAK,EAAE;IACtB,YAAY,IAAI,CAAC,WAAW,CAAC,CAAC,8BAA8B,EAAE,CAAC,EAAE,GAAG,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,MAAM,GAAG,MAAM,GAAG,KAAK,CAAC,OAAO,MAAM,IAAI,IAAI,EAAE,KAAK,MAAM,GAAG,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC;IAC1K,YAAY,MAAM,KAAK;IACvB,QAAQ;IACR,QAAQ,MAAM,QAAQ,GAAG,IAAI,CAAC,YAAY,EAAE;IAC5C,QAAQ,IAAI;IACZ,YAAY,IAAI,CAAC,aAAa,GAAG,IAAI,aAAa,CAAC,IAAI,CAAC,WAAW,EAAE,QAAQ,GAAG,EAAE,QAAQ,EAAE,GAAG,SAAS,CAAC;IACzG,QAAQ;IACR,QAAQ,OAAO,KAAK,EAAE;IACtB,YAAY,IAAI,CAAC,kBAAkB,EAAE;IACrC,YAAY,IAAI,CAAC,WAAW,CAAC,CAAC,oCAAoC,EAAE,CAAC,EAAE,GAAG,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,MAAM,GAAG,MAAM,GAAG,KAAK,CAAC,OAAO,MAAM,IAAI,IAAI,EAAE,KAAK,MAAM,GAAG,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC;IAChL,YAAY,MAAM,KAAK;IACvB,QAAQ;IACR,QAAQ,IAAI,CAAC,cAAc,GAAG,EAAE;IAChC,QAAQ,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC,GAAG,EAAE;IACxC,QAAQ,IAAI,CAAC,wBAAwB,GAAG,CAAC;IACzC,QAAQ,IAAI,CAAC,eAAe,GAAG,IAAI;IACnC,QAAQ,IAAI,CAAC,aAAa,CAAC,gBAAgB,CAAC,eAAe,EAAE,CAAC,KAAK,KAAK;IACxE,YAAY,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,EAAE;IACrC,gBAAgB,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;IACpD,YAAY;IACZ,QAAQ,CAAC,CAAC;IACV,QAAQ,IAAI,CAAC,aAAa,CAAC,gBAAgB,CAAC,MAAM,EAAE,MAAM;IAC1D,YAAY,MAAM,MAAM,GAAG,IAAI,CAAC,eAAe,EAAE;IACjD,YAAY,IAAI,IAAI,CAAC,YAAY,EAAE;IACnC,gBAAgB,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC;IACzC,YAAY;IACZ,YAAY,IAAI,CAAC,eAAe,CAAC,kBAAkB,EAAE,MAAM,CAAC;IAC5D,YAAY,IAAI,CAAC,iBAAiB,EAAE;IACpC,YAAY,IAAI,CAAC,UAAU,EAAE;IAC7B,QAAQ,CAAC,CAAC;IACV,QAAQ,IAAI,CAAC,aAAa,CAAC,gBAAgB,CAAC,OAAO,EAAE,CAAC,KAAK,KAAK;IAChE,YAAY,IAAI,EAAE,EAAE,EAAE;IACtB,YAAY,MAAM,OAAO,GAAG,CAAC,EAAE,GAAG,CAAC,EAAE,GAAG,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,MAAM,GAAG,MAAM,GAAG,KAAK,CAAC,KAAK,MAAM,IAAI,IAAI,EAAE,KAAK,MAAM,GAAG,MAAM,GAAG,EAAE,CAAC,OAAO,MAAM,IAAI,IAAI,EAAE,KAAK,MAAM,GAAG,EAAE,GAAG,kBAAkB;IACvM,YAAY,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC;IACrC,YAAY,IAAI,IAAI,CAAC,YAAY,EAAE;IACnC,gBAAgB,IAAI,CAAC,YAAY,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC;IACrD,YAAY;IACZ,YAAY,IAAI,CAAC,iBAAiB,EAAE;IACpC,YAAY,IAAI,CAAC,UAAU,EAAE;IAC7B,QAAQ,CAAC,CAAC;IACV,QAAQ,IAAI,CAAC,aAAa,CAAC,KAAK,EAAE;IAClC,QAAQ,IAAI,CAAC,MAAM,GAAGA,uBAAe,CAAC,SAAS;IAC/C,IAAI;IACJ,IAAI,MAAM,cAAc,GAAG;IAC3B,QAAQ,IAAI,CAAC,IAAI,CAAC,aAAa,IAAI,IAAI,CAAC,MAAM,KAAKA,uBAAe,CAAC,SAAS,EAAE;IAC9E,YAAY,MAAM,IAAI,CAAC,WAAW,CAAC,+BAA+B,CAAC;IACnE,QAAQ;IACR,QAAQ,IAAI,IAAI,CAAC,qBAAqB,EAAE,EAAE;IAC1C,YAAY,IAAI,CAAC,aAAa,CAAC,KAAK,EAAE;IACtC,YAAY,IAAI,CAAC,MAAM,GAAGA,uBAAe,CAAC,MAAM;IAChD,YAAY,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,GAAG,EAAE;IAC7C,YAAY,IAAI,CAAC,eAAe,CAAC,iBAAiB,EAAE,EAAE,CAAC;IACvD,QAAQ;IACR,aAAa;IACb,YAAY,MAAM,IAAI,CAAC,WAAW,CAAC,sDAAsD,CAAC;IAC1F,QAAQ;IACR,IAAI;IACJ,IAAI,MAAM,eAAe,GAAG;IAC5B,QAAQ,IAAI,CAAC,IAAI,CAAC,aAAa,IAAI,IAAI,CAAC,MAAM,KAAKA,uBAAe,CAAC,MAAM,EAAE;IAC3E,YAAY,MAAM,IAAI,CAAC,WAAW,CAAC,gCAAgC,CAAC;IACpE,QAAQ;IACR,QAAQ,IAAI,IAAI,CAAC,qBAAqB,EAAE,EAAE;IAC1C,YAAY,IAAI,CAAC,aAAa,CAAC,MAAM,EAAE;IACvC,YAAY,IAAI,IAAI,CAAC,eAAe,EAAE;IACtC,gBAAgB,IAAI,CAAC,wBAAwB,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,eAAe;IAClF,YAAY;IACZ,YAAY,IAAI,CAAC,eAAe,GAAG,IAAI;IACvC,YAAY,IAAI,CAAC,MAAM,GAAGA,uBAAe,CAAC,SAAS;IACnD,QAAQ;IACR,aAAa;IACb,YAAY,MAAM,IAAI,CAAC,WAAW,CAAC,uDAAuD,CAAC;IAC3F,QAAQ;IACR,IAAI;IACJ,IAAI,MAAM,aAAa,GAAG;IAC1B,QAAQ,IAAI,EAAE;IACd,QAAQ,IAAI,CAAC,IAAI,CAAC,aAAa,IAAI,IAAI,CAAC,MAAM,KAAKA,uBAAe,CAAC,QAAQ,EAAE;IAC7E,YAAY,MAAM,IAAI,CAAC,WAAW,CAAC,8BAA8B,CAAC;IAClE,QAAQ;IACR,QAAQ,IAAI,IAAI,CAAC,MAAM,KAAKA,uBAAe,CAAC,MAAM,IAAI,IAAI,CAAC,eAAe,EAAE;IAC5E,YAAY,IAAI,CAAC,wBAAwB,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,eAAe;IAC9E,YAAY,IAAI,CAAC,eAAe,GAAG,IAAI;IACvC,QAAQ;IACR,QAAQ,MAAM,WAAW,GAAG,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,KAAK;IAC7D,YAAY,IAAI,CAAC,YAAY,GAAG,OAAO;IACvC,YAAY,IAAI,CAAC,YAAY,GAAG,MAAM;IACtC,QAAQ,CAAC,CAAC;IACV,QAAQ,IAAI;IACZ,YAAY,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE;IACrC,QAAQ;IACR,QAAQ,OAAO,KAAK,EAAE;IACtB,YAAY,IAAI,CAAC,iBAAiB,EAAE;IACpC,YAAY,IAAI,CAAC,UAAU,EAAE;IAC7B,YAAY,IAAI,CAAC,WAAW,CAAC,CAAC,yBAAyB,EAAE,CAAC,EAAE,GAAG,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,MAAM,GAAG,MAAM,GAAG,KAAK,CAAC,OAAO,MAAM,IAAI,IAAI,EAAE,KAAK,MAAM,GAAG,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC;IACrK,YAAY,MAAM,KAAK;IACvB,QAAQ;IACR,QAAQ,OAAO,WAAW;IAC1B,IAAI;IACJ,IAAI,MAAM,eAAe,GAAG;IAC5B,QAAQ,IAAI,CAAC,IAAI,CAAC,aAAa,IAAI,IAAI,CAAC,MAAM,KAAKA,uBAAe,CAAC,QAAQ,EAAE;IAC7E,YAAY,IAAI,CAAC,UAAU,EAAE;IAC7B,YAAY;IACZ,QAAQ;IACR,QAAQ,IAAI;IACZ,YAAY,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE;IACrC,QAAQ;IACR,QAAQ,OAAO,EAAE,EAAE;IACnB;IACA,QAAQ;IACR,QAAQ,IAAI,CAAC,iBAAiB,EAAE;IAChC,QAAQ,IAAI,CAAC,UAAU,EAAE;IACzB,IAAI;IACJ,IAAI,MAAM,kBAAkB,GAAG;IAC/B,QAAQ,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE;IACtC,IAAI;IACJ,IAAI,MAAM,gBAAgB,GAAG;IAC7B,QAAQ,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,kBAAkB,EAAE;IACrD,QAAQ,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE;IACrC,IAAI;IACJ,IAAI,MAAM,kBAAkB,GAAG;IAC/B,QAAQ,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC;IACvD,QAAQ,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE;IACrC,IAAI;IACJ,IAAI,MAAM,WAAW,CAAC,SAAS,EAAE,YAAY,EAAE;IAC/C,QAAQ,OAAO,KAAK,CAAC,WAAW,CAAC,SAAS,EAAE,YAAY,CAAC;IACzD,IAAI;IACJ,IAAI,MAAM,kBAAkB,GAAG;IAC/B,QAAQ,MAAM,KAAK,CAAC,kBAAkB,EAAE;IACxC,IAAI;IACJ;IACA,IAAI,qBAAqB,GAAG;IAC5B,QAAQ,OAAO,CAAC,CAAC,IAAI,CAAC,aAAa,IAAI,OAAO,IAAI,CAAC,aAAa,CAAC,KAAK,KAAK,UAAU,IAAI,OAAO,IAAI,CAAC,aAAa,CAAC,MAAM,KAAK,UAAU;IACxI,IAAI;IACJ,IAAI,YAAY,GAAG;IACnB,QAAQ,MAAM,SAAS,GAAG,CAAC,wBAAwB,EAAE,uBAAuB,EAAE,WAAW,CAAC;IAC1F,QAAQ,KAAK,MAAM,IAAI,IAAI,SAAS,EAAE;IACtC,YAAY,IAAI,MAAM,CAAC,aAAa,IAAI,aAAa,CAAC,eAAe,IAAI,aAAa,CAAC,eAAe,CAAC,IAAI,CAAC,EAAE;IAC9G,gBAAgB,OAAO,IAAI;IAC3B,YAAY;IACZ,QAAQ;IACR,QAAQ,OAAO,SAAS;IACxB,IAAI;IACJ,IAAI,eAAe,GAAG;IACtB,QAAQ,MAAM,IAAI,GAAG,IAAI,CAAC,cAAc,CAAC,MAAM,GAAG,CAAC,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,YAAY,EAAE,IAAI,YAAY,EAAE,CAAC,GAAG,SAAS;IAC9I,QAAQ,IAAI,QAAQ;IACpB,QAAQ,IAAI,IAAI,CAAC,cAAc,EAAE;IACjC,YAAY,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC,wBAAwB;IACvF,QAAQ;IACR,QAAQ,OAAO;IACf,YAAY,IAAI;IAChB,YAAY,QAAQ;IACpB,SAAS;IACT,IAAI;IACJ,IAAI,iBAAiB,GAAG;IACxB,QAAQ,IAAI,CAAC,YAAY,GAAG,IAAI;IAChC,QAAQ,IAAI,CAAC,YAAY,GAAG,IAAI;IAChC,IAAI;IACJ,IAAI,UAAU,GAAG;IACjB,QAAQ,IAAI,CAAC,MAAM,GAAGA,uBAAe,CAAC,QAAQ;IAC9C,QAAQ,IAAI,CAAC,cAAc,GAAG,IAAI;IAClC,QAAQ,IAAI,CAAC,eAAe,GAAG,IAAI;IACnC,QAAQ,IAAI,CAAC,wBAAwB,GAAG,CAAC;IACzC,QAAQ,IAAI,CAAC,cAAc,GAAG,EAAE;IAChC,QAAQ,IAAI,CAAC,kBAAkB,EAAE;IACjC,QAAQ,IAAI,IAAI,CAAC,aAAa,EAAE;IAChC,YAAY,MAAM,QAAQ,GAAG,IAAI,CAAC,aAAa;IAC/C,YAAY,QAAQ,CAAC,eAAe,GAAG,IAAI;IAC3C,YAAY,QAAQ,CAAC,MAAM,GAAG,IAAI;IAClC,YAAY,QAAQ,CAAC,OAAO,GAAG,IAAI;IACnC,QAAQ;IACR,QAAQ,IAAI,CAAC,aAAa,GAAG,IAAI;IACjC,IAAI;IACJ,IAAI,kBAAkB,GAAG;IACzB,QAAQ,IAAI,IAAI,CAAC,WAAW,EAAE;IAC9B,YAAY,IAAI,CAAC,WAAW,CAAC,SAAS,EAAE,CAAC,OAAO,CAAC,CAAC,KAAK,KAAK,KAAK,CAAC,IAAI,EAAE,CAAC;IACzE,QAAQ;IACR,QAAQ,IAAI,CAAC,WAAW,GAAG,IAAI;IAC/B,IAAI;IACJ,IAAI,MAAM,gBAAgB,CAAC,OAAO,EAAE;IACpC,QAAQ,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,kBAAkB,EAAE;IAC5D,QAAQ,IAAI,YAAY,KAAK,SAAS,IAAI,CAAC,OAAO,EAAE;IACpD,YAAY,OAAO,YAAY;IAC/B,QAAQ;IACR,QAAQ,IAAI;IACZ,YAAY,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,YAAY,CAAC,YAAY,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IACrF,YAAY,MAAM,CAAC,SAAS,EAAE,CAAC,OAAO,CAAC,CAAC,KAAK,KAAK,KAAK,CAAC,IAAI,EAAE,CAAC;IAC/D,YAAY,OAAO,SAAS;IAC5B,QAAQ;IACR,QAAQ,OAAO,KAAK,EAAE;IACtB,YAAY,OAAO,QAAQ;IAC3B,QAAQ;IACR,IAAI;IACJ,IAAI,MAAM,kBAAkB,GAAG;IAC/B,QAAQ,IAAI,EAAE;IACd,QAAQ,IAAI,EAAE,CAAC,EAAE,GAAG,SAAS,CAAC,WAAW,MAAM,IAAI,IAAI,EAAE,KAAK,MAAM,GAAG,MAAM,GAAG,EAAE,CAAC,KAAK,CAAC,EAAE;IAC3F,YAAY,OAAO,QAAQ;IAC3B,QAAQ;IACR,QAAQ,IAAI;IACZ,YAAY,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,WAAW,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC;IACpF,YAAY,QAAQ,MAAM,CAAC,KAAK;IAChC,gBAAgB,KAAK,SAAS;IAC9B,oBAAoB,OAAO,SAAS;IACpC,gBAAgB,KAAK,QAAQ;IAC7B,oBAAoB,OAAO,QAAQ;IACnC,gBAAgB;IAChB,oBAAoB,OAAO,QAAQ;IACnC;IACA,QAAQ;IACR,QAAQ,OAAO,EAAE,EAAE;IACnB,YAAY,OAAO,QAAQ;IAC3B,QAAQ;IACR,IAAI;IACJ,IAAI,WAAW,CAAC,OAAO,EAAE;IACzB,QAAQ,IAAI,CAAC,MAAM,GAAGA,uBAAe,CAAC,QAAQ;IAC9C,QAAQ,IAAI,CAAC,eAAe,CAAC,gBAAgB,EAAE,EAAE,OAAO,EAAE,CAAC;IAC3D,IAAI;IACJ;;;;;;;;;;;;;;;"}
@@ -0,0 +1,321 @@
1
+ import AVFoundation
2
+ import Capacitor
3
+ import Foundation
4
+
5
+ @objc(CapacitorAudioRecorderPlugin)
6
+ public class CapacitorAudioRecorderPlugin: CAPPlugin, CAPBridgedPlugin, AVAudioRecorderDelegate {
7
+ public let identifier = "CapacitorAudioRecorderPlugin"
8
+ public let jsName = "CapacitorAudioRecorder"
9
+ public let pluginMethods: [CAPPluginMethod] = [
10
+ CAPPluginMethod(name: "startRecording", returnType: CAPPluginReturnPromise),
11
+ CAPPluginMethod(name: "pauseRecording", returnType: CAPPluginReturnPromise),
12
+ CAPPluginMethod(name: "resumeRecording", returnType: CAPPluginReturnPromise),
13
+ CAPPluginMethod(name: "stopRecording", returnType: CAPPluginReturnPromise),
14
+ CAPPluginMethod(name: "cancelRecording", returnType: CAPPluginReturnPromise),
15
+ CAPPluginMethod(name: "getRecordingStatus", returnType: CAPPluginReturnPromise),
16
+ CAPPluginMethod(name: "checkPermissions", returnType: CAPPluginReturnPromise),
17
+ CAPPluginMethod(name: "requestPermissions", returnType: CAPPluginReturnPromise),
18
+ CAPPluginMethod(name: "removeAllListeners", returnType: CAPPluginReturnPromise),
19
+ ]
20
+
21
+ private enum RecordingStatus: String {
22
+ case inactive = "INACTIVE"
23
+ case recording = "RECORDING"
24
+ case paused = "PAUSED"
25
+ }
26
+
27
+ private let audioSession = AVAudioSession.sharedInstance()
28
+ private var audioRecorder: AVAudioRecorder?
29
+ private var currentFileURL: URL?
30
+ private var status: RecordingStatus = .inactive
31
+ private var recordingStartDate: Date?
32
+ private var pauseStartDate: Date?
33
+ private var accumulatedPauseDuration: TimeInterval = 0
34
+ private var shouldEmitStoppedEvent = true
35
+
36
+ // MARK: - Plugin methods
37
+
38
+ @objc func startRecording(_ call: CAPPluginCall) {
39
+ guard status == .inactive else {
40
+ call.reject("A recording is already in progress.")
41
+ return
42
+ }
43
+
44
+ ensurePermission { granted in
45
+ if !granted {
46
+ call.reject("Microphone permission not granted.")
47
+ return
48
+ }
49
+
50
+ do {
51
+ try self.configureAudioSession(options: call)
52
+ try self.beginRecording(call)
53
+ call.resolve()
54
+ } catch {
55
+ self.resetRecorder(deleteFile: true)
56
+ call.reject("Failed to start recording.", nil, error)
57
+ }
58
+ }
59
+ }
60
+
61
+ @objc func pauseRecording(_ call: CAPPluginCall) {
62
+ guard let recorder = audioRecorder, status == .recording else {
63
+ call.reject("No active recording to pause.")
64
+ return
65
+ }
66
+
67
+ recorder.pause()
68
+ pauseStartDate = Date()
69
+ status = .paused
70
+ notifyListeners("recordingPaused", data: [:])
71
+ call.resolve()
72
+ }
73
+
74
+ @objc func resumeRecording(_ call: CAPPluginCall) {
75
+ guard let recorder = audioRecorder, status == .paused else {
76
+ call.reject("No paused recording to resume.")
77
+ return
78
+ }
79
+
80
+ if let pauseStartDate {
81
+ accumulatedPauseDuration += Date().timeIntervalSince(pauseStartDate)
82
+ }
83
+ recorder.record()
84
+ status = .recording
85
+ pauseStartDate = nil
86
+ call.resolve()
87
+ }
88
+
89
+ @objc func stopRecording(_ call: CAPPluginCall) {
90
+ guard let recorder = audioRecorder, status != .inactive else {
91
+ call.reject("No active recording to stop.")
92
+ return
93
+ }
94
+
95
+ shouldEmitStoppedEvent = false
96
+ recorder.stop()
97
+ deactivateSessionIfNeeded()
98
+
99
+ let durationMilliseconds = recorder.currentTime * 1000
100
+ let uri = currentFileURL?.absoluteString ?? ""
101
+
102
+ let result: [String: Any] = [
103
+ "duration": durationMilliseconds,
104
+ "uri": uri,
105
+ ]
106
+
107
+ notifyListeners("recordingStopped", data: result)
108
+ call.resolve(result)
109
+ resetRecorder(deleteFile: false)
110
+ }
111
+
112
+ @objc func cancelRecording(_ call: CAPPluginCall) {
113
+ guard audioRecorder != nil else {
114
+ resetRecorder(deleteFile: true)
115
+ call.resolve()
116
+ return
117
+ }
118
+
119
+ shouldEmitStoppedEvent = false
120
+ audioRecorder?.stop()
121
+ deactivateSessionIfNeeded()
122
+ resetRecorder(deleteFile: true)
123
+ call.resolve()
124
+ }
125
+
126
+ @objc func getRecordingStatus(_ call: CAPPluginCall) {
127
+ call.resolve(["status": status.rawValue])
128
+ }
129
+
130
+ @objc override public func checkPermissions(_ call: CAPPluginCall) {
131
+ call.resolve(["recordAudio": microphonePermissionState()])
132
+ }
133
+
134
+ @objc override public func requestPermissions(_ call: CAPPluginCall) {
135
+ ensurePermission { granted in
136
+ call.resolve(["recordAudio": granted ? "granted" : "denied"])
137
+ }
138
+ }
139
+
140
+ @objc override public func removeAllListeners(_ call: CAPPluginCall) {
141
+ super.removeAllListeners(call)
142
+ }
143
+
144
+ // MARK: - AVAudioRecorderDelegate
145
+
146
+ public func audioRecorderEncodeErrorDidOccur(_ recorder: AVAudioRecorder, error: Error?) {
147
+ resetRecorder(deleteFile: true)
148
+ let message = error?.localizedDescription ?? "Unknown encoding error."
149
+ notifyListeners("recordingError", data: ["message": message])
150
+ }
151
+
152
+ public func audioRecorderDidFinishRecording(_ recorder: AVAudioRecorder, successfully flag: Bool) {
153
+ guard shouldEmitStoppedEvent else {
154
+ return
155
+ }
156
+
157
+ if flag {
158
+ let durationMilliseconds = recorder.currentTime * 1000
159
+ let uri = currentFileURL?.absoluteString ?? ""
160
+ let result: [String: Any] = [
161
+ "duration": durationMilliseconds,
162
+ "uri": uri,
163
+ ]
164
+ notifyListeners("recordingStopped", data: result)
165
+ } else {
166
+ notifyListeners("recordingError", data: ["message": "Recording finished unsuccessfully."])
167
+ }
168
+ resetRecorder(deleteFile: !flag)
169
+ }
170
+
171
+ // MARK: - Helpers
172
+
173
+ private func configureAudioSession(options call: CAPPluginCall) throws {
174
+ var categoryOptions: AVAudioSession.CategoryOptions = []
175
+ if let options = call.getArray("audioSessionCategoryOptions", String.self) {
176
+ options.forEach {
177
+ if let option = mapCategoryOption(from: $0) {
178
+ categoryOptions.insert(option)
179
+ }
180
+ }
181
+ } else {
182
+ categoryOptions.insert(.duckOthers)
183
+ }
184
+
185
+ let mode = mapSessionMode(from: call.getString("audioSessionMode")) ?? .measurement
186
+
187
+ try audioSession.setCategory(.playAndRecord, mode: mode, options: categoryOptions.union([.allowBluetooth, .defaultToSpeaker]))
188
+ try audioSession.setActive(true, options: .notifyOthersOnDeactivation)
189
+ }
190
+
191
+ private func beginRecording(_ call: CAPPluginCall) throws {
192
+ let bitRate = call.getDouble("bitRate") ?? 192_000
193
+ let sampleRate = call.getDouble("sampleRate") ?? 44_100
194
+
195
+ let directoryURL = FileManager.default.temporaryDirectory.appendingPathComponent("CapacitorAudioRecorder", isDirectory: true)
196
+ if !FileManager.default.fileExists(atPath: directoryURL.path) {
197
+ try FileManager.default.createDirectory(at: directoryURL, withIntermediateDirectories: true)
198
+ }
199
+
200
+ let fileURL = directoryURL.appendingPathComponent("\(UUID().uuidString).m4a")
201
+ let settings: [String: Any] = [
202
+ AVFormatIDKey: Int(kAudioFormatMPEG4AAC),
203
+ AVSampleRateKey: sampleRate,
204
+ AVNumberOfChannelsKey: 1,
205
+ AVEncoderBitRateKey: bitRate,
206
+ AVEncoderAudioQualityKey: AVAudioQuality.high.rawValue,
207
+ ]
208
+
209
+ let recorder = try AVAudioRecorder(url: fileURL, settings: settings)
210
+ recorder.delegate = self
211
+ recorder.prepareToRecord()
212
+ recorder.record()
213
+
214
+ audioRecorder = recorder
215
+ currentFileURL = fileURL
216
+ status = .recording
217
+ recordingStartDate = Date()
218
+ accumulatedPauseDuration = 0
219
+ pauseStartDate = nil
220
+ shouldEmitStoppedEvent = true
221
+ }
222
+
223
+ private func resetRecorder(deleteFile: Bool) {
224
+ if deleteFile, let url = currentFileURL {
225
+ try? FileManager.default.removeItem(at: url)
226
+ }
227
+ audioRecorder = nil
228
+ currentFileURL = nil
229
+ status = .inactive
230
+ recordingStartDate = nil
231
+ pauseStartDate = nil
232
+ accumulatedPauseDuration = 0
233
+ }
234
+
235
+ private func deactivateSessionIfNeeded() {
236
+ do {
237
+ try audioSession.setActive(false, options: .notifyOthersOnDeactivation)
238
+ } catch {
239
+ CAPLog.print("CapacitorAudioRecorderPlugin", "Failed to deactivate audio session: \(error.localizedDescription)")
240
+ }
241
+ }
242
+
243
+ private func ensurePermission(completion: @escaping (Bool) -> Void) {
244
+ switch audioSession.recordPermission {
245
+ case .granted:
246
+ completion(true)
247
+ case .denied:
248
+ completion(false)
249
+ case .undetermined:
250
+ audioSession.requestRecordPermission { granted in
251
+ DispatchQueue.main.async {
252
+ completion(granted)
253
+ }
254
+ }
255
+ @unknown default:
256
+ completion(false)
257
+ }
258
+ }
259
+
260
+ private func microphonePermissionState() -> String {
261
+ switch audioSession.recordPermission {
262
+ case .granted:
263
+ return "granted"
264
+ case .denied:
265
+ return "denied"
266
+ case .undetermined:
267
+ return "prompt"
268
+ @unknown default:
269
+ return "prompt"
270
+ }
271
+ }
272
+
273
+ private func mapCategoryOption(from value: String) -> AVAudioSession.CategoryOptions? {
274
+ switch value.uppercased() {
275
+ case "ALLOW_AIR_PLAY":
276
+ return .allowAirPlay
277
+ case "ALLOW_BLUETOOTH":
278
+ return .allowBluetooth
279
+ case "ALLOW_BLUETOOTH_A2DP":
280
+ if #available(iOS 10.0, *) {
281
+ return .allowBluetoothA2DP
282
+ }
283
+ return nil
284
+ case "DEFAULT_TO_SPEAKER":
285
+ return .defaultToSpeaker
286
+ case "DUCK_OTHERS":
287
+ return .duckOthers
288
+ case "INTERRUPT_SPOKEN_AUDIO_AND_MIX_WITH_OTHERS":
289
+ return .interruptSpokenAudioAndMixWithOthers
290
+ case "MIX_WITH_OTHERS":
291
+ return .mixWithOthers
292
+ case "OVERRIDE_MUTED_MICROPHONE_INTERRUPTION":
293
+ if #available(iOS 14.5, *) {
294
+ return .overrideMutedMicrophoneInterruption
295
+ }
296
+ return nil
297
+ default:
298
+ return nil
299
+ }
300
+ }
301
+
302
+ private func mapSessionMode(from value: String?) -> AVAudioSession.Mode? {
303
+ guard let value else { return nil }
304
+ switch value.uppercased() {
305
+ case "GAME_CHAT":
306
+ return .gameChat
307
+ case "MEASUREMENT":
308
+ return .measurement
309
+ case "SPOKEN_AUDIO":
310
+ return .spokenAudio
311
+ case "VIDEO_CHAT":
312
+ return .videoChat
313
+ case "VIDEO_RECORDING":
314
+ return .videoRecording
315
+ case "VOICE_CHAT":
316
+ return .voiceChat
317
+ default:
318
+ return .default
319
+ }
320
+ }
321
+ }
@@ -0,0 +1,9 @@
1
+ import XCTest
2
+ @testable import CapacitorAudioRecorderPlugin
3
+
4
+ final class CapacitorAudioRecorderPluginTests: XCTestCase {
5
+ func testPluginInitialises() {
6
+ let plugin = CapacitorAudioRecorderPlugin()
7
+ XCTAssertEqual(plugin.identifier, "CapacitorAudioRecorderPlugin")
8
+ }
9
+ }
package/package.json ADDED
@@ -0,0 +1,89 @@
1
+ {
2
+ "name": "@capgo/capacitor-audio-recorder",
3
+ "version": "7.0.0",
4
+ "description": "Record audio on iOS, Android, and Web with Capacitor",
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/Sources",
14
+ "ios/Tests",
15
+ "Package.swift",
16
+ "CapgoCapacitorAudioRecorder.podspec"
17
+ ],
18
+ "author": "Cap-go <contact@capgo.app>",
19
+ "license": "MIT",
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "git+https://github.com/Cap-go/capacitor-audio-recorder.git"
23
+ },
24
+ "bugs": {
25
+ "url": "https://github.com/Cap-go/capacitor-audio-recorder/issues"
26
+ },
27
+ "keywords": [
28
+ "capacitor",
29
+ "plugin",
30
+ "native",
31
+ "audio",
32
+ "recording",
33
+ "microphone",
34
+ "capgo",
35
+ "capacitor"
36
+ ],
37
+ "scripts": {
38
+ "verify": "npm run verify:ios && npm run verify:android && npm run verify:web",
39
+ "verify:ios": "xcodebuild -scheme CapgoCapacitorAudioRecorder -destination generic/platform=iOS",
40
+ "verify:android": "cd android && ./gradlew clean build test && cd ..",
41
+ "verify:web": "npm run build",
42
+ "lint": "npm run eslint && npm run prettier -- --check && npm run swiftlint -- lint",
43
+ "fmt": "npm run eslint -- --fix && npm run prettier -- --write && npm run swiftlint -- --autocorrect --format",
44
+ "eslint": "eslint . --ext .ts",
45
+ "prettier": "prettier \"**/*.{css,html,ts,js,java}\" --plugin=prettier-plugin-java",
46
+ "swiftlint": "node-swiftlint",
47
+ "docgen": "docgen --api CapacitorAudioRecorderPlugin --output-readme README.md --output-json dist/docs.json",
48
+ "build": "npm run clean && npm run docgen && tsc && rollup -c rollup.config.mjs",
49
+ "clean": "rimraf ./dist",
50
+ "watch": "tsc --watch",
51
+ "prepublishOnly": "npm run build"
52
+ },
53
+ "devDependencies": {
54
+ "@capacitor/android": "^7.0.0",
55
+ "@capacitor/cli": "^7.0.0",
56
+ "@capacitor/core": "^7.0.0",
57
+ "@capacitor/docgen": "^0.3.0",
58
+ "@capacitor/ios": "^7.0.0",
59
+ "@ionic/eslint-config": "^0.4.0",
60
+ "@ionic/prettier-config": "^4.0.0",
61
+ "@ionic/swiftlint-config": "^2.0.0",
62
+ "@types/node": "^22.13.1",
63
+ "eslint": "^8.57.0",
64
+ "eslint-plugin-import": "^2.31.0",
65
+ "husky": "^9.1.7",
66
+ "prettier": "^3.4.2",
67
+ "prettier-plugin-java": "^2.6.7",
68
+ "rimraf": "^6.0.1",
69
+ "rollup": "^4.34.6",
70
+ "swiftlint": "^2.0.0",
71
+ "typescript": "^5.7.3"
72
+ },
73
+ "peerDependencies": {
74
+ "@capacitor/core": ">=7.0.0"
75
+ },
76
+ "eslintConfig": {
77
+ "extends": "@ionic/eslint-config/recommended"
78
+ },
79
+ "prettier": "@ionic/prettier-config",
80
+ "swiftlint": "@ionic/swiftlint-config",
81
+ "capacitor": {
82
+ "ios": {
83
+ "src": "ios"
84
+ },
85
+ "android": {
86
+ "src": "android"
87
+ }
88
+ }
89
+ }