[Audio Threads] Join output device workgroup
On Big Sur or newer, it is possible to join the audio threads to the same OS workgroup as the audio output device, improving response. Signed-off-by: Christopher Snowhill <kode54@gmail.com>swiftingly
parent
cdcbabd72f
commit
6179b304d0
|
@ -424,6 +424,8 @@ static void convert_be_to_le(uint8_t *buffer, size_t bitsPerSample, size_t bytes
|
|||
// when the end of stream is reached. Convert function instead processes what it can,
|
||||
// and returns 0 samples when it has nothing more to process at the end of stream.
|
||||
while([self shouldContinue] == YES) {
|
||||
[self followWorkgroup];
|
||||
|
||||
int amountConverted;
|
||||
while(paused) {
|
||||
usleep(500);
|
||||
|
@ -435,6 +437,7 @@ static void convert_be_to_le(uint8_t *buffer, size_t bitsPerSample, size_t bytes
|
|||
if(paused) {
|
||||
continue;
|
||||
} else if(streamFormatChanged) {
|
||||
[self leaveWorkgroup];
|
||||
[self cleanUp];
|
||||
[self setupWithInputFormat:newInputFormat withInputConfig:newInputChannelConfig outputFormat:outputFormat outputConfig:outputChannelConfig isLossless:rememberedLossless];
|
||||
continue;
|
||||
|
|
|
@ -148,6 +148,7 @@
|
|||
|
||||
while([self shouldContinue] == YES && [self endOfStream] == NO) {
|
||||
if(shouldSeek == YES) {
|
||||
[self leaveWorkgroup];
|
||||
BufferChain *bufferChain = [[controller controller] bufferChain];
|
||||
ConverterNode *converter = [bufferChain converter];
|
||||
DLog(@"SEEKING! Resetting Buffer");
|
||||
|
@ -173,6 +174,8 @@
|
|||
}
|
||||
|
||||
if(amountInBuffer < CHUNK_SIZE) {
|
||||
[self followWorkgroup];
|
||||
|
||||
int framesToRead = CHUNK_SIZE - amountInBuffer;
|
||||
int framesRead;
|
||||
@autoreleasepool {
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
#import "Semaphore.h"
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
#import <os/workgroup.h>
|
||||
|
||||
#define BUFFER_SIZE 1024 * 1024
|
||||
#define CHUNK_SIZE 16 * 1024
|
||||
|
||||
|
@ -31,6 +33,9 @@
|
|||
AudioStreamBasicDescription nodeFormat;
|
||||
uint32_t nodeChannelConfig;
|
||||
BOOL nodeLossless;
|
||||
|
||||
os_workgroup_t wg;
|
||||
os_workgroup_join_token_s wgToken;
|
||||
}
|
||||
- (id _Nullable)initWithController:(id _Nonnull)c previous:(id _Nullable)p;
|
||||
|
||||
|
@ -42,6 +47,9 @@
|
|||
- (void)process; // Should be overwriten by subclass
|
||||
- (void)threadEntry:(id _Nullable)arg;
|
||||
|
||||
- (void)followWorkgroup;
|
||||
- (void)leaveWorkgroup;
|
||||
|
||||
- (void)launchThread;
|
||||
|
||||
- (void)setShouldReset:(BOOL)s;
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
#import "BufferChain.h"
|
||||
#import "Logging.h"
|
||||
|
||||
#import "OutputCoreAudio.h"
|
||||
|
||||
@implementation Node
|
||||
|
||||
- (id)initWithController:(id)c previous:(id)p {
|
||||
|
@ -91,7 +93,38 @@
|
|||
|
||||
- (void)threadEntry:(id)arg {
|
||||
@autoreleasepool {
|
||||
[self followWorkgroup];
|
||||
[self process];
|
||||
[self leaveWorkgroup];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)followWorkgroup {
|
||||
if(@available(macOS 11, *)) {
|
||||
if(currentWorkgroup != wg) {
|
||||
if(wg) {
|
||||
os_workgroup_leave(wg, &wgToken);
|
||||
}
|
||||
wg = currentWorkgroup;
|
||||
if(wg) {
|
||||
int result = os_workgroup_join(wg, &wgToken);
|
||||
if(result == 0) return;
|
||||
if(result == EALREADY) {
|
||||
DLog(@"Thread already in workgroup");
|
||||
} else {
|
||||
DLog(@"Cannot join workgroup, error %d", result);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)leaveWorkgroup {
|
||||
if(@available(macOS 11, *)) {
|
||||
if(wg) {
|
||||
os_workgroup_leave(wg, &wgToken);
|
||||
wg = nil;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -33,6 +33,10 @@ using std::atomic_long;
|
|||
#import <stdio.h>
|
||||
#endif
|
||||
|
||||
#import <os/workgroup.h>
|
||||
|
||||
extern volatile os_workgroup_t currentWorkgroup;
|
||||
|
||||
@class OutputNode;
|
||||
|
||||
@interface OutputCoreAudio : NSObject {
|
||||
|
@ -84,6 +88,9 @@ using std::atomic_long;
|
|||
|
||||
VisualizationController *visController;
|
||||
|
||||
os_workgroup_t wg;
|
||||
os_workgroup_join_token_s wgToken;
|
||||
|
||||
#ifdef OUTPUT_LOG
|
||||
FILE *_logFile;
|
||||
#endif
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
|
||||
#import <Accelerate/Accelerate.h>
|
||||
|
||||
volatile os_workgroup_t currentWorkgroup;
|
||||
|
||||
extern void scale_by_volume(float *buffer, size_t count, float volume);
|
||||
|
||||
static NSString *CogPlaybackDidBeginNotficiation = @"CogPlaybackDidBeginNotficiation";
|
||||
|
@ -260,6 +262,22 @@ default_device_changed(AudioObjectID inObjectID, UInt32 inNumberAddresses, const
|
|||
atomic_store(&bytesRendered, 0);
|
||||
NSMutableArray *delayedEvents = [[NSMutableArray alloc] init];
|
||||
BOOL delayedEventsPopped = YES;
|
||||
|
||||
if(@available(macOS 11, *)) {
|
||||
if(currentWorkgroup) {
|
||||
wg = currentWorkgroup;
|
||||
int result = os_workgroup_join(wg, &wgToken);
|
||||
if(result != 0) {
|
||||
if(result == EALREADY) {
|
||||
DLog(@"Output thread already in workgroup");
|
||||
} else {
|
||||
DLog(@"Output thread could not be added to workgroup, error = %d", result);
|
||||
}
|
||||
wg = nil;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while(!stopping) {
|
||||
if(++eventCount == 48) {
|
||||
[self resetIfOutputChanged];
|
||||
|
@ -344,6 +362,14 @@ default_device_changed(AudioObjectID inObjectID, UInt32 inNumberAddresses, const
|
|||
[readSemaphore signal];
|
||||
[writeSemaphore timedWait:5000];
|
||||
}
|
||||
|
||||
if(@available(macOS 11, *)) {
|
||||
if(wg) {
|
||||
os_workgroup_leave(wg, &wgToken);
|
||||
wg = nil;
|
||||
}
|
||||
}
|
||||
|
||||
stopped = YES;
|
||||
if(!stopInvoked)
|
||||
[self stop];
|
||||
|
@ -780,6 +806,10 @@ default_device_changed(AudioObjectID inObjectID, UInt32 inNumberAddresses, const
|
|||
|
||||
visController = [VisualizationController sharedController];
|
||||
|
||||
if(@available(macOS 11, *)) {
|
||||
currentWorkgroup = _au.osWorkgroup;
|
||||
}
|
||||
|
||||
[[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:@"values.outputDevice" options:0 context:NULL];
|
||||
[[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:@"values.GraphicEQenable" options:0 context:NULL];
|
||||
[[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:@"values.eqPreamp" options:(NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew) context:NULL];
|
||||
|
@ -809,6 +839,10 @@ default_device_changed(AudioObjectID inObjectID, UInt32 inNumberAddresses, const
|
|||
}
|
||||
|
||||
- (void)stop {
|
||||
if(@available(macOS 11, *)) {
|
||||
currentWorkgroup = nil;
|
||||
}
|
||||
|
||||
stopInvoked = YES;
|
||||
if(observersapplied) {
|
||||
observersapplied = NO;
|
||||
|
|
Loading…
Reference in New Issue