gapk: add optional throttling

When throttling is enabled, one voice frame will be processed every
20ms.  This is useful for e.g. playback of a file as a RTP stream.

Without this option, the entire file would generate a flood of RTP
messages, rather than a continuous stream.

Change-Id: I0dcd4248cc800b82142722aa36a811f0657b3e0c
This commit is contained in:
Harald Welte 2020-08-01 18:31:38 +02:00
parent 5613b7d850
commit 75df4ca2a3
1 changed files with 61 additions and 8 deletions

View File

@ -36,6 +36,7 @@
#include <osmocom/core/logging.h> #include <osmocom/core/logging.h>
#include <osmocom/core/socket.h> #include <osmocom/core/socket.h>
#include <osmocom/core/utils.h> #include <osmocom/core/utils.h>
#include <osmocom/core/select.h>
#include <osmocom/gapk/common.h> #include <osmocom/gapk/common.h>
#include <osmocom/gapk/codecs.h> #include <osmocom/gapk/codecs.h>
@ -67,6 +68,7 @@ struct gapk_options
/* RTP payload type */ /* RTP payload type */
uint8_t rtp_pt_in, rtp_pt_out; uint8_t rtp_pt_in, rtp_pt_out;
int throttle;
int benchmark; int benchmark;
int verbose; int verbose;
}; };
@ -75,6 +77,8 @@ struct gapk_state
{ {
struct gapk_options opts; struct gapk_options opts;
struct osmo_gapk_pq *pq; struct osmo_gapk_pq *pq;
struct osmo_fd timerfd; /* for optional throttling */
unsigned int num_frames;
int exit; int exit;
struct { struct {
@ -139,6 +143,7 @@ print_help(char *progname)
fprintf(stdout, " -p --rtp-pt-in=TYPE\t\tRTP payload type for incoming frames\n"); fprintf(stdout, " -p --rtp-pt-in=TYPE\t\tRTP payload type for incoming frames\n");
fprintf(stdout, " -P --rtp-pt-out=TYPE\t\tRTP payload type for outgoing frames\n"); fprintf(stdout, " -P --rtp-pt-out=TYPE\t\tRTP payload type for outgoing frames\n");
fprintf(stdout, " -b, --enable-benchmark\tEnable codec benchmarking\n"); fprintf(stdout, " -b, --enable-benchmark\tEnable codec benchmarking\n");
fprintf(stdout, " -t, --throttle\tEnable throttling (one codec frame every 20ms)\n");
fprintf(stdout, " -v, --verbose\t\t\tEnable debug messages\n"); fprintf(stdout, " -v, --verbose\t\t\tEnable debug messages\n");
fprintf(stdout, "\n"); fprintf(stdout, "\n");
@ -211,10 +216,11 @@ parse_options(struct gapk_state *state, int argc, char *argv[])
{"rtp-pt-in", 1, 0, 'p'}, {"rtp-pt-in", 1, 0, 'p'},
{"rtp-pt-out", 1, 0, 'P'}, {"rtp-pt-out", 1, 0, 'P'},
{"enable-benchmark", 0, 0, 'b'}, {"enable-benchmark", 0, 0, 'b'},
{"throttle", 0, 0, 't'},
{"verbose", 0, 0, 'v'}, {"verbose", 0, 0, 'v'},
{"help", 0, 0, 'h'}, {"help", 0, 0, 'h'},
}; };
const char *short_options = "i:o:I:O:f:g:p:P:bvh" const char *short_options = "i:o:I:O:f:g:p:P:btvh"
#ifdef HAVE_ALSA #ifdef HAVE_ALSA
"a:A:" "a:A:"
#endif #endif
@ -312,6 +318,10 @@ parse_options(struct gapk_state *state, int argc, char *argv[])
opt->benchmark = 1; opt->benchmark = 1;
break; break;
case 't':
opt->throttle = 1;
break;
case 'v': case 'v':
log_parse_category_mask(osmo_stderr_target, "DAPP"); log_parse_category_mask(osmo_stderr_target, "DAPP");
opt->verbose = 1; opt->verbose = 1;
@ -667,23 +677,66 @@ make_processing_chain(struct gapk_state *gs)
return 0; return 0;
} }
static int
timerfd_cb(struct osmo_fd *ofd, unsigned int what)
{
struct gapk_state *gs = ofd->data;
uint64_t expire_count;
int rc;
rc = read(ofd->fd, (void *)&expire_count, sizeof(expire_count));
if (rc < 0 && errno == EAGAIN)
return 0;
OSMO_ASSERT(rc == sizeof(expire_count));
while (expire_count--) {
gs->num_frames++;
rc = osmo_gapk_pq_execute(gs->pq);
if (rc < 0)
gs->exit = true;
}
return 0;
}
static int static int
run(struct gapk_state *gs) run(struct gapk_state *gs)
{ {
struct osmo_gapk_pq_item *item; struct osmo_gapk_pq_item *item;
int rv, frames; int rv;
rv = osmo_gapk_pq_prepare(gs->pq); rv = osmo_gapk_pq_prepare(gs->pq);
if (rv) if (rv)
return rv; return rv;
for (frames = 0; !gs->exit; frames++) { if (!gs->opts.throttle) {
rv = osmo_gapk_pq_execute(gs->pq); for (gs->num_frames = 0; !gs->exit; gs->num_frames++) {
if (rv) rv = osmo_gapk_pq_execute(gs->pq);
break; if (rv)
break;
}
} else {
/* setup timerfd based processing */
const struct timespec interval = {
.tv_sec = 0,
.tv_nsec = 20*1000*1000,
};
gs->timerfd.fd = -1;
rv = osmo_timerfd_setup(&gs->timerfd, timerfd_cb, gs);
OSMO_ASSERT(rv == 0);
rv = osmo_timerfd_schedule(&gs->timerfd, NULL, &interval);
OSMO_ASSERT(rv == 0);
/* actual processing loop */
while (!gs->exit)
osmo_select_main(0);
/* cleanup */
osmo_timerfd_disable(&gs->timerfd);
close(gs->timerfd.fd);
osmo_fd_unregister(&gs->timerfd);
} }
LOGP(DAPP, LOGL_NOTICE, "Processed %d frames\n", frames); LOGP(DAPP, LOGL_NOTICE, "Processed %d frames\n", gs->num_frames);
/* Wait for sink to process buffers */ /* Wait for sink to process buffers */
item = llist_last_entry(&gs->pq->items, struct osmo_gapk_pq_item, list); item = llist_last_entry(&gs->pq->items, struct osmo_gapk_pq_item, list);
@ -693,7 +746,7 @@ run(struct gapk_state *gs)
continue; continue;
} }
return frames > 0 ? 0 : rv; return gs->num_frames > 0 ? 0 : rv;
} }