CoreAudio AudioTimeStamp.mHostTime时钟频率?

时间:2009-03-23 23:32:02

标签: iphone objective-c audio

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

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

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

2 个答案:

答案 0 :(得分:47)

存在以下文件:

<mach/mach_time.h>

在此文件中,您将找到名为mach_absolute_time()的函数。 mach_absolute_time()返回一个没有定义含义的uint64号码。想象一下那些是 ticks ,但没有定义单个刻度的长度。只定义了四件事:

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

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

    上述文件还定义了名为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。知道这个因素,在英特尔机器上似乎是1.0,但在PPC机器上可能会有很大不同(也可能在ARM上也不同),很容易将主机时间转换为纳秒和纳秒到主机时间。 / p>

    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保证在任何消息发送到此类之前肯定会自动执行此方法,它肯定只在应用程序运行时执行一次并且肯定以线程安全的方式执行,因此您没有担心锁定/同步或原子操作。

答案 1 :(得分:6)

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

struct mach_timebase_info {
    uint32_t    numer;
    uint32_t    denom;
};

请参阅:http://shiftedbits.org/2008/10/01/mach_absolute_time-on-the-iphone/

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

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