@siteed/expo-audio-studio 2.4.1 → 2.6.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.
Files changed (85) hide show
  1. package/CHANGELOG.md +14 -1
  2. package/README.md +25 -0
  3. package/android/src/main/java/net/siteed/audiostream/AudioAnalysisData.kt +22 -0
  4. package/android/src/main/java/net/siteed/audiostream/AudioDeviceManager.kt +1501 -0
  5. package/android/src/main/java/net/siteed/audiostream/AudioFileHandler.kt +10 -5
  6. package/android/src/main/java/net/siteed/audiostream/AudioNotificationsManager.kt +27 -25
  7. package/android/src/main/java/net/siteed/audiostream/AudioProcessor.kt +73 -71
  8. package/android/src/main/java/net/siteed/audiostream/AudioRecorderManager.kt +576 -252
  9. package/android/src/main/java/net/siteed/audiostream/Constants.kt +17 -1
  10. package/android/src/main/java/net/siteed/audiostream/ExpoAudioStreamModule.kt +419 -155
  11. package/android/src/main/java/net/siteed/audiostream/LogUtils.kt +65 -0
  12. package/android/src/main/java/net/siteed/audiostream/RecordingConfig.kt +9 -1
  13. package/build/AudioAnalysis/AudioAnalysis.types.js.map +1 -1
  14. package/build/AudioDeviceManager.d.ts +107 -0
  15. package/build/AudioDeviceManager.d.ts.map +1 -0
  16. package/build/AudioDeviceManager.js +493 -0
  17. package/build/AudioDeviceManager.js.map +1 -0
  18. package/build/AudioRecorder.provider.d.ts.map +1 -1
  19. package/build/AudioRecorder.provider.js +3 -0
  20. package/build/AudioRecorder.provider.js.map +1 -1
  21. package/build/ExpoAudioStream.types.d.ts +104 -1
  22. package/build/ExpoAudioStream.types.d.ts.map +1 -1
  23. package/build/ExpoAudioStream.types.js +7 -1
  24. package/build/ExpoAudioStream.types.js.map +1 -1
  25. package/build/ExpoAudioStream.web.d.ts +37 -0
  26. package/build/ExpoAudioStream.web.d.ts.map +1 -1
  27. package/build/ExpoAudioStream.web.js +478 -62
  28. package/build/ExpoAudioStream.web.js.map +1 -1
  29. package/build/ExpoAudioStreamModule.d.ts.map +1 -1
  30. package/build/ExpoAudioStreamModule.js +20 -0
  31. package/build/ExpoAudioStreamModule.js.map +1 -1
  32. package/build/WebRecorder.web.d.ts +74 -11
  33. package/build/WebRecorder.web.d.ts.map +1 -1
  34. package/build/WebRecorder.web.js +390 -74
  35. package/build/WebRecorder.web.js.map +1 -1
  36. package/build/hooks/useAudioDevices.d.ts +14 -0
  37. package/build/hooks/useAudioDevices.d.ts.map +1 -0
  38. package/build/hooks/useAudioDevices.js +151 -0
  39. package/build/hooks/useAudioDevices.js.map +1 -0
  40. package/build/index.d.ts +2 -0
  41. package/build/index.d.ts.map +1 -1
  42. package/build/index.js +4 -0
  43. package/build/index.js.map +1 -1
  44. package/build/useAudioRecorder.d.ts +1 -0
  45. package/build/useAudioRecorder.d.ts.map +1 -1
  46. package/build/useAudioRecorder.js +20 -1
  47. package/build/useAudioRecorder.js.map +1 -1
  48. package/build/utils/BlobFix.d.ts.map +1 -1
  49. package/build/utils/BlobFix.js +2 -2
  50. package/build/utils/BlobFix.js.map +1 -1
  51. package/build/utils/writeWavHeader.d.ts +3 -18
  52. package/build/utils/writeWavHeader.d.ts.map +1 -1
  53. package/build/utils/writeWavHeader.js +19 -26
  54. package/build/utils/writeWavHeader.js.map +1 -1
  55. package/build/workers/InlineFeaturesExtractor.web.d.ts +1 -1
  56. package/build/workers/InlineFeaturesExtractor.web.d.ts.map +1 -1
  57. package/build/workers/InlineFeaturesExtractor.web.js +27 -26
  58. package/build/workers/InlineFeaturesExtractor.web.js.map +1 -1
  59. package/build/workers/inlineAudioWebWorker.web.d.ts +1 -1
  60. package/build/workers/inlineAudioWebWorker.web.d.ts.map +1 -1
  61. package/build/workers/inlineAudioWebWorker.web.js +25 -1
  62. package/build/workers/inlineAudioWebWorker.web.js.map +1 -1
  63. package/ios/AudioDeviceManager.swift +654 -0
  64. package/ios/AudioStreamManager.swift +964 -760
  65. package/ios/ExpoAudioStreamModule.swift +174 -19
  66. package/ios/Features.swift +1 -1
  67. package/ios/ISSUE_IOS.md +45 -0
  68. package/ios/Logger.swift +13 -1
  69. package/ios/RecordingSettings.swift +12 -0
  70. package/package.json +2 -2
  71. package/src/AudioAnalysis/AudioAnalysis.types.ts +2 -2
  72. package/src/AudioDeviceManager.ts +571 -0
  73. package/src/AudioRecorder.provider.tsx +3 -0
  74. package/src/ExpoAudioStream.types.ts +113 -1
  75. package/src/ExpoAudioStream.web.ts +609 -69
  76. package/src/ExpoAudioStreamModule.ts +23 -0
  77. package/src/WebRecorder.web.ts +482 -92
  78. package/src/hooks/useAudioDevices.ts +180 -0
  79. package/src/index.ts +6 -0
  80. package/src/types/crc-32.d.ts +6 -6
  81. package/src/useAudioRecorder.tsx +27 -1
  82. package/src/utils/BlobFix.ts +6 -4
  83. package/src/utils/writeWavHeader.ts +26 -25
  84. package/src/workers/InlineFeaturesExtractor.web.tsx +27 -26
  85. package/src/workers/inlineAudioWebWorker.web.tsx +25 -1
