react-native-audio-api 0.11.0-nightly-b30bac9-20260114 → 0.11.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.
Files changed (173) hide show
  1. package/android/src/main/cpp/audioapi/android/core/AndroidAudioRecorder.cpp +3 -10
  2. package/android/src/main/cpp/audioapi/android/core/AudioPlayer.cpp +0 -4
  3. package/android/src/main/java/com/swmansion/audioapi/AudioAPIModule.kt +4 -83
  4. package/android/src/main/java/com/swmansion/audioapi/system/CentralizedForegroundService.kt +14 -29
  5. package/android/src/main/java/com/swmansion/audioapi/system/ForegroundServiceManager.kt +10 -9
  6. package/android/src/main/java/com/swmansion/audioapi/system/MediaSessionManager.kt +10 -51
  7. package/android/src/main/java/com/swmansion/audioapi/system/notification/BaseNotification.kt +6 -14
  8. package/android/src/main/java/com/swmansion/audioapi/system/notification/NotificationRegistry.kt +79 -60
  9. package/android/src/main/java/com/swmansion/audioapi/system/notification/PlaybackNotification.kt +249 -411
  10. package/android/src/main/java/com/swmansion/audioapi/system/notification/PlaybackNotificationReceiver.kt +8 -3
  11. package/android/src/main/java/com/swmansion/audioapi/system/notification/RecordingNotification.kt +240 -222
  12. package/android/src/main/java/com/swmansion/audioapi/system/notification/RecordingNotificationReceiver.kt +11 -22
  13. package/android/src/main/java/com/swmansion/audioapi/system/notification/state/RecordingNotificationState.kt +24 -0
  14. package/android/src/main/res/layout/btn_round_ripple.xml +9 -0
  15. package/android/src/main/res/layout/notification_collapsed.xml +45 -0
  16. package/android/src/main/res/layout/notification_expanded.xml +44 -0
  17. package/android/src/oldarch/NativeAudioAPIModuleSpec.java +1 -13
  18. package/common/cpp/audioapi/core/utils/AudioFileWriter.cpp +1 -1
  19. package/ios/audioapi/ios/AudioAPIModule.mm +5 -48
  20. package/ios/audioapi/ios/system/notification/BaseNotification.h +0 -7
  21. package/ios/audioapi/ios/system/notification/NotificationRegistry.h +5 -25
  22. package/ios/audioapi/ios/system/notification/NotificationRegistry.mm +19 -64
  23. package/ios/audioapi/ios/system/notification/PlaybackNotification.mm +4 -15
  24. package/lib/commonjs/AudioAPIModule/AudioAPIModule.js +2 -1
  25. package/lib/commonjs/AudioAPIModule/AudioAPIModule.js.map +1 -1
  26. package/lib/commonjs/api.js +1 -29
  27. package/lib/commonjs/api.js.map +1 -1
  28. package/lib/commonjs/core/AudioDecoder.js +42 -16
  29. package/lib/commonjs/core/AudioDecoder.js.map +1 -1
  30. package/lib/commonjs/core/AudioRecorder.js +2 -1
  31. package/lib/commonjs/core/AudioRecorder.js.map +1 -1
  32. package/lib/commonjs/core/AudioStretcher.js +2 -1
  33. package/lib/commonjs/core/AudioStretcher.js.map +1 -1
  34. package/lib/commonjs/core/BaseAudioContext.js +2 -5
  35. package/lib/commonjs/core/BaseAudioContext.js.map +1 -1
  36. package/lib/commonjs/errors/AudioApiError.js +14 -0
  37. package/lib/commonjs/errors/AudioApiError.js.map +1 -0
  38. package/lib/commonjs/errors/index.js +7 -0
  39. package/lib/commonjs/errors/index.js.map +1 -1
  40. package/lib/commonjs/specs/NativeAudioAPIModule.js.map +1 -1
  41. package/lib/commonjs/specs/NativeAudioAPIModule.web.js +0 -9
  42. package/lib/commonjs/specs/NativeAudioAPIModule.web.js.map +1 -1
  43. package/lib/commonjs/system/notification/PlaybackNotificationManager.js +40 -85
  44. package/lib/commonjs/system/notification/PlaybackNotificationManager.js.map +1 -1
  45. package/lib/commonjs/system/notification/RecordingNotificationManager.ios.js +51 -0
  46. package/lib/commonjs/system/notification/RecordingNotificationManager.ios.js.map +1 -0
  47. package/lib/commonjs/system/notification/RecordingNotificationManager.js +30 -144
  48. package/lib/commonjs/system/notification/RecordingNotificationManager.js.map +1 -1
  49. package/lib/commonjs/system/notification/index.js +1 -9
  50. package/lib/commonjs/system/notification/index.js.map +1 -1
  51. package/lib/commonjs/utils/index.js +3 -2
  52. package/lib/commonjs/utils/index.js.map +1 -1
  53. package/lib/commonjs/utils/paths.js +18 -0
  54. package/lib/commonjs/utils/paths.js.map +1 -0
  55. package/lib/commonjs/web-core/AudioContext.js +20 -11
  56. package/lib/commonjs/web-core/AudioContext.js.map +1 -1
  57. package/lib/commonjs/web-system/notification/PlaybackNotificationManager.js +0 -1
  58. package/lib/commonjs/web-system/notification/PlaybackNotificationManager.js.map +1 -1
  59. package/lib/commonjs/web-system/notification/RecordingNotificationManager.js +1 -6
  60. package/lib/commonjs/web-system/notification/RecordingNotificationManager.js.map +1 -1
  61. package/lib/module/AudioAPIModule/AudioAPIModule.js +2 -1
  62. package/lib/module/AudioAPIModule/AudioAPIModule.js.map +1 -1
  63. package/lib/module/api.js +3 -2
  64. package/lib/module/api.js.map +1 -1
  65. package/lib/module/core/AudioDecoder.js +42 -16
  66. package/lib/module/core/AudioDecoder.js.map +1 -1
  67. package/lib/module/core/AudioRecorder.js +3 -1
  68. package/lib/module/core/AudioRecorder.js.map +1 -1
  69. package/lib/module/core/AudioStretcher.js +2 -1
  70. package/lib/module/core/AudioStretcher.js.map +1 -1
  71. package/lib/module/core/BaseAudioContext.js +2 -5
  72. package/lib/module/core/BaseAudioContext.js.map +1 -1
  73. package/lib/module/errors/AudioApiError.js +10 -0
  74. package/lib/module/errors/AudioApiError.js.map +1 -0
  75. package/lib/module/errors/index.js +1 -0
  76. package/lib/module/errors/index.js.map +1 -1
  77. package/lib/module/specs/NativeAudioAPIModule.js.map +1 -1
  78. package/lib/module/specs/NativeAudioAPIModule.web.js +0 -9
  79. package/lib/module/specs/NativeAudioAPIModule.web.js.map +1 -1
  80. package/lib/module/system/notification/PlaybackNotificationManager.js +40 -85
  81. package/lib/module/system/notification/PlaybackNotificationManager.js.map +1 -1
  82. package/lib/module/system/notification/RecordingNotificationManager.ios.js +47 -0
  83. package/lib/module/system/notification/RecordingNotificationManager.ios.js.map +1 -0
  84. package/lib/module/system/notification/RecordingNotificationManager.js +30 -144
  85. package/lib/module/system/notification/RecordingNotificationManager.js.map +1 -1
  86. package/lib/module/system/notification/index.js +1 -2
  87. package/lib/module/system/notification/index.js.map +1 -1
  88. package/lib/module/utils/index.js +3 -2
  89. package/lib/module/utils/index.js.map +1 -1
  90. package/lib/module/utils/paths.js +12 -0
  91. package/lib/module/utils/paths.js.map +1 -0
  92. package/lib/module/web-core/AudioContext.js +20 -11
  93. package/lib/module/web-core/AudioContext.js.map +1 -1
  94. package/lib/module/web-system/notification/PlaybackNotificationManager.js +0 -1
  95. package/lib/module/web-system/notification/PlaybackNotificationManager.js.map +1 -1
  96. package/lib/module/web-system/notification/RecordingNotificationManager.js +1 -6
  97. package/lib/module/web-system/notification/RecordingNotificationManager.js.map +1 -1
  98. package/lib/typescript/AudioAPIModule/AudioAPIModule.d.ts.map +1 -1
  99. package/lib/typescript/api.d.ts +3 -2
  100. package/lib/typescript/api.d.ts.map +1 -1
  101. package/lib/typescript/core/AudioDecoder.d.ts +2 -1
  102. package/lib/typescript/core/AudioDecoder.d.ts.map +1 -1
  103. package/lib/typescript/core/AudioRecorder.d.ts.map +1 -1
  104. package/lib/typescript/core/AudioStretcher.d.ts.map +1 -1
  105. package/lib/typescript/core/BaseAudioContext.d.ts +2 -2
  106. package/lib/typescript/core/BaseAudioContext.d.ts.map +1 -1
  107. package/lib/typescript/errors/AudioApiError.d.ts +5 -0
  108. package/lib/typescript/errors/AudioApiError.d.ts.map +1 -0
  109. package/lib/typescript/errors/index.d.ts +1 -0
  110. package/lib/typescript/errors/index.d.ts.map +1 -1
  111. package/lib/typescript/interfaces.d.ts +1 -1
  112. package/lib/typescript/interfaces.d.ts.map +1 -1
  113. package/lib/typescript/specs/NativeAudioAPIModule.d.ts +2 -5
  114. package/lib/typescript/specs/NativeAudioAPIModule.d.ts.map +1 -1
  115. package/lib/typescript/specs/NativeAudioAPIModule.web.d.ts +1 -4
  116. package/lib/typescript/specs/NativeAudioAPIModule.web.d.ts.map +1 -1
  117. package/lib/typescript/system/notification/PlaybackNotificationManager.d.ts +32 -9
  118. package/lib/typescript/system/notification/PlaybackNotificationManager.d.ts.map +1 -1
  119. package/lib/typescript/system/notification/RecordingNotificationManager.d.ts +26 -13
  120. package/lib/typescript/system/notification/RecordingNotificationManager.d.ts.map +1 -1
  121. package/lib/typescript/system/notification/RecordingNotificationManager.ios.d.ts +36 -0
  122. package/lib/typescript/system/notification/RecordingNotificationManager.ios.d.ts.map +1 -0
  123. package/lib/typescript/system/notification/index.d.ts +0 -1
  124. package/lib/typescript/system/notification/index.d.ts.map +1 -1
  125. package/lib/typescript/system/notification/types.d.ts +12 -22
  126. package/lib/typescript/system/notification/types.d.ts.map +1 -1
  127. package/lib/typescript/types.d.ts +1 -0
  128. package/lib/typescript/types.d.ts.map +1 -1
  129. package/lib/typescript/utils/index.d.ts.map +1 -1
  130. package/lib/typescript/utils/paths.d.ts +4 -0
  131. package/lib/typescript/utils/paths.d.ts.map +1 -0
  132. package/lib/typescript/web-core/AudioContext.d.ts +8 -9
  133. package/lib/typescript/web-core/AudioContext.d.ts.map +1 -1
  134. package/lib/typescript/web-core/BaseAudioContext.d.ts +6 -7
  135. package/lib/typescript/web-core/BaseAudioContext.d.ts.map +1 -1
  136. package/lib/typescript/web-system/notification/PlaybackNotificationManager.d.ts +1 -2
  137. package/lib/typescript/web-system/notification/PlaybackNotificationManager.d.ts.map +1 -1
  138. package/lib/typescript/web-system/notification/RecordingNotificationManager.d.ts +2 -7
  139. package/lib/typescript/web-system/notification/RecordingNotificationManager.d.ts.map +1 -1
  140. package/package.json +1 -1
  141. package/src/AudioAPIModule/AudioAPIModule.ts +2 -1
  142. package/src/api.ts +2 -8
  143. package/src/core/AudioDecoder.ts +91 -21
  144. package/src/core/AudioRecorder.ts +2 -1
  145. package/src/core/AudioStretcher.ts +2 -1
  146. package/src/core/BaseAudioContext.ts +4 -6
  147. package/src/errors/AudioApiError.ts +8 -0
  148. package/src/errors/index.ts +1 -0
  149. package/src/interfaces.ts +1 -1
  150. package/src/specs/NativeAudioAPIModule.ts +5 -15
  151. package/src/specs/NativeAudioAPIModule.web.ts +1 -12
  152. package/src/system/notification/PlaybackNotificationManager.ts +42 -117
  153. package/src/system/notification/RecordingNotificationManager.ios.ts +65 -0
  154. package/src/system/notification/RecordingNotificationManager.ts +33 -183
  155. package/src/system/notification/index.ts +0 -1
  156. package/src/system/notification/types.ts +15 -37
  157. package/src/types.ts +2 -0
  158. package/src/utils/index.ts +3 -2
  159. package/src/utils/paths.ts +11 -0
  160. package/src/web-core/AudioContext.tsx +34 -19
  161. package/src/web-core/BaseAudioContext.tsx +9 -7
  162. package/src/web-system/notification/PlaybackNotificationManager.ts +1 -7
  163. package/src/web-system/notification/RecordingNotificationManager.ts +1 -16
  164. package/android/src/main/java/com/swmansion/audioapi/core/NativeAudioPlayer.kt +0 -26
  165. package/android/src/main/java/com/swmansion/audioapi/core/NativeAudioRecorder.kt +0 -26
  166. package/android/src/main/java/com/swmansion/audioapi/system/notification/SimpleNotification.kt +0 -119
  167. package/lib/commonjs/system/notification/SimpleNotificationManager.js +0 -125
  168. package/lib/commonjs/system/notification/SimpleNotificationManager.js.map +0 -1
  169. package/lib/module/system/notification/SimpleNotificationManager.js +0 -121
  170. package/lib/module/system/notification/SimpleNotificationManager.js.map +0 -1
  171. package/lib/typescript/system/notification/SimpleNotificationManager.d.ts +0 -21
  172. package/lib/typescript/system/notification/SimpleNotificationManager.d.ts.map +0 -1
  173. package/src/system/notification/SimpleNotificationManager.ts +0 -175
