/*
|
* BlueALSA - rt.h
|
* Copyright (c) 2016-2017 Arkadiusz Bokowy
|
*
|
* This file is a part of bluez-alsa.
|
*
|
* This project is licensed under the terms of the MIT license.
|
*
|
*/
|
|
#include "shared/rt.h"
|
|
#include <stdlib.h>
|
|
|
/**
|
* Synchronize time with the sampling rate.
|
*
|
* Notes:
|
* 1. Time synchronization relies on the frame counter being linear.
|
* 2. In order to prevent frame counter overflow (for more information see
|
* the asrsync structure definition), this counter should be initialized
|
* (zeroed) upon every transfer stop.
|
*
|
* @param asrs Pointer to the time synchronization structure.
|
* @param frames Number of frames since the last call to this function.
|
* @return This function returns a positive value or zero respectively for
|
* the case, when the synchronization was required or when blocking was
|
* not necessary. If an error has occurred, -1 is returned and errno is
|
* set to indicate the error. */
|
int asrsync_sync(struct asrsync *asrs, unsigned int frames) {
|
|
const unsigned int rate = asrs->rate;
|
struct timespec ts_rate;
|
struct timespec ts;
|
int rv = 0;
|
|
asrs->frames += frames;
|
frames = asrs->frames;
|
|
ts_rate.tv_sec = frames / rate;
|
ts_rate.tv_nsec = 1000000000 / rate * (frames % rate);
|
|
gettimestamp(&ts);
|
/* calculate delay since the last sync */
|
difftimespec(&asrs->ts, &ts, &asrs->ts_busy);
|
|
/* maintain constant rate */
|
difftimespec(&asrs->ts0, &ts, &ts);
|
if (difftimespec(&ts, &ts_rate, &asrs->ts_idle) > 0) {
|
nanosleep(&asrs->ts_idle, NULL);
|
rv = 1;
|
}
|
|
gettimestamp(&asrs->ts);
|
return rv;
|
}
|
|
/**
|
* Calculate time difference for two time points.
|
*
|
* @param ts1 Address to the timespec structure providing t1 time point.
|
* @param ts2 Address to the timespec structure providing t2 time point.
|
* @param ts Address to the timespec structure where the absolute time
|
* difference will be stored.
|
* @return This function returns an integer less than, equal to, or greater
|
* than zero, if t2 time point is found to be, respectively, less than,
|
* equal to, or greater than the t1 time point.*/
|
int difftimespec(
|
const struct timespec *ts1,
|
const struct timespec *ts2,
|
struct timespec *ts) {
|
|
const struct timespec _ts1 = *ts1;
|
const struct timespec _ts2 = *ts2;
|
|
if (_ts1.tv_sec == _ts2.tv_sec) {
|
ts->tv_sec = 0;
|
ts->tv_nsec = labs(_ts2.tv_nsec - _ts1.tv_nsec);
|
return _ts2.tv_nsec > _ts1.tv_nsec ? 1 : -ts->tv_nsec;
|
}
|
|
if (_ts1.tv_sec < _ts2.tv_sec) {
|
if (_ts1.tv_nsec <= _ts2.tv_nsec) {
|
ts->tv_sec = _ts2.tv_sec - _ts1.tv_sec;
|
ts->tv_nsec = _ts2.tv_nsec - _ts1.tv_nsec;
|
}
|
else {
|
ts->tv_sec = _ts2.tv_sec - 1 - _ts1.tv_sec;
|
ts->tv_nsec = _ts2.tv_nsec + 1000000000 - _ts1.tv_nsec;
|
}
|
return 1;
|
}
|
|
if (_ts1.tv_nsec >= _ts2.tv_nsec) {
|
ts->tv_sec = _ts1.tv_sec - _ts2.tv_sec;
|
ts->tv_nsec = _ts1.tv_nsec - _ts2.tv_nsec;
|
}
|
else {
|
ts->tv_sec = _ts1.tv_sec - 1 - _ts2.tv_sec;
|
ts->tv_nsec = _ts1.tv_nsec + 1000000000 - _ts2.tv_nsec;
|
}
|
return -1;
|
}
|