@siteed/expo-audio-stream 1.16.0 → 1.17.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.
@@ -21,19 +21,26 @@ const withRecordingPermission = (config, props) => {
21
21
  useLocation: false,
22
22
  useExternalAccessory: false,
23
23
  },
24
+ iosConfig: {
25
+ microphoneUsageDescription: MICROPHONE_USAGE,
26
+ notificationUsageDescription: NOTIFICATION_USAGE,
27
+ },
24
28
  ...(props || {}),
25
29
  };
26
30
  const { enablePhoneStateHandling, enableNotifications, enableBackgroundAudio, } = options;
27
31
  debugLog('📱 Configuring Recording Permissions Plugin...', options);
28
32
  // iOS Configuration
29
33
  config = (0, config_plugins_1.withInfoPlist)(config, (config) => {
30
- // Base microphone permission (always required)
34
+ // Always set the microphone usage description from options first
31
35
  config.modResults['NSMicrophoneUsageDescription'] =
32
- config.modResults['NSMicrophoneUsageDescription'] ||
36
+ options.iosConfig?.microphoneUsageDescription ||
37
+ config.modResults['NSMicrophoneUsageDescription'] ||
33
38
  MICROPHONE_USAGE;
34
39
  if (enableNotifications) {
35
40
  config.modResults['NSUserNotificationsUsageDescription'] =
36
- NOTIFICATION_USAGE;
41
+ options.iosConfig?.notificationUsageDescription ||
42
+ config.modResults['NSUserNotificationsUsageDescription'] ||
43
+ NOTIFICATION_USAGE;
37
44
  config.modResults['NSUserNotificationAlertStyle'] = 'alert';
38
45
  }
39
46
  const existingBackgroundModes = config.modResults.UIBackgroundModes || [];
@@ -30,6 +30,8 @@ interface AudioStreamPluginOptions {
30
30
  iosConfig?: {
31
31
  allowBackgroundAudioControls?: boolean
32
32
  backgroundProcessingTitle?: string
33
+ microphoneUsageDescription?: string
34
+ notificationUsageDescription?: string
33
35
  }
34
36
  }
35
37
 
@@ -48,6 +50,10 @@ const withRecordingPermission: ConfigPlugin<AudioStreamPluginOptions> = (
48
50
  useLocation: false,
49
51
  useExternalAccessory: false,
50
52
  },
53
+ iosConfig: {
54
+ microphoneUsageDescription: MICROPHONE_USAGE,
55
+ notificationUsageDescription: NOTIFICATION_USAGE,
56
+ },
51
57
  ...(props || {}),
52
58
  }
53
59
 
@@ -61,13 +67,16 @@ const withRecordingPermission: ConfigPlugin<AudioStreamPluginOptions> = (
61
67
 
62
68
  // iOS Configuration
63
69
  config = withInfoPlist(config as any, (config) => {
64
- // Base microphone permission (always required)
70
+ // Always set the microphone usage description from options first
65
71
  config.modResults['NSMicrophoneUsageDescription'] =
72
+ options.iosConfig?.microphoneUsageDescription ||
66
73
  config.modResults['NSMicrophoneUsageDescription'] ||
67
74
  MICROPHONE_USAGE
68
75
 
69
76
  if (enableNotifications) {
70
77
  config.modResults['NSUserNotificationsUsageDescription'] =
78
+ options.iosConfig?.notificationUsageDescription ||
79
+ config.modResults['NSUserNotificationsUsageDescription'] ||
71
80
  NOTIFICATION_USAGE
72
81
  config.modResults['NSUserNotificationAlertStyle'] = 'alert'
73
82
  }
@@ -20,6 +20,7 @@ export interface AudioStreamStatus {
20
20
  durationMs: number
21
21
  size: number
22
22
  interval: number
23
+ intervalAnalysis: number
23
24
  mimeType: string
24
25
  compression?: CompressionInfo
25
26
  }
@@ -36,7 +37,7 @@ export interface AudioDataEvent {
36
37
  }
37
38
 
38
39
  export type EncodingType = 'pcm_32bit' | 'pcm_16bit' | 'pcm_8bit'
39
- export type SampleRate = 16000 | 44100 | 48000
40
+ export type SampleRate = 16000 | 44100 | 48000
40
41
  export type BitDepth = 8 | 16 | 32
41
42
 
42
43
  export type ConsoleLike = {
@@ -147,7 +148,10 @@ export interface RecordingConfig {
147
148
  // Interval in milliseconds at which to emit recording data
148
149
  interval?: number
149
150
 
150
- // Continue recording when app is in background (default is true)
151
+ // Interval in milliseconds at which to emit analysis data
152
+ intervalAnalysis?: number
153
+
154
+ // Keep the device awake while recording (default is false)
151
155
  keepAwake?: boolean
152
156
 
153
157
  // Show a notification during recording (default is false)
@@ -46,9 +46,11 @@ export class ExpoAudioStreamWeb extends LegacyEventEmitter {
46
46
  currentDurationMs: number
47
47
  currentSize: number
48
48
  currentInterval: number
49
+ currentIntervalAnalysis: number
49
50
  lastEmittedSize: number
50
51
  lastEmittedTime: number
51
52
  lastEmittedCompressionSize: number
53
+ lastEmittedAnalysisTime: number
52
54
  streamUuid: string | null
53
55
  extension: 'webm' | 'wav' = 'wav' // Default extension is 'wav'
54
56
  recordingConfig?: RecordingConfig
@@ -87,10 +89,12 @@ export class ExpoAudioStreamWeb extends LegacyEventEmitter {
87
89
  this.currentSize = 0
88
90
  this.bitDepth = 32 // Default
89
91
  this.currentInterval = 1000 // Default interval in ms
92
+ this.currentIntervalAnalysis = 500 // Default analysis interval in ms
90
93
  this.lastEmittedSize = 0
91
94
  this.lastEmittedTime = 0
92
95
  this.latestPosition = 0
93
96
  this.lastEmittedCompressionSize = 0
97
+ this.lastEmittedAnalysisTime = 0
94
98
  this.streamUuid = null // Initialize UUID on first recording start
95
99
  this.audioWorkletUrl = audioWorkletUrl
96
100
  this.featuresExtratorUrl = featuresExtratorUrl
@@ -172,6 +176,9 @@ export class ExpoAudioStreamWeb extends LegacyEventEmitter {
172
176
  this.lastEmittedSize = 0
173
177
  this.lastEmittedTime = 0
174
178
  this.lastEmittedCompressionSize = 0
179
+ this.currentInterval = recordingConfig.interval ?? 1000
180
+ this.currentIntervalAnalysis = recordingConfig.intervalAnalysis ?? 500
181
+ this.lastEmittedAnalysisTime = Date.now()
175
182
 
176
183
  // Use custom filename if provided, otherwise fallback to timestamp
177
184
  if (recordingConfig.filename) {
@@ -335,6 +342,7 @@ export class ExpoAudioStreamWeb extends LegacyEventEmitter {
335
342
  durationMs: this.currentDurationMs,
336
343
  size: this.currentSize,
337
344
  interval: this.currentInterval,
345
+ intervalAnalysis: this.currentIntervalAnalysis,
338
346
  mimeType: `audio/${this.extension}`,
339
347
  compression: this.recordingConfig?.compression?.enabled
340
348
  ? {
@@ -193,6 +193,7 @@ export class WebRecorder {
193
193
  fullAudioDurationMs: this.position * 1000,
194
194
  numberOfChannels: this.numberOfChannels,
195
195
  features: this.config.features,
196
+ intervalAnalysis: this.config.intervalAnalysis,
196
197
  },
197
198
  []
198
199
  )
@@ -1,6 +1,8 @@
1
1
  export const InlineFeaturesExtractor = `
2
2
  // Unique ID counter
3
3
  let uniqueIdCounter = 0
4
+ let accumulatedDataPoints = [] // Move outside message handler
5
+ let lastEmitTime = Date.now() // Move outside message handler
4
6
 
5
7
  self.onmessage = function (event) {
6
8
  const {
@@ -12,6 +14,7 @@ self.onmessage = function (event) {
12
14
  fullAudioDurationMs,
13
15
  numberOfChannels,
14
16
  features: _features,
17
+ intervalAnalysis = 500, // Use intervalAnalysis instead of interval
15
18
  } = event.data
16
19
  const features = _features || {}
17
20
 
@@ -295,10 +298,24 @@ self.onmessage = function (event) {
295
298
  pointsPerSecond,
296
299
  algorithm
297
300
  )
298
- self.postMessage({
299
- command: 'features',
300
- result,
301
- })
301
+
302
+ // Accumulate data points
303
+ accumulatedDataPoints = accumulatedDataPoints.concat(result.dataPoints)
304
+
305
+ const currentTime = Date.now()
306
+ const shouldEmitAccumulated = currentTime - lastEmitTime >= intervalAnalysis
307
+
308
+ if (shouldEmitAccumulated) {
309
+ self.postMessage({
310
+ command: 'features',
311
+ result: {
312
+ ...result,
313
+ dataPoints: accumulatedDataPoints
314
+ }
315
+ })
316
+ accumulatedDataPoints = [] // Reset accumulator
317
+ lastEmitTime = currentTime
318
+ }
302
319
  } catch (error) {
303
320
  console.error('[AudioFeaturesExtractor] Error in processing', error)
304
321
  self.postMessage({ error: error.message })