Skip to content

Commit 472a535

Browse files
maciejmakowski2003Maciej Makowski
andauthored
Feat/custom sample rate (#277)
* refactor: moved AudioPlayer to AudioContext * refactor: refactored number of frames render by one call of renderAudio to RENDER_QUANTUM_SIZE * fix: fixed bad access exception * feat: added custom sample rate in audio context * refactor: lateinit of AudioDecoder and sampleRate --------- Co-authored-by: Maciej Makowski <maciej.makowski2608@gmail.com>
1 parent 59a8293 commit 472a535

File tree

14 files changed

+151
-17
lines changed

14 files changed

+151
-17
lines changed

packages/react-native-audio-api/android/src/main/cpp/core/AudioPlayer.cpp

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,36 @@ AudioPlayer::AudioPlayer(
2121
->setDataCallback(this)
2222
->openStream(mStream_);
2323

24+
sampleRate_ = mStream_->getSampleRate();
2425
mBus_ = std::make_shared<AudioBus>(
25-
getSampleRate(), RENDER_QUANTUM_SIZE, CHANNEL_COUNT);
26+
sampleRate_, RENDER_QUANTUM_SIZE, CHANNEL_COUNT);
27+
isInitialized_ = true;
28+
}
29+
30+
AudioPlayer::AudioPlayer(
31+
const std::function<void(AudioBus *, int)> &renderAudio,
32+
int sampleRate)
33+
: renderAudio_(renderAudio) {
34+
AudioStreamBuilder builder;
35+
36+
builder.setSharingMode(SharingMode::Exclusive)
37+
->setFormat(AudioFormat::Float)
38+
->setFormatConversionAllowed(true)
39+
->setPerformanceMode(PerformanceMode::LowLatency)
40+
->setChannelCount(CHANNEL_COUNT)
41+
->setSampleRateConversionQuality(SampleRateConversionQuality::Medium)
42+
->setDataCallback(this)
43+
->setSampleRate(sampleRate)
44+
->openStream(mStream_);
45+
46+
sampleRate_ = sampleRate;
47+
mBus_ = std::make_shared<AudioBus>(
48+
sampleRate_, RENDER_QUANTUM_SIZE, CHANNEL_COUNT);
2649
isInitialized_ = true;
2750
}
2851

2952
int AudioPlayer::getSampleRate() const {
30-
return mStream_->getSampleRate();
53+
return sampleRate_;
3154
}
3255

3356
void AudioPlayer::start() {

packages/react-native-audio-api/android/src/main/cpp/core/AudioPlayer.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ class AudioBus;
1313
class AudioPlayer : public AudioStreamDataCallback {
1414
public:
1515
explicit AudioPlayer(const std::function<void(AudioBus *, int)> &renderAudio);
16+
AudioPlayer(
17+
const std::function<void(AudioBus *, int)> &renderAudio,
18+
int sampleRate);
1619

1720
[[nodiscard]] int getSampleRate() const;
1821
void start();
@@ -28,6 +31,7 @@ class AudioPlayer : public AudioStreamDataCallback {
2831
std::shared_ptr<AudioStream> mStream_;
2932
std::shared_ptr<AudioBus> mBus_;
3033
bool isInitialized_ = false;
34+
int sampleRate_;
3135
};
3236

3337
} // namespace audioapi

packages/react-native-audio-api/common/cpp/HostObjects/AudioAPIInstallerHostObject.h

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,18 @@ class AudioAPIInstallerHostObject
3535
}
3636

3737
JSI_HOST_FUNCTION(createAudioContext) {
38-
auto audioContext = std::make_shared<AudioContext>();
39-
auto audioContextHostObject =
38+
std::shared_ptr<AudioContext> audioContext;
39+
if (args[0].isUndefined()) {
40+
audioContext = std::make_shared<AudioContext>();
41+
} else {
42+
int sampleRate = static_cast<int>(args[0].getNumber());
43+
audioContext = std::make_shared<AudioContext>(sampleRate);
44+
}
45+
46+
auto audioContextHostObject =
4047
std::make_shared<AudioContextHostObject>(audioContext, promiseVendor_);
41-
return jsi::Object::createFromHostObject(runtime, audioContextHostObject);
48+
49+
return jsi::Object::createFromHostObject(runtime, audioContextHostObject);
4250
}
4351

4452
private:

packages/react-native-audio-api/common/cpp/core/AudioContext.cpp

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,31 @@
55
#endif
66

77
#include "AudioContext.h"
8+
#include "AudioDecoder.h"
89
#include "AudioDestinationNode.h"
910

