[Audio Threads] Change workgroup system again

Now it allocates audio workgroups per thread, using work slices like the
Apple documentation describes for asynchronous threads.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
swiftingly
Christopher Snowhill 2022-06-09 01:38:30 -07:00
parent fef8821cf6
commit 91898e9e77
6 changed files with 63 additions and 42 deletions

View File

@ -430,9 +430,11 @@ static void convert_be_to_le(uint8_t *buffer, size_t bitsPerSample, size_t bytes
while(paused) {
usleep(500);
}
[self startWorkslice];
@autoreleasepool {
amountConverted = [self convert:writeBuf amount:CHUNK_SIZE];
}
[self endWorkslice];
if(!amountConverted) {
if(paused) {
continue;

View File

@ -178,9 +178,11 @@
int framesToRead = CHUNK_SIZE - amountInBuffer;
int framesRead;
[self startWorkslice];
@autoreleasepool {
framesRead = [decoder readAudio:((char *)inputBuffer) + bytesInBuffer frames:framesToRead];
}
[self endWorkslice];
if(framesRead > 0 && !seekError) {
amountInBuffer += framesRead;

View File

@ -34,7 +34,8 @@
uint32_t nodeChannelConfig;
BOOL nodeLossless;
os_workgroup_t wg;
int64_t intervalMachLength;
os_workgroup_interval_t workgroup, wg;
os_workgroup_join_token_s wgToken;
}
- (id _Nullable)initWithController:(id _Nonnull)c previous:(id _Nullable)p;
@ -49,6 +50,8 @@
- (void)followWorkgroup;
- (void)leaveWorkgroup;
- (void)startWorkslice;
- (void)endWorkslice;
- (void)launchThread;

View File

@ -13,6 +13,20 @@
#import "OutputCoreAudio.h"
#import <mach/mach_time.h>
// This workgroup attribute isn't currently used. Set it to NULL.
static os_workgroup_attr_t _Nullable attr = nil;
// One nanosecond in seconds.
static const double kOneNanosecond = 1.0e9;
// The I/O interval time in seconds.
static const double kIOIntervalTime = 0.020;
// The clock identifier that specifies interval timestamps.
static const os_clockid_t clockId = OS_CLOCK_MACH_ABSOLUTE_TIME;
@implementation Node
- (id)initWithController:(id)c previous:(id)p {
@ -32,6 +46,21 @@
nodeChannelConfig = 0;
nodeLossless = NO;
if(@available(macOS 11, *)) {
workgroup = AudioWorkIntervalCreate("Node Work Interval", clockId, attr);
// Get the mach time info.
struct mach_timebase_info timeBaseInfo;
mach_timebase_info(&timeBaseInfo);
// The frequency of the clock is: (timeBaseInfo.denom / timeBaseInfo.numer) * kOneNanosecond
const double nanoSecFrequency = (double)(timeBaseInfo.denom) / (double)(timeBaseInfo.numer);
const double frequency = nanoSecFrequency * kOneNanosecond;
// Convert the interval time in seconds to mach time length.
intervalMachLength = (int64_t)(kIOIntervalTime * frequency);
}
[self setPreviousNode:p];
}
@ -101,11 +130,8 @@
- (void)followWorkgroup {
if(@available(macOS 11, *)) {
if(currentWorkgroup != wg) {
if(wg) {
os_workgroup_leave(wg, &wgToken);
}
wg = currentWorkgroup;
if(!wg) {
wg = workgroup;
if(wg) {
int result = os_workgroup_join(wg, &wgToken);
if(result == 0) return;
@ -128,6 +154,30 @@
}
}
- (void)startWorkslice {
if(@available(macOS 11, *)) {
if(wg) {
const uint64_t currentTime = mach_absolute_time();
const uint64_t deadline = currentTime + intervalMachLength;
int result = os_workgroup_interval_start(wg, currentTime, deadline, nil);
if(result != 0) {
DLog(@"Deadline error = %d", result);
}
}
}
}
- (void)endWorkslice {
if(@available(macOS 11, *)) {
if(wg) {
int result = os_workgroup_interval_finish(wg, nil);
if(result != 0) {
DLog(@"Deadline end error = %d", result);
}
}
}
}
- (BOOL)peekFormat:(nonnull AudioStreamBasicDescription *)format channelConfig:(nonnull uint32_t *)config {
[accessLock lock];

View File

@ -33,10 +33,6 @@ using std::atomic_long;
#import <stdio.h>
#endif
#import <os/workgroup.h>
extern volatile os_workgroup_t currentWorkgroup;
@class OutputNode;
@interface OutputCoreAudio : NSObject {

View File

@ -17,8 +17,6 @@
#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";
@ -263,21 +261,6 @@ default_device_changed(AudioObjectID inObjectID, UInt32 inNumberAddresses, const
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];
@ -363,13 +346,6 @@ default_device_changed(AudioObjectID inObjectID, UInt32 inNumberAddresses, const
[writeSemaphore timedWait:5000];
}
if(@available(macOS 11, *)) {
if(wg) {
os_workgroup_leave(wg, &wgToken);
wg = nil;
}
}
stopped = YES;
if(!stopInvoked)
[self stop];
@ -806,10 +782,6 @@ 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];
@ -839,10 +811,6 @@ default_device_changed(AudioObjectID inObjectID, UInt32 inNumberAddresses, const
}
- (void)stop {
if(@available(macOS 11, *)) {
currentWorkgroup = nil;
}
stopInvoked = YES;
if(observersapplied) {
observersapplied = NO;