react-native-audio-api 0.10.0-nightly-c815c40-20251027 → 0.10.0-nightly-dedc2a2-20251029

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.
@@ -50,8 +50,6 @@ Pod::Spec.new do |s|
50
50
  external_dir_relative = "common/cpp/audioapi/external"
51
51
  lib_dir = "$(PROJECT_DIR)/#{rn_audio_dir_relative}/#{external_dir_relative}/$(PLATFORM_NAME)"
52
52
 
53
- external_dir = File.join(__dir__, "common/cpp/audioapi/external")
54
-
55
53
  s.ios.vendored_frameworks = [
56
54
  'common/cpp/audioapi/external/libavcodec.xcframework',
57
55
  'common/cpp/audioapi/external/libavformat.xcframework',
@@ -92,10 +90,6 @@ s.user_target_xcconfig = {
92
90
  $(inherited)
93
91
  $(PODS_ROOT)/Headers/Public/RNAudioAPI
94
92
  $(PODS_TARGET_SRCROOT)/common/cpp
95
- #{external_dir}/include
96
- #{external_dir}/include/opus
97
- #{external_dir}/include/vorbis
98
- #{external_dir}/ffmpeg_include
99
93
  ].join(' ')
100
94
  }
101
95
  # Use install_modules_dependencies helper to install the dependencies if React Native version >=0.71.0.