@@ -27,9 +27,7 @@ AndroidAudioRecorder::AndroidAudioRecorder(
27
27
  : AudioRecorder(audioEventHandlerRegistry),
28
28
  streamSampleRate_(0.0),
29
29
  streamChannelCount_(0),
30
- streamMaxBufferSizeInFrames_(0) {
31
- nativeAudioRecorder_ = jni::make_global(NativeAudioRecorder::create());
32
- }
30
+ streamMaxBufferSizeInFrames_(0) {}
33
31
 
34
32
  /// @brief Destructor ensures that the audio stream and each output type are closed and flushed up remaining data.
35
33
  /// TODO: Possibly locks here are not necessary, but we might have an issue with oboe having raw pointer to the
@@ -55,8 +53,6 @@ AndroidAudioRecorder::~AndroidAudioRecorder() {
55
53
  }
56
54
  }
57
55
 
58
- nativeAudioRecorder_.release();
59
-
60
56
  if (mStream_) {
61
57
  mStream_->requestStop();
62
58
  mStream_->close();
@@ -119,7 +115,7 @@ Result<std::string, std::string> AndroidAudioRecorder::start() {
119
115
  return Result<std::string, std::string>::Err(streamResult.unwrap_err());
120
116
  }
121
117
 
122
- if (!mStream_ || !nativeAudioRecorder_) {
118
+ if (!mStream_) {
123
119
  return Result<std::string, std::string>::Err("Audio stream is not initialized.");
124
120
  }
125
121
 
@@ -153,8 +149,6 @@ Result<std::string, std::string> AndroidAudioRecorder::start() {
153
149
  "Failed to start stream: " + std::string(oboe::convertToText(result)));
154
150
  }
155
151
 
156
- jni::ThreadScope::WithClassLoader([this]() { nativeAudioRecorder_->start(); });
157
-
158
152
  state_.store(RecorderState::Recording, std::memory_order_release);
159
153
  return Result<std::string, std::string>::Ok(std::format("file://{}", filePath_));
160
154
  }
