@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.
- package/CHANGELOG.md +14 -1
- package/README.md +25 -0
- package/android/src/main/java/net/siteed/audiostream/AudioAnalysisData.kt +22 -0
- package/android/src/main/java/net/siteed/audiostream/AudioDeviceManager.kt +1501 -0
- package/android/src/main/java/net/siteed/audiostream/AudioFileHandler.kt +10 -5
- package/android/src/main/java/net/siteed/audiostream/AudioNotificationsManager.kt +27 -25
- package/android/src/main/java/net/siteed/audiostream/AudioProcessor.kt +73 -71
- package/android/src/main/java/net/siteed/audiostream/AudioRecorderManager.kt +576 -252
- package/android/src/main/java/net/siteed/audiostream/Constants.kt +17 -1
- package/android/src/main/java/net/siteed/audiostream/ExpoAudioStreamModule.kt +419 -155
- package/android/src/main/java/net/siteed/audiostream/LogUtils.kt +65 -0
- package/android/src/main/java/net/siteed/audiostream/RecordingConfig.kt +9 -1
- package/build/AudioAnalysis/AudioAnalysis.types.js.map +1 -1
- package/build/AudioDeviceManager.d.ts +107 -0
- package/build/AudioDeviceManager.d.ts.map +1 -0
- package/build/AudioDeviceManager.js +493 -0
- package/build/AudioDeviceManager.js.map +1 -0
- package/build/AudioRecorder.provider.d.ts.map +1 -1
- package/build/AudioRecorder.provider.js +3 -0
- package/build/AudioRecorder.provider.js.map +1 -1
- package/build/ExpoAudioStream.types.d.ts +104 -1
- package/build/ExpoAudioStream.types.d.ts.map +1 -1
- package/build/ExpoAudioStream.types.js +7 -1
- package/build/ExpoAudioStream.types.js.map +1 -1
- package/build/ExpoAudioStream.web.d.ts +37 -0
- package/build/ExpoAudioStream.web.d.ts.map +1 -1
- package/build/ExpoAudioStream.web.js +478 -62
- package/build/ExpoAudioStream.web.js.map +1 -1
- package/build/ExpoAudioStreamModule.d.ts.map +1 -1
- package/build/ExpoAudioStreamModule.js +20 -0
- package/build/ExpoAudioStreamModule.js.map +1 -1
- package/build/WebRecorder.web.d.ts +74 -11
- package/build/WebRecorder.web.d.ts.map +1 -1
- package/build/WebRecorder.web.js +390 -74
- package/build/WebRecorder.web.js.map +1 -1
- package/build/hooks/useAudioDevices.d.ts +14 -0
- package/build/hooks/useAudioDevices.d.ts.map +1 -0
- package/build/hooks/useAudioDevices.js +151 -0
- package/build/hooks/useAudioDevices.js.map +1 -0
- package/build/index.d.ts +2 -0
- package/build/index.d.ts.map +1 -1
- package/build/index.js +4 -0
- package/build/index.js.map +1 -1
- package/build/useAudioRecorder.d.ts +1 -0
- package/build/useAudioRecorder.d.ts.map +1 -1
- package/build/useAudioRecorder.js +20 -1
- package/build/useAudioRecorder.js.map +1 -1
- package/build/utils/BlobFix.d.ts.map +1 -1
- package/build/utils/BlobFix.js +2 -2
- package/build/utils/BlobFix.js.map +1 -1
- package/build/utils/writeWavHeader.d.ts +3 -18
- package/build/utils/writeWavHeader.d.ts.map +1 -1
- package/build/utils/writeWavHeader.js +19 -26
- package/build/utils/writeWavHeader.js.map +1 -1
- package/build/workers/InlineFeaturesExtractor.web.d.ts +1 -1
- package/build/workers/InlineFeaturesExtractor.web.d.ts.map +1 -1
- package/build/workers/InlineFeaturesExtractor.web.js +27 -26
- package/build/workers/InlineFeaturesExtractor.web.js.map +1 -1
- package/build/workers/inlineAudioWebWorker.web.d.ts +1 -1
- package/build/workers/inlineAudioWebWorker.web.d.ts.map +1 -1
- package/build/workers/inlineAudioWebWorker.web.js +25 -1
- package/build/workers/inlineAudioWebWorker.web.js.map +1 -1
- package/ios/AudioDeviceManager.swift +654 -0
- package/ios/AudioStreamManager.swift +964 -760
- package/ios/ExpoAudioStreamModule.swift +174 -19
- package/ios/Features.swift +1 -1
- package/ios/ISSUE_IOS.md +45 -0
- package/ios/Logger.swift +13 -1
- package/ios/RecordingSettings.swift +12 -0
- package/package.json +2 -2
- package/src/AudioAnalysis/AudioAnalysis.types.ts +2 -2
- package/src/AudioDeviceManager.ts +571 -0
- package/src/AudioRecorder.provider.tsx +3 -0
- package/src/ExpoAudioStream.types.ts +113 -1
- package/src/ExpoAudioStream.web.ts +609 -69
- package/src/ExpoAudioStreamModule.ts +23 -0
- package/src/WebRecorder.web.ts +482 -92
- package/src/hooks/useAudioDevices.ts +180 -0
- package/src/index.ts +6 -0
- package/src/types/crc-32.d.ts +6 -6
- package/src/useAudioRecorder.tsx +27 -1
- package/src/utils/BlobFix.ts +6 -4
- package/src/utils/writeWavHeader.ts +26 -25
- package/src/workers/InlineFeaturesExtractor.web.tsx +27 -26
- 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
|
-
|
|
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
|
-
|
|
119
|
+
LogUtils.w(CLASS_NAME, "Attempted to delete null file")
|
|
115
120
|
false
|
|
116
121
|
} else if (!file.exists()) {
|
|
117
|
-
|
|
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
|
-
|
|
127
|
+
LogUtils.w(CLASS_NAME, "Failed to delete file: ${file.absolutePath}")
|
|
123
128
|
}
|
|
124
129
|
wasDeleted
|
|
125
130
|
}
|
|
126
131
|
} catch (e: Exception) {
|
|
127
|
-
|
|
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
|
|
91
|
-
setTextViewText(R.id.notification_text, recordingConfig.notification
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
385
|
+
LogUtils.d(CLASS_NAME, "Successfully reinitialized notification")
|
|
384
386
|
} catch (e: Exception) {
|
|
385
|
-
|
|
387
|
+
LogUtils.e(CLASS_NAME, "Failed to reinitialize notification", e)
|
|
386
388
|
}
|
|
387
389
|
}
|
|
388
390
|
|