153a5a1b3Sopenharmony_ci/***
253a5a1b3Sopenharmony_ci  This file is part of PulseAudio.
353a5a1b3Sopenharmony_ci
453a5a1b3Sopenharmony_ci  Copyright 2004-2006 Lennart Poettering
553a5a1b3Sopenharmony_ci  Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
653a5a1b3Sopenharmony_ci
753a5a1b3Sopenharmony_ci  PulseAudio is free software; you can redistribute it and/or modify
853a5a1b3Sopenharmony_ci  it under the terms of the GNU Lesser General Public License as
953a5a1b3Sopenharmony_ci  published by the Free Software Foundation; either version 2.1 of the
1053a5a1b3Sopenharmony_ci  License, or (at your option) any later version.
1153a5a1b3Sopenharmony_ci
1253a5a1b3Sopenharmony_ci  PulseAudio is distributed in the hope that it will be useful, but
1353a5a1b3Sopenharmony_ci  WITHOUT ANY WARRANTY; without even the implied warranty of
1453a5a1b3Sopenharmony_ci  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1553a5a1b3Sopenharmony_ci  Lesser General Public License for more details.
1653a5a1b3Sopenharmony_ci
1753a5a1b3Sopenharmony_ci  You should have received a copy of the GNU Lesser General Public
1853a5a1b3Sopenharmony_ci  License along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
1953a5a1b3Sopenharmony_ci***/
2053a5a1b3Sopenharmony_ci
2153a5a1b3Sopenharmony_ci#ifdef HAVE_CONFIG_H
2253a5a1b3Sopenharmony_ci#include <config.h>
2353a5a1b3Sopenharmony_ci#endif
2453a5a1b3Sopenharmony_ci
2553a5a1b3Sopenharmony_ci#include <stddef.h>
2653a5a1b3Sopenharmony_ci#include <sys/time.h>
2753a5a1b3Sopenharmony_ci
2853a5a1b3Sopenharmony_ci#ifdef HAVE_WINDOWS_H
2953a5a1b3Sopenharmony_ci#include <windows.h>
3053a5a1b3Sopenharmony_ci#endif
3153a5a1b3Sopenharmony_ci
3253a5a1b3Sopenharmony_ci#include <pulsecore/macro.h>
3353a5a1b3Sopenharmony_ci#include <pulsecore/core-util.h>
3453a5a1b3Sopenharmony_ci
3553a5a1b3Sopenharmony_ci#include "timeval.h"
3653a5a1b3Sopenharmony_ci
3753a5a1b3Sopenharmony_cistruct timeval *pa_gettimeofday(struct timeval *tv) {
3853a5a1b3Sopenharmony_ci    pa_assert(tv);
3953a5a1b3Sopenharmony_ci
4053a5a1b3Sopenharmony_ci#if defined(OS_IS_WIN32)
4153a5a1b3Sopenharmony_ci    /*
4253a5a1b3Sopenharmony_ci     * Copied from implementation by Steven Edwards (LGPL).
4353a5a1b3Sopenharmony_ci     * Found on wine mailing list.
4453a5a1b3Sopenharmony_ci     */
4553a5a1b3Sopenharmony_ci#if defined(_MSC_VER) || defined(__BORLANDC__)
4653a5a1b3Sopenharmony_ci#define EPOCHFILETIME (116444736000000000i64)
4753a5a1b3Sopenharmony_ci#else
4853a5a1b3Sopenharmony_ci#define EPOCHFILETIME (116444736000000000LL)
4953a5a1b3Sopenharmony_ci#endif
5053a5a1b3Sopenharmony_ci{
5153a5a1b3Sopenharmony_ci    FILETIME ft;
5253a5a1b3Sopenharmony_ci    LARGE_INTEGER li;
5353a5a1b3Sopenharmony_ci    int64_t t;
5453a5a1b3Sopenharmony_ci
5553a5a1b3Sopenharmony_ci    GetSystemTimeAsFileTime(&ft);
5653a5a1b3Sopenharmony_ci    li.LowPart  = ft.dwLowDateTime;
5753a5a1b3Sopenharmony_ci    li.HighPart = ft.dwHighDateTime;
5853a5a1b3Sopenharmony_ci    t  = li.QuadPart;       /* In 100-nanosecond intervals */
5953a5a1b3Sopenharmony_ci    t -= EPOCHFILETIME;     /* Offset to the Epoch time */
6053a5a1b3Sopenharmony_ci    t /= 10;                /* In microseconds */
6153a5a1b3Sopenharmony_ci    tv->tv_sec  = (time_t) (t / PA_USEC_PER_SEC);
6253a5a1b3Sopenharmony_ci    tv->tv_usec = (suseconds_t) (t % PA_USEC_PER_SEC);
6353a5a1b3Sopenharmony_ci}
6453a5a1b3Sopenharmony_ci#elif defined(HAVE_GETTIMEOFDAY)
6553a5a1b3Sopenharmony_ci    pa_assert_se(gettimeofday(tv, NULL) == 0);
6653a5a1b3Sopenharmony_ci#else
6753a5a1b3Sopenharmony_ci#error "Platform lacks gettimeofday() or equivalent function."
6853a5a1b3Sopenharmony_ci#endif
6953a5a1b3Sopenharmony_ci
7053a5a1b3Sopenharmony_ci    return tv;
7153a5a1b3Sopenharmony_ci}
7253a5a1b3Sopenharmony_ci
7353a5a1b3Sopenharmony_cipa_usec_t pa_timeval_diff(const struct timeval *a, const struct timeval *b) {
7453a5a1b3Sopenharmony_ci    pa_usec_t r;
7553a5a1b3Sopenharmony_ci
7653a5a1b3Sopenharmony_ci    pa_assert(a);
7753a5a1b3Sopenharmony_ci    pa_assert(b);
7853a5a1b3Sopenharmony_ci
7953a5a1b3Sopenharmony_ci    /* Check which is the earlier time and swap the two arguments if required. */
8053a5a1b3Sopenharmony_ci    if (PA_UNLIKELY(pa_timeval_cmp(a, b) < 0)) {
8153a5a1b3Sopenharmony_ci        const struct timeval *c;
8253a5a1b3Sopenharmony_ci        c = a;
8353a5a1b3Sopenharmony_ci        a = b;
8453a5a1b3Sopenharmony_ci        b = c;
8553a5a1b3Sopenharmony_ci    }
8653a5a1b3Sopenharmony_ci
8753a5a1b3Sopenharmony_ci    /* Calculate the second difference*/
8853a5a1b3Sopenharmony_ci    r = ((pa_usec_t) a->tv_sec - (pa_usec_t) b->tv_sec) * PA_USEC_PER_SEC;
8953a5a1b3Sopenharmony_ci
9053a5a1b3Sopenharmony_ci    /* Calculate the microsecond difference */
9153a5a1b3Sopenharmony_ci    if (a->tv_usec > b->tv_usec)
9253a5a1b3Sopenharmony_ci        r += (pa_usec_t) a->tv_usec - (pa_usec_t) b->tv_usec;
9353a5a1b3Sopenharmony_ci    else if (a->tv_usec < b->tv_usec)
9453a5a1b3Sopenharmony_ci        r -= (pa_usec_t) b->tv_usec - (pa_usec_t) a->tv_usec;
9553a5a1b3Sopenharmony_ci
9653a5a1b3Sopenharmony_ci    return r;
9753a5a1b3Sopenharmony_ci}
9853a5a1b3Sopenharmony_ci
9953a5a1b3Sopenharmony_ciint pa_timeval_cmp(const struct timeval *a, const struct timeval *b) {
10053a5a1b3Sopenharmony_ci    pa_assert(a);
10153a5a1b3Sopenharmony_ci    pa_assert(b);
10253a5a1b3Sopenharmony_ci
10353a5a1b3Sopenharmony_ci    if (a->tv_sec < b->tv_sec)
10453a5a1b3Sopenharmony_ci        return -1;
10553a5a1b3Sopenharmony_ci
10653a5a1b3Sopenharmony_ci    if (a->tv_sec > b->tv_sec)
10753a5a1b3Sopenharmony_ci        return 1;
10853a5a1b3Sopenharmony_ci
10953a5a1b3Sopenharmony_ci    if (a->tv_usec < b->tv_usec)
11053a5a1b3Sopenharmony_ci        return -1;
11153a5a1b3Sopenharmony_ci
11253a5a1b3Sopenharmony_ci    if (a->tv_usec > b->tv_usec)
11353a5a1b3Sopenharmony_ci        return 1;
11453a5a1b3Sopenharmony_ci
11553a5a1b3Sopenharmony_ci    return 0;
11653a5a1b3Sopenharmony_ci}
11753a5a1b3Sopenharmony_ci
11853a5a1b3Sopenharmony_cipa_usec_t pa_timeval_age(const struct timeval *tv) {
11953a5a1b3Sopenharmony_ci    struct timeval now;
12053a5a1b3Sopenharmony_ci    pa_assert(tv);
12153a5a1b3Sopenharmony_ci
12253a5a1b3Sopenharmony_ci    return pa_timeval_diff(pa_gettimeofday(&now), tv);
12353a5a1b3Sopenharmony_ci}
12453a5a1b3Sopenharmony_ci
12553a5a1b3Sopenharmony_cistruct timeval* pa_timeval_add(struct timeval *tv, pa_usec_t v) {
12653a5a1b3Sopenharmony_ci    time_t secs;
12753a5a1b3Sopenharmony_ci    pa_assert(tv);
12853a5a1b3Sopenharmony_ci
12953a5a1b3Sopenharmony_ci    secs = (time_t) (v/PA_USEC_PER_SEC);
13053a5a1b3Sopenharmony_ci
13153a5a1b3Sopenharmony_ci    if (PA_UNLIKELY(tv->tv_sec > PA_INT_TYPE_MAX(time_t) - secs))
13253a5a1b3Sopenharmony_ci        goto overflow;
13353a5a1b3Sopenharmony_ci
13453a5a1b3Sopenharmony_ci    tv->tv_sec += secs;
13553a5a1b3Sopenharmony_ci    v -= (pa_usec_t) secs * PA_USEC_PER_SEC;
13653a5a1b3Sopenharmony_ci    tv->tv_usec += (suseconds_t) v;
13753a5a1b3Sopenharmony_ci
13853a5a1b3Sopenharmony_ci    /* Normalize */
13953a5a1b3Sopenharmony_ci    while ((pa_usec_t) tv->tv_usec >= PA_USEC_PER_SEC) {
14053a5a1b3Sopenharmony_ci
14153a5a1b3Sopenharmony_ci        if (PA_UNLIKELY(tv->tv_sec >= PA_INT_TYPE_MAX(time_t)))
14253a5a1b3Sopenharmony_ci            goto overflow;
14353a5a1b3Sopenharmony_ci
14453a5a1b3Sopenharmony_ci        tv->tv_sec++;
14553a5a1b3Sopenharmony_ci        tv->tv_usec -= (suseconds_t) PA_USEC_PER_SEC;
14653a5a1b3Sopenharmony_ci    }
14753a5a1b3Sopenharmony_ci
14853a5a1b3Sopenharmony_ci    return tv;
14953a5a1b3Sopenharmony_ci
15053a5a1b3Sopenharmony_cioverflow:
15153a5a1b3Sopenharmony_ci    tv->tv_sec = PA_INT_TYPE_MAX(time_t);
15253a5a1b3Sopenharmony_ci    tv->tv_usec = (suseconds_t) (PA_USEC_PER_SEC-1);
15353a5a1b3Sopenharmony_ci    return tv;
15453a5a1b3Sopenharmony_ci}
15553a5a1b3Sopenharmony_ci
15653a5a1b3Sopenharmony_cistruct timeval* pa_timeval_sub(struct timeval *tv, pa_usec_t v) {
15753a5a1b3Sopenharmony_ci    time_t secs;
15853a5a1b3Sopenharmony_ci    pa_assert(tv);
15953a5a1b3Sopenharmony_ci
16053a5a1b3Sopenharmony_ci    secs = (time_t) (v/PA_USEC_PER_SEC);
16153a5a1b3Sopenharmony_ci
16253a5a1b3Sopenharmony_ci    if (PA_UNLIKELY(tv->tv_sec < secs))
16353a5a1b3Sopenharmony_ci        goto underflow;
16453a5a1b3Sopenharmony_ci
16553a5a1b3Sopenharmony_ci    tv->tv_sec -= secs;
16653a5a1b3Sopenharmony_ci    v -= (pa_usec_t) secs * PA_USEC_PER_SEC;
16753a5a1b3Sopenharmony_ci
16853a5a1b3Sopenharmony_ci    if (tv->tv_usec >= (suseconds_t) v)
16953a5a1b3Sopenharmony_ci        tv->tv_usec -= (suseconds_t) v;
17053a5a1b3Sopenharmony_ci    else {
17153a5a1b3Sopenharmony_ci
17253a5a1b3Sopenharmony_ci        if (PA_UNLIKELY(tv->tv_sec <= 0))
17353a5a1b3Sopenharmony_ci            goto underflow;
17453a5a1b3Sopenharmony_ci
17553a5a1b3Sopenharmony_ci        tv->tv_sec --;
17653a5a1b3Sopenharmony_ci        tv->tv_usec += (suseconds_t) (PA_USEC_PER_SEC - v);
17753a5a1b3Sopenharmony_ci    }
17853a5a1b3Sopenharmony_ci
17953a5a1b3Sopenharmony_ci    return tv;
18053a5a1b3Sopenharmony_ci
18153a5a1b3Sopenharmony_ciunderflow:
18253a5a1b3Sopenharmony_ci    tv->tv_sec = 0;
18353a5a1b3Sopenharmony_ci    tv->tv_usec = 0;
18453a5a1b3Sopenharmony_ci    return tv;
18553a5a1b3Sopenharmony_ci}
18653a5a1b3Sopenharmony_ci
18753a5a1b3Sopenharmony_cistruct timeval* pa_timeval_store(struct timeval *tv, pa_usec_t v) {
18853a5a1b3Sopenharmony_ci    pa_assert(tv);
18953a5a1b3Sopenharmony_ci
19053a5a1b3Sopenharmony_ci    if (PA_UNLIKELY(v == PA_USEC_INVALID)) {
19153a5a1b3Sopenharmony_ci        tv->tv_sec = PA_INT_TYPE_MAX(time_t);
19253a5a1b3Sopenharmony_ci        tv->tv_usec = (suseconds_t) (PA_USEC_PER_SEC-1);
19353a5a1b3Sopenharmony_ci
19453a5a1b3Sopenharmony_ci        return tv;
19553a5a1b3Sopenharmony_ci    }
19653a5a1b3Sopenharmony_ci
19753a5a1b3Sopenharmony_ci    tv->tv_sec = (time_t) (v / PA_USEC_PER_SEC);
19853a5a1b3Sopenharmony_ci    tv->tv_usec = (suseconds_t) (v % PA_USEC_PER_SEC);
19953a5a1b3Sopenharmony_ci
20053a5a1b3Sopenharmony_ci    return tv;
20153a5a1b3Sopenharmony_ci}
20253a5a1b3Sopenharmony_ci
20353a5a1b3Sopenharmony_cipa_usec_t pa_timeval_load(const struct timeval *tv) {
20453a5a1b3Sopenharmony_ci
20553a5a1b3Sopenharmony_ci    if (PA_UNLIKELY(!tv))
20653a5a1b3Sopenharmony_ci        return PA_USEC_INVALID;
20753a5a1b3Sopenharmony_ci
20853a5a1b3Sopenharmony_ci    return
20953a5a1b3Sopenharmony_ci        (pa_usec_t) tv->tv_sec * PA_USEC_PER_SEC +
21053a5a1b3Sopenharmony_ci        (pa_usec_t) tv->tv_usec;
21153a5a1b3Sopenharmony_ci}
212