Commit d1b6cc7f authored by brendan's avatar brendan

shout_(get|set)_bitrate REMOVED.

Instead of shout_set_bitrate(shout_t, int bitrate),
use
shout_set_audio_info(shout_t, SHOUT_AI_BITRATE, const char* bitrate)
For shout_get_bitrate,
use shout_get_audio_info(shout_t, SHOUT_AI_BITRATE).

Note the result is a const char*.

After some discussion with oddsock about YP, we decided it would be nice to be able
to send more information about the audio parameters of the stream. Currently
defined are SHOUT_AI_BITRATE, SHOUT_AI_SAMPLERATE, SHOUT_AI_CHANNELS, and
SHOUT_AI_QUALITY (vorbis quality). Adding more is easy, but the client can also
use its own arbitrary strings instead of the defined constants.

This is commit one, which makes no change to the wire protocol. In the second
commit, I'll change the ice-bitrate field to ice-audio-info.

svn path=/trunk/libshout/; revision=4359
parent e00755e9
/* shout.h
**
** api for libshout, the streaming library for icecast
** API for libshout, the streaming library for icecast
*/
#ifndef __LIBSHOUT_SHOUT_H__
#define __LIBSHOUT_SHOUT_H__
......@@ -26,8 +26,13 @@
#define SHOUT_PROTOCOL_XAUDIOCAST (1)
#define SHOUT_PROTOCOL_ICY (2)
#define SHOUT_AI_BITRATE "bitrate"
#define SHOUT_AI_SAMPLERATE "samplerate"
#define SHOUT_AI_CHANNELS "channels"
#define SHOUT_AI_QUALITY "quality"
typedef struct shout shout_t;
typedef struct shout_metadata shout_metadata_t;
typedef struct _util_dict shout_metadata_t;
#ifdef __cplusplus
extern "C" {
......@@ -91,9 +96,8 @@ const char *shout_get_description(shout_t *self);
int shout_set_dumpfile(shout_t *self, const char *dumpfile);
const char *shout_get_dumpfile(shout_t *self);
/* bitrate is in kbps */
int shout_set_bitrate(shout_t *self, unsigned int bitrate);
unsigned int shout_get_bitrate(shout_t *self);
int shout_set_audio_info(shout_t *self, const char *name, const char *value);
const char *shout_get_audio_info(shout_t *self, const char *name);
int shout_set_public(shout_t *self, unsigned int public);
unsigned int shout_get_public(shout_t *self);
......
......@@ -44,6 +44,11 @@ shout_t *shout_new(void)
return NULL;
}
if (!(self->audio_info = util_dict_new())) {
shout_free(self);
return NULL;
}
self->port = LIBSHOUT_DEFAULT_PORT;
self->format = LIBSHOUT_DEFAULT_FORMAT;
......@@ -65,6 +70,7 @@ void shout_free(shout_t *self)
if (self->description) free(self->description);
if (self->user) free(self->user);
if (self->useragent) free(self->useragent);
if (self->audio_info) util_dict_free (self->audio_info);
free(self);
}
......@@ -204,13 +210,7 @@ void shout_sync(shout_t *self)
shout_metadata_t *shout_metadata_new(void)
{
shout_metadata_t *self;
if (!(self = (shout_metadata_t *)calloc(1, sizeof(shout_metadata_t)))) {
return NULL;
}
return self;
return util_dict_new();
}
void shout_metadata_free(shout_metadata_t *self)
......@@ -218,7 +218,7 @@ void shout_metadata_free(shout_metadata_t *self)
if (!self)
return;
free (self);
util_dict_free(self);
}
int shout_metadata_add(shout_metadata_t *self, const char *name, const char *value)
......@@ -226,31 +226,7 @@ int shout_metadata_add(shout_metadata_t *self, const char *name, const char *val
if (!self || !name)
return SHOUTERR_INSANE;
while (self->next)
self = self->next;
/* If this is the first entry, name/value are null and available. Otherwise
* create a new entry at the end. */
if (self->name) {
shout_metadata_t* tail;
if (!(tail = shout_metadata_new()))
return SHOUTERR_MALLOC;
self->next = tail;
self = self->next;
}
if (!(self->name = util_strdup(name)))
return SHOUTERR_MALLOC;
if (!(self->value = util_strdup(value))) {
free (self->name);
self->name = NULL;
return SHOUTERR_MALLOC;
};
return SHOUTERR_SUCCESS;
return util_dict_set(self, name, value);
}
/* open second socket to server, send HTTP request to change metadata.
......@@ -281,15 +257,15 @@ int shout_set_metadata(shout_t *self, shout_metadata_t *metadata)
}
while (metadata) {
if (metadata->name) {
if (metadata->value) {
if (!(encvalue = util_url_encode(metadata->value))) {
if (metadata->key) {
if (metadata->val) {
if (!(encvalue = util_url_encode(metadata->val))) {
rv = SHOUTERR_MALLOC;
break;
}
rv = sock_write(socket, "&%s=%s", metadata->name, encvalue);
rv = sock_write(socket, "&%s=%s", metadata->key, encvalue);
} else
rv = sock_write(socket, "&%s", metadata->name);
rv = sock_write(socket, "&%s", metadata->key);
free (encvalue);
......@@ -659,25 +635,14 @@ const char *shout_get_dumpfile(shout_t *self)
return self->dumpfile;
}
int shout_set_bitrate(shout_t *self, unsigned int bitrate)
int shout_set_audio_info(shout_t *self, const char *name, const char *value)
{
if (!self)
return SHOUTERR_INSANE;
if (self->connected)
return self->error = SHOUTERR_CONNECTED;
self->bitrate = bitrate;
return self->error = SHOUTERR_SUCCESS;
return self->error = util_dict_set(self->audio_info, name, value);
}
unsigned int shout_get_bitrate(shout_t *self)
const char *shout_get_audio_info(shout_t *self, const char *name)
{
if (!self)
return 0;
return self->bitrate;
return util_dict_get(self->audio_info, name);
}
int shout_set_public(shout_t *self, unsigned int public)
......@@ -756,6 +721,9 @@ unsigned int shout_get_protocol(shout_t *self)
static int send_http_request(shout_t *self, char *username, char *password)
{
char *auth;
const char *bitrate;
bitrate = shout_get_audio_info(self, SHOUT_AI_BITRATE);
if (!sock_write(self->socket, "SOURCE %s HTTP/1.0\r\n", self->mount))
return SHOUTERR_SOCKET;
......@@ -778,7 +746,7 @@ static int send_http_request(shout_t *self, char *username, char *password)
if (!sock_write(self->socket, "ice-genre: %s\r\n", self->genre))
return SHOUTERR_SOCKET;
}
if (self->bitrate && !sock_write(self->socket, "ice-bitrate: %d\r\n", self->bitrate))
if (bitrate && !sock_write(self->socket, "ice-bitrate: %s\r\n", bitrate))
return SHOUTERR_SOCKET;
if (!sock_write(self->socket, "ice-public: %d\r\n", self->public))
return SHOUTERR_SOCKET;
......@@ -913,6 +881,11 @@ static int login_http_basic(shout_t *self)
static int login_xaudiocast(shout_t *self)
{
char response[4096];
const char *bitrate;
bitrate = shout_get_audio_info(self, SHOUT_AI_BITRATE);
if (!bitrate)
bitrate = "0";
if (!sock_write(self->socket, "SOURCE %s %s\n", self->password, self->mount))
return SHOUTERR_SOCKET;
......@@ -922,7 +895,7 @@ static int login_xaudiocast(shout_t *self)
return SHOUTERR_SOCKET;
if (!sock_write(self->socket, "x-audiocast-genre: %s\n", self->genre != NULL ? self->genre : "icecast"))
return SHOUTERR_SOCKET;
if (!sock_write(self->socket, "x-audiocast-bitrate: %i\n", self->bitrate))
if (!sock_write(self->socket, "x-audiocast-bitrate: %s\n", bitrate))
return SHOUTERR_SOCKET;
if (!sock_write(self->socket, "x-audiocast-public: %i\n", self->public))
return SHOUTERR_SOCKET;
......@@ -946,6 +919,11 @@ static int login_xaudiocast(shout_t *self)
int login_icy(shout_t *self)
{
char response[4096];
const char *bitrate;
bitrate = shout_get_audio_info(self, SHOUT_AI_BITRATE);
if (!bitrate)
bitrate = "0";
if (!sock_write(self->socket, "%s\n", self->password))
return SHOUTERR_SOCKET;
......@@ -968,7 +946,7 @@ int login_icy(shout_t *self)
if (!sock_write(self->socket, "icy-genre:%s\n", self->genre != NULL ? self->genre : "icecast"))
return SHOUTERR_SOCKET;
if (!sock_write(self->socket, "icy-br:%i\n", self->bitrate))
if (!sock_write(self->socket, "icy-br:%s\n", bitrate))
return SHOUTERR_SOCKET;
if (!sock_write(self->socket, "\n"))
......
......@@ -4,6 +4,7 @@
#define __LIBSHOUT_SHOUT_PRIVATE_H__
#include "shout.h"
#include "util.h"
#include "sock.h"
#include "timing.h"
......@@ -49,6 +50,8 @@ struct shout {
unsigned int protocol;
/* type of data being sent */
unsigned int format;
/* audio encoding parameters */
util_dict *audio_info;
/* user-agent to use when doing HTTP login */
char *useragent;
......@@ -66,8 +69,6 @@ struct shout {
char *dumpfile;
/* username to use for HTTP auth. */
char *user;
/* bitrate of this stream */
int bitrate;
/* is this stream private? */
int public;
......@@ -88,12 +89,6 @@ struct shout {
int error;
};
struct shout_metadata {
char *name;
char *value;
shout_metadata_t *next;
};
int shout_open_vorbis(shout_t *self);
int shout_open_mp3(shout_t *self);
......
......@@ -7,6 +7,7 @@
#include <sys/types.h>
#include <sys/socket.h>
#include "shout.h"
#include "util.h"
char *util_strdup(const char *s)
......@@ -124,4 +125,73 @@ char *util_url_encode(const char *data) {
*q = '\0';
return dest;
}
util_dict *util_dict_new(void)
{
return (util_dict *)calloc(1, sizeof(util_dict));
}
void util_dict_free(util_dict *dict)
{
util_dict *cur;
do {
cur = dict->next;
if (dict->key)
free (dict->key);
if (dict->val)
free (dict->val);
free (dict);
} while (cur);
}
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)
return SHOUTERR_INSANE;
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)
return SHOUTERR_MALLOC;
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);
return SHOUTERR_MALLOC;
}
dict->val = strdup(val);
if (!dict->val) {
return SHOUTERR_MALLOC;
}
return SHOUTERR_SUCCESS;
}
\ No newline at end of file
......@@ -3,7 +3,22 @@
#ifndef __LIBSHOUT_UTIL_H__
#define __LIBSHOUT_UTIL_H__
/* 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;
char *util_strdup(const char *s);
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_base64_encode(char *data);
char *util_url_encode(const char *data);
int util_read_header(int sock, char *buff, unsigned long len);
......
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