CoreAudio AudioTimeStamp.mHostTime тактовая частота? - PullRequest
19 голосов
/ 24 марта 2009

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

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

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

Ответы [ 2 ]

47 голосов
/ 11 мая 2010

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

<mach/mach_time.h>

В этом файле вы найдете функцию с именем 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;
};

Вы можете получить правильные значения для этой структуры, используя функцию 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);

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

double ns2HTimeFactor = 1.0 / hTime2nsFactor;

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

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

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

6 голосов
/ 05 мая 2009

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...