@siteed/expo-audio-studio 2.18.0 → 2.18.2
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
CHANGED
|
@@ -8,6 +8,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
10
|
|
|
11
|
+
## [2.18.2] - 2026-02-16
|
|
12
|
+
### Changed
|
|
13
|
+
- chore(expo-audio-studio): release @siteed/expo-audio-studio@2.18.1 ([067ebfe](https://github.com/deeeed/expo-audio-stream/commit/067ebfe3b6ad3c506e64c3988b67ea90dc894c18))
|
|
14
|
+
## [2.18.1] - 2025-08-02
|
|
15
|
+
### Changed
|
|
16
|
+
- feat: improved memory monitoring ([55dfe16](https://github.com/deeeed/expo-audio-stream/commit/55dfe16d7e8c372392738d1441776a760e7ecdbe))
|
|
17
|
+
- chore(expo-audio-studio): release @siteed/expo-audio-studio@2.18.0 ([cc80ac5](https://github.com/deeeed/expo-audio-stream/commit/cc80ac5fa7ece05fc9fae031f101163acce2aff4))
|
|
11
18
|
## [2.18.0] - 2025-08-01
|
|
12
19
|
### Changed
|
|
13
20
|
- feat(expo-audio-studio): optimize buffer size on android to prevent oom ([32fcb9b](https://github.com/deeeed/expo-audio-stream/commit/32fcb9b0a965669b3a37c9860998ae46a1d26cd8))
|
|
@@ -373,7 +380,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
373
380
|
- Feature: Audio features extraction during recording.
|
|
374
381
|
- Feature: Consistent WAV PCM recording format across all platforms.
|
|
375
382
|
|
|
376
|
-
[unreleased]: https://github.com/deeeed/expo-audio-stream/compare/@siteed/expo-audio-studio@2.18.
|
|
383
|
+
[unreleased]: https://github.com/deeeed/expo-audio-stream/compare/@siteed/expo-audio-studio@2.18.2...HEAD
|
|
384
|
+
[2.18.2]: https://github.com/deeeed/expo-audio-stream/compare/@siteed/expo-audio-studio@2.18.1...@siteed/expo-audio-studio@2.18.2
|
|
385
|
+
[2.18.1]: https://github.com/deeeed/expo-audio-stream/compare/@siteed/expo-audio-studio@2.18.0...@siteed/expo-audio-studio@2.18.1
|
|
377
386
|
[2.18.0]: https://github.com/deeeed/expo-audio-stream/compare/@siteed/expo-audio-studio@2.17.0...@siteed/expo-audio-studio@2.18.0
|
|
378
387
|
[2.17.0]: https://github.com/deeeed/expo-audio-stream/compare/@siteed/expo-audio-studio@2.16.2...@siteed/expo-audio-studio@2.17.0
|
|
379
388
|
[2.16.2]: https://github.com/deeeed/expo-audio-stream/compare/@siteed/expo-audio-studio@2.16.1...@siteed/expo-audio-studio@2.16.2
|
|
@@ -75,6 +75,9 @@ class AudioRecorderManager(
|
|
|
75
75
|
}
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
+
// Maximum size for analysis buffer to prevent OOM on low-RAM devices with extreme configs
|
|
79
|
+
private val MAX_ANALYSIS_BUFFER_SIZE = 20 * 1024 * 1024 // 20MB
|
|
80
|
+
|
|
78
81
|
private var audioRecord: AudioRecord? = null
|
|
79
82
|
private var bufferSizeInBytes = 0
|
|
80
83
|
private val _isRecording = AtomicBoolean(false)
|
|
@@ -1477,9 +1480,14 @@ class AudioRecorderManager(
|
|
|
1477
1480
|
|
|
1478
1481
|
accumulatedAudioData.write(audioData, 0, bytesRead)
|
|
1479
1482
|
|
|
1480
|
-
//
|
|
1481
|
-
if (
|
|
1482
|
-
|
|
1483
|
+
// Always accumulate data for analysis if enabled (moved outside shouldProcessAnalysis check)
|
|
1484
|
+
if (recordingConfig.enableProcessing) {
|
|
1485
|
+
// Check buffer size to prevent OOM on low-RAM devices with extreme configs
|
|
1486
|
+
if (accumulatedAnalysisData.size() + bytesRead <= MAX_ANALYSIS_BUFFER_SIZE) {
|
|
1487
|
+
accumulatedAnalysisData.write(audioData, 0, bytesRead)
|
|
1488
|
+
} else {
|
|
1489
|
+
LogUtils.w(CLASS_NAME, "Analysis buffer size limit reached (${accumulatedAnalysisData.size()} bytes). Skipping data to prevent OOM.")
|
|
1490
|
+
}
|
|
1483
1491
|
}
|
|
1484
1492
|
|
|
1485
1493
|
// Handle regular audio data emission
|
|
@@ -1507,31 +1515,37 @@ class AudioRecorderManager(
|
|
|
1507
1515
|
if (analysisDataSize > 0) {
|
|
1508
1516
|
// Add this check to enforce minimum interval
|
|
1509
1517
|
if (isFirstAnalysis || (currentTime - lastEmissionTimeAnalysis) >= recordingConfig.intervalAnalysis) {
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1518
|
+
try {
|
|
1519
|
+
// Process and emit analysis data
|
|
1520
|
+
val analysisData = audioProcessor.processAudioData(
|
|
1521
|
+
accumulatedAnalysisData.toByteArray(),
|
|
1522
|
+
recordingConfig
|
|
1523
|
+
)
|
|
1524
|
+
|
|
1525
|
+
LogUtils.d(CLASS_NAME, """
|
|
1526
|
+
Analysis data details:
|
|
1527
|
+
- Raw data size: ${accumulatedAnalysisData.size()} bytes
|
|
1528
|
+
""".trimIndent())
|
|
1529
|
+
|
|
1530
|
+
mainHandler.post {
|
|
1531
|
+
try {
|
|
1532
|
+
eventSender.sendExpoEvent(
|
|
1533
|
+
Constants.AUDIO_ANALYSIS_EVENT_NAME,
|
|
1534
|
+
analysisData.toBundle()
|
|
1535
|
+
)
|
|
1536
|
+
} catch (e: Exception) {
|
|
1537
|
+
LogUtils.e(CLASS_NAME, "Failed to send audio analysis event", e)
|
|
1538
|
+
}
|
|
1529
1539
|
}
|
|
1540
|
+
|
|
1541
|
+
lastEmissionTimeAnalysis = currentTime
|
|
1542
|
+
isFirstAnalysis = false
|
|
1543
|
+
} catch (e: Exception) {
|
|
1544
|
+
LogUtils.e(CLASS_NAME, "Failed to process audio analysis data", e)
|
|
1545
|
+
} finally {
|
|
1546
|
+
// Always reset the buffer to prevent unbounded growth
|
|
1547
|
+
accumulatedAnalysisData.reset()
|
|
1530
1548
|
}
|
|
1531
|
-
|
|
1532
|
-
lastEmissionTimeAnalysis = currentTime
|
|
1533
|
-
accumulatedAnalysisData.reset() // Clear the analysis accumulator
|
|
1534
|
-
isFirstAnalysis = false
|
|
1535
1549
|
}
|
|
1536
1550
|
}
|
|
1537
1551
|
}
|
|
@@ -1637,8 +1651,13 @@ class AudioRecorderManager(
|
|
|
1637
1651
|
}
|
|
1638
1652
|
}
|
|
1639
1653
|
|
|
1640
|
-
|
|
1641
|
-
|
|
1654
|
+
// Analysis is already handled in recordingProcess method to avoid duplicate processing
|
|
1655
|
+
// and prevent memory issues from accumulating data in multiple buffers
|
|
1656
|
+
|
|
1657
|
+
// Update notification waveform if needed (moved from processAudioData)
|
|
1658
|
+
if (recordingConfig.showNotification && recordingConfig.showWaveformInNotification) {
|
|
1659
|
+
val floatArray = convertByteArrayToFloatArray(audioData)
|
|
1660
|
+
notificationManager.updateNotification(floatArray)
|
|
1642
1661
|
}
|
|
1643
1662
|
}
|
|
1644
1663
|
|
|
@@ -1651,55 +1670,6 @@ class AudioRecorderManager(
|
|
|
1651
1670
|
return floatArray
|
|
1652
1671
|
}
|
|
1653
1672
|
|
|
1654
|
-
private fun processAudioData(audioData: ByteArray) {
|
|
1655
|
-
// Skip the WAV header only for the first chunk
|
|
1656
|
-
val dataToProcess = if (isFirstChunk && audioData.size > Constants.WAV_HEADER_SIZE) {
|
|
1657
|
-
audioData.copyOfRange(Constants.WAV_HEADER_SIZE, audioData.size)
|
|
1658
|
-
} else {
|
|
1659
|
-
audioData
|
|
1660
|
-
}
|
|
1661
|
-
|
|
1662
|
-
// Accumulate data for analysis
|
|
1663
|
-
if (recordingConfig.enableProcessing) {
|
|
1664
|
-
synchronized(analysisBuffer) {
|
|
1665
|
-
analysisBuffer.write(dataToProcess)
|
|
1666
|
-
}
|
|
1667
|
-
|
|
1668
|
-
val currentTime = SystemClock.elapsedRealtime()
|
|
1669
|
-
if (isFirstAnalysis || (currentTime - lastEmissionTimeAnalysis) >= recordingConfig.intervalAnalysis) {
|
|
1670
|
-
synchronized(analysisBuffer) {
|
|
1671
|
-
if (analysisBuffer.size() > 0) {
|
|
1672
|
-
val analysisData = audioProcessor.processAudioData(
|
|
1673
|
-
analysisBuffer.toByteArray(),
|
|
1674
|
-
recordingConfig
|
|
1675
|
-
)
|
|
1676
|
-
|
|
1677
|
-
mainHandler.post {
|
|
1678
|
-
eventSender.sendExpoEvent(
|
|
1679
|
-
Constants.AUDIO_ANALYSIS_EVENT_NAME,
|
|
1680
|
-
analysisData.toBundle()
|
|
1681
|
-
)
|
|
1682
|
-
}
|
|
1683
|
-
|
|
1684
|
-
// Reset buffer after processing
|
|
1685
|
-
analysisBuffer.reset()
|
|
1686
|
-
lastEmissionTimeAnalysis = currentTime
|
|
1687
|
-
isFirstAnalysis = false
|
|
1688
|
-
}
|
|
1689
|
-
}
|
|
1690
|
-
}
|
|
1691
|
-
}
|
|
1692
|
-
|
|
1693
|
-
// Only update notification if needed
|
|
1694
|
-
if (recordingConfig.showNotification && recordingConfig.showWaveformInNotification) {
|
|
1695
|
-
val floatArray = convertByteArrayToFloatArray(audioData)
|
|
1696
|
-
notificationManager.updateNotification(floatArray)
|
|
1697
|
-
}
|
|
1698
|
-
|
|
1699
|
-
// Reset isFirstChunk after processing
|
|
1700
|
-
isFirstChunk = false
|
|
1701
|
-
}
|
|
1702
|
-
|
|
1703
1673
|
fun cleanup() {
|
|
1704
1674
|
synchronized(audioRecordLock) {
|
|
1705
1675
|
try {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@siteed/expo-audio-studio",
|
|
3
|
-
"version": "2.18.
|
|
3
|
+
"version": "2.18.2",
|
|
4
4
|
"description": "Comprehensive audio processing library for React Native and Expo with recording, analysis, visualization, and streaming capabilities across iOS, Android, and web",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "commonjs",
|
|
@@ -134,8 +134,7 @@
|
|
|
134
134
|
"typescript": "~5.8.3"
|
|
135
135
|
},
|
|
136
136
|
"peerDependencies": {
|
|
137
|
-
"expo": "
|
|
138
|
-
"expo-modules-core": "~2.4.0",
|
|
137
|
+
"expo": ">=52.0.0",
|
|
139
138
|
"react": "*",
|
|
140
139
|
"react-native": "*"
|
|
141
140
|
},
|