summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobin Gareus <robin@gareus.org>2015-03-05 01:33:13 +0100
committerRobin Gareus <robin@gareus.org>2015-03-05 01:59:59 +0100
commit782dd708751a78d7b944e826e41f0e6337818e98 (patch)
treea715735341a1434b041c1f61069ec3ae0ab16a18
parent1acbd7c488956b9c48b343dded72dbfbcbb4f242 (diff)
alsa: implement timing callback
-rw-r--r--libs/backends/alsa/alsa_audiobackend.cc38
-rw-r--r--libs/backends/alsa/alsa_audiobackend.h3
2 files changed, 40 insertions, 1 deletions
diff --git a/libs/backends/alsa/alsa_audiobackend.cc b/libs/backends/alsa/alsa_audiobackend.cc
index 8090ac8c9d..18de4dc0b8 100644
--- a/libs/backends/alsa/alsa_audiobackend.cc
+++ b/libs/backends/alsa/alsa_audiobackend.cc
@@ -50,6 +50,8 @@ AlsaAudioBackend::AlsaAudioBackend (AudioEngine& e, AudioBackendInfo& info)
, _freewheel (false)
, _freewheeling (false)
, _measure_latency (false)
+ , _last_process_start (0)
+ , _process_speed_samples_per_ms (0)
, _audio_device("")
, _midi_driver_option(_("None"))
, _device_reservation(0)
@@ -500,6 +502,13 @@ AlsaAudioBackend::_start (bool for_latency_measurement)
_ports.clear();
}
+ /* reset internal state */
+ _dsp_load = 0;
+ _freewheeling = false;
+ _freewheel = false;
+ _last_process_start = 0;
+ _process_speed_samples_per_ms = 0;
+
release_device();
assert(_rmidi_in.size() == 0);
@@ -696,7 +705,25 @@ AlsaAudioBackend::sample_time_at_cycle_start ()
pframes_t
AlsaAudioBackend::samples_since_cycle_start ()
{
- return 0;
+ if (!_active || !_run || _freewheeling || _freewheel) {
+ return 0;
+ }
+ if (_last_process_start == 0 || _process_speed_samples_per_ms) {
+ return 0;
+ }
+
+ const int64_t elapsed_time_us = _last_process_start - g_get_monotonic_time();
+ const int64_t nomial_time = 1e6 * _samples_per_period / _samplerate;
+
+ assert(elapsed_time_us >=0);
+
+ /* linear extrapolation, using [low pass] filtered process-speed. */
+ const pframes_t processed_samples = elapsed_time_us * _process_speed_samples_per_ms * 1e-3;
+
+ if (processed_samples >= _samples_per_period) {
+ return _samples_per_period;
+ }
+ return processed_samples;
}
@@ -1465,6 +1492,8 @@ AlsaAudioBackend::main_process_thread ()
memset ((*it)->get_buffer (_samples_per_period), 0, _samples_per_period * sizeof (Sample));
}
+ /* call engine process callback */
+ _last_process_start = g_get_monotonic_time();
if (engine.process_callback (_samples_per_period)) {
_pcmi->pcm_stop ();
_active = false;
@@ -1504,6 +1533,12 @@ AlsaAudioBackend::main_process_thread ()
clock2 = g_get_monotonic_time();
const int64_t elapsed_time = clock2 - clock1;
_dsp_load = elapsed_time / (float) nomial_time;
+
+ const double ps = 1e3 * _samples_per_period / elapsed_time;
+ // low pass filter, The time-constant should really be
+ // 1.0 - e^(-2.0 * π * v / SR);
+ // with v = _samples_per_period / N, and SR = _samples_per_period;
+ _process_speed_samples_per_ms = _process_speed_samples_per_ms + .05 * (ps - _process_speed_samples_per_ms) + 1e-12;
}
if (xrun && (_pcmi->capt_xrun() > 0 || _pcmi->play_xrun() > 0)) {
@@ -1539,6 +1574,7 @@ AlsaAudioBackend::main_process_thread ()
rm->sync_time (clock1);
}
+ _last_process_start = -1;
if (engine.process_callback (_samples_per_period)) {
_pcmi->pcm_stop ();
_active = false;
diff --git a/libs/backends/alsa/alsa_audiobackend.h b/libs/backends/alsa/alsa_audiobackend.h
index 3823db22ed..fe29caf166 100644
--- a/libs/backends/alsa/alsa_audiobackend.h
+++ b/libs/backends/alsa/alsa_audiobackend.h
@@ -305,6 +305,9 @@ class AlsaAudioBackend : public AudioBackend {
bool _freewheeling;
bool _measure_latency;
+ uint64_t _last_process_start;
+ double _process_speed_samples_per_ms;
+
static std::vector<std::string> _midi_options;
static std::vector<AudioBackend::DeviceStatus> _audio_device_status;
static std::vector<AudioBackend::DeviceStatus> _midi_device_status;