react-native-audio-api 0.6.5-rc.0 → 0.6.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.
Files changed (97) hide show
  1. package/README.md +4 -1
  2. package/android/src/main/cpp/audioapi/android/AudioAPIModule.cpp +4 -2
  3. package/android/src/main/cpp/audioapi/android/core/AudioDecoder.cpp +12 -14
  4. package/android/src/main/cpp/audioapi/android/core/AudioPlayer.cpp +38 -8
  5. package/android/src/main/cpp/audioapi/android/core/AudioPlayer.h +9 -3
  6. package/android/src/main/java/com/swmansion/audioapi/AudioAPIModule.kt +5 -1
  7. package/android/src/main/java/com/swmansion/audioapi/system/LockScreenManager.kt +2 -2
  8. package/android/src/main/java/com/swmansion/audioapi/system/MediaNotificationManager.kt +2 -2
  9. package/android/src/main/java/com/swmansion/audioapi/system/MediaSessionManager.kt +46 -0
  10. package/android/src/main/res/drawable/skip_backward_15.xml +16 -0
  11. package/android/src/main/res/drawable/skip_forward_15.xml +16 -0
  12. package/android/src/oldarch/NativeAudioAPIModuleSpec.java +4 -0
  13. package/common/cpp/audioapi/HostObjects/AudioBufferBaseSourceNodeHostObject.h +17 -1
  14. package/common/cpp/audioapi/HostObjects/AudioBufferSourceNodeHostObject.h +3 -5
  15. package/common/cpp/audioapi/HostObjects/AudioScheduledSourceNodeHostObject.h +11 -2
  16. package/common/cpp/audioapi/core/AudioContext.cpp +6 -4
  17. package/common/cpp/audioapi/core/AudioContext.h +1 -1
  18. package/common/cpp/audioapi/core/AudioParam.cpp +17 -5
  19. package/common/cpp/audioapi/core/AudioParam.h +3 -0
  20. package/common/cpp/audioapi/core/BaseAudioContext.cpp +1 -1
  21. package/common/cpp/audioapi/core/BaseAudioContext.h +3 -2
  22. package/common/cpp/audioapi/core/OfflineAudioContext.cpp +2 -1
  23. package/common/cpp/audioapi/core/OfflineAudioContext.h +1 -1
  24. package/common/cpp/audioapi/core/effects/PeriodicWave.cpp +1 -1
  25. package/common/cpp/audioapi/core/inputs/AudioRecorder.cpp +4 -2
  26. package/common/cpp/audioapi/core/inputs/AudioRecorder.h +1 -0
  27. package/common/cpp/audioapi/core/sources/AudioBuffer.h +1 -0
  28. package/common/cpp/audioapi/core/sources/AudioBufferBaseSourceNode.cpp +26 -1
  29. package/common/cpp/audioapi/core/sources/AudioBufferBaseSourceNode.h +10 -5
  30. package/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.cpp +24 -2
  31. package/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.h +3 -1
  32. package/common/cpp/audioapi/core/utils/AudioNodeDestructor.h +1 -0
  33. package/common/cpp/audioapi/core/utils/AudioNodeManager.h +1 -2
  34. package/common/cpp/audioapi/dsp/AudioUtils.cpp +1 -1
  35. package/common/cpp/audioapi/events/AudioEventHandlerRegistry.cpp +121 -41
  36. package/common/cpp/audioapi/events/AudioEventHandlerRegistry.h +9 -5
  37. package/common/cpp/audioapi/events/IAudioEventHandlerRegistry.h +25 -0
  38. package/common/cpp/audioapi/jsi/JsiPromise.cpp +1 -0
  39. package/common/cpp/audioapi/utils/AudioArray.h +1 -0
  40. package/common/cpp/audioapi/utils/CircularAudioArray.h +1 -0
  41. package/common/cpp/test/CMakeLists.txt +63 -0
  42. package/common/cpp/test/GainTest.cpp +78 -0
  43. package/common/cpp/test/MockAudioEventHandlerRegistry.h +22 -0
  44. package/common/cpp/test/OscillatorTest.cpp +22 -0
  45. package/common/cpp/test/RunTests.sh +26 -0
  46. package/ios/audioapi/ios/AudioAPIModule.mm +17 -12
  47. package/ios/audioapi/ios/core/IOSAudioPlayer.h +2 -1
  48. package/ios/audioapi/ios/core/IOSAudioPlayer.mm +5 -2
  49. package/ios/audioapi/ios/system/AudioSessionManager.h +4 -0
  50. package/ios/audioapi/ios/system/AudioSessionManager.mm +26 -0
  51. package/ios/audioapi/ios/system/LockScreenManager.mm +2 -0
  52. package/lib/commonjs/core/AudioBufferBaseSourceNode.js +10 -6
  53. package/lib/commonjs/core/AudioBufferBaseSourceNode.js.map +1 -1
  54. package/lib/commonjs/core/AudioBufferSourceNode.js +2 -2
  55. package/lib/commonjs/core/AudioBufferSourceNode.js.map +1 -1
  56. package/lib/commonjs/core/AudioScheduledSourceNode.js +8 -4
  57. package/lib/commonjs/core/AudioScheduledSourceNode.js.map +1 -1
  58. package/lib/commonjs/plugin/withAudioAPI.js +1 -1
  59. package/lib/commonjs/plugin/withAudioAPI.js.map +1 -1
  60. package/lib/commonjs/specs/NativeAudioAPIModule.js.map +1 -1
  61. package/lib/commonjs/system/AudioManager.js +3 -0
  62. package/lib/commonjs/system/AudioManager.js.map +1 -1
  63. package/lib/module/core/AudioBufferBaseSourceNode.js +10 -6
  64. package/lib/module/core/AudioBufferBaseSourceNode.js.map +1 -1
  65. package/lib/module/core/AudioBufferSourceNode.js +2 -2
  66. package/lib/module/core/AudioBufferSourceNode.js.map +1 -1
  67. package/lib/module/core/AudioScheduledSourceNode.js +8 -4
  68. package/lib/module/core/AudioScheduledSourceNode.js.map +1 -1
  69. package/lib/module/plugin/withAudioAPI.js +1 -1
  70. package/lib/module/plugin/withAudioAPI.js.map +1 -1
  71. package/lib/module/specs/NativeAudioAPIModule.js.map +1 -1
  72. package/lib/module/system/AudioManager.js +3 -0
  73. package/lib/module/system/AudioManager.js.map +1 -1
  74. package/lib/typescript/core/AudioBufferBaseSourceNode.d.ts +6 -3
  75. package/lib/typescript/core/AudioBufferBaseSourceNode.d.ts.map +1 -1
  76. package/lib/typescript/core/AudioBufferSourceNode.d.ts.map +1 -1
  77. package/lib/typescript/core/AudioScheduledSourceNode.d.ts +3 -1
  78. package/lib/typescript/core/AudioScheduledSourceNode.d.ts.map +1 -1
  79. package/lib/typescript/interfaces.d.ts +2 -2
  80. package/lib/typescript/interfaces.d.ts.map +1 -1
  81. package/lib/typescript/specs/NativeAudioAPIModule.d.ts +2 -1
  82. package/lib/typescript/specs/NativeAudioAPIModule.d.ts.map +1 -1
  83. package/lib/typescript/system/AudioManager.d.ts +2 -1
  84. package/lib/typescript/system/AudioManager.d.ts.map +1 -1
  85. package/lib/typescript/system/types.d.ts +11 -0
  86. package/lib/typescript/system/types.d.ts.map +1 -1
  87. package/package.json +1 -1
  88. package/src/core/AudioBufferBaseSourceNode.ts +20 -7
  89. package/src/core/AudioBufferSourceNode.ts +2 -8
  90. package/src/core/AudioScheduledSourceNode.ts +11 -3
  91. package/src/interfaces.ts +2 -5
  92. package/src/plugin/withAudioAPI.ts +1 -1
  93. package/src/specs/NativeAudioAPIModule.ts +4 -1
  94. package/src/system/AudioManager.ts +10 -1
  95. package/src/system/types.ts +14 -0
  96. package/android/src/main/res/drawable/skip_backward_10.xml +0 -9
  97. package/android/src/main/res/drawable/skip_forward_10.xml +0 -9
