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.
This commit is contained in:
Andreas Eversberg
2017-03-04 06:35:38 +01:00
parent 9d0e6b82b7
commit 4201717f36
11 changed files with 56 additions and 44 deletions

View File

@@ -681,15 +681,14 @@ void process_call(int c)
int count; int count;
int rc; int rc;
count = sound_get_inbuffer(call.sound); count = sound_get_tosend(call.sound, call.latspl);
if (count < 0) { if (count < 0) {
PDEBUG(DSENDER, DEBUG_ERROR, "Failed to get samples in buffer (rc = %d)!\n", count); PDEBUG(DSENDER, DEBUG_ERROR, "Failed to get samples in buffer (rc = %d)!\n", count);
if (count == -EPIPE) if (count == -EPIPE)
PDEBUG(DSENDER, DEBUG_ERROR, "Trying to recover.\n"); PDEBUG(DSENDER, DEBUG_ERROR, "Trying to recover.\n");
return; return;
} }
if (count < call.latspl) { if (count > 0) {
count = call.latspl - count;
int16_t spl[count + 10]; /* more than enough, count will be reduced by scaling with factor */ int16_t spl[count + 10]; /* more than enough, count will be reduced by scaling with factor */
switch(call.state) { switch(call.state) {
case CALL_ALERTING: case CALL_ALERTING:

View File

@@ -234,10 +234,12 @@ int sdr_start(void __attribute__((__unused__)) *inst)
// sdr_t *sdr = (sdr_t *)inst; // sdr_t *sdr = (sdr_t *)inst;
#ifdef HAVE_UHD #ifdef HAVE_UHD
return uhd_start(); if (sdr_use_uhd)
return uhd_start();
#endif #endif
#ifdef HAVE_SOAPY #ifdef HAVE_SOAPY
return soapy_start(); if (sdr_use_soapy)
return soapy_start();
#endif #endif
return -EINVAL; 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 */ /* 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; // sdr_t *sdr = (sdr_t *)inst;
int count = 0; int count = 0;
#ifdef HAVE_UHD #ifdef HAVE_UHD
if (sdr_use_uhd) if (sdr_use_uhd)
count = uhd_get_inbuffer(); count = uhd_get_tosend(latspl);
#endif #endif
#ifdef HAVE_SOAPY #ifdef HAVE_SOAPY
if (sdr_use_soapy) if (sdr_use_soapy)
count = soapy_get_inbuffer(); count = soapy_get_tosend(latspl);
#endif #endif
if (count < 0) if (count < 0)
return count; return count;

View File

@@ -5,5 +5,5 @@ void *sdr_open(const char *audiodev, double *tx_frequency, double *rx_frequency,
void sdr_close(void *inst); 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_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_read(void *inst, sample_t **samples, int num, int channels);
int sdr_get_inbuffer(void *inst); int sdr_get_tosend(void *inst, int latspl);

View File

@@ -101,7 +101,7 @@ int sender_create(sender_t *sender, int kanal, double sendefrequenz, double empf
sender->audio_close = sdr_close; sender->audio_close = sdr_close;
sender->audio_read = sdr_read; sender->audio_read = sdr_read;
sender->audio_write = sdr_write; sender->audio_write = sdr_write;
sender->audio_get_inbuffer = sdr_get_inbuffer; sender->audio_get_tosend = sdr_get_tosend;
} else } else
#endif #endif
{ {
@@ -110,7 +110,7 @@ int sender_create(sender_t *sender, int kanal, double sendefrequenz, double empf
sender->audio_close = sound_close; sender->audio_close = sound_close;
sender->audio_read = sound_read; sender->audio_read = sound_read;
sender->audio_write = sound_write; 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]; samples[i] = buff[i];
} }
count = sender->audio_get_inbuffer(sender->audio); count = sender->audio_get_tosend(sender->audio, latspl);
if (count < 0) { 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); PDEBUG(DSENDER, DEBUG_ERROR, "Failed to get samples in buffer (rc = %d)!\n", count);
if (count == -EPIPE) { if (count == -EPIPE) {
if (cant_recover) { if (cant_recover) {
@@ -300,8 +296,7 @@ cant_recover:
} }
return; return;
} }
if (count < latspl) { if (count > 0) {
count = latspl - count;
/* loop through all channels */ /* loop through all channels */
for (i = 0, inst = sender; inst; i++, inst = inst->slave) { for (i = 0, inst = sender; inst; i++, inst = inst->slave) {
/* load TX data from audio loop or from sender instance */ /* load TX data from audio loop or from sender instance */
@@ -338,7 +333,6 @@ cant_recover:
return; return;
} }
} }
transmit_later:
count = sender->audio_read(sender->audio, samples, latspl, num_chan); count = sender->audio_read(sender->audio, samples, latspl, num_chan);
if (count < 0) { if (count < 0) {

View File

@@ -46,7 +46,7 @@ typedef struct sender {
void (*audio_close)(void *); void (*audio_close)(void *);
int (*audio_write)(void *, sample_t **, int, enum paging_signal *, int *, int); int (*audio_write)(void *, sample_t **, int, enum paging_signal *, int *, int);
int (*audio_read)(void *, sample_t **, int, int); int (*audio_read)(void *, sample_t **, int, int);
int (*audio_get_inbuffer)(void *); int (*audio_get_tosend)(void *, int);
int samplerate; int samplerate;
samplerate_t srstate; /* sample rate conversion state */ samplerate_t srstate; /* sample rate conversion state */
double rx_gain; /* factor of level to apply on rx samples */ double rx_gain; /* factor of level to apply on rx samples */

View File

@@ -262,25 +262,26 @@ int soapy_receive(float *buff, int max)
return got; return got;
} }
/* estimate current unsent number of samples */ /* estimate number of samples that can be sent */
int soapy_get_inbuffer(void) 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 */ /* we need the rx time stamp to determine how much data is already sent in advance */
if (rx_count == 0) if (rx_count == 0)
return -EAGAIN; return 0;
/* if we have not yet sent any data, we set initial tx time stamp */ /* if we have not yet sent any data, we set initial tx time stamp */
if (tx_count == 0) if (tx_count == 0)
tx_count = rx_count; tx_count = rx_count + latspl;
/* we check how advance our transmitted time stamp is */ /* we check how advance our transmitted time stamp is */
advance = tx_count - rx_count; tosend = latspl - (tx_count - rx_count);
/* in case of underrun: */ /* in case of underrun: */
if (advance < 0) if (tosend < 0)
advance = 0; tosend = 0;
return advance; return tosend;
} }

View File

@@ -4,5 +4,5 @@ int soapy_start(void);
void soapy_close(void); void soapy_close(void);
int soapy_send(float *buff, int num); int soapy_send(float *buff, int num);
int soapy_receive(float *buff, int max); int soapy_receive(float *buff, int max);
int soapy_get_inbuffer(void); int soapy_get_tosend(int latspl);

View File

@@ -6,5 +6,5 @@ int sound_start(void *inst);
void sound_close(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_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_read(void *inst, sample_t **samples, int num, int channels);
int sound_get_inbuffer(void *inst); int sound_get_tosend(void *inst, int latspl);

View File

@@ -323,8 +323,10 @@ int sound_write(void *inst, sample_t **samples, int num, enum paging_signal *pag
if (rc < 0) { if (rc < 0) {
PDEBUG(DSOUND, DEBUG_ERROR, "failed to write audio to interface (%s)\n", snd_strerror(rc)); 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_prepare(sound);
sound_start(sound);
}
return rc; return rc;
} }
@@ -363,8 +365,10 @@ int sound_read(void *inst, sample_t **samples, int num, int channels)
return 0; return 0;
PDEBUG(DSOUND, DEBUG_ERROR, "failed to read audio from interface (%s)\n", snd_strerror(rc)); PDEBUG(DSOUND, DEBUG_ERROR, "failed to read audio from interface (%s)\n", snd_strerror(rc));
/* recover read */ /* recover read */
if (rc == -EPIPE) if (rc == -EPIPE) {
sound_prepare(sound); sound_prepare(sound);
sound_start(sound);
}
return rc; 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 */ * return number of samples to be sent */
int sound_get_inbuffer(void *inst) int sound_get_tosend(void *inst, int latspl)
{ {
sound_t *sound = (sound_t *)inst; sound_t *sound = (sound_t *)inst;
int rc; int rc;
snd_pcm_sframes_t delay; snd_pcm_sframes_t delay;
int tosend;
rc = snd_pcm_delay(sound->phandle, &delay); rc = snd_pcm_delay(sound->phandle, &delay);
if (rc < 0) { 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"); PDEBUG(DSOUND, DEBUG_ERROR, "Buffer underrun: Please use higher latency and enable real time scheduling\n");
else else
PDEBUG(DSOUND, DEBUG_ERROR, "failed to get delay from interface (%s)\n", snd_strerror(rc)); 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_prepare(sound);
sound_start(sound);
}
return rc; return rc;
} }
return delay; tosend = latspl - delay;
return tosend;
} }
int sound_is_stereo_capture(void *inst) int sound_is_stereo_capture(void *inst)