@@ -175,13 +169,12 @@ Result<std::tuple<std::string, double, double>, std::string> AndroidAudioRecorde
175
169
  "Recorder is not in recording state.");
176
170
  }
177
171
 
178
- if (!mStream_ || !nativeAudioRecorder_) {
172
+ if (!mStream_) {
179
173
  return Result<std::tuple<std::string, double, double>, std::string>::Err(
180
174
  "Audio stream is not initialized.");
181
175
  }
182
176
 
183
177
  state_.store(RecorderState::Idle, std::memory_order_release);
184
- jni::ThreadScope::WithClassLoader([this]() { nativeAudioRecorder_->stop(); });
185
178
  mStream_->requestStop();
186
179
 
187
180
  if (usesFileOutput()) {
@@ -17,8 +17,6 @@ AudioPlayer::AudioPlayer(
17
17
  int channelCount)
18
18
  : renderAudio_(renderAudio), sampleRate_(sampleRate), channelCount_(channelCount) {
19
19
  isInitialized_ = openAudioStream();
20
-
21
- nativeAudioPlayer_ = jni::make_global(NativeAudioPlayer::create());
22
20
  }
23
21
 
24
22
  bool AudioPlayer::openAudioStream() {
@@ -47,7 +45,6 @@ bool AudioPlayer::openAudioStream() {
47
45
 
48
46
  bool AudioPlayer::start() {
49
47
  if (mStream_) {
50
- jni::ThreadScope::WithClassLoader([this]() { nativeAudioPlayer_->start(); });
51
48
  auto result = mStream_->requestStart();
52
49
  return result == oboe::Result::OK;
53
50
  }
@@ -57,7 +54,6 @@ bool AudioPlayer::start() {
57
54
 
58
55
  void AudioPlayer::stop() {
59
56
  if (mStream_) {
60
- jni::ThreadScope::WithClassLoader([this]() { nativeAudioPlayer_->stop(); });
61
57
  mStream_->requestStop();
62
58
  }
63
59
  }
@@ -148,10 +148,11 @@ class AudioAPIModule(
148
148
  promise.resolve(MediaSessionManager.getDevicesInfo())
149
149
  }
150
150
 
151
- // New notification system methods
152
- override fun registerNotification(
151
+ // Notification system methods
152
+ override fun showNotification(
153
153
  type: String?,
154
154
  key: String?,
155
+ options: ReadableMap?,
155
156
  promise: Promise?,
156
157
  ) {
157
158
  try {
@@ -163,61 +164,7 @@ class AudioAPIModule(
163
164
  return
164
165
  }
165
166
 
166
- MediaSessionManager.registerNotification(type, key)
167
-
168
- val result = Arguments.createMap()
169
- result.putBoolean("success", true)
170
- promise?.resolve(result)
171
- } catch (e: Exception) {
172
- val result = Arguments.createMap()
173
- result.putBoolean("success", false)
174
- result.putString("error", e.message ?: "Unknown error")
175
- promise?.resolve(result)
176
- }
177
- }
178
-
179
- override fun showNotification(
180
- key: String?,
181
- options: ReadableMap?,
182
- promise: Promise?,
183
- ) {
184
- try {
185
- if (key == null) {
186
- val result = Arguments.createMap()
187
- result.putBoolean("success", false)
188
- result.putString("error", "Key is required")
189
- promise?.resolve(result)
190
- return
191
- }
192
-
193
- MediaSessionManager.showNotification(key, options)
194
-
195
- val result = Arguments.createMap()
196
- result.putBoolean("success", true)
197
- promise?.resolve(result)
198
- } catch (e: Exception) {
199
- val result = Arguments.createMap()
200
- result.putBoolean("success", false)
201
- result.putString("error", e.message ?: "Unknown error")
202
- promise?.resolve(result)
203
- }
204
- }
205
-
206
- override fun updateNotification(
207
- key: String?,
208
- options: ReadableMap?,
209
- promise: Promise?,
210
- ) {
211
- try {
212
- if (key == null) {
213
- val result = Arguments.createMap()
214
- result.putBoolean("success", false)
215
- result.putString("error", "Key is required")
216
- promise?.resolve(result)
217
- return
218
- }
219
-
220
- MediaSessionManager.updateNotification(key, options)
167
+ MediaSessionManager.showNotification(type, key, options)
221
168
 
222
169
  val result = Arguments.createMap()
223
170
  result.putBoolean("success", true)
@@ -256,32 +203,6 @@ class AudioAPIModule(
256
203
  }
257
204
  }
258
205
 
259
- override fun unregisterNotification(
260
- key: String?,
261
- promise: Promise?,
262
- ) {
263
- try {
264
- if (key == null) {
265
- val result = Arguments.createMap()
266
- result.putBoolean("success", false)
267
- result.putString("error", "Key is required")
268
- promise?.resolve(result)
269
- return
270
- }
271
-
272
- MediaSessionManager.unregisterNotification(key)
273
-
274
- val result = Arguments.createMap()
275
- result.putBoolean("success", true)
276
- promise?.resolve(result)
277
- } catch (e: Exception) {
278
- val result = Arguments.createMap()
279
- result.putBoolean("success", false)
280
- result.putString("error", e.message ?: "Unknown error")
281
- promise?.resolve(result)
282
- }
283
- }
284
-
285
206
  override fun isNotificationActive(
286
207
  key: String?,
287
208
  promise: Promise?,
@@ -6,13 +6,14 @@ import android.app.NotificationManager
6
6
  import android.app.Service
7
7
  import android.content.Context
8
8
  import android.content.Intent
9
- import android.content.pm.ServiceInfo
10
9
  import android.os.Build
11
10
  import android.os.IBinder
12
11
  import android.util.Log
13
12
  import androidx.core.app.NotificationCompat
14
13
  import com.swmansion.audioapi.system.MediaSessionManager.CHANNEL_ID
15
14
  import com.swmansion.audioapi.system.notification.NotificationRegistry
15
+ import com.swmansion.audioapi.system.notification.PlaybackNotification
16
+ import com.swmansion.audioapi.system.notification.RecordingNotification
16
17
 
17
18
  /**
18
19
  * Centralized foreground service that can be used by any component that needs foreground capabilities.
@@ -20,7 +21,6 @@ import com.swmansion.audioapi.system.notification.NotificationRegistry
20
21
  class CentralizedForegroundService : Service() {
21
22
  companion object {
22
23
  private const val TAG = "CentralizedForegroundService"
23
- private const val NOTIFICATION_ID = 100
24
24
  const val ACTION_START = "START_FOREGROUND"
25
25
  const val ACTION_STOP = "STOP_FOREGROUND"
26
26
  }
@@ -49,21 +49,19 @@ class CentralizedForegroundService : Service() {
49
49
  try {
50
50
  createNotificationChannelIfNeeded()
51
51
 
52
- // Try to use an existing notification first
52
+ // Get the first available notification
53
53
  val existingNotification = findExistingNotification()
54
- val (notificationId, notification) =
55
- if (existingNotification != null) {
56
- existingNotification
57
- } else {
58
- // Fallback to default service notification
59
- NOTIFICATION_ID to createServiceNotification()
60
- }
54
+ if (existingNotification == null) {
55
+ Log.w(TAG, "No notification available to start foreground service")
56
+ return
57
+ }
58
+
59
+ val (notificationId, notification) = existingNotification
61
60
 
62
61
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
63
62
  startForeground(
64
63
  notificationId,
65
64
  notification,
66
- ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK,
67
65
  )
68
66
  } else {
69
67
  startForeground(notificationId, notification)
@@ -76,31 +74,18 @@ class CentralizedForegroundService : Service() {
76
74
  }
77
75
 
78
76
  private fun findExistingNotification(): Pair<Int, Notification>? {
79
- // Check for recording notification first (priority)
80
- NotificationRegistry.getBuiltNotification(101)?.let {
81
- return 101 to it
77
+ // Check for playback notification first (priority)
78
+ NotificationRegistry.getBuiltNotification(PlaybackNotification.ID)?.let {
79
+ return PlaybackNotification.ID to it
82
80
  }
83
81
 
84
- // Check for playback notification
85
- NotificationRegistry.getBuiltNotification(100)?.let {
86
- return 100 to it
82
+ NotificationRegistry.getBuiltNotification(RecordingNotification.ID)?.let {
83
+ return RecordingNotification.ID to it
87
84
  }
88
85
 
89
86
  return null
90
87
  }
91
88
 
92
- private fun createServiceNotification(): Notification =
93
- NotificationCompat
94
- .Builder(this, CHANNEL_ID)
95
- .setContentTitle("Audio Service")
96
- .setContentText("Audio processing in progress")
97
- .setSmallIcon(android.R.drawable.ic_btn_speak_now)
98
- .setPriority(NotificationCompat.PRIORITY_LOW)
99
- .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
100
- .setOngoing(true)
101
- .setAutoCancel(false)
102
- .build()
103
-
104
89
  private fun createNotificationChannelIfNeeded() {
105
90
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
106
91
  val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
@@ -4,6 +4,7 @@ import android.content.Intent
4
4
  import android.os.Build
5
5
  import android.util.Log
6
6
  import com.facebook.react.bridge.ReactApplicationContext
7
+ import com.swmansion.audioapi.system.notification.BaseNotification
7
8
  import java.lang.ref.WeakReference
8
9
 
9
10
  /**
@@ -14,7 +15,7 @@ object ForegroundServiceManager {
14
15
  private const val TAG = "ForegroundServiceManager"
15
16
 
16
17
  private lateinit var reactContext: WeakReference<ReactApplicationContext>
17
- private val subscribers = mutableSetOf<String>()
18
+ private val subscribers = mutableSetOf<BaseNotification>()
18
19
  private var isServiceRunning = false
19
20
 
20
21
  fun initialize(reactContext: WeakReference<ReactApplicationContext>) {
@@ -23,24 +24,24 @@ object ForegroundServiceManager {
23
24
 
24
25
  /**
25
26
  * Subscribe to foreground service. Service will start if not already running.
26
- * @param subscriberId Unique identifier for the subscriber
27
+ * @param subscriber Unique identifier for the subscriber
27
28
  */
28
29
  @Synchronized
29
- fun subscribe(subscriberId: String) {
30
- if (subscribers.add(subscriberId)) {
31
- Log.d(TAG, "Subscriber added: $subscriberId (total: ${subscribers.size})")
30
+ fun subscribe(subscriber: BaseNotification) {
31
+ if (subscribers.add(subscriber)) {
32
+ Log.d(TAG, "Subscriber added: $subscriber (total: ${subscribers.size})")
32
33
  startServiceIfNeeded()
33
34
  }
34
35
  }
35
36
 
36
37
  /**
37
38
  * Unsubscribe from foreground service. Service will stop if no more subscribers.
38
- * @param subscriberId Unique identifier for the subscriber
39
+ * @param subscriber Unique identifier for the subscriber
39
40
  */
40
41
  @Synchronized
41
- fun unsubscribe(subscriberId: String) {
42
- if (subscribers.remove(subscriberId)) {
43
- Log.d(TAG, "Subscriber removed: $subscriberId (total: ${subscribers.size})")
42
+ fun unsubscribe(subscriber: BaseNotification) {
43
+ if (subscribers.remove(subscriber)) {
44
+ Log.d(TAG, "Subscriber removed: $subscriber (total: ${subscribers.size})")
44
45
  stopServiceIfNotNeeded()
45
46
  }
46
47
  }
@@ -10,6 +10,7 @@ import android.media.AudioDeviceInfo
10
10
  import android.media.AudioManager
11
11
  import android.os.Build
12
12
  import androidx.annotation.RequiresApi
13
+ import androidx.annotation.RequiresPermission
13
14
  import androidx.core.app.ActivityCompat
14
15
  import androidx.core.app.NotificationCompat
15
16
  import androidx.core.content.ContextCompat
@@ -23,22 +24,17 @@ import com.swmansion.audioapi.system.PermissionRequestListener.Companion.RECORDI
23
24
  import com.swmansion.audioapi.system.notification.NotificationRegistry
24
25
  import com.swmansion.audioapi.system.notification.PlaybackNotification
25
26
  import com.swmansion.audioapi.system.notification.PlaybackNotificationReceiver
26
- import com.swmansion.audioapi.system.notification.RecordingNotification
27
- import com.swmansion.audioapi.system.notification.RecordingNotificationReceiver
28
- import com.swmansion.audioapi.system.notification.SimpleNotification
29
27
  import java.lang.ref.WeakReference
30
28
 
31
29
  object MediaSessionManager {
32
30
  private lateinit var audioAPIModule: WeakReference<AudioAPIModule>
33
31
  private lateinit var reactContext: WeakReference<ReactApplicationContext>
34
- const val NOTIFICATION_ID = 100
35
32
  const val CHANNEL_ID = "react-native-audio-api"
36
33
 
37
34
  private lateinit var audioManager: AudioManager
38
35
  private lateinit var audioFocusListener: AudioFocusListener
39
36
  private lateinit var volumeChangeListener: VolumeChangeListener
40
37
  private lateinit var playbackNotificationReceiver: PlaybackNotificationReceiver
41
- private lateinit var recordingNotificationReceiver: RecordingNotificationReceiver
42
38
 
43
39
  // New notification system
44
40
  private lateinit var notificationRegistry: NotificationRegistry
@@ -64,6 +60,10 @@ object MediaSessionManager {
64
60
 
65
61
  // Register PlaybackNotificationReceiver
66
62
  val playbackFilter = IntentFilter(PlaybackNotificationReceiver.ACTION_NOTIFICATION_DISMISSED)
63
+ playbackFilter.addAction(PlaybackNotification.MEDIA_BUTTON)
64
+ playbackFilter.addAction(PlaybackNotificationReceiver.ACTION_SKIP_FORWARD)
65
+ playbackFilter.addAction(PlaybackNotificationReceiver.ACTION_SKIP_BACKWARD)
66
+
67
67
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
68
68
  this.reactContext.get()!!.registerReceiver(playbackNotificationReceiver, playbackFilter, Context.RECEIVER_NOT_EXPORTED)
69
69
  } else {
@@ -75,29 +75,12 @@ object MediaSessionManager {
75
75
  )
76
76
  }
77
77
 
78
- // Set up RecordingNotificationReceiver
79
- RecordingNotificationReceiver.setAudioAPIModule(audioAPIModule.get())
80
- this.recordingNotificationReceiver = RecordingNotificationReceiver()
81
-
82
- // Register RecordingNotificationReceiver
83
- val recordingFilter = IntentFilter(RecordingNotificationReceiver.ACTION_NOTIFICATION_DISMISSED)
84
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
85
- this.reactContext.get()!!.registerReceiver(recordingNotificationReceiver, recordingFilter, Context.RECEIVER_NOT_EXPORTED)
86
- } else {
87
- ContextCompat.registerReceiver(
88
- this.reactContext.get()!!,
89
- recordingNotificationReceiver,
90
- recordingFilter,
91
- ContextCompat.RECEIVER_NOT_EXPORTED,
92
- )
93
- }
94
-
95
78
  this.audioFocusListener =
96
79
  AudioFocusListener(WeakReference(this.audioManager), this.audioAPIModule)
97
80
  this.volumeChangeListener = VolumeChangeListener(WeakReference(this.audioManager), this.audioAPIModule)
98
81
 
99
82
  // Initialize new notification system
100
- this.notificationRegistry = NotificationRegistry(this.reactContext)
83
+ this.notificationRegistry = NotificationRegistry(this.reactContext, this.audioAPIModule)
101
84
  }
102
85
 
103
86
  fun getDevicePreferredSampleRate(): Double {
@@ -263,43 +246,19 @@ object MediaSessionManager {
263
246
  else -> "Other (${device.type})"
264
247
  }
265
248
 
266
- // New notification system methods
267
- fun registerNotification(
268
- type: String,
269
- key: String,
270
- ) {
271
- val notification =
272
- when (type) {
273
- "simple" -> SimpleNotification(reactContext)
274
- "playback" -> PlaybackNotification(reactContext, audioAPIModule, 100, "audio_playback")
275
- "recording" -> RecordingNotification(reactContext, audioAPIModule, 101, "audio_recording23")
276
- else -> throw IllegalArgumentException("Unknown notification type: $type")
277
- }
278
-
279
- notificationRegistry.registerNotification(key, notification)
280
- }
281
-
249
+ // Notification system methods
250
+ @RequiresPermission(Manifest.permission.POST_NOTIFICATIONS)
282
251
  fun showNotification(
252
+ type: String,
283
253
  key: String,
284
254
  options: ReadableMap?,
285
255
  ) {
286
- notificationRegistry.showNotification(key, options)
287
- }
288
-
289
- fun updateNotification(
290
- key: String,
291
- options: ReadableMap?,
292
- ) {
293
- notificationRegistry.updateNotification(key, options)
256
+ notificationRegistry.showNotification(key, type, options)
294
257
  }
295
258
 
296
259
  fun hideNotification(key: String) {
297
260
  notificationRegistry.hideNotification(key)
298
261
  }
299
262
 
300
- fun unregisterNotification(key: String) {
301
- notificationRegistry.unregisterNotification(key)
302
- }
303
-
304
263
  fun isNotificationActive(key: String): Boolean = notificationRegistry.isNotificationActive(key)
305
264
  }
@@ -10,28 +10,20 @@ import com.facebook.react.bridge.ReadableMap
10
10
  */
11
11
  interface BaseNotification {
12
12
  /**
13
- * Initialize the notification with the provided options.
14
- * This method should create the notification and prepare it for display.
13
+ * Show or update the notification with the provided options.
14
+ * This method should create/update the notification and prepare it for display.
15
+ * It handles both initial display and updates.
15
16
  *
16
17
  * @param options Configuration options from JavaScript side
17
18
  * @return The built Notification ready to be shown
18
19
  */
19
- fun init(options: ReadableMap?): Notification
20
+ fun show(options: ReadableMap?): Notification
20
21
 
21
22
  /**
22
- * Update the notification with new options.
23
- * This method should rebuild the notification with updated data.
24
- *
25
- * @param options New configuration options from JavaScript side
26
- * @return The updated Notification ready to be shown
27
- */
28
- fun update(options: ReadableMap?): Notification
29
-
30
- /**
31
- * Reset the notification to its initial state.
23
+ * Hide the notification and cleanup resources.
32
24
  * This should clear any stored data and stop any ongoing processes.
33
25
  */
34
- fun reset()
26
+ fun hide()
35
27
 
36
28
  /**
37
29
  * Get the unique ID for this notification.