@@ -6,8 +6,13 @@ import java.io.IOException
6
6
  import java.io.OutputStream
7
7
  import java.io.RandomAccessFile
8
8
  import java.util.UUID
9
+ import net.siteed.audiostream.LogUtils
9
10
 
10
11
  class AudioFileHandler(private val filesDir: File) {
12
+ companion object {
13
+ private const val CLASS_NAME = "AudioFileHandler"
14
+ }
15
+
11
16
  // Method to write WAV file header
12
17
  fun writeWavHeader(out: OutputStream, sampleRateInHz: Int, channels: Int, bitDepth: Int) {
13
18
  val header = ByteArray(44)
@@ -103,7 +108,7 @@ class AudioFileHandler(private val filesDir: File) {
103
108
  createNewFile() // Create the file
104
109
  }
105
110
  } catch (e: Exception) {
106
- Log.e(Constants.TAG, "Failed to create audio file", e)
111
+ LogUtils.e(CLASS_NAME, "Failed to create audio file", e)
107
112
  throw e
108
113
  }
109
114
  }
@@ -111,20 +116,20 @@ class AudioFileHandler(private val filesDir: File) {
111
116
  fun deleteFile(file: File?): Boolean {
112
117
  return try {
113
118
  if (file == null) {
114
- Log.w(Constants.TAG, "Attempted to delete null file")
119
+ LogUtils.w(CLASS_NAME, "Attempted to delete null file")
115
120
  false
116
121
  } else if (!file.exists()) {
117
- Log.w(Constants.TAG, "File does not exist: ${file.absolutePath}")
122
+ LogUtils.w(CLASS_NAME, "File does not exist: ${file.absolutePath}")
118
123
  false
119
124
  } else {
120
125
  val wasDeleted = file.delete()
121
126
  if (!wasDeleted) {
122
- Log.w(Constants.TAG, "Failed to delete file: ${file.absolutePath}")
127
+ LogUtils.w(CLASS_NAME, "Failed to delete file: ${file.absolutePath}")
123
128
  }
124
129
  wasDeleted
125
130
  }
126
131
  } catch (e: Exception) {
127
- Log.e(Constants.TAG, "Error deleting file: ${file?.absolutePath}", e)
132
+ LogUtils.e(CLASS_NAME, "Error deleting file: ${file?.absolutePath}", e)
128
133
  false
129
134
  }
130
135
  }
@@ -19,8 +19,24 @@ import java.lang.ref.WeakReference
19
19
  import java.util.Locale
20
20
  import java.util.concurrent.atomic.AtomicBoolean
21
21
  import java.util.Objects
22
+ import net.siteed.audiostream.LogUtils
22
23
 
23
24
  class AudioNotificationManager private constructor(context: Context) {
25
+ companion object {
26
+ private const val CLASS_NAME = "AudioNotificationManager"
27
+ private const val WAVEFORM_UPDATE_INTERVAL = 100L
28
+ private const val UPDATE_INTERVAL = 1000L
29
+
30
+ @Volatile
31
+ private var instance: AudioNotificationManager? = null
32
+
33
+ fun getInstance(context: Context): AudioNotificationManager {
34
+ return instance ?: synchronized(this) {
35
+ instance ?: AudioNotificationManager(context).also { instance = it }
36
+ }
37
+ }
38
+ }
39
+
24
40
  private val contextRef = WeakReference(context.applicationContext)
25
41
  private val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
26
42
  private val mainHandler = Handler(Looper.getMainLooper())
@@ -43,20 +59,6 @@ class AudioNotificationManager private constructor(context: Context) {
43
59
  private val waveformRenderer = WaveformRenderer()
44
60
  private var lastNotificationHash: Int? = null
45
61
 
46
- companion object {
47
- private const val WAVEFORM_UPDATE_INTERVAL = 100L
48
- private const val UPDATE_INTERVAL = 1000L
49
-
50
- @Volatile
51
- private var instance: AudioNotificationManager? = null
52
-
53
- fun getInstance(context: Context): AudioNotificationManager {
54
- return instance ?: synchronized(this) {
55
- instance ?: AudioNotificationManager(context).also { instance = it }
56
- }
57
- }
58
- }
59
-
60
62
  fun initialize(config: RecordingConfig) {
61
63
  recordingConfig = config
62
64
  createNotificationChannel()
@@ -87,24 +89,24 @@ class AudioNotificationManager private constructor(context: Context) {
87
89
  try {
88
90
  remoteViews = RemoteViews(context.packageName, R.layout.notification_recording)
89
91
  remoteViews.apply {
90
- setTextViewText(R.id.notification_title, recordingConfig.notification.title)
91
- setTextViewText(R.id.notification_text, recordingConfig.notification.text)
92
+ setTextViewText(R.id.notification_title, recordingConfig.notification?.title)
93
+ setTextViewText(R.id.notification_text, recordingConfig.notification?.text)
92
94
  setTextViewText(R.id.notification_duration, formatDuration(0))
93
95
  setViewVisibility(
94
96
  R.id.notification_waveform,
95
97
  if (recordingConfig.showWaveformInNotification &&
96
- recordingConfig.notification.waveform != null) View.VISIBLE else View.GONE
98
+ recordingConfig.notification?.waveform != null) View.VISIBLE else View.GONE
97
99
  )
98
100
  }
99
101
 
100
102
  buildNotification(context)
101
103
  } catch (e: Exception) {
102
- Log.e(Constants.TAG, "Failed to initialize notification", e)
104
+ LogUtils.e(CLASS_NAME, "Failed to initialize notification", e)
103
105
  }
104
106
  }
105
107
 
106
108
  private fun buildNotification(context: Context) {
107
- val iconResId = recordingConfig.notification.icon?.let {
109
+ val iconResId = recordingConfig.notification?.icon?.let {
108
110
  getResourceIdByName(it)
109
111
  } ?: R.drawable.ic_microphone
110
112
 
@@ -214,7 +216,7 @@ class AudioNotificationManager private constructor(context: Context) {
214
216
 
215
217
  notificationManager.notify(recordingConfig.notification.notificationId, updatedNotification)
216
218
  } catch (e: Exception) {
217
- Log.e(Constants.TAG, "Failed to update notification actions", e)
219
+ LogUtils.e(CLASS_NAME, "Failed to update notification actions", e)
218
220
  }
219
221
  }
220
222
 
@@ -296,7 +298,7 @@ class AudioNotificationManager private constructor(context: Context) {
296
298
  setImageViewBitmap(R.id.notification_waveform, waveformBitmap)
297
299
  lastWaveformUpdate = currentTime
298
300
  } catch (e: Exception) {
299
- Log.e(Constants.TAG, "Error generating waveform", e)
301
+ LogUtils.e(CLASS_NAME, "Error generating waveform", e)
300
302
  }
301
303
  }
302
304
  }
@@ -325,7 +327,7 @@ class AudioNotificationManager private constructor(context: Context) {
325
327
  consecutiveUpdateFailures = 0
326
328
 
327
329
  } catch (e: Exception) {
328
- Log.e(Constants.TAG, "Error updating notification", e)
330
+ LogUtils.e(CLASS_NAME, "Error updating notification", e)
329
331
  consecutiveUpdateFailures++
330
332
 
331
333
  if (consecutiveUpdateFailures >= maxUpdateFailures) {
@@ -360,7 +362,7 @@ class AudioNotificationManager private constructor(context: Context) {
360
362
  .build()
361
363
  )
362
364
  } catch (e: Exception) {
363
- Log.e(Constants.TAG, "Error updating waveform", e)
365
+ LogUtils.e(CLASS_NAME, "Error updating waveform", e)
364
366
  }
365
367
  }
366
368
 
@@ -380,9 +382,9 @@ class AudioNotificationManager private constructor(context: Context) {
380
382
  )
381
383
 
382
384
  consecutiveUpdateFailures = 0
383
- Log.d(Constants.TAG, "Successfully reinitialized notification")
385
+ LogUtils.d(CLASS_NAME, "Successfully reinitialized notification")
384
386
  } catch (e: Exception) {
385
- Log.e(Constants.TAG, "Failed to reinitialize notification", e)
387
+ LogUtils.e(CLASS_NAME, "Failed to reinitialize notification", e)
386
388
  }
387
389
  }
388
390