I’m running into a bit of a problem with AudioTimeStamps on the iPhone. When I’m running my application in the simulator the AudioTimeStamp.mHostTime appears to be in nanoseconds (1,000,000,000th of a second) whereas when running on my device (iPod Touch 2G) the frequency appears to be about 6,000,000th of a second.
It appears that on OS X there is a function (AudioConvertHostTimeToNanos in CoreAudio/CoreAudioTypes.h) to convert HostTime to and from nanoseconds, but this function is not in the iPhone headers.
Is there any way to find out the rate of mHostTime at runtime? or to convert to seconds, nanoseconds or any other unit? Will this value change between software or hardware versions? (like it has between the simulator and my device)
There exists the following file:
In this file you’ll find a function named
mach_absolute_time().mach_absolute_time()returns an uint64 number that has no defined meaning. Imagine those are ticks, but nowhere is defined how long a single tick is. Only four things are defined:mach_absolute_time()returns the number of “ticks” since the last boot.As you can see, the tick counter is somewhat different to the normal system clock. First of all, the system clock does not start at zero when the system is booted, but at the system’s best approximation of the current “wall clock time”. The normal system clock also is not running strictly upwards, e.g. the system clock might be ahead of time and the system regularly synchronize the system time using NTP (Network Time Protocol). If the system notices that it is ahead of time by two seconds at the next NTP sync, it turns the system clock back by two seconds to correct it. This regularly breaks software, because many programmers rely on the fact that the system time never jumps backwards; but it does and it is allowed to do so. The last difference is that the normal system time won’t stop while the system is sleeping, but the tick counter will not increase while the system is sleeping. When the system wakes up again, it is only a couple of ticks ahead of the time it went to sleep.
So how do you convert those ticks into a real “time value”?
The file of above also defines a structure named
mach_timebase_info:You can get the correct values for this structure using the function
mach_timebase_info(), e.g.KERN_SUCCESS(and possible error codes) are defined inIt is very unlikely for this function to return an error, though, and
KERN_SUCCESSis equal to zero, thus you can also directly check forkerrornot being zero.Once you got the info into
tinfo, you can use it to calculate a “conversion factor”, in case you want to convert this number into a real time unit:By casting the first number to
double, GCC automatically casts the second number todoubleas well and the result will also bedouble. Knowing this factor, which seems to be 1.0 on Intel machines, but it can be quite different on PPC machines (and maybe it’s different on ARM as well), it is pretty easy to convert host time to nanoseconds and nanoseconds to host time.systemUptimeNS contains the number of nanoseconds the system was running (not sleeping) between the last boot and now. If you divide any time in nanoseconds by this factor, you get the number of ticks. This can be very useful for the function
mach_wait_until(). Assume you want the current thread to sleep for 800 nanoseconds. Here’s how you’d do it:A little tip: If you regularly need to convert time values to ticks, it is usually (depends on CPU) faster to multiply than to divide:
Now you can multiply by
ns2HTimeFactorinstead of dividing byhTime2nsFactor.Of course it is a waste of time to re-calculate the factors each time you need them. Those factors are constant, they will never change while the system is running. Thus you can calculate them somewhere near the start of the application and keep them around till the application quits again.
In Cocoa I’d recommend to write yourself a static class for everything above. You can calculate the conversion factors for either conversion in the
+(void)initializemethod of the class. Cocoa guarantees that this method is for sure automatically executed before any message is ever sent to this class, it is for sure only executed once during application run time and it is for sure executed in a thread-safe manner, so you don’t have to worry about locking/synchronizing or atomic operations.