From 14b5913c9e30978620dbb6f2b85651e8bf7147e9 Mon Sep 17 00:00:00 2001 Message-Id: <14b5913c9e30978620dbb6f2b85651e8bf7147e9.1714756945.git.mdw@distorted.org.uk> From: Mark Wooding Date: Mon, 4 May 2020 18:30:54 +0100 Subject: [PATCH] clients/playrtp.c, lib/configuration.[ch]: Static config for `playrtp'. Organization: Straylight/Edgeware From: Mark Wooding The `disorder-playrtp' program already reads the client configuration. This change sets defaults for a number of parameters which could previously only be changed from the command line, which is a problem because `disorder-playrtp' is commonly invoked by Disobedience which doesn't allow one to set a command-line. These various tweaks are experimental, and may change, or even be removed, in some later version. The `rtp_request_address' and `rtp_always_request' options, in particular, might be replaced by some more complicated policy mechanism. --- clients/playrtp.c | 53 +++++++++++++++++------ doc/disorder-playrtp.1.in | 9 ++++ doc/disorder_config.5.in | 90 +++++++++++++++++++++++++++++++++++++++ lib/configuration.c | 31 ++++++++++++++ lib/configuration.h | 16 +++++++ 5 files changed, 186 insertions(+), 13 deletions(-) diff --git a/clients/playrtp.c b/clients/playrtp.c index 539dc59..3a4757b 100644 --- a/clients/playrtp.c +++ b/clients/playrtp.c @@ -74,6 +74,7 @@ #include "configuration.h" #include "addr.h" #include "syscalls.h" +#include "printf.h" #include "rtp.h" #include "defs.h" #include "vector.h" @@ -99,7 +100,7 @@ static FILE *logfp; /** @brief Output device */ /** @brief Buffer low watermark in samples */ -unsigned minbuffer = 4 * (2 * 44100) / 10; /* 0.4 seconds */ +unsigned minbuffer; /** @brief Maximum buffer size in samples * @@ -686,7 +687,7 @@ int main(int argc, char **argv) { struct addrinfo *res; struct stringlist sl; char *sockname; - int rcvbuf, target_rcvbuf = 0; + int rcvbuf, target_rcvbuf = -1; socklen_t len; struct ip_mreq mreq; struct ipv6_mreq mreq6; @@ -767,20 +768,45 @@ int main(int argc, char **argv) { * CoreAudio/AudioHardware.h). */ disorder_fatal(0, "cannot play RTP through RTP"); } - if(!maxbuffer) - maxbuffer = 2 * minbuffer; + /* Set buffering parameters if not overridden */ + if(!minbuffer) { + minbuffer = config->rtp_minbuffer; + if(!minbuffer) minbuffer = (2*44100)*4/10; + } + if(!maxbuffer) { + maxbuffer = config->rtp_maxbuffer; + if(!maxbuffer) maxbuffer = 2 * minbuffer; + } + if(target_rcvbuf < 0) target_rcvbuf = config->rtp_rcvbuf; argc -= optind; argv += optind; switch(argc) { case 0: - /* Get configuration from server */ - if(!(c = disorder_new(1))) exit(EXIT_FAILURE); - if(disorder_connect(c)) exit(EXIT_FAILURE); - if(disorder_rtp_address(c, &address, &port)) exit(EXIT_FAILURE); - sl.n = 2; - sl.s = xcalloc(2, sizeof *sl.s); - sl.s[0] = address; - sl.s[1] = port; + sl.s = xcalloc(3, sizeof *sl.s); + if(config->rtp_always_request) { + sl.s[0] = sl.s[1] = (/*unconst*/ char *)"-"; + sl.n = 2; + } else { + /* Get configuration from server */ + if(!(c = disorder_new(1))) exit(EXIT_FAILURE); + if(disorder_connect(c)) exit(EXIT_FAILURE); + if(disorder_rtp_address(c, &address, &port)) exit(EXIT_FAILURE); + sl.s[0] = address; + sl.s[1] = port; + sl.n = 2; + } + /* If we're requesting a new stream then apply the local network address + * overrides. + */ + if(!strcmp(sl.s[0], "-")) { + if(config->rtp_request_address.port) + byte_xasprintf(&sl.s[1], "%d", config->rtp_request_address.port); + if(config->rtp_request_address.address) { + sl.s[2] = sl.s[1]; + sl.s[1] = config->rtp_request_address.address; + sl.n = 3; + } + } break; case 1: case 2: case 3: /* Use command-line ADDRESS+PORT or just PORT */ @@ -817,7 +843,8 @@ int main(int argc, char **argv) { /* If no address was given, pick something sensible based on the known- * working connectivity to the server */ if(!node) { - int family = disorder_client_af(c); + int family = config->rtp_request_address.af; + if(family == AF_UNSPEC) family = disorder_client_af(c); /* Get a list of interfaces */ struct ifaddrs *ifa, *bestifa = NULL; if(getifaddrs(&ifa) < 0) diff --git a/doc/disorder-playrtp.1.in b/doc/disorder-playrtp.1.in index 5f4fa3f..d453dcb 100644 --- a/doc/disorder-playrtp.1.in +++ b/doc/disorder-playrtp.1.in @@ -126,18 +126,27 @@ You should consult the source code for details of their effects. .B \-\-min \fIFRAMES\fR, \fB\-m \fIFRAMES\fR Specifies the buffer low watermark in frames. This also acts as the target buffer occupancy. +The default is taken from the +.B rtp_minbuffer +configuration parameter. .TP .B \-\-max \fIFRAMES\fR, \fB\-x \fIFRAMES\fR Specifies the maximum buffer size in frames. If there are this many frames in the buffer then reading from the network socket will be suspended. The default is twice the \fB\-\-min\fR value. +The default is taken from the +.B rtp_maxbuffer +configuration parameter. .TP .B \-\-rcvbuf \fIBYTES\fR, \fB\-R \fIBYTES\fR Specifies socket receive buffer size. The default is not to change the buffer size, i.e. you get whatever the local operating system chooses. The buffer size will not be reduced below the operating system's default. +The default is taken from the +.B rtp_rcvbuf +configuration parameter. .TP .B \-\-monitor\fR, \fB\-M Periodically report how close to the buffer low watermark the buffer is. diff --git a/doc/disorder_config.5.in b/doc/disorder_config.5.in index 8f0c8f3..e57e06a 100644 --- a/doc/disorder_config.5.in +++ b/doc/disorder_config.5.in @@ -654,6 +654,56 @@ anything currently listed in the recently-played list. New values of this option may be picked up from the configuration file even without a reload. .TP +.B rtp_always_request yes\fR|\fBno +If +.B yes +then +.BR disorder-playrtp (1) +will always request a dedicated RTP stream, +rather than contacting the server to discover +a broadcast or multicast address. +(This behaviour can be overridden by +setting a suitable address on the command-line.) +The default is +.BR no . +.IP +This option is experimental, +and may change or be removed in a future release. +.TP +.B rtp_maxbuffer \fIFRAMES\fR +Set +.BR disorder-playrtp (1)'s +buffer size to the given number of +.IR FRAMES . +If this is zero, then +.B disorder-playrtp +will select a default buffer size. +(This setting can be overridden by passing +a suitable command-line option.) +The default value is +.BR 0 . +.IP +This option is experimental, +and may change or be removed in a future release. +.TP +.B rtp_minbuffer \fIFRAMES\fR +Set +.BR disorder-playrtp (1)'s +buffer low-water-mark to the given number of +.IR FRAMES . +If this is zero, then +.B disorder-playrtp +will select a default low-water-mark. +(This setting can be overridden by passing +a suitable command-line option.) +.IP +This option is experimental, +and may change or be removed in a future release. +The default value is +.BR 0 . +.IP +This option is experimental, and may change or be removed in a future release. +.TP .B rtp_mode \fIMODE\fR The network transmission mode for the \fBrtp\fR backend. Possible values are: @@ -676,6 +726,46 @@ Choose one of the above based on the destination address. This is the default, for backwards compatibility reasons. .RE .TP +.B rtp_rcvbuf \fISIZE\fR +Set +.BR disorder-playrtp (1)'s +socket receive buffer to at least +.IB SIZE . +(This setting can be overridden by passing +a suitable command-line option.) +The default value is +.BR 0 . +.IP +This option is experimental, +and may change or be removed in a future release. +.TP +.B rtp_request_address \fR[\fIFAMILY\fR] \fR[\fIHOST\fR] \fISERVICE\fR +If +.BR disorder-playrtp (1) +is to request a unicast RTP stream, +then it should establish its receiving socket +to listen on the given address. +The +.I FAMILY +and +.I HOST +may be omitted, in which case +.B disorder-playrtp +uses heuristics to determine suitable values. +The +.I PORT +may be omitted, in which case +.B disorder-playrtp +uses a kernel-allocated port. +(This setting can be overridden by passing +a suitable address on the command line.) +The default is +.RB ` "\- 0" ', +which uses a heuristically-chosen address and a kernel-allocated port. +.IP +This option is experimental, +and may change or be removed in a future release. +.TP .B sample_format \fIBITS\fB/\fIRATE\fB/\fICHANNELS Describes the sample format expected by the \fBspeaker_command\fR (below). The components of the format specification are as follows: diff --git a/lib/configuration.c b/lib/configuration.c index bad3159..d1f14e9 100644 --- a/lib/configuration.c +++ b/lib/configuration.c @@ -1010,6 +1010,32 @@ static int validate_destaddr(const struct config_state attribute((unused)) *cs, return 0; } +/** @brief Validate an internet address + * @param cs Configuration state + * @param nvec Length of (proposed) new value + * @param vec Elements of new value + * @return 0 on success, non-0 on error + * + * By a destination address, it is meant that it must be either IPv4 or IPv6. + */ +static int validate_inetaddr(const struct config_state *cs, + int nvec, char **vec) { + struct netaddress na[1]; + + if(netaddress_parse(na, nvec, vec)) { + disorder_error(0, "%s:%d: invalid network address", cs->path, cs->line); + return -1; + } + switch(na->af) { + case AF_INET: case AF_INET6: case AF_UNSPEC: break; + default: + disorder_error(0, "%s:%d: must be an intenet address", + cs->path, cs->line); + return -1; + } + return 0; +} + /** @brief Item name and and offset */ #define C(x) #x, offsetof(struct config, x) /** @brief Item name and and offset */ @@ -1065,8 +1091,13 @@ static const struct conf conf[] = { { C(reminder_interval), &type_integer, validate_positive }, { C(remote_userman), &type_boolean, validate_any }, { C(replay_min), &type_integer, validate_non_negative }, + { C(rtp_always_request), &type_boolean, validate_any }, { C(rtp_delay_threshold), &type_integer, validate_positive }, + { C(rtp_maxbuffer), &type_integer, validate_non_negative }, + { C(rtp_minbuffer), &type_integer, validate_non_negative }, { C(rtp_mode), &type_string, validate_any }, + { C(rtp_rcvbuf), &type_integer, validate_non_negative }, + { C(rtp_request_address), &type_netaddress, validate_inetaddr }, { C(rtp_verbose), &type_boolean, validate_any }, { C(sample_format), &type_sample_format, validate_sample_format }, { C(scratch), &type_string_accum, validate_isreg }, diff --git a/lib/configuration.h b/lib/configuration.h index 148d08f..5c33047 100644 --- a/lib/configuration.h +++ b/lib/configuration.h @@ -234,6 +234,22 @@ struct config { /** @brief RTP delay threshold */ long rtp_delay_threshold; + /** @brief Whether to ignore the server's suggested RTP arrangement and + * always request a unicast stream */ + int rtp_always_request; + + /** @brief RTP buffer low-water mark */ + long rtp_minbuffer; + + /** @brief RTP buffer maximum size */ + long rtp_maxbuffer; + + /* @brief RTP receive buffer size */ + long rtp_rcvbuf; + + /** @brief Fixed RTP listening address */ + struct netaddress rtp_request_address; + /** @brief Verbose RTP transmission logging */ int rtp_verbose; -- [mdw]