package/README.md CHANGED
@@ -4,7 +4,10 @@
4
4
 
5
5
  [![NPM latest](https://img.shields.io/npm/v/react-native-audio-api/latest)](https://www.npmjs.com/package/react-native-audio-api)
6
6
  [![NPM next](https://img.shields.io/npm/v/react-native-audio-api/next)](https://www.npmjs.com/package/react-native-audio-api?activeTab=versions)
7
- [![github ci](https://img.shields.io/github/actions/workflow/status/software-mansion/react-native-audio-api/ci.yml)](https://github.com/software-mansion/react-native-audio-api/actions)
7
+ [![NPM nightly](https://img.shields.io/npm/v/react-native-audio-api/audio-api-nightly)](https://www.npmjs.com/package/react-native-audio-api?activeTab=versions)
8
+ [![github ci](https://github.com/software-mansion/react-native-audio-api/actions/workflows/ci.yml/badge.svg)](https://github.com/software-mansion/react-native-audio-api/actions/workflows/ci.yml)
9
+ [![NPM Audio Api publish nightly](https://github.com/software-mansion/react-native-audio-api/actions/workflows/npm-publish-nightly.yml/badge.svg)](https://github.com/software-mansion/react-native-audio-api/actions/workflows/npm-publish-nightly.yml)
10
+ [![Audio Api tests](https://github.com/software-mansion/react-native-audio-api/actions/workflows/tests.yml/badge.svg)](https://github.com/software-mansion/react-native-audio-api/actions/workflows/tests.yml)
8
11
 
9
12
  `react-native-audio-api` provides system for controlling audio in React Native environment compatible with Web Audio API specification,
10
13
  allowing developers to generate and modify audio in exact same way it is possible in browsers.
@@ -68,7 +68,9 @@ void AudioAPIModule::invokeHandlerWithEventNameAndEventBody(
68
68
  }
69
69
  }
70
70
 
71
- audioEventHandlerRegistry_->invokeHandlerWithEventBody(
72
- eventName->toStdString(), body);
71
+ if (audioEventHandlerRegistry_ != nullptr) {
72
+ audioEventHandlerRegistry_->invokeHandlerWithEventBody(
73
+ eventName->toStdString(), body);
74
+ }
73
75
  }
74
76
  } // namespace audioapi
@@ -7,7 +7,7 @@
7
7
  #define MINIAUDIO_IMPLEMENTATION
8
8
  #include <audioapi/libs/miniaudio/miniaudio.h>
9
9
 
10
- #include <android/log.h>
10
+ // #include <android/log.h>
11
11
 
12
12
  namespace audioapi {
13
13
 
@@ -18,12 +18,11 @@ std::shared_ptr<AudioBus> AudioDecoder::decodeWithFilePath(
18
18
  ma_decoder_config_init(ma_format_f32, 2, static_cast<int>(sampleRate_));
19
19
  ma_result result = ma_decoder_init_file(path.c_str(), &config, &decoder);
20
20
  if (result != MA_SUCCESS) {
21
- __android_log_print(
22
- ANDROID_LOG_ERROR,
23
- "AudioDecoder",
24
- "Failed to initialize decoder for file: %s",
25
- path.c_str());
26
-
21
+ // __android_log_print(
22
+ // ANDROID_LOG_ERROR,
23
+ // "AudioDecoder",
24
+ // "Failed to initialize decoder for file: %s",
25
+ // path.c_str());
27
26
  ma_decoder_uninit(&decoder);
28
27
 
29
28
  return nullptr;
@@ -40,7 +39,7 @@ std::shared_ptr<AudioBus> AudioDecoder::decodeWithFilePath(
40
39
  ma_decoder_read_pcm_frames(&decoder, buffer, totalFrameCount, &framesDecoded);
41
40
 
42
41
  if (framesDecoded == 0) {
43
- __android_log_print(ANDROID_LOG_ERROR, "AudioDecoder", "Failed to decode");
42
+ // __android_log_print(ANDROID_LOG_ERROR, "AudioDecoder", "Failed to decode");
44
43
 
45
44
  delete[] buffer;
46
45
  ma_decoder_uninit(&decoder);
@@ -70,11 +69,10 @@ std::shared_ptr<AudioBus> AudioDecoder::decodeWithMemoryBlock(
70
69
  ma_decoder_config_init(ma_format_f32, 2, static_cast<int>(sampleRate_));
71
70
  ma_result result = ma_decoder_init_memory(data, size, &config, &decoder);
72
71
  if (result != MA_SUCCESS) {
73
- __android_log_print(
74
- ANDROID_LOG_ERROR,
75
- "AudioDecoder",
76
- "Failed to initialize decoder for memory block");
77
-
72
+ // __android_log_print(
73
+ // ANDROID_LOG_ERROR,
74
+ // "AudioDecoder",
75
+ // "Failed to initialize decoder for memory block");
78
76
  ma_decoder_uninit(&decoder);
79
77
 
80
78
  return nullptr;
@@ -90,7 +88,7 @@ std::shared_ptr<AudioBus> AudioDecoder::decodeWithMemoryBlock(
90
88
  ma_uint64 framesDecoded;
91
89
  ma_decoder_read_pcm_frames(&decoder, buffer, totalFrameCount, &framesDecoded);
92
90
  if (framesDecoded == 0) {
93
- __android_log_print(ANDROID_LOG_ERROR, "AudioDecoder", "Failed to decode");
91
+ // __android_log_print(ANDROID_LOG_ERROR, "AudioDecoder", "Failed to decode");
94
92
 
95
93
  delete[] buffer;
96
94
  ma_decoder_uninit(&decoder);
@@ -1,3 +1,4 @@
1
+ #include <android/log.h>
1
2
  #include <audioapi/android/core/AudioPlayer.h>
2
3
  #include <audioapi/core/AudioContext.h>
3
4
  #include <audioapi/core/Constants.h>
@@ -8,23 +9,40 @@ namespace audioapi {
8
9
 
9
10
  AudioPlayer::AudioPlayer(
10
11
  const std::function<void(std::shared_ptr<AudioBus>, int)> &renderAudio,
11
- float sampleRate)
12
- : renderAudio_(renderAudio), channelCount_(2) {
12
+ float sampleRate,
13
+ int channelCount)
14
+ : renderAudio_(renderAudio),
15
+ sampleRate_(sampleRate),
16
+ channelCount_(channelCount) {
17
+ isInitialized_ = openAudioStream();
18
+ }
19
+
20
+ bool AudioPlayer::openAudioStream() {
13
21
  AudioStreamBuilder builder;
14
22
 
15
23
  builder.setSharingMode(SharingMode::Exclusive)
16
24
  ->setFormat(AudioFormat::Float)
17
25
  ->setFormatConversionAllowed(true)
18
26
  ->setPerformanceMode(PerformanceMode::None)
19
- ->setChannelCount(2)
27
+ ->setChannelCount(channelCount_)
20
28
  ->setSampleRateConversionQuality(SampleRateConversionQuality::Medium)
21
29
  ->setDataCallback(this)
22
- ->setSampleRate(static_cast<int>(sampleRate))
23
- ->openStream(mStream_);
30
+ ->setSampleRate(static_cast<int>(sampleRate_))
31
+ ->setErrorCallback(this);
32
+
33
+ auto result = builder.openStream(mStream_);
34
+ if (result != oboe::Result::OK || mStream_ == nullptr) {
35
+ __android_log_print(
36
+ ANDROID_LOG_ERROR,
37
+ "AudioPlayer",
38
+ "Failed to open stream: %s",
39
+ oboe::convertToText(result));
40
+ return false;
41
+ }
24
42
 
25
- sampleRate_ = sampleRate;
26
- mBus_ = std::make_shared<AudioBus>(RENDER_QUANTUM_SIZE, 2, sampleRate_);
27
- isInitialized_ = true;
43
+ mBus_ = std::make_shared<AudioBus>(
44
+ RENDER_QUANTUM_SIZE, channelCount_, sampleRate_);
45
+ return true;
28
46
  }
29
47
 
30
48
  void AudioPlayer::start() {
@@ -92,4 +110,16 @@ DataCallbackResult AudioPlayer::onAudioReady(
92
110
  return DataCallbackResult::Continue;
93
111
  }
94
112
 
113
+ void AudioPlayer::onErrorAfterClose(
114
+ oboe::AudioStream *stream,
115
+ oboe::Result error) {
116
+ if (error == oboe::Result::ErrorDisconnected) {
117
+ cleanup();
118
+ if (openAudioStream()) {
119
+ isInitialized_ = true;
120
+ resume();
121
+ }
122
+ }
123
+ }
124
+
95
125
  } // namespace audioapi
@@ -1,9 +1,9 @@
1
1
  #pragma once
2
2
 
3
3
  #include <oboe/Oboe.h>
4
+ #include <cassert>
4
5
  #include <functional>
5
6
  #include <memory>
6
- #include <cassert>
7
7
 
8
8
  namespace audioapi {
9
9
 
@@ -12,11 +12,12 @@ using namespace oboe;
12
12
  class AudioContext;
13
13
  class AudioBus;
14
14
 
15
- class AudioPlayer : public AudioStreamDataCallback {
15
+ class AudioPlayer : public AudioStreamDataCallback, AudioStreamErrorCallback {
16
16
  public:
17
17
  AudioPlayer(
18
18
  const std::function<void(std::shared_ptr<AudioBus>, int)> &renderAudio,
19
- float sampleRate);
19
+ float sampleRate,
20
+ int channelCount);
20
21
 
21
22
  void start();
22
23
  void stop();
@@ -29,6 +30,9 @@ class AudioPlayer : public AudioStreamDataCallback {
29
30
  void *audioData,
30
31
  int32_t numFrames) override;
31
32
 
33
+ void onErrorAfterClose(AudioStream * /* audioStream */, Result /* error */)
34
+ override;
35
+
32
36
  private:
33
37
  std::function<void(std::shared_ptr<AudioBus>, int)> renderAudio_;
34
38
  std::shared_ptr<AudioStream> mStream_;
@@ -36,6 +40,8 @@ class AudioPlayer : public AudioStreamDataCallback {
36
40
  bool isInitialized_ = false;
37
41
  float sampleRate_;
38
42
  int channelCount_;
43
+
44
+ bool openAudioStream();
39
45
  };
40
46
 
41
47
  } // namespace audioapi
@@ -60,7 +60,7 @@ class AudioAPIModule(
60
60
  enabled: Boolean,
61
61
  promise: Promise?,
62
62
  ) {
63
- // noting to do here
63
+ promise?.resolve(true)
64
64
  }
65
65
 
66
66
  override fun setAudioSessionOptions(
@@ -103,4 +103,8 @@ class AudioAPIModule(
103
103
  override fun checkRecordingPermissions(promise: Promise) {
104
104
  promise.resolve(MediaSessionManager.checkRecordingPermissions())
105
105
  }
106
+
107
+ override fun getDevicesInfo(promise: Promise) {
108
+ promise.resolve(MediaSessionManager.getDevicesInfo())
109
+ }
106
110
  }
@@ -211,7 +211,7 @@ class LockScreenManager(
211
211
  .Builder(
212
212
  "SkipBackward",
213
213
  "Skip Backward",
214
- R.drawable.skip_backward_10,
214
+ R.drawable.skip_backward_15,
215
215
  ).build(),
216
216
  )
217
217
  }
@@ -224,7 +224,7 @@ class LockScreenManager(
224
224
  .Builder(
225
225
  "SkipForward",
226
226
  "Skip Forward",
227
- R.drawable.skip_forward_10,
227
+ R.drawable.skip_forward_15,
228
228
  ).build(),
229
229
  )
230
230
  }
@@ -144,8 +144,8 @@ class MediaNotificationManager(
144
144
  stop = createAction("stop", "Stop", mask, PlaybackStateCompat.ACTION_STOP, stop)
145
145
  next = createAction("next", "Next", mask, PlaybackStateCompat.ACTION_SKIP_TO_NEXT, next)
146
146
  previous = createAction("previous", "Previous", mask, PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS, previous)
147
- skipForward = createAction("skip_forward_10", "Skip Forward", mask, PlaybackStateCompat.ACTION_FAST_FORWARD, skipForward)
148
- skipBackward = createAction("skip_backward_10", "Skip Backward", mask, PlaybackStateCompat.ACTION_REWIND, skipBackward)
147
+ skipForward = createAction("skip_forward_15", "Skip Forward", mask, PlaybackStateCompat.ACTION_FAST_FORWARD, skipForward)
148
+ skipBackward = createAction("skip_backward_15", "Skip Backward", mask, PlaybackStateCompat.ACTION_REWIND, skipBackward)
149
149
  }
150
150
 
151
151
  private fun createAction(
@@ -9,6 +9,7 @@ import android.content.Intent
9
9
  import android.content.IntentFilter
10
10
  import android.content.ServiceConnection
11
11
  import android.content.pm.PackageManager
12
+ import android.media.AudioDeviceInfo
12
13
  import android.media.AudioManager
13
14
  import android.os.Build
14
15
  import android.os.IBinder
@@ -17,6 +18,7 @@ import android.util.Log
17
18
  import androidx.annotation.RequiresApi
18
19
  import androidx.core.app.NotificationCompat
19
20
  import androidx.core.content.ContextCompat
21
+ import com.facebook.react.bridge.Arguments
20
22
  import com.facebook.react.bridge.ReactApplicationContext
21
23
  import com.facebook.react.bridge.ReadableMap
22
24
  import com.facebook.react.modules.core.PermissionAwareActivity
@@ -186,4 +188,48 @@ object MediaSessionManager {
186
188
  mChannel.lockscreenVisibility = NotificationCompat.VISIBILITY_PUBLIC
187
189
  notificationManager.createNotificationChannel(mChannel)
188
190
  }
191
+
192
+ @RequiresApi(Build.VERSION_CODES.O)
193
+ fun getDevicesInfo(): ReadableMap {
194
+ val availableInputs = Arguments.createArray()
195
+ val availableOutputs = Arguments.createArray()
196
+
197
+ for (inputDevice in this.audioManager.getDevices(AudioManager.GET_DEVICES_INPUTS)) {
198
+ val deviceInfo = Arguments.createMap()
199
+ deviceInfo.putString("name", inputDevice.productName.toString())
200
+ deviceInfo.putString("type", parseDeviceType(inputDevice))
201
+
202
+ availableInputs.pushMap(deviceInfo)
203
+ }
204
+
205
+ for (outputDevice in this.audioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS)) {
206
+ val deviceInfo = Arguments.createMap()
207
+ deviceInfo.putString("name", outputDevice.productName.toString())
208
+ deviceInfo.putString("type", parseDeviceType(outputDevice))
209
+
210
+ availableOutputs.pushMap(deviceInfo)
211
+ }
212
+
213
+ val devicesInfo = Arguments.createMap()
214
+
215
+ devicesInfo.putArray("currentInputs", Arguments.createArray())
216
+ devicesInfo.putArray("currentOutputs", Arguments.createArray())
217
+ devicesInfo.putArray("availableInputs", availableInputs)
218
+ devicesInfo.putArray("availableOutputs", availableOutputs)
219
+
220
+ return devicesInfo
221
+ }
222
+
223
+ @RequiresApi(Build.VERSION_CODES.O)
224
+ fun parseDeviceType(device: AudioDeviceInfo): String =
225
+ when (device.type) {
226
+ AudioDeviceInfo.TYPE_BUILTIN_MIC -> "Built-in Mic"
227
+ AudioDeviceInfo.TYPE_BUILTIN_EARPIECE -> "Built-in Earpiece"
228
+ AudioDeviceInfo.TYPE_BUILTIN_SPEAKER -> "Built-in Speaker"
229
+ AudioDeviceInfo.TYPE_WIRED_HEADSET -> "Wired Headset"
230
+ AudioDeviceInfo.TYPE_WIRED_HEADPHONES -> "Wired Headphones"
231
+ AudioDeviceInfo.TYPE_BLUETOOTH_A2DP -> "Bluetooth A2DP"
232
+ AudioDeviceInfo.TYPE_BLUETOOTH_SCO -> "Bluetooth SCO"
233
+ else -> "Other (${device.type})"
234
+ }
189
235
  }
@@ -0,0 +1,16 @@
1
+ <vector xmlns:android="http://schemas.android.com/apk/res/android"
2
+ android:width="24dp"
3
+ android:height="24dp"
4
+ android:viewportWidth="24"
5
+ android:viewportHeight="24">
6
+ <path
7
+ android:pathData="M12,6L12,2l-5,5l5,5L12,8c3.31,0 6,2.69 6,6s-2.69,6 -6,6s-6,-2.69 -6,-6h-2c0,4.42 3.58,8 8,8s8,-3.58 8,-8S16.42,6 12,6z"
8
+ android:fillColor="#FFFFFF"/>
9
+ <path
10
+ android:pathData="M10.9,17h-0.85v-3.26l-1.01,0.31v-0.69l1.77,-0.63h0.09L10.9,17z"
11
+ android:fillColor="#FFFFFF"/>
12
+ <path
13
+ android:pathData="M13.33,16.556C12.89,16.556 12.75,16.246 12.73,15.996L11.89,15.996C11.92,16.846 12.68,17.246 13.33,17.246C14.26,17.246 14.77,16.616 14.77,15.816C14.77,14.486 13.8,14.376 13.47,14.376C13.27,14.376 13.04,14.426 12.83,14.536L12.94,13.616L14.64,13.616L14.64,12.906L12.25,12.906L12,15.076L12.67,15.246C12.8,15.116 12.95,15.016 13.24,15.016C13.64,15.016 13.93,15.246 13.93,15.766C13.92,15.816 13.95,16.556 13.33,16.556Z"
14
+ android:strokeWidth="1"
15
+ android:fillColor="#FFFFFF"/>
16
+ </vector>
@@ -0,0 +1,16 @@
1
+ <vector xmlns:android="http://schemas.android.com/apk/res/android"
2
+ android:width="24dp"
3
+ android:height="24dp"
4
+ android:viewportWidth="24"
5
+ android:viewportHeight="24">
6
+ <path
7
+ android:pathData="M18,14c0,3.31 -2.69,6 -6,6s-6,-2.69 -6,-6s2.69,-6 6,-6v4l5,-5l-5,-5v4c-4.42,0 -8,3.58 -8,8c0,4.42 3.58,8 8,8s8,-3.58 8,-8L18,14z"
8
+ android:fillColor="#FFFFFF"/>
9
+ <path
10
+ android:pathData="M10.86,16.94l0,-4.27l-0.09,0l-1.77,0.63l0,0.69l1.01,-0.31l0,3.26z"
11
+ android:fillColor="#FFFFFF"/>
12
+ <path
13
+ android:pathData="M13.212,16.452C12.772,16.452 12.632,16.142 12.612,15.892L11.772,15.892C11.802,16.742 12.562,17.142 13.212,17.142C14.142,17.142 14.652,16.512 14.652,15.712C14.652,14.382 13.682,14.272 13.352,14.272C13.152,14.272 12.922,14.322 12.712,14.432L12.822,13.512L14.522,13.512L14.522,12.802L12.132,12.802L11.882,14.972L12.552,15.142C12.682,15.012 12.832,14.912 13.122,14.912C13.522,14.912 13.812,15.142 13.812,15.662C13.802,15.712 13.832,16.452 13.212,16.452Z"
14
+ android:strokeWidth="1"
15
+ android:fillColor="#FFFFFF"/>
16
+ </vector>
@@ -77,4 +77,8 @@
77
77
  @ReactMethod
78
78
  @DoNotStrip
79
79
  public abstract void checkRecordingPermissions(Promise promise);
80
+
81
+ @ReactMethod
82
+ @DoNotStrip
83
+ public abstract void getDevicesInfo(Promise promise);
80
84
  }
@@ -18,13 +18,23 @@ class AudioBufferBaseSourceNodeHostObject
18
18
  : AudioScheduledSourceNodeHostObject(node) {
19
19
  addGetters(
20
20
  JSI_EXPORT_PROPERTY_GETTER(AudioBufferBaseSourceNodeHostObject, detune),
21
- JSI_EXPORT_PROPERTY_GETTER(AudioBufferBaseSourceNodeHostObject, playbackRate));
21
+ JSI_EXPORT_PROPERTY_GETTER(AudioBufferBaseSourceNodeHostObject, playbackRate),
22
+ JSI_EXPORT_PROPERTY_GETTER(AudioBufferBaseSourceNodeHostObject, onPositionChangedInterval));
22
23
 
23
24
  addSetters(
24
25
  JSI_EXPORT_PROPERTY_SETTER(AudioBufferBaseSourceNodeHostObject, onPositionChanged),
25
26
  JSI_EXPORT_PROPERTY_SETTER(AudioBufferBaseSourceNodeHostObject, onPositionChangedInterval));
26
27
  }
27
28
 
29
+ ~AudioBufferBaseSourceNodeHostObject() {
30
+ auto sourceNode =
31
+ std::static_pointer_cast<AudioBufferBaseSourceNode>(node_);
32
+
33
+ // When JSI object is garbage collected (together with the eventual callback),
34
+ // underlying source node might still be active and try to call the non-existing callback.
35
+ sourceNode->clearOnPositionChangedCallback();
36
+ }
37
+
28
38
  JSI_PROPERTY_GETTER(detune) {
29
39
  auto sourceNode =
30
40
  std::static_pointer_cast<AudioBufferBaseSourceNode>(node_);
@@ -49,6 +59,12 @@ class AudioBufferBaseSourceNodeHostObject
49
59
  sourceNode->setOnPositionChangedCallbackId(std::stoull(value.getString(runtime).utf8(runtime)));
50
60
  }
51
61
 
62
+ JSI_PROPERTY_GETTER(onPositionChangedInterval) {
63
+ auto sourceNode =
64
+ std::static_pointer_cast<AudioBufferBaseSourceNode>(node_);
65
+ return jsi::Value(sourceNode->getOnPositionChangedInterval());
66
+ }
67
+
52
68
  JSI_PROPERTY_SETTER(onPositionChangedInterval) {
53
69
  auto sourceNode =
54
70
  std::static_pointer_cast<AudioBufferBaseSourceNode>(node_);
@@ -125,16 +125,14 @@ class AudioBufferSourceNodeHostObject
125
125
  auto audioBufferSourceNode =
126
126
  std::static_pointer_cast<AudioBufferSourceNode>(node_);
127
127
 
128
- auto audioBufferSourceNodeJsiObject = args[0].getObject(runtime);
129
-
130
- if (args[1].isNull()) {
128
+ if (args[0].isNull()) {
131
129
  audioBufferSourceNode->setBuffer(std::shared_ptr<AudioBuffer>(nullptr));
132
130
  return jsi::Value::undefined();
133
131
  }
134
132
 
135
133
  auto bufferHostObject =
136
- args[1].getObject(runtime).asHostObject<AudioBufferHostObject>(runtime);
137
- audioBufferSourceNodeJsiObject.setExternalMemoryPressure(runtime,
134
+ args[0].getObject(runtime).asHostObject<AudioBufferHostObject>(runtime);
135
+ thisValue.asObject(runtime).setExternalMemoryPressure(runtime,
138
136
  bufferHostObject->getSizeInBytes() + 16);
139
137
  audioBufferSourceNode->setBuffer(bufferHostObject->audioBuffer_);
140
138
  return jsi::Value::undefined();
@@ -15,13 +15,22 @@ class AudioScheduledSourceNodeHostObject : public AudioNodeHostObject {
15
15
  const std::shared_ptr<AudioScheduledSourceNode> &node)
16
16
  : AudioNodeHostObject(node) {
17
17
  addSetters(
18
- JSI_EXPORT_PROPERTY_SETTER(AudioScheduledSourceNodeHostObject, onended));
18
+ JSI_EXPORT_PROPERTY_SETTER(AudioScheduledSourceNodeHostObject, onEnded));
19
19
  addFunctions(
20
20
  JSI_EXPORT_FUNCTION(AudioScheduledSourceNodeHostObject, start),
21
21
  JSI_EXPORT_FUNCTION(AudioScheduledSourceNodeHostObject, stop));
22
22
  }
23
23
 
24
- JSI_PROPERTY_SETTER(onended) {
24
+ ~AudioScheduledSourceNodeHostObject() {
25
+ auto audioScheduledSourceNode =
26
+ std::static_pointer_cast<AudioScheduledSourceNode>(node_);
27
+
28
+ // When JSI object is garbage collected (together with the eventual callback),
29
+ // underlying source node might still be active and try to call the non-existing callback.
30
+ audioScheduledSourceNode->clearOnEndedCallback();
31
+ }
32
+
33
+ JSI_PROPERTY_SETTER(onEnded) {
25
34
  auto audioScheduleSourceNode =
26
35
  std::static_pointer_cast<AudioScheduledSourceNode>(node_);
27
36
 
@@ -13,13 +13,15 @@ namespace audioapi {
13
13
  AudioContext::AudioContext(
14
14
  float sampleRate,
15
15
  bool initSuspended,
16
- const std::shared_ptr<AudioEventHandlerRegistry> &audioEventHandlerRegistry)
16
+ const std::shared_ptr<IAudioEventHandlerRegistry>
17
+ &audioEventHandlerRegistry)
17
18
  : BaseAudioContext(audioEventHandlerRegistry) {
18
19
  #ifdef ANDROID
19
- audioPlayer_ = std::make_shared<AudioPlayer>(this->renderAudio(), sampleRate);
20
+ audioPlayer_ = std::make_shared<AudioPlayer>(
21
+ this->renderAudio(), sampleRate, destination_->getChannelCount());
20
22
  #else
21
- audioPlayer_ =
22
- std::make_shared<IOSAudioPlayer>(this->renderAudio(), sampleRate);
23
+ audioPlayer_ = std::make_shared<IOSAudioPlayer>(
24
+ this->renderAudio(), sampleRate, destination_->getChannelCount());
23
25
  #endif
24
26
 
25
27
  sampleRate_ = sampleRate;
@@ -14,7 +14,7 @@ class IOSAudioPlayer;
14
14
 
15
15
  class AudioContext : public BaseAudioContext {
16
16
  public:
17
- explicit AudioContext(float sampleRate, bool initSuspended, const std::shared_ptr<AudioEventHandlerRegistry> &audioEventHandlerRegistry);
17
+ explicit AudioContext(float sampleRate, bool initSuspended, const std::shared_ptr<IAudioEventHandlerRegistry> &audioEventHandlerRegistry);
18
18
  ~AudioContext() override;
19
19
 
20
20
  void close();
@@ -1,5 +1,6 @@
1
1
  #include <audioapi/core/AudioParam.h>
2
2
  #include <audioapi/core/BaseAudioContext.h>
3
+ #include <audioapi/core/utils/Locker.h>
3
4
  #include <audioapi/dsp/AudioUtils.h>
4
5
  #include <audioapi/dsp/VectorMath.h>
5
6
  #include <audioapi/utils/AudioArray.h>
@@ -17,11 +18,10 @@ AudioParam::AudioParam(
17
18
  minValue_(minValue),
18
19
  maxValue_(maxValue),
19
20
  context_(context),
20
- audioBus_(
21
- std::make_shared<AudioBus>(
22
- RENDER_QUANTUM_SIZE,
23
- 1,
24
- context->getSampleRate())) {
21
+ audioBus_(std::make_shared<AudioBus>(
22
+ RENDER_QUANTUM_SIZE,
23
+ 1,
24
+ context->getSampleRate())) {
25
25
  startTime_ = 0;
26
26
  endTime_ = 0;
27
27
  startValue_ = value_;
@@ -47,11 +47,16 @@ float AudioParam::getMaxValue() const {
47
47
  return maxValue_;
48
48
  }
49
49
 
50
+ std::mutex &AudioParam::getQueueLock() {
51
+ return queueLock_;
52
+ }
53
+
50
54
  void AudioParam::setValue(float value) {
51
55
  value_ = std::clamp(value, minValue_, maxValue_);
52
56
  }
53
57
 
54
58
  float AudioParam::getValueAtTime(double time) {
59
+ Locker lock(getQueueLock());
55
60
  if (endTime_ < time && !eventsQueue_.empty()) {
56
61
  auto event = eventsQueue_.front();
57
62
  startTime_ = event.getStartTime();
@@ -84,6 +89,7 @@ void AudioParam::setValueAtTime(float value, double startTime) {
84
89
  return endValue;
85
90
  };
86
91
 
92
+ Locker lock(getQueueLock());
87
93
  auto event = ParamChangeEvent(
88
94
  startTime,
89
95
  startTime,
@@ -117,6 +123,7 @@ void AudioParam::linearRampToValueAtTime(float value, double endTime) {
117
123
  return endValue;
118
124
  };
119
125
 
126
+ Locker lock(getQueueLock());
120
127
  auto event = ParamChangeEvent(
121
128
  getQueueEndTime(),
122
129
  endTime,
@@ -151,6 +158,7 @@ void AudioParam::exponentialRampToValueAtTime(float value, double endTime) {
151
158
  return endValue;
152
159
  };
153
160
 
161
+ Locker lock(getQueueLock());
154
162
  auto event = ParamChangeEvent(
155
163
  getQueueEndTime(),
156
164
  endTime,
@@ -181,6 +189,7 @@ void AudioParam::setTargetAtTime(
181
189
  (startValue - target) * exp(-(time - startTime) / timeConstant));
182
190
  };
183
191
 
192
+ Locker lock(getQueueLock());
184
193
  auto event = ParamChangeEvent(
185
194
  startTime,
186
195
  startTime,
@@ -225,6 +234,7 @@ void AudioParam::setValueCurveAtTime(
225
234
  return endValue;
226
235
  };
227
236
 
237
+ Locker lock(getQueueLock());
228
238
  auto event = ParamChangeEvent(
229
239
  startTime,
230
240
  startTime + duration,
@@ -236,6 +246,7 @@ void AudioParam::setValueCurveAtTime(
236
246
  }
237
247
 
238
248
  void AudioParam::cancelScheduledValues(double cancelTime) {
249
+ Locker lock(getQueueLock());
239
250
  auto it = eventsQueue_.rbegin();
240
251
  while (it->getEndTime() >= cancelTime) {
241
252
  if (it->getStartTime() >= cancelTime ||
@@ -248,6 +259,7 @@ void AudioParam::cancelScheduledValues(double cancelTime) {
248
259
  }
249
260
 
250
261
  void AudioParam::cancelAndHoldAtTime(double cancelTime) {
262
+ Locker lock(getQueueLock());
251
263
  auto it = eventsQueue_.rbegin();
252
264
  while (it->getEndTime() >= cancelTime) {
253
265
  if (it->getStartTime() >= cancelTime) {
@@ -10,6 +10,7 @@
10
10
  #include <vector>
11
11
  #include <unordered_set>
12
12
  #include <cstddef>
13
+ #include <mutex>
13
14
 
14
15
  namespace audioapi {
15
16
 
@@ -50,6 +51,7 @@ class AudioParam {
50
51
  std::deque<ParamChangeEvent> eventsQueue_;
51
52
  std::unordered_set<AudioNode *> inputNodes_;
52
53
  std::shared_ptr<AudioBus> audioBus_;
54
+ std::mutex queueLock_;
53
55
 
54
56
  double startTime_;
55
57
  double endTime_;
@@ -58,6 +60,7 @@ class AudioParam {
58
60
  std::function<float(double, double, float, float, double)> calculateValue_;
59
61
  std::vector<std::shared_ptr<AudioBus>> inputBuses_ = {};
60
62
 
63
+ std::mutex &getQueueLock();
61
64
  double getQueueEndTime();
62
65
  float getQueueEndValue();
63
66
  void updateQueue(ParamChangeEvent &event);
@@ -19,7 +19,7 @@
19
19
  namespace audioapi {
20
20
 
21
21
  BaseAudioContext::BaseAudioContext(
22
- const std::shared_ptr<AudioEventHandlerRegistry>
22
+ const std::shared_ptr<IAudioEventHandlerRegistry>
23
23
  &audioEventHandlerRegistry) {
24
24
  nodeManager_ = std::make_shared<AudioNodeManager>();
25
25
  destination_ = std::make_shared<AudioDestinationNode>(this);
@@ -29,10 +29,11 @@ class AudioBufferQueueSourceNode;
29
29
  class AudioDecoder;
30
30
  class AnalyserNode;
31
31
  class AudioEventHandlerRegistry;
32
+ class IAudioEventHandlerRegistry;
32
33
 
33
34
  class BaseAudioContext {
34
35
  public:
35
- explicit BaseAudioContext(const std::shared_ptr<AudioEventHandlerRegistry> &audioEventHandlerRegistry);
36
+ explicit BaseAudioContext(const std::shared_ptr<IAudioEventHandlerRegistry> &audioEventHandlerRegistry);
36
37
  virtual ~BaseAudioContext() = default;
37
38
 
38
39
  std::string getState();
@@ -86,7 +87,7 @@ class BaseAudioContext {
86
87
  std::shared_ptr<PeriodicWave> cachedTriangleWave_ = nullptr;
87
88
 
88
89
  public:
89
- std::shared_ptr<AudioEventHandlerRegistry> audioEventHandlerRegistry_;
90
+ std::shared_ptr<IAudioEventHandlerRegistry> audioEventHandlerRegistry_;
90
91
  };
91
92
 
92
93
  } // namespace audioapi
@@ -22,7 +22,8 @@ OfflineAudioContext::OfflineAudioContext(
22
22
  int numberOfChannels,
23
23
  size_t length,
24
24
  float sampleRate,
25
- const std::shared_ptr<AudioEventHandlerRegistry> &audioEventHandlerRegistry)
25
+ const std::shared_ptr<IAudioEventHandlerRegistry>
26
+ &audioEventHandlerRegistry)
26
27
  : BaseAudioContext(audioEventHandlerRegistry),
27
28
  length_(length),
28
29
  numberOfChannels_(numberOfChannels),
@@ -14,7 +14,7 @@ using OfflineAudioContextResultCallback = std::function<void(std::shared_ptr<Aud
14
14
 
15
15
  class OfflineAudioContext : public BaseAudioContext {
16
16
  public:
17
- explicit OfflineAudioContext(int numberOfChannels, size_t length, float sampleRate, const std::shared_ptr<AudioEventHandlerRegistry> &audioEventHandlerRegistry);
17
+ explicit OfflineAudioContext(int numberOfChannels, size_t length, float sampleRate, const std::shared_ptr<IAudioEventHandlerRegistry> &audioEventHandlerRegistry);
18
18
  ~OfflineAudioContext() override;
19
19
 
20
20
  void resume();
@@ -118,7 +118,7 @@ int PeriodicWave::getNumberOfPartialsPerRange(int rangeIndex) const {
118
118
  auto centsToCull = static_cast<float>(rangeIndex) * CentsPerRange;
119
119
 
120
120
  // A value from 0 -> 1 representing what fraction of the partials to keep.
121
- auto cullingScale = std::powf(2, -centsToCull / 1200);
121
+ auto cullingScale = std::pow(2, -centsToCull / 1200);
122
122
 
123
123
  // The very top range will have all the partials culled.
124
124
  int numberOfPartials =