improved "unwatching" devices

This commit is contained in:
Patrick Wardle 2024-01-17 09:34:15 -10:00
parent 120d3f1bfd
commit 74b6566011
2 changed files with 95 additions and 20 deletions

View File

@ -176,7 +176,6 @@ extern os_log_t logHandle;
} }
//device is disconnected //device is disconnected
// get its type, then unwatch it
-(void)handleDisconnectedDeviceNotification:(NSNotification *)notification -(void)handleDisconnectedDeviceNotification:(NSNotification *)notification
{ {
//device //device
@ -777,9 +776,6 @@ extern os_log_t logHandle;
//init property struct's element //init property struct's element
propertyStruct.mElement = kAudioObjectPropertyElementMaster; propertyStruct.mElement = kAudioObjectPropertyElementMaster;
//get device ID
deviceID = [self getAVObjectID:device];
//block //block
// invoked when audio changes // invoked when audio changes
AudioObjectPropertyListenerBlock listenerBlock = ^(UInt32 inNumberAddresses, const AudioObjectPropertyAddress *inAddresses) AudioObjectPropertyListenerBlock listenerBlock = ^(UInt32 inNumberAddresses, const AudioObjectPropertyAddress *inAddresses)
@ -861,6 +857,17 @@ extern os_log_t logHandle;
} //macOS 13.3+ } //macOS 13.3+
}; };
//get device ID
deviceID = [self getAVObjectID:device];
if(0 == deviceID)
{
//err msg
os_log_error(logHandle, "ERROR: 'failed to find %{public}@'s object id", device.localizedName);
//bail
goto bail;
}
//add property listener for audio changes //add property listener for audio changes
status = AudioObjectAddPropertyListenerBlock(deviceID, &propertyStruct, self.eventQueue, listenerBlock); status = AudioObjectAddPropertyListenerBlock(deviceID, &propertyStruct, self.eventQueue, listenerBlock);
if(noErr != status) if(noErr != status)
@ -910,9 +917,6 @@ bail:
//init property struct's element //init property struct's element
propertyStruct.mElement = kAudioObjectPropertyElementMaster; propertyStruct.mElement = kAudioObjectPropertyElementMaster;
//get device ID
deviceID = [self getAVObjectID:device];
//block //block
// invoked when video changes // invoked when video changes
CMIOObjectPropertyListenerBlock listenerBlock = ^(UInt32 inNumberAddresses, const CMIOObjectPropertyAddress addresses[]) CMIOObjectPropertyListenerBlock listenerBlock = ^(UInt32 inNumberAddresses, const CMIOObjectPropertyAddress addresses[])
@ -994,6 +998,17 @@ bail:
} //macOS 13.3 } //macOS 13.3
}; };
//get device ID
deviceID = [self getAVObjectID:device];
if(0 == deviceID)
{
//err msg
os_log_error(logHandle, "ERROR: 'failed to find %{public}@'s object id", device.localizedName);
//bail
goto bail;
}
//register (add) property block listener //register (add) property block listener
status = CMIOObjectAddPropertyListenerBlock(deviceID, &propertyStruct, self.eventQueue, listenerBlock); status = CMIOObjectAddPropertyListenerBlock(deviceID, &propertyStruct, self.eventQueue, listenerBlock);
if(noErr != status) if(noErr != status)
@ -1195,6 +1210,17 @@ bail:
//get device ID //get device ID
deviceID = [self getAVObjectID:device]; deviceID = [self getAVObjectID:device];
if(0 == deviceID)
{
//err msg
os_log_error(logHandle, "ERROR: 'failed to find %{public}@'s object id", device.localizedName);
//set error
isRunning = -1;
//bail
goto bail;
}
//init size //init size
propertySize = sizeof(isRunning); propertySize = sizeof(isRunning);
@ -1204,7 +1230,7 @@ bail:
if(noErr != status) if(noErr != status)
{ {
//err msg //err msg
os_log_error(logHandle, "ERROR: getting status of audio device failed with %d", status); os_log_error(logHandle, "ERROR: failed to get run state for %{public}@ (error: %#x)", device.localizedName, status);
//set error //set error
isRunning = -1; isRunning = -1;
@ -1239,6 +1265,17 @@ bail:
//get device ID //get device ID
deviceID = [self getAVObjectID:device]; deviceID = [self getAVObjectID:device];
if(0 == deviceID)
{
//err msg
os_log_error(logHandle, "ERROR: 'failed to find %{public}@'s object id", device.localizedName);
//set error
isRunning = -1;
//bail
goto bail;
}
//init size //init size
propertySize = sizeof(isRunning); propertySize = sizeof(isRunning);
@ -1257,7 +1294,7 @@ bail:
if(noErr != status) if(noErr != status)
{ {
//err msg //err msg
os_log_error(logHandle, "ERROR: failed to get camera status (error: %#x)", status); os_log_error(logHandle, "ERROR: failed to get run state for %{public}@ (error: %#x)", device.localizedName, status);
//set error //set error
isRunning = -1; isRunning = -1;
@ -1285,6 +1322,14 @@ bail:
//get device ID //get device ID
deviceID = [NSNumber numberWithInt:[self getAVObjectID:event.device]]; deviceID = [NSNumber numberWithInt:[self getAVObjectID:event.device]];
if(0 == deviceID)
{
//err msg
os_log_error(logHandle, "ERROR: 'failed to find %{public}@'s object id", event.device.localizedName);
//bail
goto bail;
}
//extract its last event //extract its last event
deviceLastEvent = self.deviceEvents[deviceID]; deviceLastEvent = self.deviceEvents[deviceID];
@ -1631,21 +1676,21 @@ bail:
//dbg msg //dbg msg
os_log_debug(logHandle, "stopping audio monitor(s)"); os_log_debug(logHandle, "stopping audio monitor(s)");
//watch all input audio (mic) devices //unwatch all input audio (mic) devices
for(AVCaptureDevice* audioDevice in [AVCaptureDevice devicesWithMediaType:AVMediaTypeAudio]) for(AVCaptureDevice* audioDevice in [AVCaptureDevice devicesWithMediaType:AVMediaTypeAudio])
{ {
//stop (device) monitor //unwatch
[self unwatchAudioDevice:audioDevice]; [self unwatchAudioDevice:audioDevice];
} }
//dbg msg //dbg msg
os_log_debug(logHandle, "stopping video monitor(s)"); os_log_debug(logHandle, "stopping video monitor(s)");
//watch all input video (cam) devices //unwatch all input video (cam) devices
for(AVCaptureDevice* videoDevice in [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]) for(AVCaptureDevice* videoDevice in [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo])
{ {
//start (device) monitor //unwatch
[self unwatchVideoDevice:videoDevice]; [self unwatchVideoDevice:videoDevice];
} }
//dbg msg //dbg msg
@ -1675,9 +1720,24 @@ bail:
//property struct //property struct
AudioObjectPropertyAddress propertyStruct = {0}; AudioObjectPropertyAddress propertyStruct = {0};
//bail if device was disconnected
if(YES == device.isConnected)
{
//bail
goto bail;
}
//get device ID //get device ID
deviceID = [self getAVObjectID:device]; deviceID = [self getAVObjectID:device];
if(0 == deviceID)
{
//err msg
os_log_error(logHandle, "ERROR: 'failed to find %{public}@'s object id", device.localizedName);
//bail
goto bail;
}
//init property struct's selector //init property struct's selector
propertyStruct.mSelector = kAudioDevicePropertyDeviceIsRunningSomewhere; propertyStruct.mSelector = kAudioDevicePropertyDeviceIsRunningSomewhere;
@ -1721,8 +1781,23 @@ bail:
//property struct //property struct
CMIOObjectPropertyAddress propertyStruct = {0}; CMIOObjectPropertyAddress propertyStruct = {0};
//bail if device was disconnected
if(YES == device.isConnected)
{
//bail
goto bail;
}
//get device ID //get device ID
deviceID = [self getAVObjectID:device]; deviceID = [self getAVObjectID:device];
if(0 == deviceID)
{
//err msg
os_log_error(logHandle, "ERROR: 'failed to find %{public}@'s object id", device.localizedName);
//bail
goto bail;
}
//init property struct's selector //init property struct's selector
propertyStruct.mSelector = kAudioDevicePropertyDeviceIsRunningSomewhere; propertyStruct.mSelector = kAudioDevicePropertyDeviceIsRunningSomewhere;
@ -1747,11 +1822,11 @@ bail:
//dbg msg //dbg msg
os_log_debug(logHandle, "stopped monitoring %{public}@ (uuid: %{public}@ / %x) for video changes", device.localizedName, device.uniqueID, deviceID); os_log_debug(logHandle, "stopped monitoring %{public}@ (uuid: %{public}@ / %x) for video changes", device.localizedName, device.uniqueID, deviceID);
//unset listener block
self.cameraListeners[device.uniqueID] = nil;
bail: bail:
//always unset listener block
self.cameraListeners[device.uniqueID] = nil;
return; return;
} }

View File

@ -115,7 +115,7 @@ bail:
[UNUserNotificationCenter.currentNotificationCenter requestAuthorizationWithOptions:(UNAuthorizationOptionAlert) completionHandler:^(BOOL granted, NSError * _Nullable error) [UNUserNotificationCenter.currentNotificationCenter requestAuthorizationWithOptions:(UNAuthorizationOptionAlert) completionHandler:^(BOOL granted, NSError * _Nullable error)
{ {
//dbg msg //dbg msg
os_log_debug(logHandle, "permission to display notifications granted? %d (error: %@)", granted, error); os_log_debug(logHandle, "permission to display notifications granted? %d (error: %{public}@)", granted, error);
//not granted/error //not granted/error
if( (nil != error) || if( (nil != error) ||