Added oggfwd
parent
46d5ddb26a
commit
63f4d4c602
@ -0,0 +1,400 @@
|
|||||||
|
/* vi:si:noexpandtab:sw=4:sts=4:ts=4
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* oggfwd -- Forward an Ogg stream from stdin to an Icecast server
|
||||||
|
* A useful demonstration of the libshout API
|
||||||
|
*
|
||||||
|
* This program is distributed under the GNU General Public License, version 2.
|
||||||
|
* A copy of this license is included with this source.
|
||||||
|
*
|
||||||
|
* This program is provided "as-is", with no explicit or implied warranties of
|
||||||
|
* any kind.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2003-2006, J <j@v2v.cc>,
|
||||||
|
* rafael2k <rafael(at)riseup(dot)net>,
|
||||||
|
* Moritz Grimm <gtgbr@gmx.net>
|
||||||
|
* Copyright (C) 2015, Philipp Schafft <lion@lion.leolix.org>
|
||||||
|
*/
|
||||||
|
/* thanx to rhatto <rhatto (AT) riseup (DOT) net> and others at submidialogia :-P */
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
#ifndef NO_UNISTD_H
|
||||||
|
# include <unistd.h>
|
||||||
|
#endif /* no-NO_UNISTD_H */
|
||||||
|
|
||||||
|
#include <shout/shout.h>
|
||||||
|
|
||||||
|
extern char *__progname;
|
||||||
|
extern char *optarg;
|
||||||
|
extern int optind;
|
||||||
|
extern int errno;
|
||||||
|
|
||||||
|
volatile sig_atomic_t print_total = 0;
|
||||||
|
volatile sig_atomic_t quit = 0;
|
||||||
|
|
||||||
|
#define METABUFSIZE 4096
|
||||||
|
char *metafilename;
|
||||||
|
shout_t *shout;
|
||||||
|
|
||||||
|
#define BUFFERSIZE 4096
|
||||||
|
|
||||||
|
#if defined(__dead)
|
||||||
|
__dead void
|
||||||
|
#else
|
||||||
|
void
|
||||||
|
#endif /* __dead */
|
||||||
|
usage(void)
|
||||||
|
{
|
||||||
|
printf("usage: %s "
|
||||||
|
"[-hp] "
|
||||||
|
#ifdef SHOUT_TLS
|
||||||
|
"[-T {disabled|auto|auto_no_plain|rfc2818|rfc2817}] "
|
||||||
|
#endif
|
||||||
|
"[-m metadata file] "
|
||||||
|
"[-d description] "
|
||||||
|
"[-g genre] "
|
||||||
|
"[-n name] "
|
||||||
|
"[-u URL]\n"
|
||||||
|
" address port password mountpoint\n",
|
||||||
|
__progname);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
load_metadata()
|
||||||
|
{
|
||||||
|
int i, fh, r;
|
||||||
|
char buf[METABUFSIZE], *key, *val;
|
||||||
|
enum {state_comment, state_key, state_value, state_unknown} state;
|
||||||
|
|
||||||
|
bzero(buf, METABUFSIZE);
|
||||||
|
|
||||||
|
if (!metafilename) {
|
||||||
|
fprintf(stderr, "Please use the -m argument to set the meta file name!\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fh = open(metafilename, O_RDONLY);
|
||||||
|
|
||||||
|
if (-1==fh) {
|
||||||
|
fprintf(stderr, "Error while opening meta file \"%s\": %s\n", metafilename, strerror(errno));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = read(fh, &buf, METABUFSIZE);
|
||||||
|
if (-1==r) {
|
||||||
|
fprintf(stderr, "Error while reading meta file \"%s\": %s\n", metafilename, strerror(errno));
|
||||||
|
close(fh);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
state = state_unknown;
|
||||||
|
key = val = NULL;
|
||||||
|
i = 0;
|
||||||
|
|
||||||
|
while (i<METABUFSIZE) {
|
||||||
|
switch (buf[i]) {
|
||||||
|
case 0:
|
||||||
|
/* we're done */
|
||||||
|
i = METABUFSIZE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '\r':
|
||||||
|
case '\n':
|
||||||
|
if (state_value==state) {
|
||||||
|
buf[i] = 0;
|
||||||
|
|
||||||
|
if (key && val) {
|
||||||
|
if (0==strcmp("name", key)) {
|
||||||
|
shout_set_name(shout, val);
|
||||||
|
} else if (0==strcmp("genre", key)) {
|
||||||
|
shout_set_genre(shout, val);
|
||||||
|
} else if (0==strcmp("description", key)) {
|
||||||
|
shout_set_description(shout, val);
|
||||||
|
} else if (0==strcmp("url", key)) {
|
||||||
|
shout_set_url(shout, val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
state = state_unknown;
|
||||||
|
key = NULL;
|
||||||
|
val = NULL;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '=':
|
||||||
|
if (state_key==state) {
|
||||||
|
buf[i] = 0;
|
||||||
|
state = state_value;
|
||||||
|
val = &buf[i+1];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '#':
|
||||||
|
if (state_unknown==state) {
|
||||||
|
state = state_comment;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
if (state_unknown==state) {
|
||||||
|
state = state_key;
|
||||||
|
key = &buf[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
close(fh);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
sig_handler(int sig)
|
||||||
|
{
|
||||||
|
switch (sig) {
|
||||||
|
case SIGHUP:
|
||||||
|
print_total = 1;
|
||||||
|
break;
|
||||||
|
case SIGTERM:
|
||||||
|
case SIGINT:
|
||||||
|
quit = 1;
|
||||||
|
break;
|
||||||
|
case SIGUSR1:
|
||||||
|
load_metadata();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* ignore */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
set_argument_string(char **param, char *opt, char optname)
|
||||||
|
{
|
||||||
|
size_t siz;
|
||||||
|
|
||||||
|
if (*param) {
|
||||||
|
fprintf(stderr, "%s: Parameter -%c given multiple times\n",
|
||||||
|
__progname, optname);
|
||||||
|
usage();
|
||||||
|
}
|
||||||
|
|
||||||
|
siz = strlen(opt) + 1;
|
||||||
|
if (siz >= MAXPATHLEN) {
|
||||||
|
fprintf(stderr, "%s: Argument for parameter -%c too long\n",
|
||||||
|
__progname, optname);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((*param = malloc(siz)) == NULL) {
|
||||||
|
fprintf(stderr, "%s: %s\n", __progname, strerror(errno));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(*param, siz, "%s", opt);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef SHOUT_TLS
|
||||||
|
void
|
||||||
|
set_tls_mode(int *tls_mode, char *opt, char optname)
|
||||||
|
{
|
||||||
|
if (0==strcasecmp("DISABLED", opt)) {
|
||||||
|
*tls_mode = SHOUT_TLS_DISABLED;
|
||||||
|
} else if (0==strcasecmp("AUTO", opt)) {
|
||||||
|
*tls_mode = SHOUT_TLS_AUTO;
|
||||||
|
} else if (0==strcasecmp("AUTO_NO_PLAIN", opt)) {
|
||||||
|
*tls_mode = SHOUT_TLS_AUTO_NO_PLAIN;
|
||||||
|
} else if (0==strcasecmp("RFC2818", opt)) {
|
||||||
|
*tls_mode = SHOUT_TLS_RFC2818;
|
||||||
|
} else if (0==strcasecmp("RFC2817", opt)) {
|
||||||
|
*tls_mode = SHOUT_TLS_RFC2817;
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "%s: Invalid value for -%c.\n",
|
||||||
|
__progname, optname);
|
||||||
|
usage();
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
unsigned char buff[BUFFERSIZE];
|
||||||
|
int ret, ch;
|
||||||
|
unsigned int pFlag;
|
||||||
|
char *description, *genre, *name, *url;
|
||||||
|
size_t bytes_read = 0;
|
||||||
|
unsigned short port;
|
||||||
|
unsigned long long total;
|
||||||
|
#ifdef SHOUT_TLS
|
||||||
|
int tls_mode = SHOUT_TLS_AUTO;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
pFlag = 0;
|
||||||
|
description = genre = name = url = metafilename = NULL;
|
||||||
|
while ((ch = getopt(argc, argv, "d:g:hn:m:pu:T:")) != -1) {
|
||||||
|
switch (ch) {
|
||||||
|
case 'd':
|
||||||
|
set_argument_string(&description, optarg, 'D');
|
||||||
|
break;
|
||||||
|
case 'g':
|
||||||
|
set_argument_string(&genre, optarg, 'g');
|
||||||
|
break;
|
||||||
|
case 'n':
|
||||||
|
set_argument_string(&name, optarg, 'n');
|
||||||
|
break;
|
||||||
|
case 'm':
|
||||||
|
set_argument_string(&metafilename, optarg, 'm');
|
||||||
|
break;
|
||||||
|
case 'p':
|
||||||
|
pFlag = 1;
|
||||||
|
break;
|
||||||
|
case 'u':
|
||||||
|
set_argument_string(&url, optarg, 'u');
|
||||||
|
break;
|
||||||
|
case 'T':
|
||||||
|
#ifdef SHOUT_TLS
|
||||||
|
set_tls_mode(&tls_mode, optarg, 'T');
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
case 'h':
|
||||||
|
default:
|
||||||
|
usage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
argc -= optind;
|
||||||
|
argv += optind;
|
||||||
|
|
||||||
|
if (argc != 4) {
|
||||||
|
fprintf(stderr, "%s: Wrong number of arguments\n", __progname);
|
||||||
|
usage();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((shout = shout_new()) == NULL) {
|
||||||
|
fprintf(stderr, "%s: Could not allocate shout_t\n",
|
||||||
|
__progname);
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
shout_set_format(shout, SHOUT_FORMAT_OGG);
|
||||||
|
|
||||||
|
#ifdef SHOUT_TLS
|
||||||
|
if (shout_set_tls(shout, tls_mode) != SHOUTERR_SUCCESS) {
|
||||||
|
fprintf(stderr, "%s: Error setting TLS mode: %s\n", __progname,
|
||||||
|
shout_get_error(shout));
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (shout_set_host(shout, argv[0]) != SHOUTERR_SUCCESS) {
|
||||||
|
fprintf(stderr, "%s: Error setting hostname: %s\n", __progname,
|
||||||
|
shout_get_error(shout));
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sscanf(argv[1], "%hu", &port) != 1) {
|
||||||
|
fprintf(stderr, "Invalid port `%s'\n", argv[1]);
|
||||||
|
usage();
|
||||||
|
}
|
||||||
|
if (shout_set_port(shout, port) != SHOUTERR_SUCCESS) {
|
||||||
|
fprintf(stderr, "%s: Error setting port: %s\n", __progname,
|
||||||
|
shout_get_error(shout));
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shout_set_password(shout, argv[2]) != SHOUTERR_SUCCESS) {
|
||||||
|
fprintf(stderr, "%s: Error setting password: %s\n", __progname,
|
||||||
|
shout_get_error(shout));
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shout_set_mount(shout, argv[3]) != SHOUTERR_SUCCESS) {
|
||||||
|
fprintf(stderr, "%s: Error setting mount: %s\n", __progname,
|
||||||
|
shout_get_error(shout));
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
shout_set_public(shout, pFlag);
|
||||||
|
|
||||||
|
if (metafilename)
|
||||||
|
load_metadata();
|
||||||
|
|
||||||
|
if (description)
|
||||||
|
shout_set_description(shout, description);
|
||||||
|
|
||||||
|
if (genre)
|
||||||
|
shout_set_genre(shout, genre);
|
||||||
|
|
||||||
|
if (name)
|
||||||
|
shout_set_name(shout, name);
|
||||||
|
|
||||||
|
if (url)
|
||||||
|
shout_set_url(shout, url);
|
||||||
|
|
||||||
|
signal(SIGUSR1, sig_handler);
|
||||||
|
|
||||||
|
//wait for data before opening connection to server
|
||||||
|
bytes_read = fread(buff, 1, sizeof(buff), stdin);
|
||||||
|
|
||||||
|
if (shout_open(shout) == SHOUTERR_SUCCESS) {
|
||||||
|
printf("%s: Connected to server\n", __progname);
|
||||||
|
total = 0;
|
||||||
|
|
||||||
|
signal(SIGHUP, sig_handler);
|
||||||
|
signal(SIGTERM, sig_handler);
|
||||||
|
signal(SIGINT, sig_handler);
|
||||||
|
|
||||||
|
while (quit == 0) {
|
||||||
|
total += bytes_read;
|
||||||
|
|
||||||
|
if (bytes_read > 0) {
|
||||||
|
ret = shout_send(shout, buff, bytes_read);
|
||||||
|
if (ret != SHOUTERR_SUCCESS) {
|
||||||
|
printf("%s: Send error: %s\n",
|
||||||
|
__progname,
|
||||||
|
shout_get_error(shout));
|
||||||
|
quit = 1;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
quit = 1;
|
||||||
|
|
||||||
|
if (quit) {
|
||||||
|
printf("%s: Quitting ...\n", __progname);
|
||||||
|
print_total = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (print_total) {
|
||||||
|
printf("%s: Total bytes read: %llu\n",
|
||||||
|
__progname, total);
|
||||||
|
print_total = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
shout_sync(shout);
|
||||||
|
|
||||||
|
bytes_read = fread(buff, 1, sizeof(buff), stdin);
|
||||||
|
if (bytes_read != sizeof(buff) && feof(stdin)) {
|
||||||
|
quit = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "%s: Error connecting: %s\n", __progname,
|
||||||
|
shout_get_error(shout));
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
shout_close(shout);
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
Loading…
Reference in New Issue