@siteed/expo-audio-studio 2.12.1 → 2.12.3

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.12.3] - 2025-06-07
12
+ ### Changed
13
+ - refactor(expo-audio-studio): adjust audio focus request timing in AudioRecorderManager ([317367c](https://github.com/deeeed/expo-audio-stream/commit/317367cb29fa09016aa73884f2f51e9cfdee1086))
14
+ - chore(expo-audio-studio): release @siteed/expo-audio-studio@2.12.2 ([14db4eb](https://github.com/deeeed/expo-audio-stream/commit/14db4ebfdeb9181e82e810d61283738d41c40a1a))
15
+ ## [2.12.2] - 2025-06-07
16
+ ### Changed
17
+ - fix: audio focus strategy implementation for Android background recording (#267) ([5b7b7ed](https://github.com/deeeed/expo-audio-stream/commit/5b7b7eda86bbd65becbe6bab44a44cdf6a1fb17d))
11
18
  ## [2.12.1] - 2025-06-07
12
19
  ### Changed
13
20
  - feat(playground): implement agent validation framework and enhance testing capabilities (#266) ([e7937e0](https://github.com/deeeed/expo-audio-stream/commit/e7937e0268f54f85ea2e0171b221f7ef29cc6248))
@@ -297,7 +304,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
297
304
  - Feature: Audio features extraction during recording.
298
305
  - Feature: Consistent WAV PCM recording format across all platforms.
299
306
 
300
- [unreleased]: https://github.com/deeeed/expo-audio-stream/compare/@siteed/expo-audio-studio@2.12.1...HEAD
307
+ [unreleased]: https://github.com/deeeed/expo-audio-stream/compare/@siteed/expo-audio-studio@2.12.3...HEAD
308
+ [2.12.3]: https://github.com/deeeed/expo-audio-stream/compare/@siteed/expo-audio-studio@2.12.2...@siteed/expo-audio-studio@2.12.3
309
+ [2.12.2]: https://github.com/deeeed/expo-audio-stream/compare/@siteed/expo-audio-studio@2.12.1...@siteed/expo-audio-studio@2.12.2
301
310
  [2.12.1]: https://github.com/deeeed/expo-audio-stream/compare/@siteed/expo-audio-studio@2.12.0...@siteed/expo-audio-studio@2.12.1
302
311
  [2.12.0]: https://github.com/deeeed/expo-audio-stream/compare/@siteed/expo-audio-studio@2.11.0...@siteed/expo-audio-studio@2.12.0
303
312
  [2.11.0]: https://github.com/deeeed/expo-audio-stream/compare/@siteed/expo-audio-studio@2.10.6...@siteed/expo-audio-studio@2.11.0
@@ -469,49 +469,6 @@ class AudioRecorderManager(
469
469
  }
470
470
  }
471
471
 
472
- @RequiresApi(Build.VERSION_CODES.O)
473
- private val audioFocusCallback = object : AudioManager.OnAudioFocusChangeListener {
474
- override fun onAudioFocusChange(focusChange: Int) {
475
- when (focusChange) {
476
- AudioManager.AUDIOFOCUS_LOSS,
477
- AudioManager.AUDIOFOCUS_LOSS_TRANSIENT -> {
478
- if (_isRecording.get() && !isPaused.get()) {
479
- mainHandler.post {
480
- pauseRecording(object : Promise {
481
- override fun resolve(value: Any?) {
482
- eventSender.sendExpoEvent(Constants.RECORDING_INTERRUPTED_EVENT_NAME, bundleOf(
483
- "reason" to "audioFocusLoss",
484
- "isPaused" to true
485
- ))
486
- }
487
- override fun reject(code: String, message: String?, cause: Throwable?) {
488
- LogUtils.e(CLASS_NAME, "Failed to pause recording on audio focus loss")
489
- }
490
- })
491
- }
492
- }
493
- }
494
- AudioManager.AUDIOFOCUS_GAIN -> {
495
- val autoResume = if (::recordingConfig.isInitialized) recordingConfig.autoResumeAfterInterruption else false
496
- if (_isRecording.get() && isPaused.get() && autoResume) {
497
- mainHandler.post {
498
- resumeRecording(object : Promise {
499
- override fun resolve(value: Any?) {
500
- eventSender.sendExpoEvent(Constants.RECORDING_INTERRUPTED_EVENT_NAME, bundleOf(
501
- "reason" to "audioFocusGain",
502
- "isPaused" to false
503
- ))
504
- }
505
- override fun reject(code: String, message: String?, cause: Throwable?) {
506
- LogUtils.e(CLASS_NAME, "Failed to resume recording on audio focus gain")
507
- }
508
- })
509
- }
510
- }
511
- }
512
- }
513
- }
514
- }
515
472
 
516
473
  @RequiresApi(Build.VERSION_CODES.R)
517
474
  fun startRecording(options: Map<String, Any?>, promise: Promise) {
@@ -522,12 +479,6 @@ class AudioRecorderManager(
522
479
  return
523
480
  }
524
481
 
525
- // Request audio focus - always do this right before starting
526
- if (!requestAudioFocus()) {
527
- promise.reject("AUDIO_FOCUS_ERROR", "Failed to obtain audio focus", null)
528
- return
529
- }
530
-
531
482
  // If already prepared, we can skip initialization
532
483
  if (!isPrepared) {
533
484
  LogUtils.d(CLASS_NAME, "Not prepared, preparing recording first")
@@ -542,7 +493,7 @@ class AudioRecorderManager(
542
493
  // Check permissions
543
494
  if (!checkPermissions(options, promise)) return
544
495
 
545
- // Parse recording configuration
496
+ // Parse recording configuration FIRST
546
497
  val configResult = RecordingConfig.fromMap(options)
547
498
  if (configResult.isFailure) {
548
499
  promise.reject(
@@ -557,6 +508,12 @@ class AudioRecorderManager(
557
508
 
558
509
  recordingConfig = tempRecordingConfig
559
510
 
511
+ // Request audio focus AFTER config is parsed so strategy is correct
512
+ if (!requestAudioFocus()) {
513
+ promise.reject("AUDIO_FOCUS_ERROR", "Failed to obtain audio focus", null)
514
+ return
515
+ }
516
+
560
517
  // Store device-related settings
561
518
  selectedDeviceId = recordingConfig.deviceId
562
519
  deviceDisconnectionBehavior = recordingConfig.deviceDisconnectionBehavior ?: "pause"
@@ -589,6 +546,12 @@ class AudioRecorderManager(
589
546
  ?: deviceDisconnectionBehavior
590
547
  ?: "pause"
591
548
  }
549
+
550
+ // Request audio focus with current config
551
+ if (!requestAudioFocus()) {
552
+ promise.reject("AUDIO_FOCUS_ERROR", "Failed to obtain audio focus", null)
553
+ return
554
+ }
592
555
  }
593
556
 
594
557
  if (!startRecordingProcess(promise)) return
@@ -1753,17 +1716,23 @@ class AudioRecorderManager(
1753
1716
  private fun getAudioFocusStrategy(): String {
1754
1717
  // Use explicit strategy if provided
1755
1718
  if (::recordingConfig.isInitialized) {
1756
- recordingConfig.audioFocusStrategy?.let { return it }
1719
+ recordingConfig.audioFocusStrategy?.let {
1720
+ LogUtils.d(CLASS_NAME, "Using explicit audio focus strategy: $it")
1721
+ return it
1722
+ }
1757
1723
 
1758
1724
  // Smart defaults based on other config
1759
- return if (recordingConfig.keepAwake && enableBackgroundAudio) {
1725
+ val defaultStrategy = if (recordingConfig.keepAwake && enableBackgroundAudio) {
1760
1726
  "background"
1761
1727
  } else {
1762
1728
  "interactive"
1763
1729
  }
1730
+ LogUtils.d(CLASS_NAME, "Using default audio focus strategy: $defaultStrategy (keepAwake=${recordingConfig.keepAwake}, enableBackgroundAudio=$enableBackgroundAudio)")
1731
+ return defaultStrategy
1764
1732
  }
1765
1733
 
1766
1734
  // Default strategy if recordingConfig is not initialized
1735
+ LogUtils.d(CLASS_NAME, "Using fallback audio focus strategy: interactive")
1767
1736
  return "interactive"
1768
1737
  }
1769
1738
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@siteed/expo-audio-studio",
3
- "version": "2.12.1",
3
+ "version": "2.12.3",
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",