Difference between various kIOPMAssertionType's - objective-c

What is the difference between kIOPMAssertionTypeNoIdleSleep, kIOPMAssertionTypePreventSystemSleep and kIOPMAssertionTypePreventUserIdleSystemSleep?
I am trying to create an IOPMAssertion that will prevent the mac from going to sleep autommatically but I really can't tell which of these I should use. I'm getting confused with their descriptions and cannot make sense of them (see the docs for this).
If you're curious, this is how I'm doing it in code:
IOReturn success = IOPMAssertionCreateWithName(kIOPMAssertionTypeNoIdleSleep, kIOPMAssertionLevelOn, CFSTR("My app is running"), &preventSleepAssertionID);
if (success != kIOReturnSuccess) {
NSLog(#"Could not create sleep prevention assertion");
}

Apple have published a Q&A note on this subject, which I believe answers your question. The key comments in the example code in question:
// kIOPMAssertionTypeNoDisplaySleep prevents display sleep,
// kIOPMAssertionTypeNoIdleSleep prevents idle sleep
The former prevents the screen dimming or turning off entirely. Use this if your app is going to be used in a way where the user won't be using the keyboard and mouse, e.g. video player or video chat.
The latter prevents the system itself from going to sleep, but allows the screen to dim and eventually switch off entirely. Useful for long-running computations and apps that only need e.g. audio.
The actual code mirrors what you've got:
//reasonForActivity is a descriptive string used by the system whenever it needs
// to tell the user why the system is not sleeping. For example,
// "Mail Compacting Mailboxes" would be a useful string.
// NOTE: IOPMAssertionCreateWithName limits the string to 128 characters.
CFStringRef* reasonForActivity= CFSTR("Describe Activity Type");
IOPMAssertionID assertionID;
IOReturn success = IOPMAssertionCreateWithName(kIOPMAssertionTypeNoDisplaySleep,
kIOPMAssertionLevelOn, reasonForActivity, &assertionID);
if (success == kIOReturnSuccess)
{
//Add the work you need to do without
// the system sleeping here.
success = IOPMAssertionRelease(assertionID);
//The system will be able to sleep again.
}
Power assertions can still be overridden by the user triggering sleep explicitly (e.g. closing the lid or selecting it in the  menu) or if the system is on battery power.
Are you having trouble getting your code to work?

The documentation for each value gives more information about what they do.
kIOPMAssertionTypePreventUserIdleSystemSleep
Prevents the system from sleeping automatically due to a lack of user activity. ... The system may still sleep for lid close, Apple menu, low battery, or other sleep reasons. This assertion does not put the system into Dark Wake.
kIOPMAssertionTypeNoIdleSleep
The system will not idle sleep when enabled. Note that the system may sleep for other reasons. ... the system will prefer to enter the Dark Wake state, or remain in Dark Wake if already there, rather than go to sleep.
kIOPMAssertionTypePreventSystemSleep
Prevents the system from sleeping and allows the system to reside in Dark Wake for an arbitrary length of time. ... the system will prefer to enter the Dark Wake state, or remain in Dark Wake if already there, rather than go to sleep.
This wording seems to imply that the first option prevents idle sleep due to lack of activity, the second option does the same but prefers to enter Dark Wake rather than sleep, and the third option entirely prevents sleep in favor of Dark Wake.
Looking at PMAssertions.c in the power management code, along with IOPMrootDomain.cpp in the iokit kernel code, it appears that kIOPMAssertionTypeNoIdleSleep is treated as an alias for kIOPMAssertionTypePreventUserIdleSystemSleep, whereas kIOPMAssertionTypePreventSystemSleep is handled differently. Setting kIOPMAssertionTypePreventSystemSleep creates a kernel assertion that entirely prevents system sleep except in extreme cases such as low battery or thermal emergency. Also, this only applies when the computer is connected to external power, unless a special flag is set.
In practice, it appears most Mac applications use kIOPMAssertionTypePreventUserIdleSystemSleep to prevent sleep while performing background tasks. For example Time Machine sets an assertion of this type while backing up. One exception is Internet Sharing, which uses kIOPMAssertionTypePreventSystemSleep to keep the computer awake indefinitely when connected to external power. Note that some users may find this behavior unexpected or undesirable.[1][2]
In summary:
If you want to prevent the computer from sleeping due to inactivity, use kIOPMAssertionTypePreventUserIdleSystemSleep.
Avoid using kIOPMAssertionTypePreventSystemSleep unless you have a
reason to entirely prevent system sleep.

Related

How to detect network disconnects (on an RTCPeerConnection) as soon as possible or the resulting frozen video?

I am using RTCPeerconnections to submit video and audio in a web-RTC-based video-messenger. I am able to detect network disconnects after approximately 7 seconds - yet, this is 7 seconds in which the user is staring at a frozen video and starts to randomly click buttons in the app. I would like to improve the user experience by shortening this timespan - e.g. by informing the user about a network issue if the video freezes for more than 1 second.
Status Quo: I am currently detecting respective situations by listening to the onconnectionstatechange event of the RTCPeerConnection. Yet, the event is only fired approximately 7 seconds after the disconnect. I determined the ~7 seconds by connecting two machines via normal WiFi, using a hardware switch on one of the laptops to switch off the wireless (such switches exist on some older Lenovo models / guarantee an immediate disconnect) and wait for the other machine to detect the event.
Consideration: The root cause being the interruption of the underlying network connection, it would be ideal to detect the changed network status as early as possible (even if its just transport delays). This said, the disturbance faced by the user ultimately stems from the video that instantly freezes when interrupting the network. If there was no way to detect the connection issue earlier, it could be an option to detect the frozen video instead. Is any of these two things possible (ideally event-driven, so that I don't need to poll things every second)?
Here's a very simple code snippet describing my current disconnect detection:
myRTCPeerConnection.onconnectionstatechange = (event: Event) => {
let newCS = myRTCPeerConnection.connectionState;
if (newCS == "disconnected" || newCS == "failed" || newCS == "closed") {
//do something on disconnect - e.g. show messages to user and start reconnect
}
}
(ice)connectionstatechange is the right event in general.
If you want more granularity you'll need to poll getStats and looks for stats like framesReceived. But there is no guaranteed frame rate sent from the other side (e.g. in screensharing you go below 1/s).
While the actual ICE statistics like requestsSent seem more useful they happen much less frequently, only once per second and you can loose a packet or it comes late.
In general this is a question of how reliable the detection of the network failure is. If it is too aggressive you end up with a poor UX showing a warning too often.
You might not end up that is significantly better than at the cost of introducing complexity that you need to maintain.
Thanks Philipp for your insights - this pointed me into the right direction.
I'm now looking into using getStats to identify any freezes. At first sight, polling the framesPerSecond value seems most promising to me. The good thing: it reacts instantly upon disconnect - and - it still works when the underlying video stream is paused (i'm allowing the user to pause video submission / implemented it by setting all video tracks to enabled = false). I.e. even if the video tracks are disabled on the sending side, the receiving side still continues to receive the agreed frames per second.
As the usage of the getStats function appears weak on documentation at the time of this being written / there's rarely a simple examples for its usage, please find my code extract below:
peerRTCPC
.getReceivers()
.forEach(
(
receiver: RTCRtpReceiver,
index: number,
array: RTCRtpReceiver[]
) => {
if (receiver.track.kind == "video") {
receiver.getStats().then((myStatsReport: RTCStatsReport) => {
myStatsReport.forEach(
(statValue: any, key: string, parent: RTCStatsReport) => {
if (statValue.type == "inbound-rtp") {
console.log(
"The PC stats returned the framesPerSecond value " +
statValue["framesPerSecond"] +
" while the full inbound-rtp stats reflect as " +
JSON.stringify(statValue)
);
}
}
);
});
}
}
);
Note that upon disconnect, the framesPerSecond do not necessarily go to zero, even though the webRTCInternals screen suggests the same. I am seeing undefined when a disconnect happens.
Runtime impact of polling this at high frequency / across larger numbers of connections probably needs to be looked at more closely. Yet, this seems like a good step into the right direction unless doing it way to frequently.

How to program factory reset switch in a small embedded device

I am building a small embedded device. I am using a reset switch, and when this is pressed for more than 5 seconds, the whole device should reset and clear all the data and go to factory reset state.
I know what to clear when this event happens. What I want to know is how do I raise this event? I mean when switch is pressed, how do I design the system to know that 5 seconds have elapsed and I have to reset now. I need high level design with any timers and interrupts. Can some one please help me?
Depends on the device. But few rough ideas:
Possibly the device manual may say about the number of interrupts per second that is produced by "holding down the switch" (switch down). If you have this value, you can easily calculate the 5 seconds.
If not, you would need to use timer too. Start the timer when you get the first interrupt of "switch down" and count up to 5 seconds.
Note that, You should also monitor for "switch up", that is, "release of switch". I hope there will be an interrupt for that too. (Possibly with different status value).
So you should break the above loop (you shouldn't do the reset) when you see this interrupt.
Hope this helps.
Interrupt-driven means low level, close to the hardware. An interrupt-driven solution, with for example a bare metal microcontroller, would look like this:
Like when reading any other switch, sample the switch n number of times and filter out the signal bounce (and potential EMI).
Start a hardware timer. Usually the on-chip timers are far too fast to count a whole 5 seconds, even when you set it to run as slow as possible. So you need to set the timer with a pre-scale value, picked so that one whole timer cycle equals a known time unit (like for example 10 milliseconds).
Upon timer overflow, trigger an interrupt. Inside the interrupt, check that the switch is still pressed, then increase a counter. When the counter reaches a given value, execute the reset code. For example, if you get a timer overflow every 10 milliseconds, your counter should count up to 5000ms/10ms = 500.
If the switch is released before the time is elapsed, reset the counter and stop the timer interrupt.
How to reset the system is highly system-specific. You should put the system in a safe system, then overwrite your current settings by overwriting the NVM where settings is stored with some default factory settings stored elsewhere in NVM. Once that is done, you should force the processor to reset itself and reboot with the new settings in place.
This means that you must have a system with electronically-erasable NVM. Depending on the size of the data, this NVM could either be data flash on-chip in a microcontroller, or some external memory circuit.
Detecting a 5S or 30S timeout can be done using a GPIO on an interrupt.
If using an rtos,
. Interrupt would wake a thread from sleep and disables itself,
. All the thread does is count the time the switch is pressed for (you scan the switch at regular intervals)
. If the switch is pressed for desired time set a global variable/setting in eeprom which will trigger the factory reset function
. Else enable the interrupt again and put the thread to sleep
. Also, use a de-bounce circuit to avoid issues.
Also define what do you mean by factory reset?
There are two kinds in general, both cases I will help using eeprom
Revert all configurations (Low cost, easier)
In this case, you partition the eeprom, have a working configuration and factory configuration. You copy over the factory configurations to the working partition and perform a software reset
Restore complete firmware (Costly, needs more testing)
This is more tricky, but can be done with help of bootloaders that allow for flashing from eeprom/or sd card.
In this case the binary firmware blob will also be stored with the factory configuration, in the safe partition and will be used to flash controller flash and configurations.
All depends on the size/memory and cost. can be designed in many more ways, i am just laying out simplest examples.
I created some products with a combined switch to. I did so by using a capacitator to initiate a reset pulse on the reset pin of the device (current and levels limit by some resistors and/or diodes). At start-up I monitor the state of the input pin connected to the switch. I simply wait until this pin goes height with a time-out of 5 seconds. In case of a time-out I reset my configuration to default.

Reducing memory size to ensure backgrounding in iOS

When developing an app that uses Bluetooth Low Energy, there comes a time when the iOS device loses connection to the peripheral. (Sometimes for hours.)
In order to reconnect to an existing peripheral, the app must constantly scan in the background at a specific rate throughout the day(s), even when the app is backgrounded.
The problem is, iOS will not guarantee that your app will not get killed, due to memory constraints, etc.
Information found in the iPhone OS Programming guide states that:
Apps that work with Bluetooth peripherals can ask to be woken up if
the peripheral delivers an update when the app is suspended. This
support is important for Bluetooth-le accessories that deliver data at
regular intervals, such as a Bluetooth heart rate belt. When an app
includes the UIBackgroundModes key with the bluetooth-central value in
its Info.plist file, the Core Bluetooth framework keeps open any
active sessions for the corresponding peripheral. In addition, new
data arriving from the peripheral causes the system to wake up the app
so that it can process the data. The system also wakes up the app to
process accessory connection and disconnection notifications.
The problem does not arise when the phone is connected to a device and the application is background. It does happen, however, when the device is disconnected and the app is backgrounded. In this specific case, the phone is no longer connected to the peripheral, and therefore no longer getting notifications.
Many people have discussed this before, either on Stack Overflow or the Apple forums, and I believe one of the Apple developers has responded saying:
We're aware of this issue and are trying to come up with a solution.
Currently, there is no workaround."
My question is, is there a way to at least improve your chances of not getting killed by iOS due to memory constraints?
For example, an instant messaging app (IMO) seems to run quite nicely in the background. After days and days of not being used, the app will wake up and display a gChat message.
I’m questioning things such as
Strong pointers
Overall memory size
Reducing memory size when app is backgrounded or minimized
Reducing frequency of background operation
Etc.
Why do you need background execution even when the bluetooth hardware is disconnected?
I don't think that you need to "rescan continuously" to reconnect again, if the hardware is "paired" with the iPhone/iPad, it will reconnect itself. Like a bluetooth headset. Or not?
AFAIK you have no chances to accomplish what you are asking for.
A normal App is always suspended when the user go back to home. The app has approx. 5 secs of background time to stop timers, save state ecc ecc.
There are special background modes that allows you to have more background time, and each of this mode (explained in the page you linked) has a different behavior.
About the bluetooth mode:
The descripted behavior is not an issue, but it's by design:
the app is suspended
when the app is suspended, it can be killed by the OS to free ram (and there are no tricks to avoid this), but the system will wake up if needed.
the app is then awaken every time a notification is received (awaken from suspended state or lauched from "previously-killed" state)
the app has 10 seconds to do tasks (save informations, ecc ecc). Moreover, can request +10 mins. of background time for a particular task
after the 10 secs (or 10 min) the app is suspended again
The example you wrote about the chat app is incorrect: chat apps usually doesn't use any background mode, simply they forward you messages using push notifications. When you open the app, the app connect to a server that stores all your messages and download it.
You can get "more uptime" using location background mode (routing app can work in background), or using a combination of significative location changes (the app is awaken) and the 10 minutes background time, but I think that Apple will reject an app that "abuse" this.
Shortly, you have to design your app to support this behavior.
I found this in some more Apple documentation:
Memory Usage for Background Apps
Every app should free up as much memory as is practical upon entering
the background. The system tries to keep as many apps in memory at the
same time as it can, but when memory runs low it terminates suspended
apps to reclaim that memory. Apps that consume large amounts of memory
while in the background are the first apps to be terminated.
Practically speaking, your app should remove strong references to
objects as soon as they are no longer needed. Removing strong
references gives the compiler the ability to release the objects right
away so that the corresponding memory can be reclaimed. However, if
you want to cache some objects to improve performance, you can wait
until the app transitions to the background before removing references
to them.
Some examples of objects that you should remove strong references to
as soon as possible include:
Image objects
Large media or data files that you can load again from disk Any other
objects that your app does not need and can recreate easily later To
help reduce your app’s memory footprint, the system automatically
purges some data allocated on behalf of your app when your app moves
to the background.
The system purges the backing store for all Core Animation layers.
This effort does not remove your app’s layer objects from memory, nor
does it change the current layer properties. It simply prevents the
contents of those layers from appearing onscreen, which given that the
app is in the background should not happen anyway. It removes any
system references to cached images. (If your app does not have a
strong reference to the images, they are subsequently removed from
memory.) It removes strong references to some other system-managed
data caches.
From the apple documentation i have always assumed the following:
connectPeripheral:options:
Establish a connection to the peripheral.
- (void)connectPeripheral:(CBPeripheral *)peripheral options:(NSDictionary *)options;
Parameters
peripheral
The peripheral to connect to.
options
A dictionary to customize the behavior of the connection. See CBConnectPeripheralOptionNotifyOnDisconnectionKey.
Discussion
**This never times out**. Use cancelPeripheralConnection: to cancel a pending connection.'
With the important part being on the fact that this never times out. I would assume this would hand off to the system so that it will connect automatically to the peripheral when it comes into range, thus removing the need for full backgrounding. Someone correct me if im wrong though!

Notification after user becomes idle on OS X?

What's the best way of detecting when a user has been idle for X amount of time, and then detect when the user becomes immediately active?
I know there's NSWorkspace which provides will/did sleep/wake notifications, but I can't rely on that because the sleep setting is usually about ~15 minutes to never. I need to be able to detect if the user's been idle for ~1-2 minutes.
This answer provides a way to get the idle time. I'd like to avoid polling if possible.
Polling is your only option, to my knowledge. As user1118321 points out, polling every O(minutes) is unlikely to cause any problems, performance or otherwise.
If your app has a GUI and receives UI events anyway, you could install a handler via +[NSEvent addLocalMonitorForEventsMatchingMask:handler:] that resets your timer on each event. That'll help reduce if not eliminate polls when the user is consistently active, in your own app at least.
Once you've determined that the user has been idle long enough, you could then install a global event tap to watch for the next event. See for example -[NSEvent addGlobalMonitorForEventsMatchingMask:handler:].
Note: you should use CGEventSourceSecondsSinceLastEventType if at all possible rather than poking into the IO registry. It's a formal, supported API and may be more efficient. Not to mention it's way simpler. There's also UKIdleTimer though it relies on Carbon, so may not be applicable.

Need iOS reference for what happens in sleep, standby and/or idle modes

I'm a new ObjC dev and after searching the Web and Apple's developer docs, I can't find a good succinct explanation of the various iOS device modes, and what goes on in these modes. I see a lot of little discussions, but nothing overarching about the big picture.
For example, I see that some Alarm applications for iPhone/iPad claim to be able to execute alarms (presumably not just system alerts) in the morning. I'm struggling to understand how that happens, even if the user lets the app just keep running overnight, assuming the device goes into sleep mode after no use.
So I don't know what happens when the device goes into sleep or standby mode. Is it just the screen dimming? Does the application in the foreground continue to execute code, go into some interim state like background mode in a saved state, or does it completely (even if temporarily) shut down?
I'd just like to be pointed to a website, a book or the portion of the Apple documentation that explains the various device states, what's going on under iOS 3 & 4 with the application in each state, and how to manage that if you'd like to build an app similar to a simulated bedside alarm clock that's "always on," etc.
Thanks in advance.
Those 'alarms' are Local Notifications, and are very handy. They're fired even when an application is closed, and even when the device is asleep.
The concept of asleep is not too tricky; when the user 'quits' your application (pressing the home button), your application will either be halted and placed into a frozen state (4.x), or quit entirely (3.x). Nonetheless, you are given the opportunity to do a few cleanup operations before the latter happens with the - (void)applicationWillTerminate:(UIApplication *)application method, and before the former happens with the - (void)applicationDidEnterBackground:(UIApplication *)application method (both are called upon your delegate class).
The concept of 'sleep' means that in both iPhone OS 3 and iOS 4 you'll receive the following method when your app loses focus (and also when an SMS comes in, or an alert, etc):
- (void)applicationWillResignActive:(UIApplication *)application
Really, most applications (with the exceptions of applications that are designed to work in the background, like voip, audio streaming, etc) simply quit on close. But if you need to, you can also suspend the freezing of your app and ask for more time to complete a task.
This was a lot easier to grasp in the 3.x days, but now with 4.x's 'multitasking' it becomes a bit harder. It's not too daunting though, and a read of this will help a bit.
This may be of help:
http://developer.apple.com/library/ios/#documentation/UIKit/Reference/UIApplication_Class/Reference/Reference.html
see the applicationState for UIApplicationState.