react-native-audio-api 0.6.0-rc.1 → 0.6.0-rc.2

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 (90) hide show
  1. package/README.md +35 -22
  2. package/android/src/main/cpp/audioapi/android/core/AndroidAudioRecorder.cpp +73 -0
  3. package/android/src/main/cpp/audioapi/android/core/AndroidAudioRecorder.h +37 -0
  4. package/android/src/main/cpp/audioapi/android/core/AudioPlayer.cpp +6 -10
  5. package/android/src/main/cpp/audioapi/android/core/AudioPlayer.h +2 -3
  6. package/android/src/main/java/com/swmansion/audioapi/AudioManagerModule.kt +10 -8
  7. package/android/src/main/java/com/swmansion/audioapi/system/MediaNotificationManager.kt +7 -7
  8. package/android/src/main/java/com/swmansion/audioapi/system/MediaSessionEventEmitter.kt +4 -0
  9. package/android/src/main/java/com/swmansion/audioapi/system/MediaSessionManager.kt +31 -13
  10. package/android/src/main/java/com/swmansion/audioapi/system/VolumeChangeListener.kt +27 -0
  11. package/common/cpp/audioapi/AudioAPIModuleInstaller.h +29 -5
  12. package/common/cpp/audioapi/HostObjects/AnalyserNodeHostObject.h +1 -0
  13. package/common/cpp/audioapi/HostObjects/AudioRecorderHostObject.h +149 -0
  14. package/common/cpp/audioapi/core/AudioContext.cpp +4 -3
  15. package/common/cpp/audioapi/core/BaseAudioContext.cpp +6 -6
  16. package/common/cpp/audioapi/core/inputs/AudioRecorder.h +38 -0
  17. package/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.h +5 -0
  18. package/common/cpp/audioapi/core/sources/OscillatorNode.cpp +1 -1
  19. package/common/cpp/audioapi/core/utils/AudioNodeManager.cpp +45 -11
  20. package/common/cpp/audioapi/core/utils/AudioNodeManager.h +6 -2
  21. package/ios/audioapi/ios/AudioManagerModule.mm +9 -10
  22. package/ios/audioapi/ios/core/IOSAudioPlayer.h +11 -12
  23. package/ios/audioapi/ios/core/IOSAudioPlayer.mm +22 -16
  24. package/ios/audioapi/ios/core/IOSAudioRecorder.h +36 -0
  25. package/ios/audioapi/ios/core/IOSAudioRecorder.mm +62 -0
  26. package/ios/audioapi/ios/core/{AudioPlayer.h → NativeAudioPlayer.h} +1 -8
  27. package/ios/audioapi/ios/core/{AudioPlayer.m → NativeAudioPlayer.m} +4 -33
  28. package/ios/audioapi/ios/core/NativeAudioRecorder.h +25 -0
  29. package/ios/audioapi/ios/core/NativeAudioRecorder.m +47 -0
  30. package/ios/audioapi/ios/system/AudioEngine.h +7 -1
  31. package/ios/audioapi/ios/system/AudioEngine.mm +64 -20
  32. package/ios/audioapi/ios/system/AudioSessionManager.h +3 -1
  33. package/ios/audioapi/ios/system/AudioSessionManager.mm +37 -25
  34. package/ios/audioapi/ios/system/NotificationManager.h +7 -1
  35. package/ios/audioapi/ios/system/NotificationManager.mm +30 -0
  36. package/lib/commonjs/api.js +15 -1
  37. package/lib/commonjs/api.js.map +1 -1
  38. package/lib/commonjs/core/AudioRecorder.js +51 -0
  39. package/lib/commonjs/core/AudioRecorder.js.map +1 -0
  40. package/lib/commonjs/errors/NotSupportedError.js.map +1 -1
  41. package/lib/commonjs/hooks/useSytemVolume.js +24 -0
  42. package/lib/commonjs/hooks/useSytemVolume.js.map +1 -0
  43. package/lib/commonjs/plugin/withAudioAPI.js +1 -1
  44. package/lib/commonjs/plugin/withAudioAPI.js.map +1 -1
  45. package/lib/commonjs/specs/NativeAudioManagerModule.js +5 -2
  46. package/lib/commonjs/specs/NativeAudioManagerModule.js.map +1 -1
  47. package/lib/commonjs/system/AudioManager.js +23 -50
  48. package/lib/commonjs/system/AudioManager.js.map +1 -1
  49. package/lib/module/api.js +3 -1
  50. package/lib/module/api.js.map +1 -1
  51. package/lib/module/core/AudioRecorder.js +45 -0
  52. package/lib/module/core/AudioRecorder.js.map +1 -0
  53. package/lib/module/errors/NotSupportedError.js.map +1 -1
  54. package/lib/module/hooks/useSytemVolume.js +19 -0
  55. package/lib/module/hooks/useSytemVolume.js.map +1 -0
  56. package/lib/module/plugin/withAudioAPI.js +1 -1
  57. package/lib/module/plugin/withAudioAPI.js.map +1 -1
  58. package/lib/module/specs/NativeAudioManagerModule.js +5 -2
  59. package/lib/module/specs/NativeAudioManagerModule.js.map +1 -1
  60. package/lib/module/system/AudioManager.js +23 -50
  61. package/lib/module/system/AudioManager.js.map +1 -1
  62. package/lib/typescript/api.d.ts +5 -1
  63. package/lib/typescript/api.d.ts.map +1 -1
  64. package/lib/typescript/core/AudioRecorder.d.ts +22 -0
  65. package/lib/typescript/core/AudioRecorder.d.ts.map +1 -0
  66. package/lib/typescript/errors/NotSupportedError.d.ts.map +1 -1
  67. package/lib/typescript/hooks/useSytemVolume.d.ts +2 -0
  68. package/lib/typescript/hooks/useSytemVolume.d.ts.map +1 -0
  69. package/lib/typescript/interfaces.d.ts +11 -5
  70. package/lib/typescript/interfaces.d.ts.map +1 -1
  71. package/lib/typescript/plugin/withAudioAPI.d.ts.map +1 -1
  72. package/lib/typescript/specs/NativeAudioManagerModule.d.ts +2 -1
  73. package/lib/typescript/specs/NativeAudioManagerModule.d.ts.map +1 -1
  74. package/lib/typescript/system/AudioManager.d.ts +4 -3
  75. package/lib/typescript/system/AudioManager.d.ts.map +1 -1
  76. package/lib/typescript/system/types.d.ts +26 -7
  77. package/lib/typescript/system/types.d.ts.map +1 -1
  78. package/lib/typescript/types.d.ts +5 -0
  79. package/lib/typescript/types.d.ts.map +1 -1
  80. package/package.json +2 -1
  81. package/src/api.ts +13 -2
  82. package/src/core/AudioRecorder.ts +81 -0
  83. package/src/hooks/useSytemVolume.ts +19 -0
  84. package/src/interfaces.ts +25 -11
  85. package/src/plugin/withAudioAPI.ts +2 -1
  86. package/src/specs/NativeAudioManagerModule.ts +5 -8
  87. package/src/system/AudioManager.ts +30 -107
  88. package/src/system/types.ts +31 -21
  89. package/src/types.ts +13 -0
  90. /package/src/errors/{NotSupportedError.tsx → NotSupportedError.ts} +0 -0