View File

@@ -379,19 +379,24 @@ int uhd_receive(float *buff, int max)
return got; return got;
} }
/* estimate current unsent number of samples */ /* estimate number of samples that can be sent */
int uhd_get_inbuffer(void) int uhd_get_tosend(int latspl)
{ {
double advance; double advance;
int tosend;
/* we need the rx time stamp to determine how much data is already sent in advance */ /* 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) 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 we have not yet sent any data, we set initial tx time stamp */
if (tx_time_secs == 0 && tx_time_fract_sec == 0.0) { if (tx_time_secs == 0 && tx_time_fract_sec == 0.0) {
tx_time_secs = rx_time_secs; 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 */ /* we check how advance our transmitted time stamp is */
@@ -399,7 +404,10 @@ int uhd_get_inbuffer(void)
/* in case of underrun: */ /* in case of underrun: */
if (advance < 0) if (advance < 0)
advance = 0; advance = 0;
tosend = latspl - (int)(advance * samplerate);
if (tosend < 0)
tosend = 0;
return (int)(advance * samplerate); return tosend;
} }

View File

@@ -4,5 +4,5 @@ int uhd_start(void);
void uhd_close(void); void uhd_close(void);
int uhd_send(float *buff, int num); int uhd_send(float *buff, int num);
int uhd_receive(float *buff, int max); int uhd_receive(float *buff, int max);
int uhd_get_inbuffer(void); int uhd_get_tosend(int latspl);