@siteed/expo-audio-stream 1.15.1 → 1.16.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 CHANGED
@@ -8,6 +8,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
8
8
  ## [Unreleased]
9
9
 
10
10
 
11
+ ## [1.16.0] - 2025-02-17
12
+ ### Changed
13
+ - fix(expo-audio-stream): prevent adding iOS background modes when disabled ([5c9d09c](https://github.com/deeeed/expo-audio-stream/commit/5c9d09c715ce008fe72177431224a10f5fd7a865))
14
+ - fix(ios): replace CallKit with AVAudioSession for phone call detection ([e3b664b](https://github.com/deeeed/expo-audio-stream/commit/e3b664ba6925c379b323ded5fc408154e5f092c6))
15
+ - chore(expo-audio-stream): release @siteed/expo-audio-stream@1.15.1 ([cbc3d10](https://github.com/deeeed/expo-audio-stream/commit/cbc3d10661a415811f1fe46cb3acaf63451a9df9))
11
16
  ## [1.15.1] - 2025-02-17
12
17
  ### Changed
13
18
  - fix: restore Opus compression support on iOS (#122) ([06614e6](https://github.com/deeeed/expo-audio-stream/commit/06614e6d96fa2a6af56edf0fd2e2b3966e13c8f7))
@@ -124,7 +129,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
124
129
  - Feature: Audio features extraction during recording.
125
130
  - Feature: Consistent WAV PCM recording format across all platforms.
126
131
 
127
- [unreleased]: https://github.com/deeeed/expo-audio-stream/compare/@siteed/expo-audio-stream@1.15.1...HEAD
132
+ [unreleased]: https://github.com/deeeed/expo-audio-stream/compare/@siteed/expo-audio-stream@1.16.0...HEAD
133
+ [1.16.0]: https://github.com/deeeed/expo-audio-stream/compare/@siteed/expo-audio-stream@1.15.1...@siteed/expo-audio-stream@1.16.0
128
134
  [1.15.1]: https://github.com/deeeed/expo-audio-stream/compare/@siteed/expo-audio-stream@1.15.0...@siteed/expo-audio-stream@1.15.1
129
135
  [1.15.0]: https://github.com/deeeed/expo-audio-stream/compare/@siteed/expo-audio-stream@1.14.2...@siteed/expo-audio-stream@1.15.0
130
136
  [1.14.2]: https://github.com/deeeed/expo-audio-stream/compare/@siteed/expo-audio-stream@1.14.1...@siteed/expo-audio-stream@1.14.2
@@ -11,7 +11,6 @@ import Accelerate
11
11
  import UIKit
12
12
  import MediaPlayer
13
13
  import UserNotifications
14
- import CallKit
15
14
 
16
15
  // Helper to convert to little-endian byte array
17
16
  extension UInt32 {
@@ -566,17 +565,26 @@ class AudioStreamManager: NSObject {
566
565
  return status
567
566
  }
568
567
 
568
+ /// Detects if a phone call is active without using CallKit.
569
+ /// We avoid CallKit because its usage prevents apps from being available in China's App Store.
570
+ /// This is a workaround that uses AVAudioSession to detect phone calls instead.
571
+ private func isPhoneCallActive() -> Bool {
572
+ let audioSession = AVAudioSession.sharedInstance()
573
+ return audioSession.isOtherAudioPlaying &&
574
+ audioSession.secondaryAudioShouldBeSilencedHint &&
575
+ audioSession.currentRoute.outputs.contains { $0.portType == .builtInReceiver }
576
+ }
577
+
569
578
  /// Starts a new audio recording with the specified settings and interval.
570
579
  /// - Parameters:
571
580
  /// - settings: The recording settings to use.
572
581
  /// - intervalMilliseconds: The interval in milliseconds for emitting audio data.
573
582
  /// - Returns: A StartRecordingResult object if recording starts successfully, or nil otherwise.
574
583
  func startRecording(settings: RecordingSettings, intervalMilliseconds: Int) -> StartRecordingResult? {
575
- // Check for active call first
576
- let callCenter = CXCallObserver()
577
- if callCenter.calls.contains(where: { $0.hasEnded == false }) {
578
- Logger.debug("Cannot start recording during an active call")
579
- delegate?.audioStreamManager(self, didFailWithError: "Cannot start recording during an active call")
584
+ // Check for active call using the new method
585
+ if isPhoneCallActive() {
586
+ Logger.debug("Cannot start recording during an active phone call")
587
+ delegate?.audioStreamManager(self, didFailWithError: "Cannot start recording during an active phone call")
580
588
  return nil
581
589
  }
582
590
 
@@ -922,11 +930,10 @@ class AudioStreamManager: NSObject {
922
930
 
923
931
  /// Resumes the current audio recording.
924
932
  func resumeRecording() {
925
- // Check for active call first
926
- let callCenter = CXCallObserver()
927
- if callCenter.calls.contains(where: { $0.hasEnded == false }) {
928
- Logger.debug("Cannot resume recording during an active call")
929
- delegate?.audioStreamManager(self, didFailWithError: "Cannot resume recording during an active call")
933
+ // Check for active call using the new method
934
+ if isPhoneCallActive() {
935
+ Logger.debug("Cannot resume recording during an active phone call")
936
+ delegate?.audioStreamManager(self, didFailWithError: "Cannot resume recording during an active phone call")
930
937
  return
931
938
  }
932
939
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@siteed/expo-audio-stream",
3
- "version": "1.15.1",
3
+ "version": "1.16.0",
4
4
  "description": "stream audio crossplatform",
5
5
  "license": "MIT",
6
6
  "main": "build/index.js",
@@ -37,13 +37,14 @@ const withRecordingPermission = (config, props) => {
37
37
  config.modResults['NSUserNotificationAlertStyle'] = 'alert';
38
38
  }
39
39
  const existingBackgroundModes = config.modResults.UIBackgroundModes || [];
40
- // Only add background modes if explicitly enabled
41
- if (options.iosBackgroundModes?.useAudio &&
42
- enableBackgroundAudio &&
40
+ // Only add background modes if explicitly enabled and set to true
41
+ if (options.iosBackgroundModes?.useAudio === true &&
42
+ enableBackgroundAudio === true &&
43
43
  !existingBackgroundModes.includes('audio')) {
44
44
  existingBackgroundModes.push('audio');
45
45
  }
46
- if (options.iosBackgroundModes?.useVoIP && enablePhoneStateHandling) {
46
+ if (options.iosBackgroundModes?.useVoIP === true &&
47
+ enablePhoneStateHandling === true) {
47
48
  if (!existingBackgroundModes.includes('voip')) {
48
49
  existingBackgroundModes.push('voip');
49
50
  }
@@ -55,22 +56,22 @@ const withRecordingPermission = (config, props) => {
55
56
  config.modResults.UIRequiredDeviceCapabilities =
56
57
  existingCapabilities;
57
58
  }
58
- // Add additional background modes if enabled
59
- if (options.iosBackgroundModes?.useProcessing) {
59
+ // Add additional background modes only if explicitly set to true
60
+ if (options.iosBackgroundModes?.useProcessing === true) {
60
61
  if (!existingBackgroundModes.includes('processing')) {
61
62
  existingBackgroundModes.push('processing');
62
63
  }
63
64
  // Add processing info if enabled
64
65
  config.modResults.BGTaskSchedulerPermittedIdentifiers = [
65
- 'com.siteed.audiostream.processing'
66
+ 'com.siteed.audiostream.processing',
66
67
  ];
67
68
  }
68
- if (options.iosBackgroundModes?.useLocation) {
69
+ if (options.iosBackgroundModes?.useLocation === true) {
69
70
  if (!existingBackgroundModes.includes('location')) {
70
71
  existingBackgroundModes.push('location');
71
72
  }
72
73
  }
73
- if (options.iosBackgroundModes?.useExternalAccessory) {
74
+ if (options.iosBackgroundModes?.useExternalAccessory === true) {
74
75
  if (!existingBackgroundModes.includes('external-accessory')) {
75
76
  existingBackgroundModes.push('external-accessory');
76
77
  }
@@ -84,7 +85,7 @@ const withRecordingPermission = (config, props) => {
84
85
  if (options.iosConfig?.allowBackgroundAudioControls) {
85
86
  config.modResults.UIBackgroundModes = [
86
87
  ...existingBackgroundModes,
87
- 'remote-notification'
88
+ 'remote-notification',
88
89
  ];
89
90
  config.modResults.MPNowPlayingInfoPropertyPlaybackRate = true;
90
91
  }
@@ -17,7 +17,7 @@ function debugLog(message: string, ...args: unknown[]): void {
17
17
  }
18
18
 
19
19
  interface AudioStreamPluginOptions {
20
- enablePhoneStateHandling?: boolean // Controls READ_PHONE_STATE permission
20
+ enablePhoneStateHandling?: boolean // Controls READ_PHONE_STATE permission
21
21
  enableNotifications?: boolean
22
22
  enableBackgroundAudio?: boolean
23
23
  iosBackgroundModes?: {
@@ -38,7 +38,7 @@ const withRecordingPermission: ConfigPlugin<AudioStreamPluginOptions> = (
38
38
  props: AudioStreamPluginOptions | void
39
39
  ) => {
40
40
  const options: AudioStreamPluginOptions = {
41
- enablePhoneStateHandling: true, // Default to true for backward compatibility
41
+ enablePhoneStateHandling: true, // Default to true for backward compatibility
42
42
  enableNotifications: true,
43
43
  enableBackgroundAudio: true,
44
44
  iosBackgroundModes: {
@@ -75,16 +75,19 @@ const withRecordingPermission: ConfigPlugin<AudioStreamPluginOptions> = (
75
75
  const existingBackgroundModes =
76
76
  config.modResults.UIBackgroundModes || []
77
77
 
78
- // Only add background modes if explicitly enabled
78
+ // Only add background modes if explicitly enabled and set to true
79
79
  if (
80
- options.iosBackgroundModes?.useAudio &&
81
- enableBackgroundAudio &&
80
+ options.iosBackgroundModes?.useAudio === true &&
81
+ enableBackgroundAudio === true &&
82
82
  !existingBackgroundModes.includes('audio')
83
83
  ) {
84
84
  existingBackgroundModes.push('audio')
85
85
  }
86
86
 
87
- if (options.iosBackgroundModes?.useVoIP && enablePhoneStateHandling) {
87
+ if (
88
+ options.iosBackgroundModes?.useVoIP === true &&
89
+ enablePhoneStateHandling === true
90
+ ) {
88
91
  if (!existingBackgroundModes.includes('voip')) {
89
92
  existingBackgroundModes.push('voip')
90
93
  }
@@ -97,24 +100,24 @@ const withRecordingPermission: ConfigPlugin<AudioStreamPluginOptions> = (
97
100
  existingCapabilities
98
101
  }
99
102
 
100
- // Add additional background modes if enabled
101
- if (options.iosBackgroundModes?.useProcessing) {
103
+ // Add additional background modes only if explicitly set to true
104
+ if (options.iosBackgroundModes?.useProcessing === true) {
102
105
  if (!existingBackgroundModes.includes('processing')) {
103
106
  existingBackgroundModes.push('processing')
104
107
  }
105
108
  // Add processing info if enabled
106
109
  config.modResults.BGTaskSchedulerPermittedIdentifiers = [
107
- 'com.siteed.audiostream.processing'
110
+ 'com.siteed.audiostream.processing',
108
111
  ]
109
112
  }
110
113
 
111
- if (options.iosBackgroundModes?.useLocation) {
114
+ if (options.iosBackgroundModes?.useLocation === true) {
112
115
  if (!existingBackgroundModes.includes('location')) {
113
116
  existingBackgroundModes.push('location')
114
117
  }
115
118
  }
116
119
 
117
- if (options.iosBackgroundModes?.useExternalAccessory) {
120
+ if (options.iosBackgroundModes?.useExternalAccessory === true) {
118
121
  if (!existingBackgroundModes.includes('external-accessory')) {
119
122
  existingBackgroundModes.push('external-accessory')
120
123
  }
@@ -122,7 +125,7 @@ const withRecordingPermission: ConfigPlugin<AudioStreamPluginOptions> = (
122
125
 
123
126
  // Configure background processing info if enabled
124
127
  if (options.iosConfig?.backgroundProcessingTitle) {
125
- config.modResults.BGProcessingTaskTitle =
128
+ config.modResults.BGProcessingTaskTitle =
126
129
  options.iosConfig.backgroundProcessingTitle
127
130
  }
128
131
 
@@ -130,7 +133,7 @@ const withRecordingPermission: ConfigPlugin<AudioStreamPluginOptions> = (
130
133
  if (options.iosConfig?.allowBackgroundAudioControls) {
131
134
  config.modResults.UIBackgroundModes = [
132
135
  ...existingBackgroundModes,
133
- 'remote-notification'
136
+ 'remote-notification',
134
137
  ]
135
138
  config.modResults.MPNowPlayingInfoPropertyPlaybackRate = true
136
139
  }