CoreAudio AudioTimeStamp.mHostTime时钟频率?

qru*_*key 19 iphone audio objective-c

iPhone上的AudioTimeStamps遇到了一些问题.当我在模拟器中运行我的应用程序时,AudioTimeStamp.mHostTime似乎是以纳秒为单位(1,000,000,000秒),而在我的设备(iPod Touch 2G)上运行时,频率似乎是大约6,000,000秒.

似乎在OS X上有一个函数(CoreAudio/CoreAudioTypes.h中的AudioConvertHostTimeToNanos)将HostTime转换为纳秒,但是这个函数不在iPhone头文件中.

有没有办法在运行时找出mHostTime的速率?或转换为秒,纳秒或任何其他单位?这个值会在软件或硬件版本之间发生变化吗?(就像它在模拟器和我的设备之间)

Mec*_*cki 47

存在以下文件:

<mach/mach_time.h>
Run Code Online (Sandbox Code Playgroud)

在这个文件中,你会找到一个名为的函数mach_absolute_time().mach_absolute_time()返回没有定义含义的uint64数字.想象一下这些是刻度线,但没有定义单个刻度线的长度.只定义了四件事:

  1. mach_absolute_time() 返回自上次启动以来的"滴答"数.
  2. 每次启动时,滴答计数器从零开始.
  3. 滴答计数器严格向上计数(它永远不会倒退).
  4. 滴答计数器仅在系统运行时计算滴答.

如您所见,滴答计数器与正常系统时钟略有不同.首先,系统时钟在系统启动时不会从零开始,而是在系统最佳近似当前"挂钟时间"时.正常系统时钟也没有严格向上运行,例如系统时钟可能提前,系统使用NTP(网络时间协议)定期同步系统时间.如果系统在下一次NTP同步时注意到它提前了两秒钟,它会将系统时钟向后转动两秒钟以进行纠正.这经常打破软件,因为许多程序员依赖于系统时间永远不会倒退的事实; 但确实如此,并且允许这样做.最后一个区别是正常的系统时间不会在系统休眠时停止,但在系统休眠时,滴答计数器不会增加.当系统再次唤醒时,它在进入睡眠状态之前只有几个小时.

那么如何将这些刻度转换为真正的"时间价值"?

上面的文件还定义了一个名为的结构mach_timebase_info:

struct mach_timebase_info {
        uint32_t        numer;
        uint32_t        denom;
};
Run Code Online (Sandbox Code Playgroud)

您可以使用该函数获取此结构的正确值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
}
Run Code Online (Sandbox Code Playgroud)

KERN_SUCCESS (和可能的错误代码)定义在

<mach/kern_return.h>
Run Code Online (Sandbox Code Playgroud)

但是,此函数不太可能返回错误,并且KERN_SUCCESS等于零,因此您也可以直接检查kerror不是零.

获得信息后tinfo,您可以使用它来计算"转换因子",以防您想将此数字转换为实时单位:

double hTime2nsFactor = (double)tinfo.numer / tinfo.denom;
Run Code Online (Sandbox Code Playgroud)

通过将第一个数字double转换为,GCC double也会自动转换第二个数字,结果也是如此double.知道了这些因素,这似乎是1.0的Intel的机器,但它可以在PPC机器(也许是ARM的不同以及)完全不同,它是很容易的主机时间转换为纳秒纳秒举办时间.

uint64_t systemUptimeNS = (uint64_t)(mach_absolute_time() * hTime2nsFactor);
Run Code Online (Sandbox Code Playgroud)

systemUptimeNS包含系统在上次启动和现在之间运行(不睡眠)的纳秒数.如果按此因子除以纳秒的任何时间,则得到刻度数.这对于该功能非常有用mach_wait_until().假设您希望当前线程休眠800纳秒.这是你如何做到的:

uint64_t sleepTimeInTicks = (uint64_t)(800 / hTime2nsFactor);
mach_wait_until(mach_absolute_time() + sleepTimeInTicks);
Run Code Online (Sandbox Code Playgroud)

一个小提示:如果您经常需要将时间值转换为滴答,通常(取决于CPU)乘以更快的速度比除以:

double ns2HTimeFactor = 1.0 / hTime2nsFactor;
Run Code Online (Sandbox Code Playgroud)

现在你可以乘以ns2HTimeFactor而不是除以hTime2nsFactor.

当然,每次需要时重新计算因子都是浪费时间.这些因素是不变的,它们在系统运行时永远不会改变.因此,您可以在应用程序开始附近的某处计算它们并保持它们直到应用程序再次退出.

在Cocoa中,我建议为上面的所有内容编写一个静态类.您可以+(void)initialize在类的方法中计算转换的转换因子.Cocoa保证在任何消息发送到此类之前肯定会自动执行此方法,它肯定只在应用程序运行时执行一次并且肯定以线程安全的方式执行,因此您没有担心锁定/同步或原子操作.


小智 6

您需要使用该mach_timebase_info结构来解决这个问题.

struct mach_timebase_info {
    uint32_t    numer;
    uint32_t    denom;
};
Run Code Online (Sandbox Code Playgroud)

看到: http://shiftedbits.org/2008/10/01/mach_absolute_time-on-the-iphone/

最简单的方法是使用Apple为您提供的CAHostTimeBase助手类 - Developer/Examples/CoreAudio/PublicUtility.

CAHostTimeBase.cpp和CAHostTimeBase.h - 您需要做的所有事情.