From c4c97f2f2c977bf663b788b406527ce731286acc Mon Sep 17 00:00:00 2001 From: Patrick Wardle Date: Fri, 11 Nov 2022 17:06:25 -1000 Subject: [PATCH] improved handling of device off/inactive events --- Application/Application/AVMonitor.h | 3 + Application/Application/AVMonitor.m | 142 ++++++++++++++++++++++-- Application/Application/Preferences.xib | 16 +-- 3 files changed, 142 insertions(+), 19 deletions(-) diff --git a/Application/Application/AVMonitor.h b/Application/Application/AVMonitor.h index 0053956..75db62b 100644 --- a/Application/Application/AVMonitor.h +++ b/Application/Application/AVMonitor.h @@ -52,6 +52,9 @@ //audio listeners @property(nonatomic, retain)NSMutableDictionary* audioListeners; +//camera listeners +@property(nonatomic, retain)NSMutableDictionary* cameraListeners; + //per device events @property(nonatomic, retain)NSMutableDictionary* deviceEvents; diff --git a/Application/Application/AVMonitor.m b/Application/Application/AVMonitor.m index 738b078..8c9e078 100644 --- a/Application/Application/AVMonitor.m +++ b/Application/Application/AVMonitor.m @@ -56,9 +56,12 @@ extern os_log_t logHandle; //init camera attributions self.cameraAttributions = [NSMutableArray array]; - //init audio listener + //init audio listeners self.audioListeners = [NSMutableDictionary dictionary]; + //init video listeners + self.cameraListeners = [NSMutableDictionary dictionary]; + //set up delegate UNUserNotificationCenter.currentNotificationCenter.delegate = self; @@ -232,7 +235,7 @@ extern os_log_t logHandle; continue; } - //cameraAttributionsList list? + //cameraAttributions list? if(YES == [line hasPrefix:@"cameraAttributions = "]) { //set flag @@ -628,6 +631,9 @@ extern os_log_t logHandle; goto bail; } + //save + self.audioListeners[device.uniqueID] = listenerBlock; + //dbg msg os_log_debug(logHandle, "monitoring %{public}@ for audio changes", device.localizedName); @@ -648,6 +654,7 @@ bail: //status var OSStatus status = -1; + //device id CMIOObjectID deviceID = 0; //property struct @@ -697,13 +704,15 @@ bail: goto bail; } + //save + self.cameraListeners[device.uniqueID] = listenerBlock; + //dbg msg os_log_debug(logHandle, "monitoring %{public}@ for video changes", device.localizedName); //happy bRegistered = YES; -//bail bail: return bRegistered; @@ -995,7 +1004,7 @@ bail: //external device? // don't show notification if( (YES != [self.builtInMic.uniqueID isEqualToString:event.device.uniqueID]) && - (YES != [self.builtInCamera.uniqueID isEqualToString:event.device.uniqueID]) ) + (YES != [self.builtInCamera.uniqueID isEqualToString:event.device.uniqueID]) ) { //set result result = NOTIFICATION_SKIPPED; @@ -1012,13 +1021,10 @@ bail: // check last device that turned off else { - //wait - // since logging event might come thru first - [NSThread sleepForTimeInterval:1.0f]; - //mic // check last mic off device - if( (event.deviceType = Device_Microphone) && + if( (Device_Microphone == event.deviceType) && + (nil != self.lastMicOff) && (YES != [self.builtInMic.uniqueID isEqualToString:self.lastMicOff.uniqueID]) ) { //set result @@ -1033,8 +1039,9 @@ bail: //camera // check last camera off device - if( (event.deviceType = Device_Camera) && - (YES != [self.builtInMic.uniqueID isEqualToString:self.lastCameraOff.uniqueID]) ) + if( (Device_Camera == event.deviceType) && + (nil != self.lastCameraOff) && + (YES != [self.builtInCamera.uniqueID isEqualToString:self.lastCameraOff.uniqueID]) ) { //set result result = NOTIFICATION_SKIPPED; @@ -1288,12 +1295,125 @@ bail: //stop monitor -(void)stop { + //dbg msg + os_log_debug(logHandle, "stopping log monitor"); + //stop log monitoring [self.logMonitor stop]; + //dbg msg + os_log_debug(logHandle, "stopping audio monitor(s)"); + + //watch all input audio (mic) devices + for(AVCaptureDevice* audioDevice in [AVCaptureDevice devicesWithMediaType:AVMediaTypeAudio]) + { + //stop (device) monitor + [self unwatchAudioDevice:audioDevice]; + } + + //dbg msg + os_log_debug(logHandle, "stopping video monitor(s)"); + + //watch all input video (cam) devices + for(AVCaptureDevice* videoDevice in [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]) + { + //start (device) monitor + [self unwatchVideoDevice:videoDevice]; + } + + //dbg msg + os_log_debug(logHandle, "all stopped..."); + return; } +//stop audio monitor +-(void)unwatchAudioDevice:(AVCaptureDevice*)device +{ + //status + OSStatus status = -1; + + //device ID + AudioObjectID deviceID = 0; + + //property struct + AudioObjectPropertyAddress propertyStruct = {0}; + + //get device ID + deviceID = [self getAVObjectID:device]; + + //init property struct's selector + propertyStruct.mSelector = kAudioDevicePropertyDeviceIsRunningSomewhere; + + //init property struct's scope + propertyStruct.mScope = kAudioObjectPropertyScopeGlobal; + + //init property struct's element + propertyStruct.mElement = kAudioObjectPropertyElementMaster; + + //remove + status = AudioObjectRemovePropertyListenerBlock(deviceID, &propertyStruct, dispatch_get_main_queue(), self.audioListeners[device.uniqueID]); + if(noErr != status) + { + //err msg + os_log_error(logHandle, "ERROR: 'AudioObjectRemovePropertyListenerBlock' failed with %d", status); + + //bail + goto bail; + } + + //unset listener block + self.audioListeners[device.uniqueID] = nil; + +bail: + + return; +} + +//stop video monitor +-(void)unwatchVideoDevice:(AVCaptureDevice*)device +{ + //status + OSStatus status = -1; + + //device id + CMIOObjectID deviceID = 0; + + //property struct + CMIOObjectPropertyAddress propertyStruct = {0}; + + //get device ID + deviceID = [self getAVObjectID:device]; + + //init property struct's selector + propertyStruct.mSelector = kAudioDevicePropertyDeviceIsRunningSomewhere; + + //init property struct's scope + propertyStruct.mScope = kAudioObjectPropertyScopeGlobal; + + //init property struct's element + propertyStruct.mElement = kAudioObjectPropertyElementMaster; + + //remove + status = CMIOObjectRemovePropertyListenerBlock(deviceID, &propertyStruct, dispatch_get_main_queue(), self.cameraListeners[device.uniqueID]); + if(noErr != status) + { + //err msg + os_log_error(logHandle, "ERROR: 'AudioObjectRemovePropertyListenerBlock' failed with %d", status); + + //bail + goto bail; + } + + //unset listener block + self.cameraListeners[device.uniqueID] = nil; + +bail: + + return; + +} + # pragma mark UNNotificationCenter Delegate Methods //handle user response to notification diff --git a/Application/Application/Preferences.xib b/Application/Application/Preferences.xib index cd65cbc..bfcb894 100644 --- a/Application/Application/Preferences.xib +++ b/Application/Application/Preferences.xib @@ -94,7 +94,7 @@ - + @@ -103,7 +103,7 @@ - + @@ -123,7 +123,7 @@ - + @@ -143,7 +143,7 @@ - + @@ -152,7 +152,7 @@ - + @@ -172,7 +172,7 @@ - + @@ -181,7 +181,7 @@ - + @@ -201,7 +201,7 @@ - +