gapk: Implement optional looping/rewinding of input files

Together with the recently-added throttling, this can be useful to
generate a continuous stream of RTP data from an input file.

Change-Id: I2d552695dfb4cc96039838e79e0f5ae25a6737c8
This commit is contained in:
Harald Welte 2020-08-01 19:01:03 +02:00
parent 75df4ca2a3
commit ac4a44c836
4 changed files with 27 additions and 8 deletions

View File

@ -20,6 +20,7 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h> /* for FILE */
#include <osmocom/core/linuxlist.h>
@ -85,7 +86,7 @@ char *osmo_gapk_pq_describe(struct osmo_gapk_pq *pq);
struct osmo_gapk_pq_item *osmo_gapk_pq_add_item(struct osmo_gapk_pq *pq);
/* File */
int osmo_gapk_pq_queue_file_input(struct osmo_gapk_pq *pq, FILE *src, unsigned int block_len);
int osmo_gapk_pq_queue_file_input(struct osmo_gapk_pq *pq, FILE *src, unsigned int block_len, bool loop);
int osmo_gapk_pq_queue_file_output(struct osmo_gapk_pq *pq, FILE *dst, unsigned int block_len);
/* RTP */

View File

@ -68,6 +68,7 @@ struct gapk_options
/* RTP payload type */
uint8_t rtp_pt_in, rtp_pt_out;
bool loop_input;
int throttle;
int benchmark;
int verbose;
@ -144,6 +145,7 @@ print_help(char *progname)
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, " -t, --throttle\tEnable throttling (one codec frame every 20ms)\n");
fprintf(stdout, " -l, --loop-input\tEnable looping of the input file\n");
fprintf(stdout, " -v, --verbose\t\t\tEnable debug messages\n");
fprintf(stdout, "\n");
@ -217,10 +219,11 @@ parse_options(struct gapk_state *state, int argc, char *argv[])
{"rtp-pt-out", 1, 0, 'P'},
{"enable-benchmark", 0, 0, 'b'},
{"throttle", 0, 0, 't'},
{"loop-input", 0, 0, 'l'},
{"verbose", 0, 0, 'v'},
{"help", 0, 0, 'h'},
};
const char *short_options = "i:o:I:O:f:g:p:P:btvh"
const char *short_options = "i:o:I:O:f:g:p:P:btlvh"
#ifdef HAVE_ALSA
"a:A:"
#endif
@ -322,6 +325,10 @@ parse_options(struct gapk_state *state, int argc, char *argv[])
opt->throttle = 1;
break;
case 'l':
opt->loop_input = true;
break;
case 'v':
log_parse_category_mask(osmo_stderr_target, "DAPP");
opt->verbose = 1;
@ -577,7 +584,7 @@ make_processing_chain(struct gapk_state *gs)
/* File read */
if (gs->in.file.fh)
osmo_gapk_pq_queue_file_input(gs->pq, gs->in.file.fh, fmt_in->frame_len);
osmo_gapk_pq_queue_file_input(gs->pq, gs->in.file.fh, fmt_in->frame_len, gs->opts.loop_input);
else if (gs->in.rtp.fd != -1)
osmo_gapk_pq_queue_rtp_input(gs->pq, gs->in.rtp.fd,
fmt_in->frame_len, gs->opts.rtp_pt_in);

View File

@ -19,6 +19,7 @@
#include <errno.h>
#include <stdint.h>
#include <stdbool.h>
#include <talloc.h>
#include <osmocom/gapk/logging.h>
@ -30,6 +31,7 @@
struct pq_state_file {
FILE *fh;
unsigned int blk_len;
bool loop_input;
};
@ -39,6 +41,14 @@ pq_cb_file_input(void *_state, uint8_t *out, const uint8_t *in, unsigned int in_
struct pq_state_file *state = _state;
int rv;
rv = fread(out, state->blk_len, 1, state->fh);
if (rv == 0 && state->loop_input && feof(state->fh)) {
/* FIXME: this only works for files without a header
* (e.g. .gsm files) but not for those with header (like
* .amr files). gs->opts.fmt_in->header is not
* accessible here :/ */
fseek(state->fh, 0, SEEK_SET);
rv = fread(out, state->blk_len, 1, state->fh);
}
if (rv <= 0)
return -1;
return rv * state->blk_len;
@ -60,7 +70,7 @@ pq_cb_file_exit(void *_state)
}
static int
pq_queue_file_op(struct osmo_gapk_pq *pq, FILE *fh, unsigned int blk_len, int in_out_n)
pq_queue_file_op(struct osmo_gapk_pq *pq, FILE *fh, unsigned int blk_len, int in_out_n, bool loop_input)
{
struct osmo_gapk_pq_item *item;
struct pq_state_file *state;
@ -71,6 +81,7 @@ pq_queue_file_op(struct osmo_gapk_pq *pq, FILE *fh, unsigned int blk_len, int in
state->fh = fh;
state->blk_len = blk_len;
state->loop_input = loop_input;
item = osmo_gapk_pq_add_item(pq);
if (!item) {
@ -105,11 +116,11 @@ pq_queue_file_op(struct osmo_gapk_pq *pq, FILE *fh, unsigned int blk_len, int in
* \param[in] blk_len block length to be read from file
* \returns 0 on success; negative on error */
int
osmo_gapk_pq_queue_file_input(struct osmo_gapk_pq *pq, FILE *src, unsigned int blk_len)
osmo_gapk_pq_queue_file_input(struct osmo_gapk_pq *pq, FILE *src, unsigned int blk_len, bool loop)
{
LOGPGAPK(LOGL_DEBUG, "PQ '%s': Adding file input (blk_len=%u)\n",
pq->name, blk_len);
return pq_queue_file_op(pq, src, blk_len, 1);
return pq_queue_file_op(pq, src, blk_len, 1, loop);
}
/*! Add file output to given processing queue
@ -123,5 +134,5 @@ osmo_gapk_pq_queue_file_output(struct osmo_gapk_pq *pq, FILE *dst, unsigned int
{
LOGPGAPK(LOGL_DEBUG, "PQ '%s': Adding file output (blk_len=%u)\n",
pq->name, blk_len);
return pq_queue_file_op(pq, dst, blk_len, 0);
return pq_queue_file_op(pq, dst, blk_len, 0, false);
}

View File

@ -81,7 +81,7 @@ static int pq_file_check(FILE *src_file, unsigned int blk_len)
assert(pq != NULL);
/* Add a file sink */
rc = osmo_gapk_pq_queue_file_input(pq, src_file, blk_len);
rc = osmo_gapk_pq_queue_file_input(pq, src_file, blk_len, false);
assert(rc == 0);
/* Add a processing item */