From 360e46683bd5d2b4fa786431b049687204a03736 Mon Sep 17 00:00:00 2001 From: ejurgensen Date: Tue, 12 May 2020 20:16:44 +0200 Subject: [PATCH] [input] Add a simple input for testing timing --- src/Makefile.am | 2 +- src/conffile.c | 1 + src/input.c | 7 +++ src/input.h | 1 + src/inputs/timer.c | 127 +++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 137 insertions(+), 1 deletion(-) create mode 100644 src/inputs/timer.c diff --git a/src/Makefile.am b/src/Makefile.am index 81c2c1be..a65d2372 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -130,7 +130,7 @@ forked_daapd_SOURCES = main.c \ worker.c worker.h \ settings.c settings.h \ input.h input.c \ - inputs/file_http.c inputs/pipe.c \ + inputs/file_http.c inputs/pipe.c inputs/timer.c \ outputs.h outputs.c \ outputs/rtp_common.h outputs/rtp_common.c \ outputs/raop.c $(RAOP_VERIFICATION_SRC) \ diff --git a/src/conffile.c b/src/conffile.c index 924b2c4d..68ad686a 100644 --- a/src/conffile.c +++ b/src/conffile.c @@ -66,6 +66,7 @@ static cfg_opt_t sec_general[] = CFG_INT("db_pragma_synchronous", -1, CFGF_NONE), CFG_STR("allow_origin", "*", CFGF_NONE), CFG_STR("user_agent", PACKAGE_NAME "/" PACKAGE_VERSION, CFGF_NONE), + CFG_BOOL("timer_test", cfg_false, CFGF_NONE), CFG_END() }; diff --git a/src/input.c b/src/input.c index 307616ca..a890a909 100644 --- a/src/input.c +++ b/src/input.c @@ -38,6 +38,7 @@ #include "misc.h" #include "logger.h" +#include "conffile.h" #include "commands.h" #include "input.h" @@ -56,6 +57,7 @@ extern struct input_definition input_file; extern struct input_definition input_http; extern struct input_definition input_pipe; +extern struct input_definition input_timer; #ifdef HAVE_SPOTIFY_H extern struct input_definition input_spotify; #endif @@ -65,6 +67,7 @@ static struct input_definition *inputs[] = { &input_file, &input_http, &input_pipe, + &input_timer, #ifdef HAVE_SPOTIFY_H &input_spotify, #endif @@ -153,6 +156,10 @@ int debug_underrun_trigger; static int map_data_kind(int data_kind) { + // Test mode - ignores the actual source and just plays a signal with clicks + if (cfg_getbool(cfg_getsec(cfg, "general"), "timer_test")) + return INPUT_TYPE_TIMER; + switch (data_kind) { case DATA_KIND_FILE: diff --git a/src/input.h b/src/input.h index d426b5c9..2d098465 100644 --- a/src/input.h +++ b/src/input.h @@ -15,6 +15,7 @@ enum input_types INPUT_TYPE_FILE, INPUT_TYPE_HTTP, INPUT_TYPE_PIPE, + INPUT_TYPE_TIMER, #ifdef HAVE_SPOTIFY_H INPUT_TYPE_SPOTIFY, #endif diff --git a/src/inputs/timer.c b/src/inputs/timer.c new file mode 100644 index 00000000..1a7298c0 --- /dev/null +++ b/src/inputs/timer.c @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2020 Espen Jurgensen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include + +#include + +#include "misc.h" +#include "logger.h" +#include "input.h" + +#define TIMER_NOISE_INTERVAL 5 +#define TIMER_METADATA_INTERVAL 30 +#define TIMER_SAMPLE_RATE 44100 +#define TIMER_BPS 16 +#define TIMER_CHANNELS 2 +#define TIMER_BUFSIZE (STOB(TIMER_SAMPLE_RATE, TIMER_BPS, TIMER_CHANNELS) / 20) + +struct timer_ctx +{ + uint8_t silence[TIMER_BUFSIZE]; + uint8_t noise[TIMER_BUFSIZE]; + uint64_t pos; +}; + +static int +setup(struct input_source *source) +{ + struct timer_ctx *ctx; + + ctx = calloc(1, sizeof(struct timer_ctx)); + if (!ctx) + return -1; + + memset(&ctx->noise, 0x88, TIMER_BUFSIZE); + + CHECK_NULL(L_PLAYER, source->evbuf = evbuffer_new()); + + source->quality.sample_rate = TIMER_SAMPLE_RATE; + source->quality.bits_per_sample = TIMER_BPS; + source->quality.channels = TIMER_CHANNELS; + + source->input_ctx = ctx; + + return 0; +} + +static int +stop(struct input_source *source) +{ + struct timer_ctx *ctx = source->input_ctx; + + free(ctx); + + if (source->evbuf) + evbuffer_free(source->evbuf); + + source->input_ctx = NULL; + source->evbuf = NULL; + + return 0; +} + +static int +play(struct input_source *source) +{ + struct timer_ctx *ctx = source->input_ctx; + short flags; + + if (ctx->pos % (TIMER_METADATA_INTERVAL * source->quality.sample_rate) == 0) + flags = INPUT_FLAG_METADATA; + else + flags = 0; + + if (ctx->pos % (TIMER_NOISE_INTERVAL * source->quality.sample_rate) == 0) + evbuffer_add(source->evbuf, ctx->noise, TIMER_BUFSIZE); + else + evbuffer_add(source->evbuf, ctx->silence, TIMER_BUFSIZE); + + ctx->pos += BTOS(TIMER_BUFSIZE, TIMER_BPS, TIMER_CHANNELS); + + input_write(source->evbuf, &source->quality, flags); + + return 0; +} + +static int +metadata_get(struct input_metadata *metadata, struct input_source *source) +{ + metadata->title = strdup("Timing test"); + + metadata->pos_is_updated = true; + metadata->pos_ms = 0; + metadata->len_ms = TIMER_METADATA_INTERVAL * 1000; + return 0; +} + +struct input_definition input_timer = +{ + .name = "timer", + .type = INPUT_TYPE_TIMER, + .disabled = 0, + .setup = setup, + .play = play, + .stop = stop, + .metadata_get = metadata_get, +}; +