@@ -18,9 +18,10 @@ AudioContext::AudioContext(float sampleRate) : BaseAudioContext() {
18
18
  std::make_shared<IOSAudioPlayer>(this->renderAudio(), sampleRate);
19
19
  #endif
20
20
 
21
- sampleRate_ = audioPlayer_->getSampleRate();
22
- audioDecoder_ = std::make_shared<AudioDecoder>(sampleRate_);
21
+ sampleRate_ = sampleRate;
22
+ audioDecoder_ = std::make_shared<AudioDecoder>(sampleRate);
23
23
 
24
+ state_ = ContextState::RUNNING;
24
25
  audioPlayer_->start();
25
26
  }
26
27
 
@@ -53,7 +54,7 @@ bool AudioContext::suspend() {
53
54
  }
54
55
 
55
56
  state_ = ContextState::SUSPENDED;
56
- audioPlayer_->suspend();
57
+ audioPlayer_->pause();
57
58
  return true;
58
59
  }
59
60
 
@@ -43,25 +43,25 @@ std::shared_ptr<AudioDestinationNode> BaseAudioContext::getDestination() {
43
43
 
44
44
  std::shared_ptr<OscillatorNode> BaseAudioContext::createOscillator() {
45
45
  auto oscillator = std::make_shared<OscillatorNode>(this);
46
- nodeManager_->addNode(oscillator);
46
+ nodeManager_->addSourceNode(oscillator);
47
47
  return oscillator;
48
48
  }
49
49
 
50
50
  std::shared_ptr<GainNode> BaseAudioContext::createGain() {
51
51
  auto gain = std::make_shared<GainNode>(this);
52
- nodeManager_->addNode(gain);
52
+ nodeManager_->addProcessingNode(gain);
53
53
  return gain;
54
54
  }
55
55
 
56
56
  std::shared_ptr<StereoPannerNode> BaseAudioContext::createStereoPanner() {
57
57
  auto stereoPanner = std::make_shared<StereoPannerNode>(this);
58
- nodeManager_->addNode(stereoPanner);
58
+ nodeManager_->addProcessingNode(stereoPanner);
59
59
  return stereoPanner;
60
60
  }
61
61
 
62
62
  std::shared_ptr<BiquadFilterNode> BaseAudioContext::createBiquadFilter() {
63
63
  auto biquadFilter = std::make_shared<BiquadFilterNode>(this);
64
- nodeManager_->addNode(biquadFilter);
64
+ nodeManager_->addProcessingNode(biquadFilter);
65
65
  return biquadFilter;
66
66
  }
67
67
 
@@ -69,7 +69,7 @@ std::shared_ptr<AudioBufferSourceNode> BaseAudioContext::createBufferSource(
69
69
  bool pitchCorrection) {
70
70
  auto bufferSource =
71
71
  std::make_shared<AudioBufferSourceNode>(this, pitchCorrection);
72
- nodeManager_->addNode(bufferSource);
72
+ nodeManager_->addSourceNode(bufferSource);
73
73
  return bufferSource;
74
74
  }
75
75
 
@@ -90,7 +90,7 @@ std::shared_ptr<PeriodicWave> BaseAudioContext::createPeriodicWave(
90
90
 
91
91
  std::shared_ptr<AnalyserNode> BaseAudioContext::createAnalyser() {
92
92
  auto analyser = std::make_shared<AnalyserNode>(this);
93
- nodeManager_->addNode(analyser);
93
+ nodeManager_->addProcessingNode(analyser);
94
94
  return analyser;
95
95
  }
96
96
 
@@ -0,0 +1,38 @@
1
+ #pragma once
2
+
3
+ #include <memory>
4
+ #include <functional>
5
+
6
+ namespace audioapi {
7
+ class AudioBus;
8
+
9
+ class AudioRecorder {
10
+ public:
11
+ explicit AudioRecorder(
12
+ float sampleRate,
13
+ int bufferLength,
14
+ const std::function<void(void)> &onError,
15
+ const std::function<void(void)> &onStatusChange,
16
+ const std::function<void(std::shared_ptr<AudioBus>, int, double)> &onAudioReady
17
+ )
18
+ : sampleRate_(sampleRate),
19
+ bufferLength_(bufferLength),
20
+ onError_(onError),
21
+ onStatusChange_(onStatusChange),
22
+ onAudioReady_(onAudioReady) {}
23
+
24
+ virtual ~AudioRecorder() = default;
25
+
26
+ virtual void start() = 0;
27
+ virtual void stop() = 0;
28
+
29
+ protected:
30
+ float sampleRate_;
31
+ int bufferLength_;
32
+
33
+ std::function<void(void)> onError_;
34
+ std::function<void(void)> onStatusChange_;
35
+ std::function<void(std::shared_ptr<AudioBus>, int, double)> onAudioReady_;
36
+ };
37
+
38
+ } // namespace audioapi
@@ -18,6 +18,11 @@ namespace audioapi {
18
18
 
19
19
  class AudioScheduledSourceNode : public AudioNode {
20
20
  public:
21
+ // UNSCHEDULED: The node is not scheduled to play.
22
+ // SCHEDULED: The node is scheduled to play at a specific time.
23
+ // PLAYING: The node is currently playing.
24
+ // FINISHED: The node has finished playing.
25
+ // STOP_SCHEDULED: The node is scheduled to stop at a specific time, but is still playing.
21
26
  enum class PlaybackState { UNSCHEDULED, SCHEDULED, PLAYING, FINISHED, STOP_SCHEDULED };
22
27
  explicit AudioScheduledSourceNode(BaseAudioContext *context);
23
28
 
@@ -51,7 +51,7 @@ void OscillatorNode::processNode(
51
51
 
52
52
  updatePlaybackInfo(processingBus, framesToProcess, startOffset, offsetLength);
53
53
 
54
- if (!isPlaying()) {
54
+ if (!isPlaying() && !isStopScheduled()) {
55
55
  processingBus->zero();
56
56
  return;
57
57
  }
@@ -1,4 +1,5 @@
1
1
  #include <audioapi/core/AudioNode.h>
2
+ #include <audioapi/core/sources/AudioScheduledSourceNode.h>
2
3
  #include <audioapi/core/utils/AudioNodeManager.h>
3
4
  #include <audioapi/core/utils/Locker.h>
4
5
 
@@ -28,9 +29,16 @@ std::mutex &AudioNodeManager::getGraphLock() {
28
29
  return graphLock_;
29
30
  }
30
31
 
31
- void AudioNodeManager::addNode(const std::shared_ptr<AudioNode> &node) {
32
+ void AudioNodeManager::addProcessingNode(
33
+ const std::shared_ptr<AudioNode> &node) {
32
34
  Locker lock(getGraphLock());
33
- nodes_.insert(node);
35
+ processingNodes_.insert(node);
36
+ }
37
+
38
+ void AudioNodeManager::addSourceNode(
39
+ const std::shared_ptr<AudioScheduledSourceNode> &node) {
40
+ Locker lock(getGraphLock());
41
+ sourceNodes_.insert(node);
34
42
  }
35
43
 
36
44
  void AudioNodeManager::settlePendingConnections() {
@@ -54,17 +62,35 @@ void AudioNodeManager::settlePendingConnections() {
54
62
  audioNodesToConnect_.clear();
55
63
  }
56
64
 
65
+ void AudioNodeManager::cleanupNode(const std::shared_ptr<AudioNode> &node) {
66
+ nodeDeconstructor_.addNodeForDeconstruction(node);
67
+ node.get()->cleanup();
68
+ }
69
+
57
70
  void AudioNodeManager::prepareNodesForDestruction() {
58
71
  nodeDeconstructor_.tryCallWithLock([this]() {
59
- auto it = nodes_.begin();
72
+ auto sNodesIt = sourceNodes_.begin();
73
+
74
+ while (sNodesIt != sourceNodes_.end()) {
75
+ // we don't want to destroy nodes that are still playing or will be
76
+ // playing
77
+ if (sNodesIt->use_count() == 1 &&
78
+ (sNodesIt->get()->isUnscheduled() || sNodesIt->get()->isFinished())) {
79
+ cleanupNode(*sNodesIt);
80
+ sNodesIt = sourceNodes_.erase(sNodesIt);
81
+ } else {
82
+ ++sNodesIt;
83
+ }
84
+ }
60
85
 
61
- while (it != nodes_.end()) {
62
- if (it->use_count() == 1) {
63
- nodeDeconstructor_.addNodeForDeconstruction(*it);
64
- it->get()->cleanup();
65
- it = nodes_.erase(it);
86
+ auto pNodesIt = processingNodes_.begin();
87
+
88
+ while (pNodesIt != processingNodes_.end()) {
89
+ if (pNodesIt->use_count() == 1) {
90
+ cleanupNode(*pNodesIt);
91
+ pNodesIt = processingNodes_.erase(pNodesIt);
66
92
  } else {
67
- ++it;
93
+ ++pNodesIt;
68
94
  }
69
95
  }
70
96
  });
@@ -74,11 +100,19 @@ void AudioNodeManager::prepareNodesForDestruction() {
74
100
  void AudioNodeManager::cleanup() {
75
101
  Locker lock(getGraphLock());
76
102
 
77
- for (auto it = nodes_.begin(), end = nodes_.end(); it != end; ++it) {
103
+ for (auto it = sourceNodes_.begin(), end = sourceNodes_.end(); it != end;
104
+ ++it) {
105
+ it->get()->cleanup();
106
+ }
107
+
108
+ for (auto it = processingNodes_.begin(), end = processingNodes_.end();
109
+ it != end;
110
+ ++it) {
78
111
  it->get()->cleanup();
79
112
  }
80
113
 
81
- nodes_.clear();
114
+ sourceNodes_.clear();
115
+ processingNodes_.clear();
82
116
  }
83
117
 
84
118
  } // namespace audioapi
@@ -11,6 +11,7 @@
11
11
  namespace audioapi {
12
12
 
13
13
  class AudioNode;
14
+ class AudioScheduledSourceNode;
14
15
 
15
16
  class AudioNodeManager {
16
17
  public:
@@ -27,7 +28,8 @@ class AudioNodeManager {
27
28
  const std::shared_ptr<AudioNode> &to,
28
29
  ConnectionType type);
29
30
 
30
- void addNode(const std::shared_ptr<AudioNode> &node);
31
+ void addProcessingNode(const std::shared_ptr<AudioNode> &node);
32
+ void addSourceNode(const std::shared_ptr<AudioScheduledSourceNode> &node);
31
33
 
32
34
  void cleanup();
33
35
 
@@ -36,7 +38,8 @@ class AudioNodeManager {
36
38
  AudioNodeDestructor nodeDeconstructor_;
37
39
 
38
40
  // all nodes created in the context
39
- std::unordered_set<std::shared_ptr<AudioNode>> nodes_;
41
+ std::unordered_set<std::shared_ptr<AudioScheduledSourceNode>> sourceNodes_;
42
+ std::unordered_set<std::shared_ptr<AudioNode>> processingNodes_;
40
43
 
41
44
  // connections to be settled
42
45
  std::vector<std::tuple<
@@ -46,6 +49,7 @@ class AudioNodeManager {
46
49
  audioNodesToConnect_;
47
50
 
48
51
  void settlePendingConnections();
52
+ void cleanupNode(const std::shared_ptr<AudioNode> &node);
49
53
  void prepareNodesForDestruction();
50
54
  };
51
55
 
@@ -49,16 +49,9 @@ RCT_EXPORT_METHOD(enableRemoteCommand : (NSString *)name enabled : (BOOL)enabled
49
49
  [self.lockScreenManager enableRemoteCommand:name enabled:enabled];
50
50
  }
51
51
 
52
- RCT_EXPORT_METHOD(setAudioSessionOptions : (NSString *)category mode : (NSString *)mode options : (NSArray *)
53
- options active : (BOOL)active)
52
+ RCT_EXPORT_METHOD(setAudioSessionOptions : (NSString *)category mode : (NSString *)mode options : (NSArray *)options)
54
53
  {
55
- NSError *error = nil;
56
-
57
- if (active) {
58
- [self.audioSessionManager setAudioSessionOptions:category mode:mode options:options];
59
- } else {
60
- [self.audioSessionManager setActive:false error:&error];
61
- }
54
+ [self.audioSessionManager setAudioSessionOptions:category mode:mode options:options];
62
55
  }
63
56
 
64
57
  RCT_EXPORT_METHOD(observeAudioInterruptions : (BOOL)enabled)
@@ -66,6 +59,11 @@ RCT_EXPORT_METHOD(observeAudioInterruptions : (BOOL)enabled)
66
59
  [self.notificationManager observeAudioInterruptions:enabled];
67
60
  }
68
61
 
62
+ RCT_EXPORT_METHOD(observeVolumeChanges : (BOOL)enabled)
63
+ {
64
+ [self.notificationManager observeVolumeChanges:(BOOL)enabled];
65
+ }
66
+
69
67
  RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(getDevicePreferredSampleRate)
70
68
  {
71
69
  return [self.audioSessionManager getDevicePreferredSampleRate];
@@ -87,7 +85,8 @@ RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(getDevicePreferredSampleRate)
87
85
  @"onRemoteSeekBackward",
88
86
  @"onRemoteChangePlaybackPosition",
89
87
  @"onInterruption",
90
- @"onRouteChange"
88
+ @"onRouteChange",
89
+ @"onVolumeChange"
91
90
  ];
92
91
  }
93
92
 
@@ -1,9 +1,9 @@
1
1
  #pragma once
2
2
 
3
3
  #ifdef __OBJC__ // when compiled as Objective-C++
4
- #import <AudioPlayer.h>
4
+ #import <NativeAudioPlayer.h>
5
5
  #else // when compiled as C++
6
- typedef struct objc_object AudioPlayer;
6
+ typedef struct objc_object NativeAudioPlayer;
7
7
  #endif // __OBJC__
8
8
 
9
9
  #include <functional>
@@ -14,23 +14,22 @@ class AudioBus;
14
14
  class AudioContext;
15
15
 
16
16
  class IOSAudioPlayer {
17
- protected:
18
- std::shared_ptr<AudioBus> audioBus_;
19
- AudioPlayer *audioPlayer_;
20
- std::function<void(std::shared_ptr<AudioBus>, int)> renderAudio_;
21
- int channelCount_;
22
-
23
17
  public:
24
18
  IOSAudioPlayer(
25
19
  const std::function<void(std::shared_ptr<AudioBus>, int)> &renderAudio,
26
20
  float sampleRate);
27
21
  ~IOSAudioPlayer();
28
22
 
29
- float getSampleRate() const;
30
-
31
23
  void start();
32
- void stop();
33
24
  void resume();
34
- void suspend();
25
+ void stop();
26
+ void pause();
27
+
28
+ protected:
29
+ std::shared_ptr<AudioBus> audioBus_;
30
+ NativeAudioPlayer *audioPlayer_;
31
+ std::function<void(std::shared_ptr<AudioBus>, int)> renderAudio_;
32
+ int channelCount_;
33
+ std::atomic<bool> isRunning_;
35
34
  };
36
35
  } // namespace audioapi
@@ -9,14 +9,19 @@
9
9
  namespace audioapi {
10
10
 
11
11
  IOSAudioPlayer::IOSAudioPlayer(const std::function<void(std::shared_ptr<AudioBus>, int)> &renderAudio, float sampleRate)
12
- : channelCount_(2), renderAudio_(renderAudio), audioBus_(0)
12
+ : channelCount_(2), renderAudio_(renderAudio), audioBus_(0), isRunning_(false)
13
13
  {
14
14
  RenderAudioBlock renderAudioBlock = ^(AudioBufferList *outputData, int numFrames) {
15
15
  int processedFrames = 0;
16
16
 
17
17
  while (processedFrames < numFrames) {
18
18
  int framesToProcess = std::min(numFrames - processedFrames, RENDER_QUANTUM_SIZE);
19
- renderAudio_(audioBus_, framesToProcess);
19
+
20
+ if (isRunning_.load()) {
21
+ renderAudio_(audioBus_, framesToProcess);
22
+ } else {
23
+ audioBus_->zero();
24
+ }
20
25
 
21
26
  for (int channel = 0; channel < channelCount_; channel += 1) {
22
27
  float *outputChannel = (float *)outputData->mBuffers[channel].mData;
@@ -29,11 +34,11 @@ IOSAudioPlayer::IOSAudioPlayer(const std::function<void(std::shared_ptr<AudioBus
29
34
  }
30
35
  };
31
36
 
32
- audioPlayer_ = [[AudioPlayer alloc] initWithRenderAudio:renderAudioBlock
33
- sampleRate:sampleRate
34
- channelCount:channelCount_];
37
+ audioPlayer_ = [[NativeAudioPlayer alloc] initWithRenderAudio:renderAudioBlock
38
+ sampleRate:sampleRate
39
+ channelCount:channelCount_];
35
40
 
36
- audioBus_ = std::make_shared<AudioBus>(RENDER_QUANTUM_SIZE, channelCount_, getSampleRate());
41
+ audioBus_ = std::make_shared<AudioBus>(RENDER_QUANTUM_SIZE, channelCount_, sampleRate);
37
42
  }
38
43
 
39
44
  IOSAudioPlayer::~IOSAudioPlayer()
@@ -48,27 +53,28 @@ IOSAudioPlayer::~IOSAudioPlayer()
48
53
 
49
54
  void IOSAudioPlayer::start()
50
55
  {
51
- return [audioPlayer_ start];
52
- }
56
+ if (isRunning_.load()) {
57
+ return;
58
+ }
53
59
 
54
- void IOSAudioPlayer::stop()
55
- {
56
- return [audioPlayer_ stop];
60
+ [audioPlayer_ start];
61
+ isRunning_.store(true);
57
62
  }
58
63
 
59
64
  void IOSAudioPlayer::resume()
60
65
  {
61
- return [audioPlayer_ resume];
66
+ isRunning_.store(true);
62
67
  }
63
68
 
64
- void IOSAudioPlayer::suspend()
69
+ void IOSAudioPlayer::stop()
65
70
  {
66
- return [audioPlayer_ suspend];
71
+ isRunning_.store(false);
72
+ [audioPlayer_ stop];
67
73
  }
68
74
 
69
- float IOSAudioPlayer::getSampleRate() const
75
+ void IOSAudioPlayer::pause()
70
76
  {
71
- return [audioPlayer_ getSampleRate];
77
+ isRunning_.store(false);
72
78
  }
73
79
 
74
80
  } // namespace audioapi
@@ -0,0 +1,36 @@
1
+ #pragma once
2
+
3
+ #ifdef __OBJC__ // when compiled as Objective-C++
4
+ #import <NativeAudioRecorder.h>
5
+ #else // when compiled as C++
6
+ typedef struct objc_object NativeAudioRecorder;
7
+ #endif // __OBJC__
8
+
9
+ #include <audioapi/core/inputs/AudioRecorder.h>
10
+ #include <functional>
11
+
12
+ namespace audioapi {
13
+
14
+ class AudioBus;
15
+
16
+ class IOSAudioRecorder : public AudioRecorder {
17
+ public:
18
+ IOSAudioRecorder(
19
+ float sampleRate,
20
+ int bufferLength,
21
+ const std::function<void(void)> &onError,
22
+ const std::function<void(void)> &onStatusChange,
23
+ const std::function<void(std::shared_ptr<AudioBus>, int, double)>
24
+ &onAudioReady);
25
+
26
+ ~IOSAudioRecorder() override;
27
+
28
+ void start() override;
29
+ void stop() override;
30
+
31
+ private:
32
+ NativeAudioRecorder *audioRecorder_;
33
+ std::atomic<bool> isRunning_;
34
+ };
35
+
36
+ } // namespace audioapi
@@ -0,0 +1,62 @@
1
+ #import <AVFoundation/AVFoundation.h>
2
+
3
+ #include <audioapi/core/Constants.h>
4
+ #include <audioapi/dsp/VectorMath.h>
5
+ #include <audioapi/ios/core/IOSAudioRecorder.h>
6
+ #include <audioapi/utils/AudioArray.h>
7
+ #include <audioapi/utils/AudioBus.h>
8
+
9
+ namespace audioapi {
10
+
11
+ IOSAudioRecorder::IOSAudioRecorder(
12
+ float sampleRate,
13
+ int bufferLength,
14
+ const std::function<void(void)> &onError,
15
+ const std::function<void(void)> &onStatusChange,
16
+ const std::function<void(std::shared_ptr<AudioBus>, int, double)> &onAudioReady)
17
+ : AudioRecorder(sampleRate, bufferLength, onError, onStatusChange, onAudioReady)
18
+ {
19
+ AudioReceiverBlock audioReceiverBlock = ^(const AudioBufferList *inputBuffer, int numFrames, AVAudioTime *when) {
20
+ if (isRunning_.load()) {
21
+ auto bus = std::make_shared<AudioBus>(numFrames, 1, sampleRate);
22
+
23
+ auto *inputChannel = (float *)inputBuffer->mBuffers[0].mData;
24
+ auto *outputChannel = bus->getChannel(0)->getData();
25
+
26
+ memcpy(outputChannel, inputChannel, numFrames * sizeof(float));
27
+ onAudioReady_(bus, numFrames, [when sampleTime] / [when sampleRate]);
28
+ }
29
+ };
30
+
31
+ audioRecorder_ = [[NativeAudioRecorder alloc] initWithReceiverBlock:audioReceiverBlock bufferLength:bufferLength];
32
+ }
33
+
34
+ IOSAudioRecorder::~IOSAudioRecorder()
35
+ {
36
+ AudioRecorder::~AudioRecorder();
37
+
38
+ stop();
39
+ [audioRecorder_ cleanup];
40
+ }
41
+
42
+ void IOSAudioRecorder::start()
43
+ {
44
+ if (isRunning_.load()) {
45
+ return;
46
+ }
47
+
48
+ [audioRecorder_ start];
49
+ isRunning_.store(true);
50
+ }
51
+
52
+ void IOSAudioRecorder::stop()
53
+ {
54
+ if (!isRunning_.load()) {
55
+ return;
56
+ }
57
+
58
+ isRunning_.store(false);
59
+ [audioRecorder_ stop];
60
+ }
61
+
62
+ } // namespace audioapi
@@ -5,14 +5,13 @@
5
5
 
6
6
  typedef void (^RenderAudioBlock)(AudioBufferList *outputBuffer, int numFrames);
7
7
 
8
- @interface AudioPlayer : NSObject
8
+ @interface NativeAudioPlayer : NSObject
9
9
 
10
10
  @property (nonatomic, strong) AVAudioFormat *format;
11
11
  @property (nonatomic, strong) AVAudioSourceNode *sourceNode;
12
12
  @property (nonatomic, copy) RenderAudioBlock renderAudio;
13
13
  @property (nonatomic, assign) float sampleRate;
14
14
  @property (nonatomic, assign) int channelCount;
15
- @property (nonatomic, assign) bool isRunning;
16
15
  @property (nonatomic, strong) NSString *sourceNodeId;
17
16
  @property (nonatomic, strong) AVAudioSourceNodeRenderBlock renderBlock;
18
17
 
@@ -20,16 +19,10 @@ typedef void (^RenderAudioBlock)(AudioBufferList *outputBuffer, int numFrames);
20
19
  sampleRate:(float)sampleRate
21
20
  channelCount:(int)channelCount;
22
21
 
23
- - (float)getSampleRate;
24
-
25
22
  - (void)start;
26
23
 
27
24
  - (void)stop;
28
25
 
29
- - (void)resume;
30
-
31
- - (void)suspend;
32
-
33
26
  - (void)cleanup;
34
27
 
35
28
  @end
@@ -1,7 +1,7 @@
1
- #import <audioapi/ios/core/AudioPlayer.h>
1
+ #import <audioapi/ios/core/NativeAudioPlayer.h>
2
2
  #import <audioapi/ios/system/AudioEngine.h>
3
3
 
4
- @implementation AudioPlayer
4
+ @implementation NativeAudioPlayer
5
5
 
6
6
  - (instancetype)initWithRenderAudio:(RenderAudioBlock)renderAudio
7
7
  sampleRate:(float)sampleRate
@@ -21,6 +21,7 @@
21
21
  }
22
22
 
23
23
  weakSelf.renderAudio(outputData, frameCount);
24
+
24
25
  return kAudioServicesNoError;
25
26
  };
26
27
 
@@ -31,53 +32,23 @@
31
32
  return self;
32
33
  }
33
34
 
34
- - (float)getSampleRate
35
- {
36
- return self.sampleRate;
37
- }
38
-
39
35
  - (void)start
40
36
  {
41
37
  NSLog(@"[AudioPlayer] start");
38
+
42
39
  AudioEngine *audioEngine = [AudioEngine sharedInstance];
43
- self.isRunning = true;
44
40
  self.sourceNodeId = [audioEngine attachSourceNode:self.sourceNode format:self.format];
45
41
  }
46
42
 
47
43
  - (void)stop
48
44
  {
49
45
  NSLog(@"[AudioPlayer] stop");
50
- if (!self.isRunning) {
51
- return;
52
- }
53
46
 
54
47
  AudioEngine *audioEngine = [AudioEngine sharedInstance];
55
- self.isRunning = false;
56
48
  [audioEngine detachSourceNodeWithId:self.sourceNodeId];
57
49
  self.sourceNodeId = nil;
58
50
  }
59
51
 
60
- - (void)suspend
61
- {
62
- NSLog(@"[AudioPlayer] suspend");
63
- if (!self.isRunning) {
64
- return;
65
- }
66
-
67
- AudioEngine *audioEngine = [AudioEngine sharedInstance];
68
- self.isRunning = false;
69
- [audioEngine detachSourceNodeWithId:self.sourceNodeId];
70
- self.sourceNodeId = nil;
71
- }
72
-
73
- - (void)resume
74
- {
75
- NSLog(@"[AudioPlayer] resume");
76
- AudioEngine *audioEngine = [AudioEngine sharedInstance];
77
- self.isRunning = true;
78
- self.sourceNodeId = [audioEngine attachSourceNode:self.sourceNode format:self.format];
79
- }
80
-
81
52
  - (void)cleanup
82
53
  {
83
54
  self.renderAudio = nil;
@@ -0,0 +1,25 @@
1
+ #pragma once
2
+
3
+ #import <AVFoundation/AVFoundation.h>
4
+ #import <Foundation/Foundation.h>
5
+
6
+ typedef void (^AudioReceiverBlock)(const AudioBufferList *inputBuffer, int numFrames, AVAudioTime *when);
7
+
8
+ @interface NativeAudioRecorder : NSObject
9
+
10
+ @property (nonatomic, assign) int bufferLength;
11
+ @property (nonatomic, assign) double sampleRate;
12
+
13
+ @property (nonatomic, strong) AVAudioSinkNode *sinkNode;
14
+ @property (nonatomic, copy) AVAudioSinkNodeReceiverBlock receiverSinkBlock;
15
+ @property (nonatomic, copy) AudioReceiverBlock receiverBlock;
16
+
17
+ - (instancetype)initWithReceiverBlock:(AudioReceiverBlock)receiverBlock bufferLength:(int)bufferLength;
18
+
19
+ - (void)start;
20
+
21
+ - (void)stop;
22
+
23
+ - (void)cleanup;
24
+
25
+ @end