1
0
mirror of https://gitlab.xiph.org/xiph/ezstream.git synced 2024-11-03 04:17:18 -05:00

Make media inputs ("intakes") a list of things, too

This commit is contained in:
Moritz Grimm 2017-11-23 18:34:57 +01:00
parent 184e2dd8c3
commit 0b260b3c08
28 changed files with 872 additions and 335 deletions

View File

@ -307,6 +307,15 @@ The broadcast is private (the default).
.It Ar 1|Yes|True
The broadcast is public.
.El
.It Sy \&<intake\ /\&>
Use the intake
.Po
input media
.Pc
configuration with the provided symbolic name for this stream.
.Pp
Default:
.Ar default
.It Sy \&<server\ /\&>
Use the server configuration with the provided symbolic name for this stream.
.Pp
@ -376,17 +385,41 @@ Informational number of audio channels of the broadcast.
Default:
.Em none
.El
.Ss Media block
.Ss Intakes block
.Bl -tag -width -Ds
.It Sy \&<media\ /\&>
.Pq Mandatory.
This element contains the entire input media configuration as child elements.
.It Sy \&<intakes\ /\&>
This element contains all intake blocks as child elements.
Its parent is the
.Sy \&<ezstream\ /\&>
element.
.Pp
A configuration file may contain multiple named intake configurations.
The stream configuration determines what intake
.Po
media input
.Pc
configuration should be used.
.El
.Ss Media configuration
.Ss Intake block
.Bl -tag -width -Ds
.It Sy \&<intake\ /\&>
.Pq Mandatory.
This element contains the entire input media configuration as child elements.
Its parent is the
.Sy \&<intakes\ /\&>
element.
.El
.Ss Intake configuration
.Bl -tag -width -Ds
.It Sy \&<name\ /\&>
Set the name of the intake configuration.
This may be referenced in a
.Sy \&<stream\ /\&> .
.Pp
The name is case-aware, but not case-sensitive.
.Pp
Default:
.Ar default
.It Sy \&<type\ /\&>
Configure the input media type:
.Pp

View File

@ -26,9 +26,11 @@
</stream>
</streams>
<media>
<filename>%FILENAME%</filename>
</media>
<intakes>
<intake>
<filename>%FILENAME%</filename>
</intake>
</intakes>
<decoders>
<decoder>

View File

@ -75,6 +75,9 @@
<!-- Mount point on server -->
<mountpoint>/stream.ogg</mountpoint>
<!-- Name of the intake entry to use (default: "default") -->
<intake>Default</intake>
<!-- Name of the server entry to use (default: "default") -->
<server>Default</server>
@ -100,21 +103,26 @@
</streams>
<!--
Media configuration
Intake configuration
-->
<media>
<!-- Media type: autodetect, file, playlist, program, stdin -->
<type>autodetect</type>
<intakes>
<intake>
<!-- Identifying name; default: "default" -->
<name>Default</name>
<!-- Input file, program name, or "stdin" keyword -->
<filename>playlist.m3u</filename>
<!-- Media type: autodetect, file, playlist, program, stdin -->
<type>autodetect</type>
<!-- Setting to shuffle playlists -->
<shuffle>Yes</shuffle>
<!-- Input file, program name, or "stdin" keyword -->
<filename>playlist.m3u</filename>
<!-- Setting whether to stream input indefinitely or only once -->
<stream_once>No</stream_once>
</media>
<!-- Setting to shuffle playlists -->
<shuffle>Yes</shuffle>
<!-- Setting whether to stream intake indefinitely or only once -->
<stream_once>No</stream_once>
</intake>
</intakes>
<!--
Metadata configuration

View File

@ -22,8 +22,10 @@
</stream>
</streams>
<media>
<filename>playlist.m3u</filename>
</media>
<intakes>
<intake>
<filename>playlist.m3u</filename>
</intake>
</intakes>
</ezstream>

View File

@ -22,8 +22,10 @@
</stream>
</streams>
<media>
<type>stdin</type>
</media>
<intakes>
<intake>
<type>stdin</type>
</intake>
</intakes>
</ezstream>

View File

@ -21,9 +21,11 @@
</stream>
</streams>
<media>
<filename>playlist.m3u</filename>
</media>
<intakes>
<intake>
<filename>playlist.m3u</filename>
</intake>
</intakes>
<decoders>
<decoder>

View File

@ -6,6 +6,7 @@ noinst_HEADERS = \
cfg.h \
cfg_decoder.h \
cfg_encoder.h \
cfg_intake.h \
cfg_private.h \
cfg_server.h \
cfg_stream.h \
@ -22,6 +23,7 @@ libezstream_la_SOURCES = \
cfg.c \
cfg_decoder.c \
cfg_encoder.c \
cfg_intake.c \
cfg_server.c \
cfg_stream.c \
cfg_xmlfile.c \

124
src/cfg.c
View File

