Skip to content

Commit 68f15a3

Browse files
committed
core(audio,frames): fix .bin replay pacing drift and lag
1 parent bf00b7d commit 68f15a3

4 files changed

Lines changed: 63 additions & 10 deletions

File tree

include/dsd-neo/core/state.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -772,8 +772,9 @@ struct dsd_state {
772772
uint8_t p25_call_is_packet[2]; // 1 if call/service marked as packet (data), else 0
773773

774774
//experimental symbol file capture read throttle
775-
int symbol_throttle; //throttle speed
776-
int use_throttle; //only use throttle if set to 1
775+
int symbol_throttle; //throttle speed
776+
int use_throttle; //only use throttle if set to 1
777+
uint64_t symbol_replay_next_deadline_ns; //0 when uninitialized
777778

778779
//dmr trunking stuff
779780
int dmr_rest_channel;

src/core/audio/dsd_audio.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -811,6 +811,11 @@ openAudioInDevice(dsd_opts* opts, dsd_state* state) {
811811
dsd_net_audio_input_hook_udp_stop(opts);
812812
}
813813
dsd_opts_reset_pcm_input_state(opts);
814+
if (state) {
815+
/* .bin symbol replay can opt into paced playback; reset before probing input type. */
816+
state->use_throttle = 0;
817+
state->symbol_replay_next_deadline_ns = 0;
818+
}
814819

815820
char* extension;
816821
const char ch = '.';
@@ -1002,6 +1007,10 @@ openAudioInDevice(dsd_opts* opts, dsd_state* state) {
10021007
return -1;
10031008
}
10041009
opts->audio_in_type = AUDIO_IN_SYMBOL_BIN; //symbol capture bin files
1010+
if (state) {
1011+
state->use_throttle = 1;
1012+
state->symbol_replay_next_deadline_ns = 0;
1013+
}
10051014
} else {
10061015
opts->audio_in_type = AUDIO_IN_PULSE;
10071016
}

src/core/frames/dsd_dibit.c

Lines changed: 48 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,52 @@
4141
#include "dsd-neo/core/opts_fwd.h"
4242
#include "dsd-neo/core/state_fwd.h"
4343

44+
static void
45+
throttle_symbol_bin_replay(dsd_opts* opts, dsd_state* state) {
46+
if (!opts || !state || state->use_throttle != 1) {
47+
return;
48+
}
49+
50+
/* Keep legacy microsecond override support when explicitly configured. */
51+
if (state->symbol_throttle > 0) {
52+
dsd_sleep_us((uint64_t)state->symbol_throttle);
53+
return;
54+
}
55+
56+
int input_rate_hz = dsd_opts_current_input_timing_rate(opts);
57+
if (input_rate_hz <= 0) {
58+
input_rate_hz = SAMPLE_RATE_IN;
59+
}
60+
61+
int sps = state->samplesPerSymbol;
62+
if (sps <= 0) {
63+
sps = 10;
64+
}
65+
66+
uint64_t period_ns = ((uint64_t)sps * 1000000000ULL) / (uint64_t)input_rate_hz;
67+
if (period_ns == 0ULL) {
68+
dsd_sleep_ms(0U);
69+
return;
70+
}
71+
72+
uint64_t now_ns = dsd_time_monotonic_ns();
73+
uint64_t deadline_ns = state->symbol_replay_next_deadline_ns;
74+
if (deadline_ns == 0ULL) {
75+
state->symbol_replay_next_deadline_ns = now_ns + period_ns;
76+
return;
77+
}
78+
79+
if (now_ns < deadline_ns) {
80+
dsd_sleep_ns(deadline_ns - now_ns);
81+
} else if ((now_ns - deadline_ns) > 250000000ULL) {
82+
/* Rebase pacing after long scheduler stalls/debug pauses. */
83+
state->symbol_replay_next_deadline_ns = now_ns + period_ns;
84+
return;
85+
}
86+
87+
state->symbol_replay_next_deadline_ns = deadline_ns + period_ns;
88+
}
89+
4490
static void
4591
print_datascope(dsd_opts* opts, dsd_state* state, const float* sbuf2, int count) {
4692
int i, j, o;
@@ -766,9 +812,7 @@ get_dibit_and_analog_signal(dsd_opts* opts, dsd_state* state, int* out_analog_si
766812
if (opts->audio_in_type == AUDIO_IN_SYMBOL_BIN) {
767813
//assign dibit from last symbol/dibit read from capture bin
768814
dibit = state->symbolc;
769-
if (state->use_throttle == 1) {
770-
dsd_sleep_ms(0); /* yield CPU */
771-
}
815+
throttle_symbol_bin_replay(opts, state);
772816
}
773817

774818
//symbol/dibit file capture/writing
@@ -858,9 +902,7 @@ getDibitAndSoftSymbol(dsd_opts* opts, dsd_state* state, float* out_soft_symbol)
858902

859903
if (opts->audio_in_type == AUDIO_IN_SYMBOL_BIN) {
860904
dibit = state->symbolc;
861-
if (state->use_throttle == 1) {
862-
dsd_sleep_ms(0); /* yield CPU */
863-
}
905+
throttle_symbol_bin_replay(opts, state);
864906
}
865907

866908
if (opts->symbol_out_f) {

src/core/util/dsd_init.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -767,8 +767,9 @@ initState(dsd_state* state) {
767767
state->p25_vc_cqpsk_override = -1;
768768

769769
//experimental symbol file capture read throttle
770-
state->symbol_throttle = 100; //throttle speed
771-
state->use_throttle = 0; //only use throttle if set to 1
770+
state->symbol_throttle = 0; //0 = auto pace from symbol timing
771+
state->use_throttle = 0; //only use throttle if set to 1
772+
state->symbol_replay_next_deadline_ns = 0;
772773

773774
state->p2_scramble_offset = 0;
774775
state->p2_vch_chan_num = 0;

0 commit comments

Comments
 (0)