iphone - CoreAudio AudioTimeStamp.mHostTime时钟频率?

标签 iphone objective-c audio

我在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/

    相关文章:

    iphone - 如何使用 UIButtonBarItem 触发方法?

    ios - 减小 AppStore 的 iOS 应用程序大小 (Xamarin)

    iphone - LibXML2.dylib 和 Xcode4

    iphone - iPhone Web应用程序:HTML5数据库和音频文件

    ipad - 仅在iPad上播放时显示HTML5控件

    android - "Android Supported Media (Encoder) Format"现在包括AAC和AMR-WB,但是我们如何使用它们呢?

    ios - 无法在 iPhone 6 上打开 Apple Pay 表

    ios - 如何在我的应用程序中检测设备当前是否已连接到车辆 Carplay

    objective-c - 为 app ios 创建一个设置 View

    ios - 在 NSUserDefaults iOS 中保存 int 的问题