Skip to content

Commit 4076b9f

Browse files
committed
chore(audio-context): performance op
1 parent c7f1835 commit 4076b9f

4 files changed

Lines changed: 477 additions & 378 deletions

File tree

Binary file not shown.

packages/audio-context/platforms/ios/src/NSCAudioParam.m

Lines changed: 28 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#import "NSCAudioContext.h"
2+
#include <stdlib.h>
23

34
typedef NS_ENUM(NSInteger, ParamEventType) {
45
ParamEventTypeSet = 0,
@@ -23,6 +24,12 @@ - (instancetype)initWithType:(ParamEventType)type time:(double)time value:(doubl
2324
}
2425
@end
2526

27+
typedef struct {
28+
ParamEventType type;
29+
double time;
30+
double value;
31+
} NSCParamEventSnapshot;
32+
2633
@implementation NSCAudioParam {
2734
__strong NSCAudioContext *_context;
2835
NSMutableArray<ParamEvent *> *_events;
@@ -182,7 +189,18 @@ - (BOOL)fillValuesForRange:(double)startTime
182189
return NO;
183190
}
184191

185-
struct { ParamEventType type; double time; double value; } evts[evtCount];
192+
const NSUInteger kStackSnapshotCapacity = 64;
193+
NSCParamEventSnapshot stackEvents[kStackSnapshotCapacity];
194+
NSCParamEventSnapshot *evts = stackEvents;
195+
if (evtCount > kStackSnapshotCapacity) {
196+
evts = (NSCParamEventSnapshot *)malloc(sizeof(NSCParamEventSnapshot) * evtCount);
197+
if (!evts) {
198+
double cur = _currentValueInternal;
199+
[_lock unlock];
200+
for (NSInteger i = 0; i < frameCount; ++i) outValues[i] = cur;
201+
return NO;
202+
}
203+
}
186204
for (NSUInteger i = 0; i < evtCount; ++i) {
187205
ParamEvent *e = _events[i];
188206
evts[i].type = e.type;
@@ -214,6 +232,7 @@ - (BOOL)fillValuesForRange:(double)startTime
214232
}
215233
}
216234
for (NSInteger i = 0; i < frameCount; ++i) outValues[i] = v;
235+
if (evts != stackEvents) free(evts);
217236
return YES;
218237
}
219238

@@ -244,77 +263,20 @@ - (BOOL)fillValuesForRange:(double)startTime
244263
}
245264
outValues[i] = value;
246265
}
266+
if (evts != stackEvents) free(evts);
247267
return YES;
248268
}
249269

250270
- (NSArray<NSNumber *> *)getValuesForRange:(double)startTime :(double)sampleRate :(NSInteger)frameCount {
251-
[_lock lock];
252-
NSArray<ParamEvent *> *evts = [_events copy];
253-
double def = _defaultValue;
254-
[_lock unlock];
255-
271+
if (frameCount <= 0) return @[];
272+
273+
NSMutableData *scratch = [NSMutableData dataWithLength:sizeof(double) * (NSUInteger)frameCount];
274+
double *values = (double *)scratch.mutableBytes;
275+
[self fillValuesForRange:startTime sampleRate:sampleRate frameCount:frameCount into:values];
276+
256277
NSMutableArray<NSNumber *> *out = [NSMutableArray arrayWithCapacity:frameCount];
257-
if ([_automationRate isEqualToString:@"k-rate"]) {
258-
double v = def;
259-
if (evts.count == 0) {
260-
v = def;
261-
} else {
262-
NSUInteger idx = [evts indexOfObjectPassingTest:^BOOL(ParamEvent *obj, NSUInteger idx, BOOL *stop) {
263-
return obj.time > startTime;
264-
}];
265-
if (idx == NSNotFound) {
266-
v = evts.lastObject.value;
267-
} else if (idx == 0) {
268-
v = def;
269-
} else {
270-
ParamEvent *prev = evts[idx - 1];
271-
ParamEvent *next = evts[idx];
272-
if (next.type == ParamEventTypeLinearRamp) {
273-
double t0 = prev.time;
274-
double t1 = next.time;
275-
if (t1 <= t0) v = next.value;
276-
else {
277-
double ratio = fmax(0.0, fmin(1.0, (startTime - t0) / (t1 - t0)));
278-
v = prev.value + (next.value - prev.value) * ratio;
279-
}
280-
} else {
281-
v = prev.value;
282-
}
283-
}
284-
}
285-
for (NSInteger i = 0; i < frameCount; ++i) [out addObject:@(v)];
286-
return out;
287-
}
288-
289-
NSInteger nextEventIndex = 0;
290-
NSInteger previousEventIndex = -1;
291278
for (NSInteger i = 0; i < frameCount; ++i) {
292-
double t = startTime + (double)i / sampleRate;
293-
while (nextEventIndex < evts.count && evts[nextEventIndex].time <= t) {
294-
previousEventIndex = nextEventIndex;
295-
nextEventIndex += 1;
296-
}
297-
double value;
298-
if (previousEventIndex < 0) {
299-
value = def;
300-
} else if (nextEventIndex >= evts.count) {
301-
value = evts[previousEventIndex].value;
302-
} else {
303-
ParamEvent *prev = evts[previousEventIndex];
304-
ParamEvent *next = evts[nextEventIndex];
305-
if (next.type == ParamEventTypeLinearRamp) {
306-
double t0 = prev.time;
307-
double t1 = next.time;
308-
if (t1 <= t0) value = next.value;
309-
else {
310-
double ratio = fmax(0.0, fmin(1.0, (t - t0) / (t1 - t0)));
311-
value = prev.value + (next.value - prev.value) * ratio;
312-
}
313-
} else {
314-
value = prev.value;
315-
}
316-
}
317-
[out addObject:@(value)];
279+
[out addObject:@(values[i])];
318280
}
319281
return out;
320282
}

