improved handling of device off/inactive events
This commit is contained in:
parent
dbcecf60c4
commit
c4c97f2f2c
|
@ -52,6 +52,9 @@
|
||||||
//audio listeners
|
//audio listeners
|
||||||
@property(nonatomic, retain)NSMutableDictionary* audioListeners;
|
@property(nonatomic, retain)NSMutableDictionary* audioListeners;
|
||||||
|
|
||||||
|
//camera listeners
|
||||||
|
@property(nonatomic, retain)NSMutableDictionary* cameraListeners;
|
||||||
|
|
||||||
//per device events
|
//per device events
|
||||||
@property(nonatomic, retain)NSMutableDictionary* deviceEvents;
|
@property(nonatomic, retain)NSMutableDictionary* deviceEvents;
|
||||||
|
|
||||||
|
|
|
@ -56,9 +56,12 @@ extern os_log_t logHandle;
|
||||||
//init camera attributions
|
//init camera attributions
|
||||||
self.cameraAttributions = [NSMutableArray array];
|
self.cameraAttributions = [NSMutableArray array];
|
||||||
|
|
||||||
//init audio listener
|
//init audio listeners
|
||||||
self.audioListeners = [NSMutableDictionary dictionary];
|
self.audioListeners = [NSMutableDictionary dictionary];
|
||||||
|
|
||||||
|
//init video listeners
|
||||||
|
self.cameraListeners = [NSMutableDictionary dictionary];
|
||||||
|
|
||||||
//set up delegate
|
//set up delegate
|
||||||
UNUserNotificationCenter.currentNotificationCenter.delegate = self;
|
UNUserNotificationCenter.currentNotificationCenter.delegate = self;
|
||||||
|
|
||||||
|
@ -232,7 +235,7 @@ extern os_log_t logHandle;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
//cameraAttributionsList list?
|
//cameraAttributions list?
|
||||||
if(YES == [line hasPrefix:@"cameraAttributions = "])
|
if(YES == [line hasPrefix:@"cameraAttributions = "])
|
||||||
{
|
{
|
||||||
//set flag
|
//set flag
|
||||||
|
@ -628,6 +631,9 @@ extern os_log_t logHandle;
|
||||||
goto bail;
|
goto bail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//save
|
||||||
|
self.audioListeners[device.uniqueID] = listenerBlock;
|
||||||
|
|
||||||
//dbg msg
|
//dbg msg
|
||||||
os_log_debug(logHandle, "monitoring %{public}@ for audio changes", device.localizedName);
|
os_log_debug(logHandle, "monitoring %{public}@ for audio changes", device.localizedName);
|
||||||
|
|
||||||
|
@ -648,6 +654,7 @@ bail:
|
||||||
//status var
|
//status var
|
||||||
OSStatus status = -1;
|
OSStatus status = -1;
|
||||||
|
|
||||||
|
//device id
|
||||||
CMIOObjectID deviceID = 0;
|
CMIOObjectID deviceID = 0;
|
||||||
|
|
||||||
//property struct
|
//property struct
|
||||||
|
@ -697,13 +704,15 @@ bail:
|
||||||
goto bail;
|
goto bail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//save
|
||||||
|
self.cameraListeners[device.uniqueID] = listenerBlock;
|
||||||
|
|
||||||
//dbg msg
|
//dbg msg
|
||||||
os_log_debug(logHandle, "monitoring %{public}@ for video changes", device.localizedName);
|
os_log_debug(logHandle, "monitoring %{public}@ for video changes", device.localizedName);
|
||||||
|
|
||||||
//happy
|
//happy
|
||||||
bRegistered = YES;
|
bRegistered = YES;
|
||||||
|
|
||||||
//bail
|
|
||||||
bail:
|
bail:
|
||||||
|
|
||||||
return bRegistered;
|
return bRegistered;
|
||||||
|
@ -995,7 +1004,7 @@ bail:
|
||||||
//external device?
|
//external device?
|
||||||
// don't show notification
|
// don't show notification
|
||||||
if( (YES != [self.builtInMic.uniqueID isEqualToString:event.device.uniqueID]) &&
|
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
|
//set result
|
||||||
result = NOTIFICATION_SKIPPED;
|
result = NOTIFICATION_SKIPPED;
|
||||||
|
@ -1012,13 +1021,10 @@ bail:
|
||||||
// check last device that turned off
|
// check last device that turned off
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//wait
|
|
||||||
// since logging event might come thru first
|
|
||||||
[NSThread sleepForTimeInterval:1.0f];
|
|
||||||
|
|
||||||
//mic
|
//mic
|
||||||
// check last mic off device
|
// 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]) )
|
(YES != [self.builtInMic.uniqueID isEqualToString:self.lastMicOff.uniqueID]) )
|
||||||
{
|
{
|
||||||
//set result
|
//set result
|
||||||
|
@ -1033,8 +1039,9 @@ bail:
|
||||||
|
|
||||||
//camera
|
//camera
|
||||||
// check last camera off device
|
// check last camera off device
|
||||||
if( (event.deviceType = Device_Camera) &&
|
if( (Device_Camera == event.deviceType) &&
|
||||||
(YES != [self.builtInMic.uniqueID isEqualToString:self.lastCameraOff.uniqueID]) )
|
(nil != self.lastCameraOff) &&
|
||||||
|
(YES != [self.builtInCamera.uniqueID isEqualToString:self.lastCameraOff.uniqueID]) )
|
||||||
{
|
{
|
||||||
//set result
|
//set result
|
||||||
result = NOTIFICATION_SKIPPED;
|
result = NOTIFICATION_SKIPPED;
|
||||||
|
@ -1288,12 +1295,125 @@ bail:
|
||||||
//stop monitor
|
//stop monitor
|
||||||
-(void)stop
|
-(void)stop
|
||||||
{
|
{
|
||||||
|
//dbg msg
|
||||||
|
os_log_debug(logHandle, "stopping log monitor");
|
||||||
|
|
||||||
//stop log monitoring
|
//stop log monitoring
|
||||||
[self.logMonitor stop];
|
[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;
|
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
|
# pragma mark UNNotificationCenter Delegate Methods
|
||||||
|
|
||||||
//handle user response to notification
|
//handle user response to notification
|
||||||
|
|
|
@ -94,7 +94,7 @@
|
||||||
</connections>
|
</connections>
|
||||||
</button>
|
</button>
|
||||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" preferredMaxLayoutWidth="156" translatesAutoresizingMaskIntoConstraints="NO" id="xbe-1S-lpy">
|
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" preferredMaxLayoutWidth="156" translatesAutoresizingMaskIntoConstraints="NO" id="xbe-1S-lpy">
|
||||||
<rect key="frame" x="72" y="326" width="114" height="15"/>
|
<rect key="frame" x="72" y="327" width="114" height="15"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
<textFieldCell key="cell" sendsActionOnEndEditing="YES" title="Start at Login" id="JVI-Or-h0u">
|
<textFieldCell key="cell" sendsActionOnEndEditing="YES" title="Start at Login" id="JVI-Or-h0u">
|
||||||
<font key="font" size="13" name="Menlo-Bold"/>
|
<font key="font" size="13" name="Menlo-Bold"/>
|
||||||
|
@ -103,7 +103,7 @@
|
||||||
</textFieldCell>
|
</textFieldCell>
|
||||||
</textField>
|
</textField>
|
||||||
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" allowsCharacterPickerTouchBarItem="YES" preferredMaxLayoutWidth="471" translatesAutoresizingMaskIntoConstraints="NO" id="tFB-E4-zbp">
|
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" allowsCharacterPickerTouchBarItem="YES" preferredMaxLayoutWidth="471" translatesAutoresizingMaskIntoConstraints="NO" id="tFB-E4-zbp">
|
||||||
<rect key="frame" x="72" y="309" width="475" height="15"/>
|
<rect key="frame" x="72" y="310" width="475" height="15"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
<textFieldCell key="cell" sendsActionOnEndEditing="YES" title="Automatically (re)start each time you login." id="E0T-Ug-P8f">
|
<textFieldCell key="cell" sendsActionOnEndEditing="YES" title="Automatically (re)start each time you login." id="E0T-Ug-P8f">
|
||||||
<font key="font" size="13" name="Menlo-Regular"/>
|
<font key="font" size="13" name="Menlo-Regular"/>
|
||||||
|
@ -123,7 +123,7 @@
|
||||||
</connections>
|
</connections>
|
||||||
</button>
|
</button>
|
||||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" preferredMaxLayoutWidth="156" translatesAutoresizingMaskIntoConstraints="NO" id="Kjh-jc-STu">
|
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" preferredMaxLayoutWidth="156" translatesAutoresizingMaskIntoConstraints="NO" id="Kjh-jc-STu">
|
||||||
<rect key="frame" x="72" y="264" width="98" height="15"/>
|
<rect key="frame" x="72" y="265" width="98" height="15"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="No Icon Mode" id="4EN-j2-enV">
|
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="No Icon Mode" id="4EN-j2-enV">
|
||||||
<font key="font" size="13" name="Menlo-Bold"/>
|
<font key="font" size="13" name="Menlo-Bold"/>
|
||||||
|
@ -143,7 +143,7 @@
|
||||||
</connections>
|
</connections>
|
||||||
</button>
|
</button>
|
||||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" preferredMaxLayoutWidth="262" translatesAutoresizingMaskIntoConstraints="NO" id="Enr-tn-mwG">
|
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" preferredMaxLayoutWidth="262" translatesAutoresizingMaskIntoConstraints="NO" id="Enr-tn-mwG">
|
||||||
<rect key="frame" x="72" y="201" width="177" height="15"/>
|
<rect key="frame" x="72" y="202" width="177" height="15"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Ignore External Device" id="a5n-tt-65v">
|
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Ignore External Device" id="a5n-tt-65v">
|
||||||
<font key="font" size="13" name="Menlo-Bold"/>
|
<font key="font" size="13" name="Menlo-Bold"/>
|
||||||
|
@ -152,7 +152,7 @@
|
||||||
</textFieldCell>
|
</textFieldCell>
|
||||||
</textField>
|
</textField>
|
||||||
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" allowsCharacterPickerTouchBarItem="YES" preferredMaxLayoutWidth="471" translatesAutoresizingMaskIntoConstraints="NO" id="AAL-QY-azK">
|
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" allowsCharacterPickerTouchBarItem="YES" preferredMaxLayoutWidth="471" translatesAutoresizingMaskIntoConstraints="NO" id="AAL-QY-azK">
|
||||||
<rect key="frame" x="72" y="184" width="522" height="15"/>
|
<rect key="frame" x="72" y="185" width="522" height="15"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
<textFieldCell key="cell" sendsActionOnEndEditing="YES" title="Do not show an alert when external devices trigger an event." id="SYJ-Qv-cRq">
|
<textFieldCell key="cell" sendsActionOnEndEditing="YES" title="Do not show an alert when external devices trigger an event." id="SYJ-Qv-cRq">
|
||||||
<font key="font" size="13" name="Menlo-Regular"/>
|
<font key="font" size="13" name="Menlo-Regular"/>
|
||||||
|
@ -172,7 +172,7 @@
|
||||||
</connections>
|
</connections>
|
||||||
</button>
|
</button>
|
||||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" preferredMaxLayoutWidth="262" translatesAutoresizingMaskIntoConstraints="NO" id="K3U-Od-Xdy">
|
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" preferredMaxLayoutWidth="262" translatesAutoresizingMaskIntoConstraints="NO" id="K3U-Od-Xdy">
|
||||||
<rect key="frame" x="72" y="149" width="200" height="15"/>
|
<rect key="frame" x="72" y="150" width="200" height="15"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Disable 'Inactive' Alerts" id="Gsa-fn-iag">
|
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Disable 'Inactive' Alerts" id="Gsa-fn-iag">
|
||||||
<font key="font" size="13" name="Menlo-Bold"/>
|
<font key="font" size="13" name="Menlo-Bold"/>
|
||||||
|
@ -181,7 +181,7 @@
|
||||||
</textFieldCell>
|
</textFieldCell>
|
||||||
</textField>
|
</textField>
|
||||||
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" allowsCharacterPickerTouchBarItem="YES" preferredMaxLayoutWidth="471" translatesAutoresizingMaskIntoConstraints="NO" id="5xo-jp-5qA">
|
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" allowsCharacterPickerTouchBarItem="YES" preferredMaxLayoutWidth="471" translatesAutoresizingMaskIntoConstraints="NO" id="5xo-jp-5qA">
|
||||||
<rect key="frame" x="72" y="132" width="522" height="15"/>
|
<rect key="frame" x="72" y="133" width="522" height="15"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
<textFieldCell key="cell" sendsActionOnEndEditing="YES" title="Do not show an alert when the camera/microphone is deactivated. " id="1A2-j2-kqG">
|
<textFieldCell key="cell" sendsActionOnEndEditing="YES" title="Do not show an alert when the camera/microphone is deactivated. " id="1A2-j2-kqG">
|
||||||
<font key="font" size="13" name="Menlo-Regular"/>
|
<font key="font" size="13" name="Menlo-Regular"/>
|
||||||
|
@ -201,7 +201,7 @@
|
||||||
</connections>
|
</connections>
|
||||||
</button>
|
</button>
|
||||||
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" allowsCharacterPickerTouchBarItem="YES" preferredMaxLayoutWidth="471" translatesAutoresizingMaskIntoConstraints="NO" id="xaO-g8-rdS">
|
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" allowsCharacterPickerTouchBarItem="YES" preferredMaxLayoutWidth="471" translatesAutoresizingMaskIntoConstraints="NO" id="xaO-g8-rdS">
|
||||||
<rect key="frame" x="72" y="247" width="475" height="15"/>
|
<rect key="frame" x="72" y="248" width="475" height="15"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
<textFieldCell key="cell" sendsActionOnEndEditing="YES" title="Run without showing an icon in the status menu bar." id="SG5-YM-BoV">
|
<textFieldCell key="cell" sendsActionOnEndEditing="YES" title="Run without showing an icon in the status menu bar." id="SG5-YM-BoV">
|
||||||
<font key="font" size="13" name="Menlo-Regular"/>
|
<font key="font" size="13" name="Menlo-Regular"/>
|
||||||
|
|
Loading…
Reference in New Issue