@siteed/audio-studio 3.0.3 → 3.0.5

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,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
8
8
  ## [Unreleased]
9
9
 
10
10
 
11
+ ## [3.0.5] - 2026-04-25
12
+ ### Changed
13
+ - fix(audio-studio): don't start notification on prepareRecording (Android) (#364) ([5d40d7e](https://github.com/deeeed/audiolab/commit/5d40d7e730f2b74459d319979fd9c112891b10f2))
14
+ - docs: update api references for v3.0.4 ([12421ee](https://github.com/deeeed/audiolab/commit/12421ee6146187888492b957c0eee428fcab3e8b))
15
+ - chore(audio-studio): release @siteed/audio-studio@3.0.4 ([3a5b7da](https://github.com/deeeed/audiolab/commit/3a5b7da8f4289a599d928dce01f262ab97398143))
16
+ ## [3.0.4] - 2026-04-25
17
+ ### Changed
18
+ - fix(audio-studio): move module ops off main thread + fix iOS stop crash (#363) ([1a07d2d](https://github.com/deeeed/audiolab/commit/1a07d2d9222bfac1083b00d6de992fcb2a3be42d))
19
+ - chore(audio-studio): release @siteed/audio-studio@3.0.3 ([9d4d14e](https://github.com/deeeed/audiolab/commit/9d4d14e8dffd4378a71f2d3dfb5d7140b8248c0f))
20
+ - fix(audio-studio): convert trim ranges from Double to Long on Android (#347) (#360) ([6099e0e](https://github.com/deeeed/audiolab/commit/6099e0e81f3c8d7b1c109b415ad63e924f3f043b))
21
+ - feat(audio-studio): web trimAudio, WASM refactor, new utilities (#344) ([3d4862a](https://github.com/deeeed/audiolab/commit/3d4862a57a5eb2496169d27f758d7628d7d3659a))
22
+ - feat(sherpa-voice): comprehensive logging + fix Android prod model extraction (#342) ([5b20594](https://github.com/deeeed/audiolab/commit/5b20594c729a9deb703cbc2e23c07daa616149ab))
23
+ - fix(audio-studio): remove blocking CDN poll from publish.sh, sync wasmConfig to 3.0.2 ([290409a](https://github.com/deeeed/audiolab/commit/290409aae8d1160e1952a5ee1961ce3864fbb0c8))
24
+ - chore(audio-studio): release @siteed/audio-studio@3.0.2 ([ebd3300](https://github.com/deeeed/audiolab/commit/ebd330098d2756e6d5a555126e2dfc3fb038d155))
11
25
  ## [3.0.3] - 2026-04-12
12
26
  ### Changed
13
27
  - fix(audio-studio): convert trim ranges from Double to Long on Android (#347) (#360) ([6099e0e](https://github.com/deeeed/audiolab/commit/6099e0e81f3c8d7b1c109b415ad63e924f3f043b))
@@ -335,7 +349,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
335
349
  - Audio features extraction during recording
336
350
  - Consistent WAV PCM recording format across all platforms
337
351
 
338
- [unreleased]: https://github.com/deeeed/audiolab/compare/@siteed/audio-studio@3.0.3...HEAD
352
+ [unreleased]: https://github.com/deeeed/audiolab/compare/@siteed/audio-studio@3.0.5...HEAD
353
+ [3.0.5]: https://github.com/deeeed/audiolab/compare/@siteed/audio-studio@3.0.4...@siteed/audio-studio@3.0.5
354
+ [3.0.4]: https://github.com/deeeed/audiolab/compare/@siteed/audio-studio@3.0.3...@siteed/audio-studio@3.0.4
339
355
  [3.0.3]: https://github.com/deeeed/audiolab/compare/@siteed/audio-studio@3.0.2...@siteed/audio-studio@3.0.3
340
356
  [3.0.2]: https://github.com/deeeed/audiolab/compare/@siteed/audio-studio@3.0.2-beta.2...@siteed/audio-studio@3.0.2
341
357
  [3.0.1]: https://github.com/deeeed/audiolab/compare/@siteed/audio-studio@3.0.0...@siteed/audio-studio@3.0.1
@@ -455,49 +455,55 @@ class AudioRecorderManager(
455
455
  }
456
456
 
457
457
  private fun initializePhoneStateListener() {
458
- try {
459
- LogUtils.d(CLASS_NAME, "Initializing phone state listener...")
460
-
461
- if (permissionUtils.checkPhoneStatePermission()) {
462
- LogUtils.d(CLASS_NAME, "Phone state permission granted")
463
-
464
- val localTelephonyManager = telephonyManager
465
- if (localTelephonyManager != null) {
466
- try {
467
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
468
- // API 31+: Use modern TelephonyCallback which reliably fires on Android 12+
469
- val callback = object : TelephonyCallback(), TelephonyCallback.CallStateListener {
470
- override fun onCallStateChanged(state: Int) {
471
- handleCallStateChanged(state)
458
+ // The legacy PhoneStateListener (API < 31) requires a Looper on the
459
+ // thread that constructs it; calling listen() also expects the same.
460
+ // prepareRecording now runs on Dispatchers.IO (no Looper), so we
461
+ // marshal the whole registration to the main thread's Looper. The
462
+ // API 31+ path uses context.mainExecutor and is thread-safe, but we
463
+ // route everything through main for consistency.
464
+ android.os.Handler(android.os.Looper.getMainLooper()).post {
465
+ try {
466
+ LogUtils.d(CLASS_NAME, "Initializing phone state listener...")
467
+
468
+ if (permissionUtils.checkPhoneStatePermission()) {
469
+ LogUtils.d(CLASS_NAME, "Phone state permission granted")
470
+
471
+ val localTelephonyManager = telephonyManager
472
+ if (localTelephonyManager != null) {
473
+ try {
474
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
475
+ val callback = object : TelephonyCallback(), TelephonyCallback.CallStateListener {
476
+ override fun onCallStateChanged(state: Int) {
477
+ handleCallStateChanged(state)
478
+ }
472
479
  }
473
- }
474
- telephonyCallback = callback
475
- localTelephonyManager.registerTelephonyCallback(context.mainExecutor, callback)
476
- LogUtils.d(CLASS_NAME, "Successfully registered TelephonyCallback (API 31+)")
477
- } else {
478
- // Legacy: PhoneStateListener for API < 31
479
- phoneStateListener = object : PhoneStateListener() {
480
- @Deprecated("Deprecated in API 31")
481
- override fun onCallStateChanged(state: Int, phoneNumber: String?) {
482
- handleCallStateChanged(state)
480
+ telephonyCallback = callback
481
+ localTelephonyManager.registerTelephonyCallback(context.mainExecutor, callback)
482
+ LogUtils.d(CLASS_NAME, "Successfully registered TelephonyCallback (API 31+)")
483
+ } else {
484
+ phoneStateListener = object : PhoneStateListener() {
485
+ @Deprecated("Deprecated in API 31")
486
+ override fun onCallStateChanged(state: Int, phoneNumber: String?) {
487
+ handleCallStateChanged(state)
488
+ }
483
489
  }
490
+ localTelephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE)
491
+ LogUtils.d(CLASS_NAME, "Successfully registered PhoneStateListener (legacy)")
484
492
  }
485
- localTelephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE)
486
- LogUtils.d(CLASS_NAME, "Successfully registered PhoneStateListener (legacy)")
493
+ } catch (e: SecurityException) {
494
+ LogUtils.w(CLASS_NAME, "Missing permission for phone state listener: ${e.message}")
495
+ } catch (e: Exception) {
496
+ LogUtils.e(CLASS_NAME, "Failed to register phone state listener", e)
487
497
  }
488
- } catch (e: SecurityException) {
489
- LogUtils.w(CLASS_NAME, "Missing permission for phone state listener: ${e.message}")
490
- } catch (e: Exception) {
491
- LogUtils.e(CLASS_NAME, "Failed to register phone state listener", e)
498
+ } else {
499
+ LogUtils.w(CLASS_NAME, "TelephonyManager is null, phone call interruption handling disabled (device may not have telephony service)")
492
500
  }
493
501
  } else {
494
- LogUtils.w(CLASS_NAME, "TelephonyManager is null, phone call interruption handling disabled (device may not have telephony service)")
502
+ LogUtils.w(CLASS_NAME, "READ_PHONE_STATE permission not granted, phone call interruption handling disabled")
495
503
  }
496
- } else {
497
- LogUtils.w(CLASS_NAME, "READ_PHONE_STATE permission not granted, phone call interruption handling disabled")
504
+ } catch (e: Exception) {
505
+ LogUtils.e(CLASS_NAME, "Failed to initialize phone state listener", e)
498
506
  }
499
- } catch (e: Exception) {
500
- LogUtils.e(CLASS_NAME, "Failed to initialize phone state listener", e)
501
507
  }
502
508
  }
503
509
 
@@ -903,12 +909,6 @@ class AudioRecorderManager(
903
909
  LogUtils.d(CLASS_NAME, "Skipping primary file creation - primary output is disabled")
904
910
  }
905
911
 
906
- if (recordingConfig.showNotification && enableBackgroundAudio) {
907
- notificationManager.initialize(recordingConfig)
908
- notificationManager.startUpdates(System.currentTimeMillis())
909
- AudioRecordingService.startService(context)
910
- }
911
-
912
912
  acquireWakeLock()
913
913
  audioProcessor.resetCumulativeAmplitudeRange()
914
914
  return true
@@ -954,20 +954,28 @@ class AudioRecorderManager(
954
954
 
955
955
  audioRecord?.startRecording()
956
956
  isPaused.set(false)
957
- _isRecording.set(true)
958
957
  isFirstChunk = true
959
-
960
- if (!isPaused.get()) {
961
- recordingStartTime = System.currentTimeMillis()
958
+ recordingStartTime = System.currentTimeMillis()
959
+
960
+ // Start notification + foreground service before flipping isRecording (#298, #288).
961
+ // Previously the notification block fired in initializeRecordingResources, which is
962
+ // also reached from prepareRecording, so the notification timer started on prepare.
963
+ // Mirrors iOS fix in AudioStreamManager.swift. Service start is shared by both
964
+ // showNotification and keepAwake gates and must precede _isRecording=true so
965
+ // getStatus() can't observe (isRecording=true && !isServiceRunning).
966
+ val needsService = (recordingConfig.showNotification || recordingConfig.keepAwake) &&
967
+ enableBackgroundAudio
968
+ if (recordingConfig.showNotification && enableBackgroundAudio) {
969
+ notificationManager.initialize(recordingConfig)
970
+ notificationManager.startUpdates(recordingStartTime)
962
971
  }
963
-
964
- recordingThread = Thread { recordingProcess() }.apply { start() }
965
-
966
- // Start service if keepAwake is true, but only if background audio is enabled (#288)
967
- if (recordingConfig.keepAwake && enableBackgroundAudio) {
972
+ if (needsService) {
968
973
  AudioRecordingService.startService(context)
969
974
  }
970
-
975
+
976
+ _isRecording.set(true)
977
+ recordingThread = Thread { recordingProcess() }.apply { start() }
978
+
971
979
  return true
972
980
 
973
981
  } catch (e: Exception) {