@ -45,10 +45,11 @@ static void _cfg_commit(void);
static void
_cfg_reset(struct cfg *c)
{
cfg_server_list_destroy(&c->servers);
cfg_stream_list_destroy(&c->streams);
cfg_decoder_list_destroy(&c->decoders);
cfg_server_list_destroy(&c->servers);
cfg_intake_list_destroy(&c->intakes);
cfg_encoder_list_destroy(&c->encoders);
cfg_decoder_list_destroy(&c->decoders);
xfree(c->metadata.format_str);
@ -133,47 +134,13 @@ cfg_file_reload(void)
}
int
cfg_check(const char **errstrp)
cfg_check(const char **not_used)
{
if (!cfg_get_media_filename() &&
CFG_MEDIA_STDIN != cfg_get_media_type()) {
if (NULL != errstrp)
*errstrp = "media filename missing";
return (-1);
}
(void)not_used;
return (0);
}
int
cfg_stream_str2fmt(const char *str, enum cfg_stream_format *fmt_p)
{
if (0 == strcasecmp(str, CFG_SFMT_VORBIS)) {
*fmt_p = CFG_STREAM_VORBIS;
} else if (0 == strcasecmp(str, CFG_SFMT_MP3)) {
*fmt_p = CFG_STREAM_MP3;
} else if (0 == strcasecmp(str, CFG_SFMT_THEORA)) {
*fmt_p = CFG_STREAM_THEORA;
} else
return (-1);
return (0);
}
const char *
cfg_stream_fmt2str(enum cfg_stream_format fmt)
{
switch (fmt) {
case CFG_STREAM_VORBIS:
return (CFG_SFMT_VORBIS);
case CFG_STREAM_MP3:
return (CFG_SFMT_MP3);
case CFG_STREAM_THEORA:
return (CFG_SFMT_THEORA);
default:
return (NULL);
}
}
int
cfg_file_check(const char *file)
{
@ -215,6 +182,15 @@ cfg_get_encoders(void)
return (cfg.encoders);
}
cfg_intake_list_t
cfg_get_intakes(void)
{
if (!cfg.intakes)
cfg.intakes = cfg_intake_list_create();
return (cfg.intakes);
}
cfg_server_list_t
cfg_get_servers(void)
{
@ -290,54 +266,6 @@ cfg_set_program_verbosity(unsigned int verbosity, const char **not_used)
return (0);
}
int
cfg_set_media_type(const char *type, const char **errstrp)
{
if (!type || !type[0]) {
if (errstrp)
*errstrp = "empty";
return (-1);
}
if (0 == strcasecmp("autodetect", type))
cfg.media.type = CFG_MEDIA_AUTODETECT;
else if (0 == strcasecmp("file", type))
cfg.media.type = CFG_MEDIA_FILE;
else if (0 == strcasecmp("playlist", type))
cfg.media.type = CFG_MEDIA_PLAYLIST;
else if (0 == strcasecmp("program", type))
cfg.media.type = CFG_MEDIA_PROGRAM;
else if (0 == strcasecmp("stdin", type))
cfg.media.type = CFG_MEDIA_STDIN;
else {
if (errstrp)
*errstrp = "unsupported";
return (-1);
}
return (0);
}
int
cfg_set_media_filename(const char *filename, const char **errstrp)
{
SET_STRLCPY(cfg.media.filename, filename, errstrp);
return (0);
}
int
cfg_set_media_shuffle(const char *shuffle, const char **errstrp)
{
SET_BOOLEAN(cfg.media.shuffle, shuffle, errstrp);
return (0);
}
int
cfg_set_media_stream_once(const char *stream_once, const char **errstrp)
{
SET_BOOLEAN(cfg.media.stream_once, stream_once, errstrp);
return (0);
}
int
cfg_set_metadata_program(const char *program, const char **errstrp)
{
@ -433,30 +361,6 @@ cfg_get_program_verbosity(void)
return (cfg_program.verbosity);
}
enum cfg_media_type
cfg_get_media_type(void)
{
return (cfg.media.type);
}
const char *
cfg_get_media_filename(void)
{
return (cfg.media.filename[0] ? cfg.media.filename : NULL);
}
int
cfg_get_media_shuffle(void)
{
return (cfg.media.shuffle);
}
int
cfg_get_media_stream_once(void)
{
return (cfg.media.stream_once);
}
const char *
cfg_get_metadata_program(void)
{

View File

@ -17,10 +17,6 @@
#ifndef __CFG_H__
#define __CFG_H__
#define CFG_SFMT_VORBIS "VORBIS"
#define CFG_SFMT_MP3 "MP3"
#define CFG_SFMT_THEORA "THEORA"
#define PLACEHOLDER_METADATA "@M@"
#define PLACEHOLDER_ARTIST "@a@"
#define PLACEHOLDER_ALBUM "@b@"
@ -36,27 +32,9 @@ enum cfg_config_type {
CFG_TYPE_MAX = CFG_TYPE_XMLFILE,
};
enum cfg_media_type {
CFG_MEDIA_AUTODETECT = 0,
CFG_MEDIA_FILE,
CFG_MEDIA_PLAYLIST,
CFG_MEDIA_PROGRAM,
CFG_MEDIA_STDIN,
CFG_MEDIA_MIN = CFG_MEDIA_AUTODETECT,
CFG_MEDIA_MAX = CFG_MEDIA_STDIN,
};
enum cfg_stream_format {
CFG_STREAM_INVALID = 0,
CFG_STREAM_VORBIS,
CFG_STREAM_MP3,
CFG_STREAM_THEORA,
CFG_STREAM_MIN = CFG_STREAM_VORBIS,
CFG_STREAM_MAX = CFG_STREAM_THEORA,
};
#include "cfg_decoder.h"
#include "cfg_encoder.h"
#include "cfg_intake.h"
#include "cfg_server.h"
#include "cfg_stream.h"
@ -67,16 +45,14 @@ int cfg_file_reload(void);
int cfg_check(const char **);
int cfg_stream_str2fmt(const char *, enum cfg_stream_format *);
const char *
cfg_stream_fmt2str(enum cfg_stream_format);
int cfg_file_check(const char *);
cfg_decoder_list_t
cfg_get_decoders(void);
cfg_encoder_list_t
cfg_get_encoders(void);
cfg_intake_list_t
cfg_get_intakes(void);
cfg_server_list_t
cfg_get_servers(void);
cfg_stream_list_t
@ -90,11 +66,6 @@ int cfg_set_program_quiet_stderr(int, const char **);
int cfg_set_program_rtstatus_output(int, const char **);
int cfg_set_program_verbosity(unsigned int, const char **);
int cfg_set_media_type(const char *, const char **);
int cfg_set_media_filename(const char *, const char **);
int cfg_set_media_shuffle(const char *, const char **);
int cfg_set_media_stream_once(const char *, const char **);
int cfg_set_metadata_program(const char *, const char **);
int cfg_set_metadata_format_str(const char *, const char **);
int cfg_set_metadata_refresh_interval(const char *, const char **);
@ -114,13 +85,6 @@ int cfg_get_program_rtstatus_output(void);
unsigned int
cfg_get_program_verbosity(void);
enum cfg_media_type
cfg_get_media_type(void);
const char *
cfg_get_media_filename(void);
int cfg_get_media_shuffle(void);
int cfg_get_media_stream_once(void);
const char *
cfg_get_metadata_program(void);
const char *

View File

@ -17,6 +17,8 @@
#ifndef __CFG_ENCODER_H__
#define __CFG_ENCODER_H__
#include "cfg_stream.h"
typedef struct cfg_encoder * cfg_encoder_t;
typedef struct cfg_encoder_list * cfg_encoder_list_t;

247
src/cfg_intake.c Normal file
View File

@ -0,0 +1,247 @@
/*
* Copyright (c) 2017 Moritz Grimm <mgrimm@mrsserver.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif /* HAVE_CONFIG_H */
#include "compat.h"
#include <sys/queue.h>
#include <string.h>
#include "cfg_private.h"
#include "cfg_intake.h"
#include "xalloc.h"
struct cfg_intake {
TAILQ_ENTRY(cfg_intake) entry;
char *name;
enum cfg_intake_type type;
char filename[PATH_MAX];
int shuffle;
int stream_once;
};
TAILQ_HEAD(cfg_intake_list, cfg_intake);
struct cfg_intake_list *
cfg_intake_list_create(void)
{
struct cfg_intake_list *il;
il = xcalloc(1UL, sizeof(*il));
TAILQ_INIT(il);
return (il);
}
void
cfg_intake_list_destroy(cfg_intake_list_t *il_p)
{
struct cfg_intake_list *il = *il_p;
struct cfg_intake *i;
if (!il)
return;
while (NULL != (i = TAILQ_FIRST(il))) {
TAILQ_REMOVE(il, i, entry);
cfg_intake_destroy(&i);
}
xfree(il);
*il_p = NULL;
}
struct cfg_intake *
cfg_intake_list_find(struct cfg_intake_list *il, const char *name)
{
struct cfg_intake *i;
TAILQ_FOREACH(i, il, entry) {
if (0 == strcasecmp(i->name, name))
return (i);
}
return (NULL);
}
struct cfg_intake *
cfg_intake_list_get(struct cfg_intake_list *il, const char *name)
{
struct cfg_intake *i;
i = cfg_intake_list_find(il, name);
if (i)
return (i);
i = cfg_intake_create(name);
if (!i)
return (NULL);
TAILQ_INSERT_TAIL(il, i, entry);
return (i);
}
struct cfg_intake *
cfg_intake_create(const char *name)
{
struct cfg_intake *i;
if (!name || !name[0])
return (NULL);
i = xcalloc(1UL, sizeof(*i));
i->name = xstrdup(name);
return (i);
}
void
cfg_intake_destroy(struct cfg_intake **i_p)
{
struct cfg_intake *i = *i_p;
xfree(i->name);
xfree(i);
*i_p = NULL;
}
int
cfg_intake_set_name(struct cfg_intake *i, struct cfg_intake_list *il,
const char *name, const char **errstrp)
{
struct cfg_intake *i2;
if (!name || !name[0]) {
if (errstrp)
*errstrp = "empty";
return (-1);
}
i2 = cfg_intake_list_find(il, name);
if (i2 && i2 != i) {
if (errstrp)
*errstrp = "already exists";
return (-1);
}
SET_XSTRDUP(i->name, name, errstrp);
return (0);
}
int
cfg_intake_set_type(struct cfg_intake *i, struct cfg_intake_list *not_used,
const char *type, const char **errstrp)
{
(void)not_used;
if (!type || !type[0]) {
if (errstrp)
*errstrp = "empty";
return (-1);
}
if (0 == strcasecmp("autodetect", type))
i->type = CFG_INTAKE_AUTODETECT;
else if (0 == strcasecmp("file", type))
i->type = CFG_INTAKE_FILE;
else if (0 == strcasecmp("playlist", type))
i->type = CFG_INTAKE_PLAYLIST;
else if (0 == strcasecmp("program", type))
i->type = CFG_INTAKE_PROGRAM;
else if (0 == strcasecmp("stdin", type))
i->type = CFG_INTAKE_STDIN;
else {
if (errstrp)
*errstrp = "unsupported";
return (-1);
}
return (0);
}
int
cfg_intake_set_filename(struct cfg_intake *i, struct cfg_intake_list *not_used,
const char *filename, const char **errstrp)
{
(void)not_used;
SET_STRLCPY(i->filename, filename, errstrp);
return (0);
}
int
cfg_intake_set_shuffle(struct cfg_intake *i, struct cfg_intake_list *not_used,
const char *shuffle, const char **errstrp)
{
(void)not_used;
SET_BOOLEAN(i->shuffle, shuffle, errstrp);
return (0);
}
int
cfg_intake_set_stream_once(struct cfg_intake *i, struct cfg_intake_list *not_used,
const char *stream_once, const char **errstrp)
{
(void)not_used;
SET_BOOLEAN(i->stream_once, stream_once, errstrp);
return (0);
}
int
cfg_intake_validate(struct cfg_intake *i, const char **errstrp)
{
if (!cfg_intake_get_filename(i) &&
CFG_INTAKE_STDIN != cfg_intake_get_type(i)) {
if (NULL != errstrp)
*errstrp = "intake filename missing";
return (-1);
}
return (0);
}
const char *
cfg_intake_get_name(struct cfg_intake *i)
{
return (i->name);
}
enum cfg_intake_type
cfg_intake_get_type(struct cfg_intake *i)
{
return (i->type);
}
const char *
cfg_intake_get_filename(struct cfg_intake *i)
{
return (i->filename[0] ? i->filename : NULL);
}
int
cfg_intake_get_shuffle(struct cfg_intake *i)
{
return (i->shuffle);
}
int
cfg_intake_get_stream_once(struct cfg_intake *i)
{
return (i->stream_once);
}

68
src/cfg_intake.h Normal file
View File

@ -0,0 +1,68 @@
/*
* Copyright (c) 2017 Moritz Grimm <mgrimm@mrsserver.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef __CFG_INTAKE_H__
#define __CFG_INTAKE_H__
enum cfg_intake_type {
CFG_INTAKE_AUTODETECT = 0,
CFG_INTAKE_FILE,
CFG_INTAKE_PLAYLIST,
CFG_INTAKE_PROGRAM,
CFG_INTAKE_STDIN,
CFG_INTAKE_MIN = CFG_INTAKE_AUTODETECT,
CFG_INTAKE_MAX = CFG_INTAKE_STDIN,
};
typedef struct cfg_intake * cfg_intake_t;
typedef struct cfg_intake_list * cfg_intake_list_t;
cfg_intake_list_t
cfg_intake_list_create(void);
void cfg_intake_list_destroy(cfg_intake_list_t *);
cfg_intake_t
cfg_intake_list_find(cfg_intake_list_t, const char *);
cfg_intake_t
cfg_intake_list_get(cfg_intake_list_t, const char *);
cfg_intake_t
cfg_intake_create(const char *);
void cfg_intake_destroy(cfg_intake_t *);
int cfg_intake_set_name(cfg_intake_t, cfg_intake_list_t, const char *,
const char **);
int cfg_intake_set_type(cfg_intake_t, cfg_intake_list_t, const char *,
const char **);
int cfg_intake_set_filename(cfg_intake_t, cfg_intake_list_t, const char *,
const char **);
int cfg_intake_set_shuffle(cfg_intake_t, cfg_intake_list_t, const char *,
const char **);
int cfg_intake_set_stream_once(cfg_intake_t, cfg_intake_list_t,
const char *, const char **);
int cfg_intake_validate(cfg_intake_t, const char **);
const char *
cfg_intake_get_name(cfg_intake_t);
enum cfg_intake_type
cfg_intake_get_type(cfg_intake_t);
const char *
cfg_intake_get_filename(cfg_intake_t);
int cfg_intake_get_shuffle(cfg_intake_t);
int cfg_intake_get_stream_once(cfg_intake_t);
#endif /* __CFG_INTAKE_H__ */

View File

@ -44,14 +44,11 @@ struct cfg_program {
};
struct cfg {
cfg_decoder_list_t decoders;
cfg_encoder_list_t encoders;
cfg_intake_list_t intakes;
cfg_server_list_t servers;
cfg_stream_list_t streams;
struct media {
enum cfg_media_type type;
char filename[PATH_MAX];
int shuffle;
int stream_once;
} media;
struct metadata {
char program[PATH_MAX];
char *format_str;
@ -59,8 +56,6 @@ struct cfg {
int normalize_strings;
int no_updates;
} metadata;
cfg_decoder_list_t decoders;
cfg_encoder_list_t encoders;
};
#define SET_STRLCPY(t, s, e) do { \

View File

@ -30,6 +30,7 @@ struct cfg_stream {
TAILQ_ENTRY(cfg_stream) entry;
char *name;
char *mountpoint;
char *intake;
char *server;
int public;
enum cfg_stream_format format;
@ -126,6 +127,7 @@ cfg_stream_destroy(struct cfg_stream **s_p)
xfree(s->name);
xfree(s->mountpoint);
xfree(s->intake);
xfree(s->server);
xfree(s->encoder);
xfree(s->stream_name);
@ -140,6 +142,36 @@ cfg_stream_destroy(struct cfg_stream **s_p)
*s_p = NULL;
}
int
cfg_stream_str2fmt(const char *str, enum cfg_stream_format *fmt_p)
{
if (0 == strcasecmp(str, CFG_SFMT_VORBIS)) {
*fmt_p = CFG_STREAM_VORBIS;
} else if (0 == strcasecmp(str, CFG_SFMT_MP3)) {
*fmt_p = CFG_STREAM_MP3;
} else if (0 == strcasecmp(str, CFG_SFMT_THEORA)) {
*fmt_p = CFG_STREAM_THEORA;
} else
return (-1);
return (0);
}
const char *
cfg_stream_fmt2str(enum cfg_stream_format fmt)
{
switch (fmt) {
case CFG_STREAM_VORBIS:
return (CFG_SFMT_VORBIS);
case CFG_STREAM_MP3:
return (CFG_SFMT_MP3);
case CFG_STREAM_THEORA:
return (CFG_SFMT_THEORA);
default:
return (NULL);
}
}
int
cfg_stream_set_name(struct cfg_stream *s, struct cfg_stream_list *sl,
const char *name, const char **errstrp)
@ -174,6 +206,15 @@ cfg_stream_set_mountpoint(struct cfg_stream *s,
return (0);
}
int
cfg_stream_set_intake(struct cfg_stream *s, struct cfg_stream_list *not_used,
const char *intake, const char **errstrp)
{
(void)not_used;
SET_XSTRDUP(s->intake, intake, errstrp);
return (0);
}
int
cfg_stream_set_server(struct cfg_stream *s, struct cfg_stream_list *not_used,
const char *server, const char **errstrp)
@ -330,6 +371,12 @@ cfg_stream_get_mountpoint(struct cfg_stream *s)
return (s->mountpoint);
}
const char *
cfg_stream_get_intake(struct cfg_stream *s)
{
return (s->intake);
}
const char *
cfg_stream_get_server(struct cfg_stream *s)
{

View File

@ -17,6 +17,19 @@
#ifndef __CFG_STREAM_H__
#define __CFG_STREAM_H__
#define CFG_SFMT_VORBIS "VORBIS"
#define CFG_SFMT_MP3 "MP3"
#define CFG_SFMT_THEORA "THEORA"
enum cfg_stream_format {
CFG_STREAM_INVALID = 0,
CFG_STREAM_VORBIS,
CFG_STREAM_MP3,
CFG_STREAM_THEORA,
CFG_STREAM_MIN = CFG_STREAM_VORBIS,
CFG_STREAM_MAX = CFG_STREAM_THEORA,
};
typedef struct cfg_stream * cfg_stream_t;
typedef struct cfg_stream_list * cfg_stream_list_t;
@ -33,10 +46,16 @@ cfg_stream_t
cfg_stream_create(const char *);
void cfg_stream_destroy(cfg_stream_t *);
int cfg_stream_str2fmt(const char *, enum cfg_stream_format *);
const char *
cfg_stream_fmt2str(enum cfg_stream_format);
int cfg_stream_set_name(cfg_stream_t, cfg_stream_list_t, const char *,
const char **);
int cfg_stream_set_mountpoint(cfg_stream_t, cfg_stream_list_t,
const char *, const char **);
int cfg_stream_set_intake(cfg_stream_t, cfg_stream_list_t, const char *,
const char **);
int cfg_stream_set_server(cfg_stream_t, cfg_stream_list_t, const char *,
const char **);
int cfg_stream_set_public(cfg_stream_t, cfg_stream_list_t, const char *,
@ -68,6 +87,8 @@ const char *
cfg_stream_get_name(cfg_stream_t);
const char *
cfg_stream_get_mountpoint(cfg_stream_t);
const char *
cfg_stream_get_intake(cfg_stream_t);
const char *
cfg_stream_get_server(cfg_stream_t);
int cfg_stream_get_public(cfg_stream_t);

View File

@ -29,7 +29,8 @@ static int _cfg_xmlfile_parse_server(xmlDocPtr, xmlNodePtr);
static int _cfg_xmlfile_parse_servers(xmlDocPtr, xmlNodePtr);
static int _cfg_xmlfile_parse_stream(xmlDocPtr, xmlNodePtr);
static int _cfg_xmlfile_parse_streams(xmlDocPtr, xmlNodePtr);
static int _cfg_xmlfile_parse_media(xmlDocPtr, xmlNodePtr);
static int _cfg_xmlfile_parse_intake(xmlDocPtr, xmlNodePtr);
static int _cfg_xmlfile_parse_intakes(xmlDocPtr, xmlNodePtr);
static int _cfg_xmlfile_parse_metadata(xmlDocPtr, xmlNodePtr);
static int _cfg_xmlfile_parse_decoder(xmlDocPtr, xmlNodePtr);
static int _cfg_xmlfile_parse_decoders(xmlDocPtr, xmlNodePtr);
@ -46,7 +47,7 @@ static int _cfg_xmlfile_parse_encoders(xmlDocPtr, xmlNodePtr);
int error = 0; \
\
val = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); \
if (0 > (f)((c), (l), STD_CHAR(val), &err_str)) { \
if (0 > (f)((c), (l), STD_CHAR(val), &err_str)) { \
log_error("%s[%ld]: server (%s): %s: %s", \
doc->name, xmlGetLineNo(cur), \
cfg_server_get_name((c)), (e), err_str); \
@ -112,7 +113,7 @@ _cfg_xmlfile_parse_servers(xmlDocPtr doc, xmlNodePtr cur)
int error = 0; \
\
val = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); \
if (0 > (f)((c), (l), STD_CHAR(val), &err_str)) { \
if (0 > (f)((c), (l), STD_CHAR(val), &err_str)) { \
log_error("%s[%ld]: stream (%s): %s: %s", \
doc->name, xmlGetLineNo(cur), \
cfg_stream_get_name((c)), (e), err_str); \
@ -138,6 +139,7 @@ _cfg_xmlfile_parse_stream(xmlDocPtr doc, xmlNodePtr cur)
for (cur = cur->xmlChildrenNode; cur; cur = cur->next) {
XML_STREAM_SET(s, sl, cfg_stream_set_name, "name");
XML_STREAM_SET(s, sl, cfg_stream_set_mountpoint, "mountpoint");
XML_STREAM_SET(s, sl, cfg_stream_set_intake, "intake");
XML_STREAM_SET(s, sl, cfg_stream_set_server, "server");
XML_STREAM_SET(s, sl, cfg_stream_set_public, "public");
XML_STREAM_SET(s, sl, cfg_stream_set_format, "format");
@ -172,6 +174,65 @@ _cfg_xmlfile_parse_streams(xmlDocPtr doc, xmlNodePtr cur)
return (0);
}
#define XML_INPUT_SET(c, l, f, e) do { \
if (0 == xmlStrcasecmp(cur->name, XML_CHAR((e)))) { \
xmlChar *val; \
const char *err_str; \
int error = 0; \
\
val = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); \
if (0 > (f)((c), (l), STD_CHAR(val), &err_str)) { \
log_error("%s[%ld]: intake (%s): %s: %s", \
doc->name, xmlGetLineNo(cur), \
cfg_intake_get_name((c)), (e), err_str); \
error = 1; \
} \
xmlFree(val); \
if (error) \
return (-1); \
} \
} while (0)
static int
_cfg_xmlfile_parse_intake(xmlDocPtr doc, xmlNodePtr cur)
{
cfg_intake_list_t il;
cfg_intake_t i;
const char *errstr;
long int line_no = xmlGetLineNo(cur);
il = cfg_get_intakes();
i = cfg_intake_list_get(il, CFG_DEFAULT);
for (cur = cur->xmlChildrenNode; cur; cur = cur->next) {
XML_INPUT_SET(i, il, cfg_intake_set_name, "name");
XML_INPUT_SET(i, il, cfg_intake_set_type, "type");
XML_INPUT_SET(i, il, cfg_intake_set_filename, "filename");
XML_INPUT_SET(i, il, cfg_intake_set_shuffle, "shuffle");
XML_INPUT_SET(i, il, cfg_intake_set_stream_once, "stream_once");
}
if (0 > cfg_intake_validate(i, &errstr)) {
log_error("%s[%ld]: intake (%s): %s", doc->name, line_no,
cfg_intake_get_name(i), errstr);
return (-1);
}
return (0);
}
static int
_cfg_xmlfile_parse_intakes(xmlDocPtr doc, xmlNodePtr cur)
{
for (cur = cur->xmlChildrenNode; cur; cur = cur->next) {
if (0 == xmlStrcasecmp(cur->name, XML_CHAR("intake")) &&
0 > _cfg_xmlfile_parse_intake(doc, cur))
return (-1);
}
return (0);
}
#define XML_STRCONFIG(s, f, e) do { \
if (0 == xmlStrcasecmp(cur->name, XML_CHAR((e)))) { \
xmlChar *val; \
@ -187,24 +248,6 @@ _cfg_xmlfile_parse_streams(xmlDocPtr doc, xmlNodePtr cur)
} \
} while (0)
static int
_cfg_xmlfile_parse_media(xmlDocPtr doc, xmlNodePtr cur)
{
int error = 0;
for (cur = cur->xmlChildrenNode; cur; cur = cur->next) {
XML_STRCONFIG("media", cfg_set_media_type, "type");
XML_STRCONFIG("media", cfg_set_media_filename, "filename");
XML_STRCONFIG("media", cfg_set_media_shuffle, "shuffle");
XML_STRCONFIG("media", cfg_set_media_stream_once, "stream_once");
}
if (error)
return (-1);
return (0);
}
static int
_cfg_xmlfile_parse_metadata(xmlDocPtr doc, xmlNodePtr cur)
{
@ -233,7 +276,7 @@ _cfg_xmlfile_parse_metadata(xmlDocPtr doc, xmlNodePtr cur)
int error = 0; \
\
val = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); \
if (0 > (f)((c), (l), STD_CHAR(val), &err_str)) { \
if (0 > (f)((c), (l), STD_CHAR(val), &err_str)) { \
log_error("%s[%ld]: decoder (%s): %s: %s", \
doc->name, xmlGetLineNo(cur), \
cfg_decoder_get_name((c)), (e), err_str); \
@ -290,7 +333,7 @@ _cfg_xmlfile_parse_decoders(xmlDocPtr doc, xmlNodePtr cur)
int error = 0; \
\
val = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); \
if (0 > (f)((c), (l), STD_CHAR(val), &err_str)) { \
if (0 > (f)((c), (l), STD_CHAR(val), &err_str)) { \
log_error("%s[%ld]: encoder (%s): %s: %s", \
doc->name, xmlGetLineNo(cur), \
cfg_encoder_get_name((c)), (e), err_str); \
@ -364,6 +407,7 @@ _cfg_xmlfile_parse_encoders(xmlDocPtr doc, xmlNodePtr cur)
* name
* mountpoint
* public
* intake
* server
* format
* encoder
@ -376,11 +420,13 @@ _cfg_xmlfile_parse_encoders(xmlDocPtr doc, xmlNodePtr cur)
* stream_samplerate
* stream_channels
* ...
* media
* type
* filename
* shuffle
* stream_once
* intakes
* intake
* type
* filename
* shuffle
* stream_once
* ...
* metadata
* program
* format_str
@ -441,8 +487,8 @@ cfg_xmlfile_parse(const char *config_file)
error = 1;
continue;
}
if (0 == xmlStrcasecmp(cur->name, XML_CHAR("media"))) {
if (0 > _cfg_xmlfile_parse_media(doc, cur))
if (0 == xmlStrcasecmp(cur->name, XML_CHAR("intakes"))) {
if (0 > _cfg_xmlfile_parse_intakes(doc, cur))
error = 1;
continue;
}

View File

@ -407,6 +407,7 @@ sendStream(stream_t stream, FILE *filepstream, const char *fileName,
struct timespec timeStamp, *startTime = tv;
struct timespec callTime, currentTime;
cfg_server_t cfg_server = stream_get_cfg_server(stream);
cfg_intake_t cfg_intake = stream_get_cfg_intake(stream);
clock_gettime(CLOCK_MONOTONIC, &callTime);
@ -437,7 +438,7 @@ sendStream(stream_t stream, FILE *filepstream, const char *fileName,
break;
if (rereadPlaylist_notify) {
rereadPlaylist_notify = 0;
if (CFG_MEDIA_PLAYLIST == cfg_get_media_type())
if (CFG_INTAKE_PLAYLIST == cfg_intake_get_type(cfg_intake))
log_notice("HUP signal received: playlist re-read scheduled");
}
if (skipTrack) {
@ -464,8 +465,8 @@ sendStream(stream_t stream, FILE *filepstream, const char *fileName,
double oldTime, newTime;
if (!isStdin && playlistMode) {
if (CFG_MEDIA_PROGRAM == cfg_get_media_type()) {
char *tmp = xstrdup(cfg_get_media_filename());
if (CFG_INTAKE_PROGRAM == cfg_intake_get_type(cfg_intake)) {
char *tmp = xstrdup(cfg_intake_get_filename(cfg_intake));
printf(" [%s]", basename(tmp));
xfree(tmp);
} else
@ -523,12 +524,13 @@ streamFile(stream_t stream, const char *fileName)
FILE *filepstream = NULL;
int popenFlag = 0;
char *songLenStr = NULL;
int isStdin = cfg_get_media_type() == CFG_MEDIA_STDIN;
int ret, retval = 0;
long songLen;
mdata_t md = NULL;
struct timespec startTime;
cfg_stream_t cfg_stream = stream_get_cfg_stream(stream);
cfg_intake_t cfg_intake = stream_get_cfg_intake(stream);
int isStdin = cfg_intake_get_type(cfg_intake) == CFG_INTAKE_STDIN;
if ((filepstream = openResource(stream, fileName, &popenFlag, &md, &isStdin, &songLen))
== NULL) {
@ -633,23 +635,24 @@ streamPlaylist(stream_t stream)
{
const char *song;
char lastSong[PATH_MAX];
cfg_intake_t cfg_intake = stream_get_cfg_intake(stream);
if (playlist == NULL) {
switch (cfg_get_media_type()) {
case CFG_MEDIA_PROGRAM:
if ((playlist = playlist_program(cfg_get_media_filename())) == NULL)
switch (cfg_intake_get_type(cfg_intake)) {
case CFG_INTAKE_PROGRAM:
if ((playlist = playlist_program(cfg_intake_get_filename(cfg_intake))) == NULL)
return (0);
break;
case CFG_MEDIA_STDIN:
case CFG_INTAKE_STDIN:
if ((playlist = playlist_read(NULL)) == NULL)
return (0);
break;
default:
if ((playlist = playlist_read(cfg_get_media_filename())) == NULL)
if ((playlist = playlist_read(cfg_intake_get_filename(cfg_intake))) == NULL)
return (0);
if (playlist_get_num_items(playlist) == 0)
log_warning("%s: playlist empty",
cfg_get_media_filename());
cfg_intake_get_filename(cfg_intake));
break;
}
} else {
@ -661,8 +664,8 @@ streamPlaylist(stream_t stream)
playlist_rewind(playlist);
}
if (CFG_MEDIA_PROGRAM != cfg_get_media_type() &&
cfg_get_media_shuffle())
if (CFG_INTAKE_PROGRAM != cfg_intake_get_type(cfg_intake) &&
cfg_intake_get_shuffle(cfg_intake))
playlist_shuffle(playlist);
while ((song = playlist_get_next(playlist)) != NULL) {
@ -673,12 +676,12 @@ streamPlaylist(stream_t stream)
break;
if (rereadPlaylist) {
rereadPlaylist = rereadPlaylist_notify = 0;
if (CFG_MEDIA_PROGRAM == cfg_get_media_type())
if (CFG_INTAKE_PROGRAM == cfg_intake_get_type(cfg_intake))
continue;
log_notice("rereading playlist");
if (!playlist_reread(&playlist))
return (0);
if (cfg_get_media_shuffle())
if (cfg_intake_get_shuffle(cfg_intake))
playlist_shuffle(playlist);
else {
playlist_goto_entry(playlist, lastSong);
@ -716,6 +719,7 @@ main(int argc, char *argv[])
unsigned int i;
cfg_server_t cfg_server;
cfg_stream_t cfg_stream;
cfg_intake_t cfg_intake;
ret = 1;
if (0 > cfg_init() ||
@ -736,6 +740,7 @@ main(int argc, char *argv[])
return (ez_shutdown(1));
cfg_server = stream_get_cfg_server(main_stream);
cfg_stream = stream_get_cfg_stream(main_stream);
cfg_intake = stream_get_cfg_intake(main_stream);
memset(&act, 0, sizeof(act));
act.sa_handler = sig_handler;
@ -774,11 +779,11 @@ main(int argc, char *argv[])
cfg_server_get_port(cfg_server),
cfg_stream_get_mountpoint(cfg_stream));
if (CFG_MEDIA_PROGRAM == cfg_get_media_type() ||
CFG_MEDIA_PLAYLIST == cfg_get_media_type() ||
(CFG_MEDIA_AUTODETECT == cfg_get_media_type() &&
(util_strrcasecmp(cfg_get_media_filename(), ".m3u") == 0 ||
util_strrcasecmp(cfg_get_media_filename(), ".txt") == 0)))
if (CFG_INTAKE_PROGRAM == cfg_intake_get_type(cfg_intake) ||
CFG_INTAKE_PLAYLIST == cfg_intake_get_type(cfg_intake) ||
(CFG_INTAKE_AUTODETECT == cfg_intake_get_type(cfg_intake) &&
(util_strrcasecmp(cfg_intake_get_filename(cfg_intake), ".m3u") == 0 ||
util_strrcasecmp(cfg_intake_get_filename(cfg_intake), ".txt") == 0)))
playlistMode = 1;
else
playlistMode = 0;
@ -788,11 +793,11 @@ main(int argc, char *argv[])
cont = streamPlaylist(main_stream);
} else {
cont = streamFile(main_stream,
cfg_get_media_filename());
cfg_intake_get_filename(cfg_intake));
}
if (quit)
break;
if (cfg_get_media_stream_once())
if (cfg_intake_get_stream_once(cfg_intake))
break;
} while (cont);

View File

@ -447,6 +447,19 @@ stream_get_cfg_stream(struct stream *s)
return (cfg_stream_list_find(cfg_get_streams(), s->name));
}
cfg_intake_t
stream_get_cfg_intake(struct stream *s)
{
cfg_stream_t cfg_stream;
const char *intake;
cfg_stream = cfg_stream_list_get(cfg_get_streams(), s->name);
intake = cfg_stream_get_intake(cfg_stream);
if (!intake)
intake = CFG_DEFAULT;
return (cfg_intake_list_get(cfg_get_intakes(), intake));
}
cfg_server_t
stream_get_cfg_server(struct stream *s)
{

View File

@ -39,6 +39,8 @@ const char *
int stream_get_connected(stream_t);
cfg_stream_t
stream_get_cfg_stream(stream_t);
cfg_intake_t
stream_get_cfg_intake(stream_t);
cfg_server_t
stream_get_cfg_server(stream_t);

View File

@ -4,6 +4,7 @@ TESTS = \
check_cfg \
check_cfg_decoder \
check_cfg_encoder \
check_cfg_intake \
check_cfg_server \
check_cfg_stream \
check_cfg_xmlfile \
@ -30,6 +31,10 @@ check_cfg_encoder_SOURCES = check_cfg_encoder.c
check_cfg_encoder_DEPENDENCIES = $(top_builddir)/src/libezstream.la
check_cfg_encoder_LDADD = $(check_cfg_encoder_DEPENDENCIES) @CHECK_LIBS@
check_cfg_intake_SOURCES = check_cfg_intake.c
check_cfg_intake_DEPENDENCIES = $(top_builddir)/src/libezstream.la
check_cfg_intake_LDADD = $(check_cfg_intake_DEPENDENCIES) @CHECK_LIBS@
check_cfg_server_SOURCES = check_cfg_server.c
check_cfg_server_DEPENDENCIES = $(top_builddir)/src/libezstream.la
check_cfg_server_LDADD = $(check_cfg_server_DEPENDENCIES) @CHECK_LIBS@
@ -87,6 +92,7 @@ EXTRA_DIST = \
config-bad3.xml \
config-bad4.xml \
config-bad5.xml \
config-bad6.xml \
play-bad.sh \
play-bad2.sh \
play-bad3.sh \

View File

@ -13,49 +13,7 @@ void teardown_checked(void);
START_TEST(test_check)
{
const char *errstr = NULL;
ck_assert_int_eq(cfg_check(NULL), -1);
ck_assert_int_eq(cfg_check(&errstr), -1);
ck_assert_str_eq(errstr, "media filename missing");
ck_assert_int_eq(cfg_set_media_type("stdin", NULL), 0);
ck_assert_int_eq(cfg_check(NULL), 0);
ck_assert_int_eq(cfg_set_media_type("autodetect", NULL), 0);
ck_assert_int_eq(cfg_check(NULL), -1);
ck_assert_int_eq(cfg_check(&errstr), -1);
ck_assert_str_eq(errstr, "media filename missing");
ck_assert_int_eq(cfg_set_media_filename(SRCDIR "/playlist.txt", NULL),
0);
ck_assert_int_eq(cfg_check(NULL), 0);
}
END_TEST
START_TEST(test_stream_str2fmt)
{
enum cfg_stream_format fmt;
ck_assert_int_eq(cfg_stream_str2fmt(CFG_SFMT_VORBIS, &fmt), 0);
ck_assert_int_eq(fmt, CFG_STREAM_VORBIS);
ck_assert_int_eq(cfg_stream_str2fmt(CFG_SFMT_MP3, &fmt), 0);
ck_assert_int_eq(fmt, CFG_STREAM_MP3);
ck_assert_int_eq(cfg_stream_str2fmt(CFG_SFMT_THEORA, &fmt), 0);
ck_assert_int_eq(fmt, CFG_STREAM_THEORA);
ck_assert_int_eq(cfg_stream_str2fmt("<something else>", &fmt), -1);
}
END_TEST
START_TEST(test_stream_fmt2str)
{
ck_assert_str_eq(cfg_stream_fmt2str(CFG_STREAM_VORBIS),
CFG_SFMT_VORBIS);
ck_assert_str_eq(cfg_stream_fmt2str(CFG_STREAM_MP3),
CFG_SFMT_MP3);
ck_assert_str_eq(cfg_stream_fmt2str(CFG_STREAM_THEORA),
CFG_SFMT_THEORA);
ck_assert_ptr_eq(cfg_stream_fmt2str(CFG_STREAM_INVALID), NULL);
}
END_TEST
@ -121,46 +79,6 @@ START_TEST(test_program_verbosity)
}
END_TEST
START_TEST(test_media_type)
{
const char *errstr2;
TEST_EMPTYSTR(cfg_set_media_type);
ck_assert_int_eq(cfg_set_media_type("<something else>", &errstr2), -1);
ck_assert_str_eq(errstr2, "unsupported");
ck_assert_int_eq(cfg_set_media_type("aUtOdEtEcT", NULL), 0);
ck_assert_int_eq(cfg_get_media_type(), CFG_MEDIA_AUTODETECT);
ck_assert_int_eq(cfg_set_media_type("FiLe", NULL), 0);
ck_assert_int_eq(cfg_get_media_type(), CFG_MEDIA_FILE);
ck_assert_int_eq(cfg_set_media_type("pLaYlIsT", NULL), 0);
ck_assert_int_eq(cfg_get_media_type(), CFG_MEDIA_PLAYLIST);
ck_assert_int_eq(cfg_set_media_type("PrOgRaM", NULL), 0);
ck_assert_int_eq(cfg_get_media_type(), CFG_MEDIA_PROGRAM);
ck_assert_int_eq(cfg_set_media_type("sTdIn", NULL), 0);
ck_assert_int_eq(cfg_get_media_type(), CFG_MEDIA_STDIN);
}
END_TEST
START_TEST(test_media_filename)
{
TEST_STRLCPY(cfg_set_media_filename, cfg_get_media_filename, PATH_MAX);
}
END_TEST
START_TEST(test_media_shuffle)
{
TEST_BOOLEAN(cfg_set_media_shuffle, cfg_get_media_shuffle);
}
END_TEST
START_TEST(test_media_stream_once)
{
TEST_BOOLEAN(cfg_set_media_stream_once, cfg_get_media_stream_once);
}
END_TEST
START_TEST(test_metadata_program)
{
ck_assert_ptr_eq(cfg_get_metadata_program(), NULL);
@ -240,7 +158,6 @@ cfg_suite(void)
Suite *s;
TCase *tc_core;
TCase *tc_program;
TCase *tc_media;
TCase *tc_metadata;
s = suite_create("Config");
@ -248,8 +165,6 @@ cfg_suite(void)
tc_core = tcase_create("Core");
tcase_add_checked_fixture(tc_core, setup_checked, teardown_checked);
tcase_add_test(tc_core, test_check);
tcase_add_test(tc_core, test_stream_str2fmt);
tcase_add_test(tc_core, test_stream_fmt2str);
tcase_add_test(tc_core, test_file_check);
suite_add_tcase(s, tc_core);
@ -265,14 +180,6 @@ cfg_suite(void)
tcase_add_test(tc_program, test_program_verbosity);
suite_add_tcase(s, tc_program);
tc_media = tcase_create("Media");
tcase_add_checked_fixture(tc_media, setup_checked, teardown_checked);
tcase_add_test(tc_media, test_media_type);
tcase_add_test(tc_media, test_media_filename);
tcase_add_test(tc_media, test_media_shuffle);
tcase_add_test(tc_media, test_media_stream_once);
suite_add_tcase(s, tc_media);
tc_metadata = tcase_create("Metadata");
tcase_add_checked_fixture(tc_metadata, setup_checked,
teardown_checked);

170
tests/check_cfg_intake.c Normal file
View File

@ -0,0 +1,170 @@
#include <check.h>
#include <limits.h>
#include <netdb.h>
#include "cfg_private.h"
#include "log.h"
#include "check_cfg.h"
Suite * cfg_suite(void);
void setup_checked(void);
void teardown_checked(void);
cfg_intake_list_t intakes;
START_TEST(test_intake_list_get)
{
cfg_intake_t in, in2;
ck_assert_ptr_eq(cfg_intake_list_get(intakes, NULL), NULL);
ck_assert_ptr_eq(cfg_intake_list_get(intakes, ""), NULL);
in = cfg_intake_list_get(intakes, "TeSt");
in2 = cfg_intake_list_get(intakes, "test");
ck_assert_ptr_eq(in, in2);
}
END_TEST
START_TEST(test_intake_set_name)
{
TEST_XSTRDUP_T(cfg_intake_t, cfg_intake_list_get, intakes,
cfg_intake_set_name, cfg_intake_get_name);
}
END_TEST
START_TEST(test_intake_set_type)
{
const char *errstr2;
cfg_intake_t in = cfg_intake_list_get(intakes, "test_intake_set_type");
TEST_EMPTYSTR_T(cfg_intake_t, cfg_intake_list_get, intakes,
cfg_intake_set_type);
ck_assert_int_eq(cfg_intake_set_type(in, intakes, "<something else>",
NULL), -1);
ck_assert_int_eq(cfg_intake_set_type(in, intakes, "<something else>",
&errstr2), -1);
ck_assert_str_eq(errstr2, "unsupported");
ck_assert_int_eq(cfg_intake_set_type(in, intakes, "aUtOdEtEcT", NULL),
0);
ck_assert_int_eq(cfg_intake_get_type(in), CFG_INTAKE_AUTODETECT);
ck_assert_int_eq(cfg_intake_set_type(in, intakes, "FiLe", NULL), 0);
ck_assert_int_eq(cfg_intake_get_type(in), CFG_INTAKE_FILE);
ck_assert_int_eq(cfg_intake_set_type(in, intakes, "pLaYlIsT", NULL),
0);
ck_assert_int_eq(cfg_intake_get_type(in), CFG_INTAKE_PLAYLIST);
ck_assert_int_eq(cfg_intake_set_type(in, intakes, "PrOgRaM", NULL), 0);
ck_assert_int_eq(cfg_intake_get_type(in), CFG_INTAKE_PROGRAM);
ck_assert_int_eq(cfg_intake_set_type(in, intakes, "sTdIn", NULL), 0);
ck_assert_int_eq(cfg_intake_get_type(in), CFG_INTAKE_STDIN);
}
END_TEST
START_TEST(test_intake_set_filename)
{
TEST_STRLCPY_T(cfg_intake_t, cfg_intake_list_get, intakes,
cfg_intake_set_filename, cfg_intake_get_filename, PATH_MAX);
}
END_TEST
START_TEST(test_intake_set_shuffle)
{
TEST_BOOLEAN_T(cfg_intake_t, cfg_intake_list_get, intakes,
cfg_intake_set_shuffle, cfg_intake_get_shuffle);
}
END_TEST
START_TEST(test_intake_set_stream_once)
{
TEST_BOOLEAN_T(cfg_intake_t, cfg_intake_list_get, intakes,
cfg_intake_set_stream_once, cfg_intake_get_stream_once);
}
END_TEST
START_TEST(test_intake_validate)
{
cfg_intake_t in = cfg_intake_list_get(intakes, "test_intake_validate");
const char *errstr;
ck_assert_int_ne(cfg_intake_validate(in, NULL), 0);
ck_assert_int_ne(cfg_intake_validate(in, &errstr), 0);
ck_assert_str_eq(errstr, "intake filename missing");
ck_assert_int_eq(cfg_intake_set_type(in, intakes, "stdin", NULL), 0);
ck_assert_int_eq(cfg_intake_validate(in, NULL), 0);
ck_assert_int_eq(cfg_intake_set_type(in, intakes, "autodetect", NULL),
0);
ck_assert_int_ne(cfg_intake_validate(in, NULL), 0);
ck_assert_int_ne(cfg_intake_validate(in, &errstr), 0);
ck_assert_str_eq(errstr, "intake filename missing");
ck_assert_int_eq(cfg_intake_set_filename(in, intakes,
SRCDIR "/playlist.txt", NULL), 0);
ck_assert_int_eq(cfg_intake_validate(in, NULL), 0);
}
END_TEST
Suite *
cfg_suite(void)
{
Suite *s;
TCase *tc_intake;
s = suite_create("Config");
tc_intake = tcase_create("Intake");
tcase_add_checked_fixture(tc_intake, setup_checked,
teardown_checked);
tcase_add_test(tc_intake, test_intake_list_get);
tcase_add_test(tc_intake, test_intake_set_name);
tcase_add_test(tc_intake, test_intake_set_type);
tcase_add_test(tc_intake, test_intake_set_filename);
tcase_add_test(tc_intake, test_intake_set_shuffle);
tcase_add_test(tc_intake, test_intake_set_stream_once);
tcase_add_test(tc_intake, test_intake_validate);
suite_add_tcase(s, tc_intake);
return (s);
}
void
setup_checked(void)
{
if (0 < cfg_init() ||
0 < log_init())
ck_abort_msg("setup_checked failed");
intakes = cfg_intake_list_create();
}
void
teardown_checked(void)
{
cfg_intake_list_destroy(&intakes);
log_exit();
cfg_exit();
}
int
main(void)
{
int num_failed;
Suite *s;
SRunner *sr;
s = cfg_suite();
sr = srunner_create(s);
srunner_run_all(sr, CK_NORMAL);
num_failed = srunner_ntests_failed(sr);
srunner_free(sr);
if (num_failed)
return (1);
return (0);
}

View File

@ -26,6 +26,32 @@ START_TEST(test_stream_list_get)
}
END_TEST
START_TEST(test_stream_str2fmt)
{
enum cfg_stream_format fmt;
ck_assert_int_eq(cfg_stream_str2fmt(CFG_SFMT_VORBIS, &fmt), 0);
ck_assert_int_eq(fmt, CFG_STREAM_VORBIS);
ck_assert_int_eq(cfg_stream_str2fmt(CFG_SFMT_MP3, &fmt), 0);
ck_assert_int_eq(fmt, CFG_STREAM_MP3);
ck_assert_int_eq(cfg_stream_str2fmt(CFG_SFMT_THEORA, &fmt), 0);
ck_assert_int_eq(fmt, CFG_STREAM_THEORA);
ck_assert_int_eq(cfg_stream_str2fmt("<something else>", &fmt), -1);
}
END_TEST
START_TEST(test_stream_fmt2str)
{
ck_assert_str_eq(cfg_stream_fmt2str(CFG_STREAM_VORBIS),
CFG_SFMT_VORBIS);
ck_assert_str_eq(cfg_stream_fmt2str(CFG_STREAM_MP3),
CFG_SFMT_MP3);
ck_assert_str_eq(cfg_stream_fmt2str(CFG_STREAM_THEORA),
CFG_SFMT_THEORA);
ck_assert_ptr_eq(cfg_stream_fmt2str(CFG_STREAM_INVALID), NULL);
}
END_TEST
START_TEST(test_stream_name)
{
}
@ -38,6 +64,13 @@ START_TEST(test_stream_mountpoint)
}
END_TEST
START_TEST(test_stream_intake)
{
TEST_XSTRDUP_T(cfg_stream_t, cfg_stream_list_get, streams,
cfg_stream_set_intake, cfg_stream_get_intake);
}
END_TEST
START_TEST(test_stream_server)
{
TEST_XSTRDUP_T(cfg_stream_t, cfg_stream_list_get, streams,
@ -164,8 +197,11 @@ cfg_suite(void)
tc_stream = tcase_create("Stream");
tcase_add_checked_fixture(tc_stream, setup_checked, teardown_checked);
tcase_add_test(tc_stream, test_stream_list_get);
tcase_add_test(tc_stream, test_stream_str2fmt);
tcase_add_test(tc_stream, test_stream_fmt2str);
tcase_add_test(tc_stream, test_stream_name);
tcase_add_test(tc_stream, test_stream_mountpoint);
tcase_add_test(tc_stream, test_stream_intake);
tcase_add_test(tc_stream, test_stream_server);
tcase_add_test(tc_stream, test_stream_public);
tcase_add_test(tc_stream, test_stream_format);

View File

@ -40,6 +40,9 @@ START_TEST(test_reload)
ck_assert_int_eq(cfg_set_program_config_file(SRCDIR "/config-bad5.xml",
NULL), 0);
ck_assert_int_eq(cfg_file_reload(), -1);
ck_assert_int_eq(cfg_set_program_config_file(SRCDIR "/config-bad6.xml",
NULL), 0);
ck_assert_int_eq(cfg_file_reload(), -1);
}
END_TEST

View File

@ -31,6 +31,7 @@ START_TEST(test_stream)
ck_assert_ptr_ne(srv_cfg, NULL);
str_cfg = stream_get_cfg_stream(s);
ck_assert_ptr_ne(str_cfg, NULL);
ck_assert_ptr_ne(stream_get_cfg_intake(s), NULL);
ck_assert_int_ne(stream_configure(s), 0);
cfg_server_set_hostname(srv_cfg, servers, "localhost", NULL);
@ -94,6 +95,8 @@ START_TEST(test_stream)
m_str = NULL;
mdata_destroy(&m);
stream_destroy(&s);
}
END_TEST

View File

@ -25,6 +25,7 @@
<name></name>
<mountpoint></mountpoint>
<public></public>
<intake></intake>
<server></server>
<format></format>
<encoder></encoder>
@ -40,12 +41,15 @@
<!-- ... -->
</streams>
<media>
<type></type>
<filename></filename>
<shuffle></shuffle>
<stream_once></stream_once>
</media>
<intakes>
<intake>
<name></name>
<type></type>
<filename></filename>
<shuffle></shuffle>
<stream_once></stream_once>
</intake>
</intakes>
<metadata>
<program></program>

View File

@ -15,6 +15,17 @@
</server>
</servers>
<intakes>
<intake>
<filename>secret</filename>
<name>duplicate</name>
</intake>
<intake>
<filename>secret</filename>
<name>duplicate</name>
</intake>
</intakes>
<streams>
<stream>
<format>vorbis</format>

32
tests/config-bad6.xml Normal file
View File

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<ezstream>
<servers>
<server>
<hostname>127.0.0.1</hostname>
</server>
</servers>
<streams>
<stream>
<mountpoint>/stream.ogg</mountpoint>
</stream>
</streams>
<intakes>
<intake>
</intake>
</intakes>
<decoders>
<decoder>
</decoder>
</decoders>
<encoders>
<encoder>
</encoder>
</encoders>
</ezstream>