我在iPhone上遇到AudioTimeStamps的问题。当我在模拟器中运行应用程序时,AudioTimeStamp.mHostTime似乎以纳秒(1,000,000,000秒)为单位,而在我的设备(iPod Touch 2G)上运行时,频率似乎为6,000,000秒。
似乎在OS X上有一个函数(CoreAudio / CoreAudioTypes.h中的AudioConvertHostTimeToNanos)可以将HostTime转换为纳秒或从纳秒转换,但是此功能不在iPhone header 中。
有什么方法可以在运行时找出mHostTime的速率吗?或转换为秒,纳秒或任何其他单位?这个值会在软件或硬件版本之间改变吗? (就像它在模拟器和我的设备之间一样)
最佳答案
存在以下文件:
<mach/mach_time.h>
在此文件中,您将找到一个名为
mach_absolute_time()
的函数。 mach_absolute_time()
返回没有定义含义的uint64数字。想象一下那些是滴答声,但是没有定义单个滴答声的持续时间。仅定义了四件事:mach_absolute_time()
返回自上次引导以来的“滴答声”数。 如您所见,滴答计数器与正常系统时钟有些不同。首先,启动系统时,系统时钟并非从零开始,而是以系统当前“挂钟时间”的最佳近似值开始。正常系统时钟也不严格向上运行,例如系统时钟可能会提前,并且系统会使用NTP(网络时间协议(protocol))定期同步系统时间。如果系统在下一次NTP同步中注意到提前2秒钟,则会将系统时钟调回2秒钟以进行更正。这经常破坏软件,因为许多程序员都依赖这样的事实,即系统时间永远不会向后跳。但确实如此,并且允许这样做。最后一个区别是,正常的系统时间不会在系统处于睡眠状态时停止,但是滴答计数器不会在系统处于睡眠状态时增加。当系统再次醒来时,它只比睡眠时间提前了几个滴答声。
那么,如何将这些刻度线转换为真实的“时间值”?
上面的文件还定义了一个名为
mach_timebase_info
的结构:struct mach_timebase_info {
uint32_t numer;
uint32_t denom;
};
您可以使用
mach_timebase_info()
函数获取此结构的正确值,例如kern_return_t kerror;
mach_timebase_info_data_t tinfo;
kerror = mach_timebase_info(&tinfo);
if (kerror != KERN_SUCCESS) {
// TODO: handle error
}
KERN_SUCCESS
(以及可能的错误代码)在<mach/kern_return.h>
但是,此函数返回错误的可能性很小,而且
KERN_SUCCESS
等于零,因此您也可以直接检查kerror
不为零。将信息输入
tinfo
后,可以将其用于计算“转换因子”,以防万一要将此数字转换为实时单位:double hTime2nsFactor = (double)tinfo.numer / tinfo.denom;
通过将第一个数字转换为
double
,GCC也会自动将第二个数字转换为double
,结果也将为double
。知道这个因素,在Intel机器上似乎是1.0,但是在PPC机器上却可能大不相同(也许在ARM上也有所不同),将主机时间转换为纳秒和将纳秒转换为主机时间非常容易。uint64_t systemUptimeNS = (uint64_t)(mach_absolute_time() * hTime2nsFactor);
systemUptimeNS包含上次引导到现在之间系统正在运行(不休眠)的纳秒数。如果您将任何时间(以纳秒为单位)除以该因子,则将获得刻度数。这对于
mach_wait_until()
函数非常有用。假设您希望当前线程休眠800纳秒。这是您的处理方式:uint64_t sleepTimeInTicks = (uint64_t)(800 / hTime2nsFactor);
mach_wait_until(mach_absolute_time() + sleepTimeInTicks);
一个小技巧:如果您经常需要将时间值转换为刻度,通常(取决于CPU),乘法要快于除法:
double ns2HTimeFactor = 1.0 / hTime2nsFactor;
现在,您可以乘以
ns2HTimeFactor
而不是除以hTime2nsFactor
。当然,每次需要时重新计算这些因素都是浪费时间。这些因素是恒定的,它们在系统运行时永远不会改变。因此,您可以在应用程序开始附近的某个位置计算它们,并保持它们直到应用程序再次退出。
在 cocoa 中,我建议您为上述所有内容编写一个静态类。您可以在该类的
+(void)initialize
方法中计算任一转换的转换因子。 Cocoa保证在将任何消息发送到此类之前,此方法肯定会自动执行,它肯定在应用程序运行时仅执行一次,并且肯定是以线程安全的方式执行的,因此您不必担心锁定/同步或原子操作。
关于iphone - CoreAudio AudioTimeStamp.mHostTime时钟频率?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/675626/