[Audio Threads] Change workgroup code for safety

The changes include no longer leaving the workgroup for seeking or for
converter format changes, and also still leaving the workgroup on thread
termination if there was an error with intervals starting or finishing.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
swiftingly
Christopher Snowhill 2022-06-15 21:44:03 -07:00
parent 02d2ab01a7
commit e9230a080c
4 changed files with 10 additions and 15 deletions

View File

@ -446,22 +446,19 @@ 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, // 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. // and returns 0 samples when it has nothing more to process at the end of stream.
while([self shouldContinue] == YES) { while([self shouldContinue] == YES) {
[self followWorkgroup];
int amountConverted; int amountConverted;
while(paused) { while(paused) {
usleep(500); usleep(500);
} }
[self startWorkslice];
@autoreleasepool { @autoreleasepool {
[self startWorkslice];
amountConverted = [self convert:writeBuf amount:CHUNK_SIZE]; amountConverted = [self convert:writeBuf amount:CHUNK_SIZE];
[self endWorkslice];
} }
[self endWorkslice];
if(!amountConverted) { if(!amountConverted) {
if(paused) { if(paused) {
continue; continue;
} else if(streamFormatChanged) { } else if(streamFormatChanged) {
[self leaveWorkgroup];
[self cleanUp]; [self cleanUp];
[self setupWithInputFormat:newInputFormat withInputConfig:newInputChannelConfig outputFormat:outputFormat outputConfig:outputChannelConfig isLossless:rememberedLossless]; [self setupWithInputFormat:newInputFormat withInputConfig:newInputChannelConfig outputFormat:outputFormat outputConfig:outputChannelConfig isLossless:rememberedLossless];
continue; continue;

View File

@ -157,7 +157,6 @@ static void *kInputNodeContext = &kInputNodeContext;
while([self shouldContinue] == YES && [self endOfStream] == NO) { while([self shouldContinue] == YES && [self endOfStream] == NO) {
if(shouldSeek == YES) { if(shouldSeek == YES) {
[self leaveWorkgroup];
BufferChain *bufferChain = [[controller controller] bufferChain]; BufferChain *bufferChain = [[controller controller] bufferChain];
ConverterNode *converter = [bufferChain converter]; ConverterNode *converter = [bufferChain converter];
DLog(@"SEEKING! Resetting Buffer"); DLog(@"SEEKING! Resetting Buffer");
@ -183,15 +182,13 @@ static void *kInputNodeContext = &kInputNodeContext;
} }
if(amountInBuffer < CHUNK_SIZE) { if(amountInBuffer < CHUNK_SIZE) {
[self followWorkgroup];
int framesToRead = CHUNK_SIZE - amountInBuffer; int framesToRead = CHUNK_SIZE - amountInBuffer;
int framesRead; int framesRead;
[self startWorkslice];
@autoreleasepool { @autoreleasepool {
[self startWorkslice];
framesRead = [decoder readAudio:((char *)inputBuffer) + bytesInBuffer frames:framesToRead]; framesRead = [decoder readAudio:((char *)inputBuffer) + bytesInBuffer frames:framesToRead];
[self endWorkslice];
} }
[self endWorkslice];
if(framesRead > 0 && !seekError) { if(framesRead > 0 && !seekError) {
amountInBuffer += framesRead; amountInBuffer += framesRead;

View File

@ -29,7 +29,7 @@
BOOL shouldContinue; BOOL shouldContinue;
BOOL endOfStream; // All data is now in buffer BOOL endOfStream; // All data is now in buffer
BOOL initialBufferFilled; BOOL initialBufferFilled;
BOOL isRealtime, isRealtimeError; // If was successfully set realtime, or if error BOOL isRealtime, isRealtimeError, isDeadlineError; // If was successfully set realtime, or if error
AudioStreamBasicDescription nodeFormat; AudioStreamBasicDescription nodeFormat;
uint32_t nodeChannelConfig; uint32_t nodeChannelConfig;

View File

@ -222,6 +222,7 @@ BOOL SetPriorityRealtimeAudio(mach_port_t mach_thread_id) {
wg = workgroup; wg = workgroup;
if(wg && !isRealtimeError) { if(wg && !isRealtimeError) {
int result = os_workgroup_join(wg, &wgToken); int result = os_workgroup_join(wg, &wgToken);
isDeadlineError = NO;
if(result == 0) return; if(result == 0) return;
if(result == EALREADY) { if(result == EALREADY) {
DLog(@"Thread already in workgroup"); DLog(@"Thread already in workgroup");
@ -251,13 +252,13 @@ BOOL SetPriorityRealtimeAudio(mach_port_t mach_thread_id) {
- (void)startWorkslice { - (void)startWorkslice {
if(@available(macOS 11, *)) { if(@available(macOS 11, *)) {
if(wg && !isRealtimeError) { if(wg && !isRealtimeError && !isDeadlineError) {
const uint64_t currentTime = mach_absolute_time(); const uint64_t currentTime = mach_absolute_time();
const uint64_t deadline = currentTime + intervalMachLength; const uint64_t deadline = currentTime + intervalMachLength;
int result = os_workgroup_interval_start(wg, currentTime, deadline, nil); int result = os_workgroup_interval_start(wg, currentTime, deadline, nil);
if(result != 0) { if(result != 0) {
DLog(@"Deadline error = %d", result); DLog(@"Deadline error = %d", result);
isRealtimeError = YES; isDeadlineError = YES;
} }
} }
} }
@ -265,11 +266,11 @@ BOOL SetPriorityRealtimeAudio(mach_port_t mach_thread_id) {
- (void)endWorkslice { - (void)endWorkslice {
if(@available(macOS 11, *)) { if(@available(macOS 11, *)) {
if(wg && !isRealtimeError) { if(wg && !isRealtimeError && !isDeadlineError) {
int result = os_workgroup_interval_finish(wg, nil); int result = os_workgroup_interval_finish(wg, nil);
if(result != 0) { if(result != 0) {
DLog(@"Deadline end error = %d", result); DLog(@"Deadline end error = %d", result);
isRealtimeError = YES; isDeadlineError = YES;
} }
} }
} }