react-native-audio-api 0.6.5-rc.1 → 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.
- package/README.md +4 -1
- package/android/src/main/cpp/audioapi/android/core/AudioDecoder.cpp +12 -14
- package/android/src/main/cpp/audioapi/android/core/AudioPlayer.cpp +38 -8
- package/android/src/main/cpp/audioapi/android/core/AudioPlayer.h +9 -3
- package/android/src/main/java/com/swmansion/audioapi/AudioAPIModule.kt +4 -0
- package/android/src/main/java/com/swmansion/audioapi/system/LockScreenManager.kt +2 -2
- package/android/src/main/java/com/swmansion/audioapi/system/MediaNotificationManager.kt +2 -2
- package/android/src/main/java/com/swmansion/audioapi/system/MediaSessionManager.kt +46 -0
- package/android/src/main/res/drawable/skip_backward_15.xml +16 -0
- package/android/src/main/res/drawable/skip_forward_15.xml +16 -0
- package/android/src/oldarch/NativeAudioAPIModuleSpec.java +4 -0
- package/common/cpp/audioapi/HostObjects/AudioBufferBaseSourceNodeHostObject.h +9 -0
- package/common/cpp/audioapi/HostObjects/AudioBufferSourceNodeHostObject.h +3 -5
- package/common/cpp/audioapi/HostObjects/AudioScheduledSourceNodeHostObject.h +11 -2
- package/common/cpp/audioapi/core/AudioContext.cpp +6 -4
- package/common/cpp/audioapi/core/AudioContext.h +1 -1
- package/common/cpp/audioapi/core/AudioParam.cpp +13 -0
- package/common/cpp/audioapi/core/AudioParam.h +3 -0
- package/common/cpp/audioapi/core/BaseAudioContext.cpp +1 -1
- package/common/cpp/audioapi/core/BaseAudioContext.h +3 -2
- package/common/cpp/audioapi/core/OfflineAudioContext.cpp +2 -1
- package/common/cpp/audioapi/core/OfflineAudioContext.h +1 -1
- package/common/cpp/audioapi/core/effects/PeriodicWave.cpp +1 -1
- package/common/cpp/audioapi/core/inputs/AudioRecorder.h +1 -0
- package/common/cpp/audioapi/core/sources/AudioBuffer.h +1 -0
- package/common/cpp/audioapi/core/sources/AudioBufferBaseSourceNode.cpp +11 -0
- package/common/cpp/audioapi/core/sources/AudioBufferBaseSourceNode.h +4 -1
- package/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.cpp +11 -0
- package/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.h +2 -1
- package/common/cpp/audioapi/core/utils/AudioNodeDestructor.h +1 -0
- package/common/cpp/audioapi/core/utils/AudioNodeManager.h +1 -2
- package/common/cpp/audioapi/dsp/AudioUtils.cpp +1 -1
- package/common/cpp/audioapi/events/AudioEventHandlerRegistry.cpp +47 -17
- package/common/cpp/audioapi/events/AudioEventHandlerRegistry.h +6 -5
- package/common/cpp/audioapi/events/IAudioEventHandlerRegistry.h +25 -0
- package/common/cpp/audioapi/jsi/JsiPromise.cpp +1 -0
- package/common/cpp/audioapi/utils/AudioArray.h +1 -0
- package/common/cpp/audioapi/utils/CircularAudioArray.h +1 -0
- package/common/cpp/test/CMakeLists.txt +63 -0
- package/common/cpp/test/GainTest.cpp +78 -0
- package/common/cpp/test/MockAudioEventHandlerRegistry.h +22 -0
- package/common/cpp/test/OscillatorTest.cpp +22 -0
- package/common/cpp/test/RunTests.sh +26 -0
- package/ios/audioapi/ios/AudioAPIModule.mm +6 -0
- package/ios/audioapi/ios/core/IOSAudioPlayer.h +2 -1
- package/ios/audioapi/ios/core/IOSAudioPlayer.mm +5 -2
- package/ios/audioapi/ios/system/AudioSessionManager.h +4 -0
- package/ios/audioapi/ios/system/AudioSessionManager.mm +26 -0
- package/ios/audioapi/ios/system/LockScreenManager.mm +2 -0
- package/lib/commonjs/core/AudioBufferSourceNode.js +2 -2
- package/lib/commonjs/core/AudioBufferSourceNode.js.map +1 -1
- package/lib/commonjs/core/AudioScheduledSourceNode.js +4 -4
- package/lib/commonjs/core/AudioScheduledSourceNode.js.map +1 -1
- package/lib/commonjs/plugin/withAudioAPI.js +1 -1
- package/lib/commonjs/plugin/withAudioAPI.js.map +1 -1
- package/lib/commonjs/specs/NativeAudioAPIModule.js.map +1 -1
- package/lib/commonjs/system/AudioManager.js +3 -0
- package/lib/commonjs/system/AudioManager.js.map +1 -1
- package/lib/module/core/AudioBufferSourceNode.js +2 -2
- package/lib/module/core/AudioBufferSourceNode.js.map +1 -1
- package/lib/module/core/AudioScheduledSourceNode.js +4 -4
- package/lib/module/core/AudioScheduledSourceNode.js.map +1 -1
- package/lib/module/plugin/withAudioAPI.js +1 -1
- package/lib/module/plugin/withAudioAPI.js.map +1 -1
- package/lib/module/specs/NativeAudioAPIModule.js.map +1 -1
- package/lib/module/system/AudioManager.js +3 -0
- package/lib/module/system/AudioManager.js.map +1 -1
- package/lib/typescript/core/AudioBufferSourceNode.d.ts.map +1 -1
- package/lib/typescript/core/AudioScheduledSourceNode.d.ts +2 -2
- package/lib/typescript/interfaces.d.ts +2 -2
- package/lib/typescript/interfaces.d.ts.map +1 -1
- package/lib/typescript/specs/NativeAudioAPIModule.d.ts +2 -1
- package/lib/typescript/specs/NativeAudioAPIModule.d.ts.map +1 -1
- package/lib/typescript/system/AudioManager.d.ts +2 -1
- package/lib/typescript/system/AudioManager.d.ts.map +1 -1
- package/lib/typescript/system/types.d.ts +11 -0
- package/lib/typescript/system/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/core/AudioBufferSourceNode.ts +2 -8
- package/src/core/AudioScheduledSourceNode.ts +4 -4
- package/src/interfaces.ts +2 -5
- package/src/plugin/withAudioAPI.ts +1 -1
- package/src/specs/NativeAudioAPIModule.ts +4 -1
- package/src/system/AudioManager.ts +10 -1
- package/src/system/types.ts +14 -0
- package/android/src/main/res/drawable/skip_backward_10.xml +0 -9
- package/android/src/main/res/drawable/skip_forward_10.xml +0 -9
package/README.md
CHANGED
|
@@ -4,7 +4,10 @@
|
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/react-native-audio-api)
|
|
6
6
|
[](https://www.npmjs.com/package/react-native-audio-api?activeTab=versions)
|
|
7
|
-
[](https://www.npmjs.com/package/react-native-audio-api?activeTab=versions)
|
|
8
|
+
[](https://github.com/software-mansion/react-native-audio-api/actions/workflows/ci.yml)
|
|
9
|
+
[](https://github.com/software-mansion/react-native-audio-api/actions/workflows/npm-publish-nightly.yml)
|
|
10
|
+
[](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.
|
|
@@ -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
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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
|
-
|
|
75
|
-
|
|
76
|
-
|
|
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
|
-
|
|
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(
|
|
27
|
+
->setChannelCount(channelCount_)
|
|
20
28
|
->setSampleRateConversionQuality(SampleRateConversionQuality::Medium)
|
|
21
29
|
->setDataCallback(this)
|
|
22
|
-
->setSampleRate(static_cast<int>(
|
|
23
|
-
->
|
|
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
|
-
|
|
26
|
-
|
|
27
|
-
|
|
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
|
|
@@ -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.
|
|
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.
|
|
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("
|
|
148
|
-
skipBackward = createAction("
|
|
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>
|
|
@@ -26,6 +26,15 @@ class AudioBufferBaseSourceNodeHostObject
|
|
|
26
26
|
JSI_EXPORT_PROPERTY_SETTER(AudioBufferBaseSourceNodeHostObject, onPositionChangedInterval));
|
|
27
27
|
}
|
|
28
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
|
+
|
|
29
38
|
JSI_PROPERTY_GETTER(detune) {
|
|
30
39
|
auto sourceNode =
|
|
31
40
|
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
|
-
|
|
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[
|
|
137
|
-
|
|
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,
|
|
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
|
-
|
|
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<
|
|
16
|
+
const std::shared_ptr<IAudioEventHandlerRegistry>
|
|
17
|
+
&audioEventHandlerRegistry)
|
|
17
18
|
: BaseAudioContext(audioEventHandlerRegistry) {
|
|
18
19
|
#ifdef ANDROID
|
|
19
|
-
audioPlayer_ = std::make_shared<AudioPlayer>(
|
|
20
|
+
audioPlayer_ = std::make_shared<AudioPlayer>(
|
|
21
|
+
this->renderAudio(), sampleRate, destination_->getChannelCount());
|
|
20
22
|
#else
|
|
21
|
-
audioPlayer_ =
|
|
22
|
-
|
|
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<
|
|
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>
|
|
@@ -46,11 +47,16 @@ float AudioParam::getMaxValue() const {
|
|
|
46
47
|
return maxValue_;
|
|
47
48
|
}
|
|
48
49
|
|
|
50
|
+
std::mutex &AudioParam::getQueueLock() {
|
|
51
|
+
return queueLock_;
|
|
52
|
+
}
|
|
53
|
+
|
|
49
54
|
void AudioParam::setValue(float value) {
|
|
50
55
|
value_ = std::clamp(value, minValue_, maxValue_);
|
|
51
56
|
}
|
|
52
57
|
|
|
53
58
|
float AudioParam::getValueAtTime(double time) {
|
|
59
|
+
Locker lock(getQueueLock());
|
|
54
60
|
if (endTime_ < time && !eventsQueue_.empty()) {
|
|
55
61
|
auto event = eventsQueue_.front();
|
|
56
62
|
startTime_ = event.getStartTime();
|
|
@@ -83,6 +89,7 @@ void AudioParam::setValueAtTime(float value, double startTime) {
|
|
|
83
89
|
return endValue;
|
|
84
90
|
};
|
|
85
91
|
|
|
92
|
+
Locker lock(getQueueLock());
|
|
86
93
|
auto event = ParamChangeEvent(
|
|
87
94
|
startTime,
|
|
88
95
|
startTime,
|
|
@@ -116,6 +123,7 @@ void AudioParam::linearRampToValueAtTime(float value, double endTime) {
|
|
|
116
123
|
return endValue;
|
|
117
124
|
};
|
|
118
125
|
|
|
126
|
+
Locker lock(getQueueLock());
|
|
119
127
|
auto event = ParamChangeEvent(
|
|
120
128
|
getQueueEndTime(),
|
|
121
129
|
endTime,
|
|
@@ -150,6 +158,7 @@ void AudioParam::exponentialRampToValueAtTime(float value, double endTime) {
|
|
|
150
158
|
return endValue;
|
|
151
159
|
};
|
|
152
160
|
|
|
161
|
+
Locker lock(getQueueLock());
|
|
153
162
|
auto event = ParamChangeEvent(
|
|
154
163
|
getQueueEndTime(),
|
|
155
164
|
endTime,
|
|
@@ -180,6 +189,7 @@ void AudioParam::setTargetAtTime(
|
|
|
180
189
|
(startValue - target) * exp(-(time - startTime) / timeConstant));
|
|
181
190
|
};
|
|
182
191
|
|
|
192
|
+
Locker lock(getQueueLock());
|
|
183
193
|
auto event = ParamChangeEvent(
|
|
184
194
|
startTime,
|
|
185
195
|
startTime,
|
|
@@ -224,6 +234,7 @@ void AudioParam::setValueCurveAtTime(
|
|
|
224
234
|
return endValue;
|
|
225
235
|
};
|
|
226
236
|
|
|
237
|
+
Locker lock(getQueueLock());
|
|
227
238
|
auto event = ParamChangeEvent(
|
|
228
239
|
startTime,
|
|
229
240
|
startTime + duration,
|
|
@@ -235,6 +246,7 @@ void AudioParam::setValueCurveAtTime(
|
|
|
235
246
|
}
|
|
236
247
|
|
|
237
248
|
void AudioParam::cancelScheduledValues(double cancelTime) {
|
|
249
|
+
Locker lock(getQueueLock());
|
|
238
250
|
auto it = eventsQueue_.rbegin();
|
|
239
251
|
while (it->getEndTime() >= cancelTime) {
|
|
240
252
|
if (it->getStartTime() >= cancelTime ||
|
|
@@ -247,6 +259,7 @@ void AudioParam::cancelScheduledValues(double cancelTime) {
|
|
|
247
259
|
}
|
|
248
260
|
|
|
249
261
|
void AudioParam::cancelAndHoldAtTime(double cancelTime) {
|
|
262
|
+
Locker lock(getQueueLock());
|
|
250
263
|
auto it = eventsQueue_.rbegin();
|
|
251
264
|
while (it->getEndTime() >= cancelTime) {
|
|
252
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<
|
|
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<
|
|
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<
|
|
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<
|
|
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<
|
|
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::
|
|
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 =
|
|
@@ -41,6 +41,17 @@ std::shared_ptr<AudioParam> AudioBufferBaseSourceNode::getPlaybackRateParam()
|
|
|
41
41
|
return playbackRateParam_;
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
+
void AudioBufferBaseSourceNode::clearOnPositionChangedCallback() {
|
|
45
|
+
if (onPositionChangedCallbackId_ == 0 || context_ == nullptr ||
|
|
46
|
+
context_->audioEventHandlerRegistry_ == nullptr) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
context_->audioEventHandlerRegistry_->unregisterHandler(
|
|
51
|
+
"positionChanged", onPositionChangedCallbackId_);
|
|
52
|
+
onPositionChangedCallbackId_ = 0;
|
|
53
|
+
}
|
|
54
|
+
|
|
44
55
|
void AudioBufferBaseSourceNode::setOnPositionChangedCallbackId(
|
|
45
56
|
uint64_t callbackId) {
|
|
46
57
|
onPositionChangedCallbackId_ = callbackId;
|