@@ -53,8 +53,6 @@ class AudioAPIModule(
53
53
  if (BuildConfig.RN_AUDIO_API_ENABLE_WORKLETS) {
54
54
  try {
55
55
  workletsModule = reactContext.getNativeModule("WorkletsModule")
56
- reanimatedModule = reactContext.getNativeModule("ReanimatedModule")
57
- reanimatedModule
58
56
  } catch (ex: Exception) {
59
57
  throw RuntimeException("WorkletsModule not found - make sure react-native-worklets is properly installed")
60
58
  }
@@ -77,11 +75,11 @@ class AudioAPIModule(
77
75
  }
78
76
 
79
77
  override fun onHostPause() {
80
- closeAllContexts()
78
+ // do nothing
81
79
  }
82
80
 
83
81
  override fun onHostDestroy() {
84
- // do nothing
82
+ closeAllContexts()
85
83
  }
86
84
 
87
85
  override fun initialize() {
@@ -89,6 +87,8 @@ class AudioAPIModule(
89
87
  }
90
88
 
91
89
  override fun invalidate() {
90
+ closeAllContexts()
91
+ reactContext.get()?.removeLifecycleEventListener(this)
92
92
  // think about cleaning up resources, singletons etc.
93
93
  }
94
94
 
@@ -42,13 +42,11 @@ class LockScreenManager(
42
42
  private var playbackState: Int = PlaybackStateCompat.STATE_PAUSED
43
43
 
44
44
  init {
45
- this.pb.setActions(controls)
46
-
47
- this.nb.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
48
- this.nb.setPriority(NotificationCompat.PRIORITY_HIGH)
45
+ pb.setActions(controls)
46
+ nb.setPriority(NotificationCompat.PRIORITY_HIGH)
47
+ nb.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
49
48
 
50
49
  updateNotificationMediaStyle()
51
-
52
50
  mediaNotificationManager.get()?.updateActions(controls)
53
51
  }
54
52
 
@@ -174,8 +172,31 @@ class LockScreenManager(
174
172
  if (artworkThread != null && artworkThread!!.isAlive) artworkThread!!.interrupt()
175
173
  artworkThread = null
176
174
 
177
- mediaNotificationManager.get()?.cancelNotification()
175
+ title = null
176
+ artist = null
177
+ album = null
178
+ description = null
179
+ duration = 0L
180
+ speed = 1.0F
181
+ elapsedTime = 0L
182
+ artwork = null
183
+ playbackState = PlaybackStateCompat.STATE_PAUSED
184
+ isPlaying = false
185
+
186
+ val emptyMetadata = MediaMetadataCompat.Builder().build()
187
+ mediaSession.get()?.setMetadata(emptyMetadata)
188
+
189
+ pb.setState(PlaybackStateCompat.STATE_NONE, 0, 0f)
190
+ pb.setActions(controls)
191
+ state = pb.build()
192
+ mediaSession.get()?.setPlaybackState(state)
178
193
  mediaSession.get()?.setActive(false)
194
+
195
+ nb.setContentTitle("")
196
+ nb.setContentText("")
197
+ nb.setContentInfo("")
198
+
199
+ mediaNotificationManager.get()?.updateNotification(nb, isPlaying)
179
200
  }
180
201
 
181
202
  fun enableRemoteCommand(
@@ -20,6 +20,11 @@ class ThreadPool {
20
20
  struct TaskEvent { audioapi::move_only_function<void()> task; };
21
21
  using Event = std::variant<TaskEvent, StopEvent>;
22
22
 
23
+ struct Cntrl {
24
+ std::atomic<bool> waitingForTasks{false};
25
+ std::atomic<size_t> tasksScheduled{0};
26
+ };
27
+
23
28
  using Sender = channels::spsc::Sender<Event, channels::spsc::OverflowStrategy::WAIT_ON_FULL, channels::spsc::WaitStrategy::ATOMIC_WAIT>;
24
29
  using Receiver = channels::spsc::Receiver<Event, channels::spsc::OverflowStrategy::WAIT_ON_FULL, channels::spsc::WaitStrategy::ATOMIC_WAIT>;
25
30
  public:
@@ -38,8 +43,30 @@ public:
38
43
  workerSenders.emplace_back(std::move(workerSender));
39
44
  }
40
45
  loadBalancerThread = std::thread(&ThreadPool::loadBalancerThreadFunc, this, std::move(receiver), std::move(workerSenders));
46
+ controlBlock_ = std::make_unique<Cntrl>();
47
+ }
48
+ ThreadPool(const ThreadPool&) = delete;
49
+ ThreadPool& operator=(const ThreadPool&) = delete;
50
+ ThreadPool(ThreadPool&& other):
51
+ loadBalancerThread(std::move(other.loadBalancerThread)),
52
+ workers(std::move(other.workers)),
53
+ loadBalancerSender(std::move(other.loadBalancerSender)),
54
+ controlBlock_(std::move(other.controlBlock_)) {}
55
+ ThreadPool& operator=(ThreadPool&& other) {
56
+ if (this != &other) {
57
+ loadBalancerThread = std::move(other.loadBalancerThread);
58
+ workers = std::move(other.workers);
59
+ loadBalancerSender = std::move(other.loadBalancerSender);
60
+ controlBlock_ = std::move(other.controlBlock_);
61
+ other.movedFrom_ = true;
62
+ }
63
+ return *this;
41
64
  }
65
+
42
66
  ~ThreadPool() {
67
+ if (movedFrom_) {
68
+ return;
69
+ }
43
70
  loadBalancerSender.send(StopEvent{});
44
71
  loadBalancerThread.join();
45
72
  for (auto& worker : workers) {
@@ -59,16 +86,47 @@ public:
59
86
  /// @note IMPORTANT: This function is not thread-safe and should be called from a single thread only.
60
87
  template<typename Func, typename ... Args, typename = std::enable_if_t<std::is_invocable_r_v<void, Func, Args...>>>
61
88
  void schedule(Func &&task, Args &&... args) noexcept {
62
- auto boundTask = [f = std::forward<Func>(task), ...capturedArgs = std::forward<Args>(args)]() mutable {
89
+ controlBlock_->tasksScheduled.fetch_add(1, std::memory_order_release);
90
+
91
+ /// We know that lifetime of each worker thus spsc thus lambda is strongly bounded by ThreadPool lifetime
92
+ /// so we can safely capture control block pointer unsafely here
93
+ Cntrl *cntrl = controlBlock_.get();
94
+ auto boundTask = [cntrl, f= std::forward<Func>(task), ...capturedArgs = std::forward<Args>(args)]() mutable {
63
95
  f(std::forward<Args>(capturedArgs)...);
96
+ size_t left = cntrl->tasksScheduled.fetch_sub(1, std::memory_order_acq_rel) - 1;
97
+ if (left == 0) {
98
+ cntrl->waitingForTasks.store(false, std::memory_order_release);
99
+ cntrl->waitingForTasks.notify_one();
100
+ }
64
101
  };
65
102
  loadBalancerSender.send(TaskEvent{audioapi::move_only_function<void()>(std::move(boundTask))});
66
103
  }
67
104
 
105
+ /// @brief Waits for all scheduled tasks to complete
106
+ void wait() {
107
+ /// This logic might seem incorrect at first glance
108
+ /// Main principle for this is that there is only one thread scheduling tasks
109
+ /// If he is waiting for the tasks he CANNOT schedule new tasks so we can assume partial
110
+ /// synchronization here.
111
+ /// We first store true so if any task finishes at this moment he will flip it
112
+ /// Then we check if there are any tasks scheduled
113
+ /// If there are none we can return immediately
114
+ /// If there are some we wait until the last task flips the flag to false
115
+ controlBlock_->waitingForTasks.store(true, std::memory_order_release);
116
+ if (controlBlock_->tasksScheduled.load(std::memory_order_acquire) == 0) {
117
+ controlBlock_->waitingForTasks.store(false, std::memory_order_release);
118
+ return;
119
+ }
120
+ controlBlock_->waitingForTasks.wait(true, std::memory_order_acquire);
121
+ return;
122
+ }
123
+
68
124
  private:
69
125
  std::thread loadBalancerThread;
70
126
  std::vector<std::thread> workers;
71
127
  Sender loadBalancerSender;
128
+ std::unique_ptr<Cntrl> controlBlock_;
129
+ bool movedFrom_ = false;
72
130
 
73
131
  void workerThreadFunc(Receiver &&receiver) {
74
132
  Receiver localReceiver = std::move(receiver);
@@ -18,8 +18,7 @@ class IOSAudioRecorder : public AudioRecorder {
18
18
  IOSAudioRecorder(
19
19
  float sampleRate,
20
20
  int bufferLength,
21
- const std::shared_ptr<AudioEventHandlerRegistry>
22
- &audioEventHandlerRegistry);
21
+ const std::shared_ptr<AudioEventHandlerRegistry> &audioEventHandlerRegistry);
23
22
 
24
23
  ~IOSAudioRecorder() override;
25
24
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-audio-api",
3
- "version": "0.10.0-nightly-c815c40-20251027",
3
+ "version": "0.10.0-nightly-dedc2a2-20251029",
4
4
  "description": "react-native-audio-api provides system for controlling audio in React Native environment compatible with Web Audio API specification",
5
5
  "bin": {
6
6
  "setup-rn-audio-api-web": "./scripts/setup-rn-audio-api-web.js"