Commit 1658f171 authored by Ed "oddsock" Zaleski's avatar Ed "oddsock" Zaleski

added parsing of new icy-audio-info header which will be used to

communicate things like samplerate/quality/number of channels to
icecast2. This info will be then forwarded to the yp servers for
better stream info.

also factored out some logic in source_main into common functions

added a few new routines into util.c (taken from Brendan's
updates to libshout)

svn path=/trunk/icecast/; revision=4379
parent 680e56bf
......@@ -34,12 +34,28 @@
#undef CATMODULE
#define CATMODULE "source"
#define YP_SERVER_NAME 1
#define YP_SERVER_DESC 2
#define YP_SERVER_GENRE 3
#define YP_SERVER_URL 4
#define YP_BITRATE 5
#define YP_AUDIO_INFO 6
#define YP_SERVER_TYPE 7
#define YP_CURRENT_SONG 8
#define YP_URL_TIMEOUT 9
#define YP_TOUCH_INTERVAL 10
#define YP_LAST_TOUCH 11
/* avl tree helper */
static int _compare_clients(void *compare_arg, void *a, void *b);
static int _remove_client(void *key);
static int _free_client(void *key);
static int _parse_audio_info(source_t *source, char *s);
static void _add_yp_info(source_t *source, char *stat_name,
void *info, int type);
source_t *source_create(client_t *client, connection_t *con, http_parser_t *parser, const char *mount, format_type_t type)
source_t *source_create(client_t *client, connection_t *con,
http_parser_t *parser, const char *mount, format_type_t type)
{
int i = 0;
source_t *src;
......@@ -57,6 +73,7 @@ source_t *source_create(client_t *client, connection_t *con, http_parser_t *pars
src->num_yp_directories = 0;
src->listeners = 0;
src->send_return = 0;
src->audio_info = util_dict_new();
for (i=0;i<config_get_config()->num_yp_directories;i++) {
if (config_get_config()->yp_url[i]) {
src->ypdata[src->num_yp_directories] = yp_create_ypdata();
......@@ -124,6 +141,7 @@ int source_free_source(void *key)
for (i=0; i<source->num_yp_directories; i++) {
yp_destroy_ypdata(source->ypdata[i]);
}
util_dict_free(source->audio_info);
free(source);
return 1;
......@@ -149,9 +167,11 @@ void *source_main(void *arg)
refbuf_t *refbuf, *abuf;
int data_done;
int listeners = 0;
int i=0;
int suppress_yp = 0;
int listeners = 0;
int i=0;
int suppress_yp = 0;
util_dict *audio_info;
char *ai;
long queue_limit = config_get_config()->queue_size_limit;
......@@ -191,59 +211,32 @@ void *source_main(void *arg)
stats_event(source->mount, "listeners", "0");
source->listeners = 0;
if ((s = httpp_getvar(source->parser, "ice-name"))) {
for (i=0;i<source->num_yp_directories;i++) {
if (source->ypdata[i]->server_name) {
free(source->ypdata[i]->server_name);
}
source->ypdata[i]->server_name = malloc(strlen(s) +1);
strcpy(source->ypdata[i]->server_name, s);
}
stats_event(source->mount, "name", s);
_add_yp_info(source, "server name", s, YP_SERVER_NAME);
}
if ((s = httpp_getvar(source->parser, "ice-url"))) {
for (i=0;i<source->num_yp_directories;i++) {
if (source->ypdata[i]->server_url) {
free(source->ypdata[i]->server_url);
}
source->ypdata[i]->server_url = malloc(strlen(s) +1);
strcpy(source->ypdata[i]->server_url, s);
}
stats_event(source->mount, "url", s);
_add_yp_info(source, "server url", s, YP_SERVER_URL);
}
if ((s = httpp_getvar(source->parser, "ice-genre"))) {
for (i=0;i<source->num_yp_directories;i++) {
if (source->ypdata[i]->server_genre) {
free(source->ypdata[i]->server_genre);
}
source->ypdata[i]->server_genre = malloc(strlen(s) +1);
strcpy(source->ypdata[i]->server_genre, s);
}
stats_event(source->mount, "genre", s);
_add_yp_info(source, "genre", s, YP_SERVER_GENRE);
}
if ((s = httpp_getvar(source->parser, "ice-bitrate"))) {
for (i=0;i<source->num_yp_directories;i++) {
if (source->ypdata[i]->bitrate) {
free(source->ypdata[i]->bitrate);
}
source->ypdata[i]->bitrate = malloc(strlen(s) +1);
strcpy(source->ypdata[i]->bitrate, s);
}
stats_event(source->mount, "bitrate", s);
_add_yp_info(source, "bitrate", s, YP_BITRATE);
}
if ((s = httpp_getvar(source->parser, "ice-description"))) {
for (i=0;i<source->num_yp_directories;i++) {
if (source->ypdata[i]->server_desc) {
free(source->ypdata[i]->server_desc);
}
source->ypdata[i]->server_desc = malloc(strlen(s) +1);
strcpy(source->ypdata[i]->server_desc, s);
}
stats_event(source->mount, "description", s);
_add_yp_info(source, "server description", s, YP_SERVER_DESC);
}
if ((s = httpp_getvar(source->parser, "ice-private"))) {
stats_event(source->mount, "public", s);
suppress_yp = atoi(s);
}
if ((s = httpp_getvar(source->parser, "ice-audio-info"))) {
if (_parse_audio_info(source, s)) {
ai = util_dict_urlencode(source->audio_info, '&');
_add_yp_info(source, "audio info",
ai,
YP_AUDIO_INFO);
}
}
for (i=0;i<source->num_yp_directories;i++) {
if (source->ypdata[i]->server_type) {
free(source->ypdata[i]->server_type);
......@@ -275,8 +268,14 @@ void *source_main(void *arg)
current_time = time(NULL);
_add_yp_info(source, "last_touch", (void *)current_time,
YP_LAST_TOUCH);
for (i=0;i<source->num_yp_directories;i++) {
source->ypdata[i]->yp_last_touch = current_time;
/* Give the source 5 seconds to update the metadata
before we do our first touch */
source->ypdata[i]->yp_last_touch = current_time -
source->ypdata[i]->yp_touch_interval + 5;
/* Don't permit touch intervals of less than 30 seconds */
if (source->ypdata[i]->yp_touch_interval <= 30) {
source->ypdata[i]->yp_touch_interval = 30;
......@@ -622,3 +621,127 @@ static int _free_client(void *key)
return 1;
}
static int _parse_audio_info(source_t *source, char *s)
{
char *token;
char *pvar;
char *variable;
char *value;
while ((token = strtok(s,";")) != NULL) {
pvar = strchr(token, '=');
if (pvar) {
variable = (char *)malloc(pvar-token+1);
memset(variable, '\000', pvar-token+1);
strncpy(variable, token, pvar-token);
pvar++;
if (strlen(pvar)) {
value = (char *)malloc(strlen(pvar)+1);
memset(value, '\000', strlen(pvar)+1);
strncpy(value, pvar, strlen(pvar));
util_dict_set(source->audio_info, variable, value);
stats_event(source->mount, variable, value);
}
if (variable) {
free(variable);
}
if (value) {
free(value);
}
}
s = NULL;
}
return 1;
}
static void _add_yp_info(source_t *source, char *stat_name,
void *info, int type)
{
int i;
if (!info) {
return;
}
for (i=0;i<source->num_yp_directories;i++) {
switch (type) {
case YP_SERVER_NAME:
if (source->ypdata[i]->server_name) {
free(source->ypdata[i]->server_name);
}
source->ypdata[i]->server_name =
malloc(strlen((char *)info) +1);
strcpy(source->ypdata[i]->server_name, (char *)info);
stats_event(source->mount, stat_name, (char *)info);
break;
case YP_SERVER_DESC:
if (source->ypdata[i]->server_desc) {
free(source->ypdata[i]->server_desc);
}
source->ypdata[i]->server_desc =
malloc(strlen((char *)info) +1);
strcpy(source->ypdata[i]->server_desc, (char *)info);
stats_event(source->mount, stat_name, (char *)info);
break;
case YP_SERVER_GENRE:
if (source->ypdata[i]->server_genre) {
free(source->ypdata[i]->server_genre);
}
source->ypdata[i]->server_genre =
malloc(strlen((char *)info) +1);
strcpy(source->ypdata[i]->server_genre, (char *)info);
stats_event(source->mount, stat_name, (char *)info);
break;
case YP_SERVER_URL:
if (source->ypdata[i]->server_url) {
free(source->ypdata[i]->server_url);
}
source->ypdata[i]->server_url =
malloc(strlen((char *)info) +1);
strcpy(source->ypdata[i]->server_url, (char *)info);
stats_event(source->mount, stat_name, (char *)info);
break;
case YP_BITRATE:
if (source->ypdata[i]->bitrate) {
free(source->ypdata[i]->bitrate);
}
source->ypdata[i]->bitrate =
malloc(strlen((char *)info) +1);
strcpy(source->ypdata[i]->bitrate, (char *)info);
stats_event(source->mount, stat_name, (char *)info);
break;
case YP_AUDIO_INFO:
if (source->ypdata[i]->audio_info) {
free(source->ypdata[i]->audio_info);
}
source->ypdata[i]->audio_info =
malloc(strlen((char *)info) +1);
strcpy(source->ypdata[i]->audio_info, (char *)info);
break;
case YP_SERVER_TYPE:
if (source->ypdata[i]->server_type) {
free(source->ypdata[i]->server_type);
}
source->ypdata[i]->server_type =
malloc(strlen((char *)info) +1);
strcpy(source->ypdata[i]->server_type, (char *)info);
break;
case YP_CURRENT_SONG:
if (source->ypdata[i]->current_song) {
free(source->ypdata[i]->current_song);
}
source->ypdata[i]->current_song =
malloc(strlen((char *)info) +1);
strcpy(source->ypdata[i]->current_song, (char *)info);
stats_event(source->mount, stat_name, (char *)info);
break;
case YP_URL_TIMEOUT:
source->ypdata[i]->yp_url_timeout = (int)info;
break;
case YP_LAST_TOUCH:
source->ypdata[i]->yp_last_touch = (int)info;
break;
case YP_TOUCH_INTERVAL:
source->ypdata[i]->yp_touch_interval = (int)info;
break;
}
}
}
......@@ -3,6 +3,7 @@
#include "config.h"
#include "yp.h"
#include "util.h"
#include "format.h"
typedef struct source_tag
......@@ -27,6 +28,7 @@ typedef struct source_tag
rwlock_t *shutdown_rwlock;
ypdata_t *ypdata[MAX_YP_DIRECTORIES];
util_dict *audio_info;
int num_yp_directories;
long listeners;
long max_listeners;
......
......@@ -385,3 +385,139 @@ char *util_base64_decode(unsigned char *input)
return result;
}
util_dict *util_dict_new(void)
{
return (util_dict *)calloc(1, sizeof(util_dict));
}
void util_dict_free(util_dict *dict)
{
util_dict *next;
while (dict) {
next = dict->next;
if (dict->key)
free (dict->key);
if (dict->val)
free (dict->val);
free (dict);
dict = next;
}
}
const char *util_dict_get(util_dict *dict, const char *key)
{
while (dict) {
if (!strcmp(key, dict->key))
return dict->val;
dict = dict->next;
}
}
int util_dict_set(util_dict *dict, const char *key, const char *val)
{
util_dict *prev;
if (!dict || !key) {
ERROR0("NULL values passed to util_dict_set()");
return 0;
}
prev = NULL;
while (dict) {
if (!dict->key || !strcmp(dict->key, key))
break;
prev = dict;
dict = dict->next;
}
if (!dict) {
dict = util_dict_new();
if (!dict) {
ERROR0("unable to allocate new dictionary");
return 0;
}
if (prev)
prev->next = dict;
}
if (dict->key)
free (dict->val);
else if (!(dict->key = strdup(key))) {
if (prev)
prev->next = NULL;
util_dict_free (dict);
ERROR0("unable to allocate new dictionary key");
return 0;
}
dict->val = strdup(val);
if (!dict->val) {
ERROR0("unable to allocate new dictionary value");
return 0;
}
return 1;
}
/* given a dictionary, URL-encode each key and val and
stringify them in order as key=val&key=val... if val
is set, or just key&key if val is NULL.
TODO: Memory management needs overhaul. */
char *util_dict_urlencode(util_dict *dict, char delim)
{
char *res, *tmp;
char *enc;
int start = 1;
for (res = NULL; dict; dict = dict->next) {
/* encode key */
if (!dict->key)
continue;
if (!(enc = util_url_escape(dict->key))) {
if (res)
free(res);
return NULL;
}
if (start) {
if (!(res = malloc(strlen(enc) + 1))) {
free(enc);
return NULL;
}
sprintf(res, "%s", enc);
free(enc);
start = 0;
} else {
if (!(tmp = realloc(res, strlen(res) + strlen(enc) + 2))) {
free(enc);
free(res);
return NULL;
} else
res = tmp;
sprintf(res + strlen(res), "%c%s", delim, enc);
free(enc);
}
/* encode value */
if (!dict->val)
continue;
if (!(enc = util_url_escape(dict->val))) {
free(res);
return NULL;
}
if (!(tmp = realloc(res, strlen(res) + strlen(enc) + 2))) {
free(enc);
free(res);
return NULL;
} else
res = tmp;
sprintf(res + strlen(res), "=%s", enc);
free(enc);
}
return res;
}
......@@ -16,4 +16,18 @@ char *util_base64_decode(unsigned char *input);
char *util_url_escape(char *src);
/* String dictionary type, without support for NULL keys, or multiple
* instances of the same key */
typedef struct _util_dict {
char *key;
char *val;
struct _util_dict *next;
} util_dict;
util_dict *util_dict_new(void);
void util_dict_free(util_dict *dict);
/* dict, key must not be NULL. */
int util_dict_set(util_dict *dict, const char *key, const char *val);
const char *util_dict_get(util_dict *dict, const char *key);
char *util_dict_urlencode(util_dict *dict, char delim);
#endif /* __UTIL_H__ */
......@@ -196,8 +196,9 @@ int yp_add(source_t *source, int which)
if (ok) {
if (source->ypdata[i]) {
url_size = strlen("action=add&sn=&genre=&cpswd=&desc=&url="
"&listenurl=&type=&b=") + 1;
url_size = strlen("action=add&sn=&genre=&cpswd="
"&desc=&url=&listenurl=&type=&b=&")
+ 1;
if (source->ypdata[i]->server_name) {
url_size += strlen(source->ypdata[i]->server_name);
}
......@@ -261,10 +262,18 @@ int yp_add(source_t *source, int which)
source->ypdata[i]->current_song = (char *)malloc(1);
source->ypdata[i]->current_song[0] = 0;
}
if (source->ypdata[i]->audio_info) {
url_size += strlen(source->ypdata[i]->audio_info);
}
else {
source->ypdata[i]->audio_info = (char *)malloc(1);
source->ypdata[i]->audio_info[0] = 0;
}
url_size += 1024;
url = malloc(url_size);
sprintf(url, "action=add&sn=%s&genre=%s&cpswd=%s&desc=%s&url=%s"
"&listenurl=%s&type=%s&b=%s",
sprintf(url, "action=add&sn=%s&genre=%s&cpswd=%s&desc="
"%s&url=%s&listenurl=%s&type=%s&b=%s&%s",
source->ypdata[i]->server_name,
source->ypdata[i]->server_genre,
source->ypdata[i]->cluster_password,
......@@ -272,7 +281,8 @@ int yp_add(source_t *source, int which)
source->ypdata[i]->server_url,
source->ypdata[i]->listen_url,
source->ypdata[i]->server_type,
source->ypdata[i]->bitrate);
source->ypdata[i]->bitrate,
source->ypdata[i]->audio_info);
curl_con = curl_get_connection();
if (curl_con < 0) {
......@@ -350,6 +360,9 @@ void yp_destroy_ypdata(ypdata_t *ypdata)
if (ypdata->server_type) {
free(ypdata->server_type);
}
if (ypdata->audio_info) {
free(ypdata->audio_info);
}
free(ypdata);
}
}
......
......@@ -16,6 +16,7 @@ typedef struct ypdata_tag
char *server_url;
char *listen_url;
char *bitrate;
char *audio_info;
char *server_type;
char *current_song;
char *yp_url;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment