From 4201717f36f1236fd0de1597679f5e9411c8a7eb Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Sat, 4 Mar 2017 06:35:38 +0100 Subject: [PATCH] Rework on audio buffer management Use function to get samples to be sent to fill audio buffers to a level. This replaces the function that only shows how much data is in the buffer. This way the function itself can control how much data will be sent. --- src/common/call.c | 5 ++--- src/common/sdr.c | 12 +++++++----- src/common/sdr.h | 2 +- src/common/sender.c | 14 ++++---------- src/common/sender.h | 2 +- src/common/soapy.c | 19 ++++++++++--------- src/common/soapy.h | 2 +- src/common/sound.h | 2 +- src/common/sound_alsa.c | 22 +++++++++++++++------- src/common/uhd.c | 18 +++++++++++++----- src/common/uhd.h | 2 +- 11 files changed, 56 insertions(+), 44 deletions(-) diff --git a/src/common/call.c b/src/common/call.c index f2db043..a8ac8e1 100644 --- a/src/common/call.c +++ b/src/common/call.c @@ -681,15 +681,14 @@ void process_call(int c) int count; int rc; - count = sound_get_inbuffer(call.sound); + count = sound_get_tosend(call.sound, call.latspl); if (count < 0) { PDEBUG(DSENDER, DEBUG_ERROR, "Failed to get samples in buffer (rc = %d)!\n", count); if (count == -EPIPE) PDEBUG(DSENDER, DEBUG_ERROR, "Trying to recover.\n"); return; } - if (count < call.latspl) { - count = call.latspl - count; + if (count > 0) { int16_t spl[count + 10]; /* more than enough, count will be reduced by scaling with factor */ switch(call.state) { case CALL_ALERTING: diff --git a/src/common/sdr.c b/src/common/sdr.c index ea080d4..372824d 100644 --- a/src/common/sdr.c +++ b/src/common/sdr.c @@ -234,10 +234,12 @@ int sdr_start(void __attribute__((__unused__)) *inst) // sdr_t *sdr = (sdr_t *)inst; #ifdef HAVE_UHD - return uhd_start(); + if (sdr_use_uhd) + return uhd_start(); #endif #ifdef HAVE_SOAPY - return soapy_start(); + if (sdr_use_soapy) + return soapy_start(); #endif return -EINVAL; } @@ -356,18 +358,18 @@ int sdr_read(void *inst, sample_t **samples, int num, int channels) } /* how many delay (in audio sample duration) do we have in the buffer */ -int sdr_get_inbuffer(void __attribute__((__unused__)) *inst) +int sdr_get_tosend(void __attribute__((__unused__)) *inst, int latspl) { // sdr_t *sdr = (sdr_t *)inst; int count = 0; #ifdef HAVE_UHD if (sdr_use_uhd) - count = uhd_get_inbuffer(); + count = uhd_get_tosend(latspl); #endif #ifdef HAVE_SOAPY if (sdr_use_soapy) - count = soapy_get_inbuffer(); + count = soapy_get_tosend(latspl); #endif if (count < 0) return count; diff --git a/src/common/sdr.h b/src/common/sdr.h index 3d1aaca..0d02e0f 100644 --- a/src/common/sdr.h +++ b/src/common/sdr.h @@ -5,5 +5,5 @@ void *sdr_open(const char *audiodev, double *tx_frequency, double *rx_frequency, void sdr_close(void *inst); int sdr_write(void *inst, sample_t **samples, int num, enum paging_signal *paging_signal, int *on, int channels); int sdr_read(void *inst, sample_t **samples, int num, int channels); -int sdr_get_inbuffer(void *inst); +int sdr_get_tosend(void *inst, int latspl); diff --git a/src/common/sender.c b/src/common/sender.c index b24db0b..055f84e 100644 --- a/src/common/sender.c +++ b/src/common/sender.c @@ -101,7 +101,7 @@ int sender_create(sender_t *sender, int kanal, double sendefrequenz, double empf sender->audio_close = sdr_close; sender->audio_read = sdr_read; sender->audio_write = sdr_write; - sender->audio_get_inbuffer = sdr_get_inbuffer; + sender->audio_get_tosend = sdr_get_tosend; } else #endif { @@ -110,7 +110,7 @@ int sender_create(sender_t *sender, int kanal, double sendefrequenz, double empf sender->audio_close = sound_close; sender->audio_read = sound_read; sender->audio_write = sound_write; - sender->audio_get_inbuffer = sound_get_inbuffer; + sender->audio_get_tosend = sound_get_tosend; } } @@ -282,12 +282,8 @@ void process_sender_audio(sender_t *sender, int *quit, int latspl) samples[i] = buff[i]; } - count = sender->audio_get_inbuffer(sender->audio); + count = sender->audio_get_tosend(sender->audio, latspl); if (count < 0) { - /* special case when the device is not yet ready to transmit packets */ - if (count == -EAGAIN) { - goto transmit_later; - } PDEBUG(DSENDER, DEBUG_ERROR, "Failed to get samples in buffer (rc = %d)!\n", count); if (count == -EPIPE) { if (cant_recover) { @@ -300,8 +296,7 @@ cant_recover: } return; } - if (count < latspl) { - count = latspl - count; + if (count > 0) { /* loop through all channels */ for (i = 0, inst = sender; inst; i++, inst = inst->slave) { /* load TX data from audio loop or from sender instance */ @@ -338,7 +333,6 @@ cant_recover: return; } } -transmit_later: count = sender->audio_read(sender->audio, samples, latspl, num_chan); if (count < 0) { diff --git a/src/common/sender.h b/src/common/sender.h index 658d444..b371591 100644 --- a/src/common/sender.h +++ b/src/common/sender.h @@ -46,7 +46,7 @@ typedef struct sender { void (*audio_close)(void *); int (*audio_write)(void *, sample_t **, int, enum paging_signal *, int *, int); int (*audio_read)(void *, sample_t **, int, int); - int (*audio_get_inbuffer)(void *); + int (*audio_get_tosend)(void *, int); int samplerate; samplerate_t srstate; /* sample rate conversion state */ double rx_gain; /* factor of level to apply on rx samples */ diff --git a/src/common/soapy.c b/src/common/soapy.c index b01f586..76e213e 100644 --- a/src/common/soapy.c +++ b/src/common/soapy.c @@ -262,25 +262,26 @@ int soapy_receive(float *buff, int max) return got; } -/* estimate current unsent number of samples */ -int soapy_get_inbuffer(void) +/* estimate number of samples that can be sent */ +int soapy_get_tosend(int latspl) { - long long advance; + int tosend; /* we need the rx time stamp to determine how much data is already sent in advance */ if (rx_count == 0) - return -EAGAIN; + return 0; /* if we have not yet sent any data, we set initial tx time stamp */ if (tx_count == 0) - tx_count = rx_count; + tx_count = rx_count + latspl; /* we check how advance our transmitted time stamp is */ - advance = tx_count - rx_count; + tosend = latspl - (tx_count - rx_count); /* in case of underrun: */ - if (advance < 0) - advance = 0; + if (tosend < 0) + tosend = 0; - return advance; + return tosend; } + diff --git a/src/common/soapy.h b/src/common/soapy.h index 36ec304..dcfadde 100644 --- a/src/common/soapy.h +++ b/src/common/soapy.h @@ -4,5 +4,5 @@ int soapy_start(void); void soapy_close(void); int soapy_send(float *buff, int num); int soapy_receive(float *buff, int max); -int soapy_get_inbuffer(void); +int soapy_get_tosend(int latspl); diff --git a/src/common/sound.h b/src/common/sound.h index 339cea6..1054eb4 100644 --- a/src/common/sound.h +++ b/src/common/sound.h @@ -6,5 +6,5 @@ int sound_start(void *inst); void sound_close(void *inst); int sound_write(void *inst, sample_t **samples, int num, enum paging_signal *paging_signal, int *on, int channels); int sound_read(void *inst, sample_t **samples, int num, int channels); -int sound_get_inbuffer(void *inst); +int sound_get_tosend(void *inst, int latspl); diff --git a/src/common/sound_alsa.c b/src/common/sound_alsa.c index 22b1b77..752f82f 100644 --- a/src/common/sound_alsa.c +++ b/src/common/sound_alsa.c @@ -323,8 +323,10 @@ int sound_write(void *inst, sample_t **samples, int num, enum paging_signal *pag if (rc < 0) { PDEBUG(DSOUND, DEBUG_ERROR, "failed to write audio to interface (%s)\n", snd_strerror(rc)); - if (rc == -EPIPE) + if (rc == -EPIPE) { sound_prepare(sound); + sound_start(sound); + } return rc; } @@ -363,8 +365,10 @@ int sound_read(void *inst, sample_t **samples, int num, int channels) return 0; PDEBUG(DSOUND, DEBUG_ERROR, "failed to read audio from interface (%s)\n", snd_strerror(rc)); /* recover read */ - if (rc == -EPIPE) + if (rc == -EPIPE) { sound_prepare(sound); + sound_start(sound); + } return rc; } @@ -391,14 +395,15 @@ int sound_read(void *inst, sample_t **samples, int num, int channels) } /* - * get playback buffer fill + * get playback buffer space * - * return number of frames */ -int sound_get_inbuffer(void *inst) + * return number of samples to be sent */ +int sound_get_tosend(void *inst, int latspl) { sound_t *sound = (sound_t *)inst; int rc; snd_pcm_sframes_t delay; + int tosend; rc = snd_pcm_delay(sound->phandle, &delay); if (rc < 0) { @@ -406,12 +411,15 @@ int sound_get_inbuffer(void *inst) PDEBUG(DSOUND, DEBUG_ERROR, "Buffer underrun: Please use higher latency and enable real time scheduling\n"); else PDEBUG(DSOUND, DEBUG_ERROR, "failed to get delay from interface (%s)\n", snd_strerror(rc)); - if (rc == -EPIPE) + if (rc == -EPIPE) { sound_prepare(sound); + sound_start(sound); + } return rc; } - return delay; + tosend = latspl - delay; + return tosend; } int sound_is_stereo_capture(void *inst) diff --git a/src/common/uhd.c b/src/common/uhd.c index 15c13b9..1423703 100644 --- a/src/common/uhd.c +++ b/src/common/uhd.c @@ -379,19 +379,24 @@ int uhd_receive(float *buff, int max) return got; } -/* estimate current unsent number of samples */ -int uhd_get_inbuffer(void) +/* estimate number of samples that can be sent */ +int uhd_get_tosend(int latspl) { double advance; + int tosend; /* we need the rx time stamp to determine how much data is already sent in advance */ if (rx_time_secs == 0 && rx_time_fract_sec == 0.0) - return -EAGAIN; + return 0; /* if we have not yet sent any data, we set initial tx time stamp */ if (tx_time_secs == 0 && tx_time_fract_sec == 0.0) { tx_time_secs = rx_time_secs; - tx_time_fract_sec = rx_time_fract_sec; + tx_time_fract_sec = rx_time_fract_sec + (double)latspl / samplerate; + if (tx_time_fract_sec >= 1.0) { + tx_time_fract_sec -= 1.0; + tx_time_secs++; + } } /* we check how advance our transmitted time stamp is */ @@ -399,7 +404,10 @@ int uhd_get_inbuffer(void) /* in case of underrun: */ if (advance < 0) advance = 0; + tosend = latspl - (int)(advance * samplerate); + if (tosend < 0) + tosend = 0; - return (int)(advance * samplerate); + return tosend; } diff --git a/src/common/uhd.h b/src/common/uhd.h index 09ae519..686d658 100644 --- a/src/common/uhd.h +++ b/src/common/uhd.h @@ -4,5 +4,5 @@ int uhd_start(void); void uhd_close(void); int uhd_send(float *buff, int num); int uhd_receive(float *buff, int max); -int uhd_get_inbuffer(void); +int uhd_get_tosend(int latspl);