packages/audio-context/platforms/ios/src/NSCMediaElementSourceTap.m

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -748,6 +748,8 @@ + (nullable instancetype)attachToPlayer:(AVPlayer *)player
748748
dispatch_source_set_timer(sched, dispatch_time(DISPATCH_TIME_NOW, 0), interval, (uint64_t)(NSEC_PER_MSEC * 5));
749749
__weak typeof(pnode) weakP = pnode;
750750
__weak typeof(self_) weakSelfTap = self_;
751+
__block uint8_t *playerScratch = NULL;
752+
__block uint32_t playerScratchBytes = 0;
751753
dispatch_source_set_event_handler(sched, ^{
752754
__strong typeof(weakP) strongP = weakP;
753755
__strong typeof(weakSelfTap) strongTap = weakSelfTap;
@@ -776,26 +778,36 @@ + (nullable instancetype)attachToPlayer:(AVPlayer *)player
776778
}
777779

778780
const uint32_t framesPerBuffer = 1024;
781+
uint32_t scratchNeeded = framesPerBuffer * bytesPerFrameLocal;
782+
if (scratchNeeded > playerScratchBytes) {
783+
void *resized = realloc(playerScratch, (size_t)scratchNeeded);
784+
if (!resized) return;
785+
playerScratch = (uint8_t *)resized;
786+
playerScratchBytes = scratchNeeded;
787+
}
788+
789+
AVAudioFormat *pnodeFormat = nil;
790+
@try {
791+
pnodeFormat = [strongP outputFormatForBus:0];
792+
} @catch (NSException *e) {
793+
pnodeFormat = nil;
794+
}
795+
AVAudioFormat *useFormat = pnodeFormat ?: nodeFormat;
796+
uint32_t srcChannels = channelCount;
797+
uint32_t dstChannels = (uint32_t)(useFormat.channelCount);
798+
779799
while (framesAvailable > 0) {
780800
uint32_t framesThis = framesAvailable >= framesPerBuffer ? framesPerBuffer : framesAvailable;
781801
uint32_t bytesNeeded = framesThis * bytesPerFrameLocal;
782-
uint8_t *tmpBuf = (uint8_t *)malloc((size_t)bytesNeeded);
783-
if (!tmpBuf) break;
784-
uint32_t got = NSCRingRead(&coreLocal->ring, tmpBuf, bytesNeeded);
802+
uint32_t got = NSCRingRead(&coreLocal->ring, playerScratch, bytesNeeded);
785803
uint32_t gotFrames = got / bytesPerFrameLocal;
786-
if (gotFrames == 0) { free(tmpBuf); break; }
804+
if (gotFrames == 0) { break; }
787805
AVAudioFrameCount fc = (AVAudioFrameCount)gotFrames;
788806

789-
AVAudioFormat *pnodeFormat = nil;
790-
@try { pnodeFormat = [strongP outputFormatForBus:0]; } @catch (NSException *e) { pnodeFormat = nil; }
791-
AVAudioFormat *useFormat = pnodeFormat ?: nodeFormat;
792-
793807
AVAudioPCMBuffer *pcm = [[AVAudioPCMBuffer alloc] initWithPCMFormat:useFormat frameCapacity:fc];
794808
if (pcm) {
795809
pcm.frameLength = fc;
796-
float *srcFloat = (float *)tmpBuf;
797-
uint32_t srcChannels = channelCount;
798-
uint32_t dstChannels = (uint32_t)(useFormat.channelCount);
810+
float *srcFloat = (float *)playerScratch;
799811

800812
if (dstChannels == srcChannels) {
801813
for (UInt32 ch = 0; ch < dstChannels; ch++) {
@@ -827,12 +839,18 @@ + (nullable instancetype)attachToPlayer:(AVPlayer *)player
827839

828840
[strongP scheduleBuffer:pcm completionHandler:NULL];
829841
}
830-
free(tmpBuf);
831842
avail = NSCRingAvailableRead(&coreLocal->ring);
832843
framesAvailable = avail / bytesPerFrameLocal;
833844
if (framesThis < framesPerBuffer) break;
834845
}
835846
});
847+
dispatch_source_set_cancel_handler(sched, ^{
848+
if (playerScratch) {
849+
free(playerScratch);
850+
playerScratch = NULL;
851+
playerScratchBytes = 0;
852+
}
853+
});
836854
dispatch_resume(sched);
837855
self_->_playerSchedulingSource = sched;
838856
}

0 commit comments

Comments
 (0)