Подтвердить что ты не робот

Частота часов CoreAudio AudioTimeStamp.mHostTime?

У меня возникла проблема с AudioTimeStamps на iPhone. Когда я запускаю свое приложение в симуляторе, AudioTimeStamp.mHostTime появляется в наносекундах (1 000 000 000 000 секунд), тогда как при работе на моем устройстве (iPod Touch 2G) частота составляет около 6 000 000 000 секунд.

Похоже, что на OS X есть функция (AudioConvertHostTimeToNanos в CoreAudio/CoreAudioTypes.h) для преобразования HostTime в и от наносекунд, но эта функция не находится в заголовках iPhone.

Есть ли способ узнать скорость mHostTime во время выполнения? или конвертировать в секунды, наносекунды или любую другую единицу? Будет ли это изменение изменяться между версиями программного обеспечения или оборудования? (например, между симулятором и моим устройством)

4b9b3361

Ответ 1

Существует следующий файл:

<mach/mach_time.h>

В этом файле вы найдете функцию с именем mach_absolute_time(). mach_absolute_time() возвращает номер uint64, который не имеет определенного значения. Представьте, что это тики, но нигде не определено, как долго один тик. Определяются только четыре вещи:

  • mach_absolute_time() возвращает число "тиков" с момента последней загрузки.
  • При каждой загрузке счетчик тиков начинается с нуля.
  • Счетчик счетчиков строго строит вверх (он никогда не идет назад).
  • Счетчик тиков учитывает только тики во время работы системы.

Как вы можете видеть, счетчик тиков несколько отличается от обычных системных часов. Прежде всего, системные часы не начинаются с нуля при загрузке системы, а в наилучшем приближении системы к текущему "времени настенных часов". Обычные системные часы также не работают строго вверх, например. системные часы могут быть раньше времени, и система регулярно синхронизирует системное время с использованием NTP (Network Time Protocol). Если система заметила, что на следующей синхронизации 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 на машинах Intel, но он может быть совсем другим на машинах 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);

Маленький совет: Если вам регулярно нужно преобразовывать значения времени в тики, обычно (в зависимости от процессора) быстрее умножаться, чем делиться:

double ns2HTimeFactor = 1.0 / hTime2nsFactor;

Теперь вы можете умножить на ns2HTimeFactor вместо деления на hTime2nsFactor.

Конечно, это пустая трата времени, чтобы пересчитать коэффициенты каждый раз, когда вы в них нуждаетесь. Эти факторы постоянны, они никогда не изменятся во время работы системы. Таким образом, вы можете рассчитать их где-то рядом с началом приложения и сохранить их до тех пор, пока приложение не закроется.

В Cocoa я бы рекомендовал написать статический класс для всего выше. Вы можете рассчитать коэффициенты преобразования для любого преобразования в методе +(void)initialize класса. Cocoa гарантирует, что этот метод, безусловно, будет автоматически выполнен до того, как какое-либо сообщение будет отправлено этому классу, оно наверняка выполняется только один раз во время выполнения приложения, и оно, безусловно, выполняется поточно-безопасным образом, t нужно беспокоиться о блокировке/синхронизации или атомных операциях.

Ответ 2

Вам нужно использовать структуру 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/

Проще всего просто использовать вспомогательный класс CAHostTimeBase, предоставленный вам Apple - Developer/Examples/CoreAudio/PublicUtility.

CAHostTimeBase.cpp и CAHostTimeBase.h - все, что вам нужно для этого.