1011
namespace audioapi {
11-
1212
AudioContext::AudioContext() : BaseAudioContext() {
1313
#ifdef ANDROID
1414
audioPlayer_ = std::make_shared<AudioPlayer>(this->renderAudio());
1515
#else
1616
audioPlayer_ = std::make_shared<IOSAudioPlayer>(this->renderAudio());
1717
#endif
1818
sampleRate_ = audioPlayer_->getSampleRate();
19+
audioDecoder_ = std::make_shared<AudioDecoder>(sampleRate_);
20+
21+
audioPlayer_->start();
22+
}
23+
24+
AudioContext::AudioContext(int sampleRate) : BaseAudioContext() {
25+
#ifdef ANDROID
26+
audioPlayer_ = std::make_shared<AudioPlayer>(this->renderAudio(), sampleRate);
27+
#else
28+
audioPlayer_ =
29+
std::make_shared<IOSAudioPlayer>(this->renderAudio(), sampleRate);
30+
#endif
31+
sampleRate_ = audioPlayer_->getSampleRate();
32+
audioDecoder_ = std::make_shared<AudioDecoder>(sampleRate_);
1933

2034
audioPlayer_->start();
2135
}

packages/react-native-audio-api/common/cpp/core/AudioContext.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ class IOSAudioPlayer;
1414
class AudioContext : public BaseAudioContext {
1515
public:
1616
AudioContext();
17+
explicit AudioContext(int sampleRate);
1718
~AudioContext() override;
1819

1920
void close();

packages/react-native-audio-api/common/cpp/core/BaseAudioContext.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,7 @@
1616

1717
namespace audioapi {
1818

19-
BaseAudioContext::BaseAudioContext() : sampleRate_(DEFAULT_SAMPLE_RATE) {
20-
audioDecoder_ = std::make_shared<AudioDecoder>(sampleRate_);
21-
19+
BaseAudioContext::BaseAudioContext() {
2220
nodeManager_ = std::make_shared<AudioNodeManager>();
2321
destination_ = std::make_shared<AudioDestinationNode>(this);
2422
}

packages/react-native-audio-api/common/cpp/core/BaseAudioContext.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,11 @@ class BaseAudioContext {
5858
protected:
5959
static std::string toString(ContextState state);
6060
std::shared_ptr<AudioDestinationNode> destination_;
61-
std::shared_ptr<AudioDecoder> audioDecoder_;
61+
// init in AudioContext or OfflineContext constructor
62+
std::shared_ptr<AudioDecoder> audioDecoder_ {};
6263

63-
int sampleRate_;
64+
// init in AudioContext or OfflineContext constructor
65+
int sampleRate_ {};
6466
ContextState state_ = ContextState::RUNNING;
6567
std::shared_ptr<AudioNodeManager> nodeManager_;
6668

packages/react-native-audio-api/ios/core/AudioPlayer.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,12 @@ typedef void (^RenderAudioBlock)(AudioBufferList *outputBuffer, int numFrames);
1212
@property (nonatomic, strong) AVAudioFormat *format;
1313
@property (nonatomic, strong) AVAudioSourceNode *sourceNode;
1414
@property (nonatomic, copy) RenderAudioBlock renderAudio;
15+
@property (nonatomic, assign) int sampleRate;
1516

1617
- (instancetype)initWithRenderAudioBlock:(RenderAudioBlock)renderAudio;
1718

19+
- (instancetype)initWithRenderAudioBlock:(RenderAudioBlock)renderAudio sampleRate:(int)sampleRate;
20+
1821
- (int)getSampleRate;
1922

2023
- (void)start;

packages/react-native-audio-api/ios/core/AudioPlayer.m

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,56 @@ - (instancetype)initWithRenderAudioBlock:(RenderAudioBlock)renderAudio
2828
@throw error;
2929
}
3030

31-
_format = [[AVAudioFormat alloc] initStandardFormatWithSampleRate:[self.audioSession sampleRate] channels:2];
31+
self.sampleRate = [self.audioSession sampleRate];
32+
33+
_format = [[AVAudioFormat alloc] initStandardFormatWithSampleRate:self.sampleRate channels:2];
34+
35+
__weak typeof(self) weakSelf = self;
36+
_sourceNode = [[AVAudioSourceNode alloc] initWithFormat:self.format
37+
renderBlock:^OSStatus(
38+
BOOL *isSilence,
39+
const AudioTimeStamp *timestamp,
40+
AVAudioFrameCount frameCount,
41+
AudioBufferList *outputData) {
42+
return [weakSelf renderCallbackWithIsSilence:isSilence
43+
timestamp:timestamp
44+
frameCount:frameCount
45+
outputData:outputData];
46+
}];
47+
}
48+
49+
return self;
50+
}
51+
52+
- (instancetype)initWithRenderAudioBlock:(RenderAudioBlock)renderAudio sampleRate:(int)sampleRate
53+
{
54+
if (self = [super init]) {
55+
self.renderAudio = [renderAudio copy];
56+
self.audioEngine = [[AVAudioEngine alloc] init];
57+
self.audioEngine.mainMixerNode.outputVolume = 1;
58+
59+
self.audioSession = AVAudioSession.sharedInstance;
60+
NSError *error = nil;
61+
62+
// TODO:
63+
// We will probably want to change it to AVAudioSessionCategoryPlayAndRecord in the future.
64+
// Eventually we to make this a dynamic setting, if user of the lib wants to use recording features.
65+
// But setting a recording category might require some setup first, so lets skip it for now :)
66+
[self.audioSession setCategory:AVAudioSessionCategoryPlayback error:&error];
67+
68+
if (error != nil) {
69+
@throw error;
70+
}
71+
72+
[self.audioSession setActive:true error:&error];
73+
74+
if (error != nil) {
75+
@throw error;
76+
}
77+
78+
self.sampleRate = sampleRate;
79+
80+
_format = [[AVAudioFormat alloc] initStandardFormatWithSampleRate:self.sampleRate channels:2];
3281

3382
__weak typeof(self) weakSelf = self;
3483
_sourceNode = [[AVAudioSourceNode alloc] initWithFormat:self.format
@@ -49,7 +98,7 @@ - (instancetype)initWithRenderAudioBlock:(RenderAudioBlock)renderAudio
4998

5099
- (int)getSampleRate
51100
{
52-
return [self.audioSession sampleRate];
101+
return self.sampleRate;
53102
}
54103

55104
- (void)start

packages/react-native-audio-api/ios/core/IOSAudioPlayer.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ class IOSAudioPlayer {
2222
public:
2323
explicit IOSAudioPlayer(
2424
const std::function<void(AudioBus *, int)> &renderAudio);
25+
IOSAudioPlayer(
26+
const std::function<void(AudioBus *, int)> &renderAudio,
27+
int sampleRate);
2528
~IOSAudioPlayer();
2629

2730
int getSampleRate() const;

0 commit comments

Comments
 (0)