From e9230a080c3474e9b337ad5dda0e798c4de13940 Mon Sep 17 00:00:00 2001 From: Christopher Snowhill Date: Wed, 15 Jun 2022 21:44:03 -0700 Subject: [PATCH] [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 --- Audio/Chain/ConverterNode.mm | 7 ++----- Audio/Chain/InputNode.m | 7 ++----- Audio/Chain/Node.h | 2 +- Audio/Chain/Node.m | 9 +++++---- 4 files changed, 10 insertions(+), 15 deletions(-) diff --git a/Audio/Chain/ConverterNode.mm b/Audio/Chain/ConverterNode.mm index ac6d654f9..e9b238a4b 100644 --- a/Audio/Chain/ConverterNode.mm +++ b/Audio/Chain/ConverterNode.mm @@ -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, // 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); } - [self startWorkslice]; @autoreleasepool { + [self startWorkslice]; amountConverted = [self convert:writeBuf amount:CHUNK_SIZE]; + [self endWorkslice]; } - [self endWorkslice]; if(!amountConverted) { if(paused) { continue; } else if(streamFormatChanged) { - [self leaveWorkgroup]; [self cleanUp]; [self setupWithInputFormat:newInputFormat withInputConfig:newInputChannelConfig outputFormat:outputFormat outputConfig:outputChannelConfig isLossless:rememberedLossless]; continue; diff --git a/Audio/Chain/InputNode.m b/Audio/Chain/InputNode.m index a3d2a2993..021a90ea5 100644 --- a/Audio/Chain/InputNode.m +++ b/Audio/Chain/InputNode.m @@ -157,7 +157,6 @@ static void *kInputNodeContext = &kInputNodeContext; 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"); @@ -183,15 +182,13 @@ static void *kInputNodeContext = &kInputNodeContext; } if(amountInBuffer < CHUNK_SIZE) { - [self followWorkgroup]; - int framesToRead = CHUNK_SIZE - amountInBuffer; int framesRead; - [self startWorkslice]; @autoreleasepool { + [self startWorkslice]; framesRead = [decoder readAudio:((char *)inputBuffer) + bytesInBuffer frames:framesToRead]; + [self endWorkslice]; } - [self endWorkslice]; if(framesRead > 0 && !seekError) { amountInBuffer += framesRead; diff --git a/Audio/Chain/Node.h b/Audio/Chain/Node.h index c0bdadacf..09684cd8d 100644 --- a/Audio/Chain/Node.h +++ b/Audio/Chain/Node.h @@ -29,7 +29,7 @@ BOOL shouldContinue; BOOL endOfStream; // All data is now in buffer 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; uint32_t nodeChannelConfig; diff --git a/Audio/Chain/Node.m b/Audio/Chain/Node.m index 2ed4bd2d4..fa100d826 100644 --- a/Audio/Chain/Node.m +++ b/Audio/Chain/Node.m @@ -222,6 +222,7 @@ BOOL SetPriorityRealtimeAudio(mach_port_t mach_thread_id) { wg = workgroup; if(wg && !isRealtimeError) { int result = os_workgroup_join(wg, &wgToken); + isDeadlineError = NO; if(result == 0) return; if(result == EALREADY) { DLog(@"Thread already in workgroup"); @@ -251,13 +252,13 @@ BOOL SetPriorityRealtimeAudio(mach_port_t mach_thread_id) { - (void)startWorkslice { if(@available(macOS 11, *)) { - if(wg && !isRealtimeError) { + if(wg && !isRealtimeError && !isDeadlineError) { 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); - isRealtimeError = YES; + isDeadlineError = YES; } } } @@ -265,11 +266,11 @@ BOOL SetPriorityRealtimeAudio(mach_port_t mach_thread_id) { - (void)endWorkslice { if(@available(macOS 11, *)) { - if(wg && !isRealtimeError) { + if(wg && !isRealtimeError && !isDeadlineError) { int result = os_workgroup_interval_finish(wg, nil); if(result != 0) { DLog(@"Deadline end error = %d", result); - isRealtimeError = YES; + isDeadlineError = YES; } } }