Skip to content

Commit

Permalink
Feature: Added support for setting format and usage
Browse files Browse the repository at this point in the history
  • Loading branch information
phschafft authored and ph3-der-loewe committed May 22, 2019
1 parent de5569d commit 0ac03fd
Show file tree
Hide file tree
Showing 4 changed files with 153 additions and 26 deletions.
19 changes: 19 additions & 0 deletions include/shout/shout.h.in
Expand Up @@ -56,6 +56,22 @@ extern "C" {
/* backward-compatibility alias */
#define SHOUT_FORMAT_VORBIS SHOUT_FORMAT_OGG

/* Usages */
#define SHOUT_USAGE_AUDIO (0x0001U) /* Audio substreams*/
#define SHOUT_USAGE_VISUAL (0x0002U) /* Picture/Video substreams (most often combined with SHOUT_USAGE_AUDIO) */
#define SHOUT_USAGE_TEXT (0x0004U) /* Text substreams that are not subtitles */
#define SHOUT_USAGE_SUBTITLE (0x0008U) /* Subtitle substreams */
#define SHOUT_USAGE_LIGHT (0x0010U) /* Light control substreams */
#define SHOUT_USAGE_UI (0x0020U) /* User interface data, such as DVD menus or buttons */
#define SHOUT_USAGE_METADATA (0x0040U) /* Substreams that include metadata for the stream */
#define SHOUT_USAGE_APPLICATION (0x0080U) /* Application specific data substreams */
#define SHOUT_USAGE_CONTROL (0x0100U) /* Substreams that control the infrastructure */
#define SHOUT_USAGE_COMPLEX (0x0200U) /* Substreams that are themself a mixture of other types */
#define SHOUT_USAGE_OTHER (0x0400U) /* Substream of types not listed here */
#define SHOUT_USAGE_UNKNOWN (0x0800U) /* The stream MAY contain additional substreams of unknown nature */
#define SHOUT_USAGE_3D (0x1000U) /* The Stream contains information for 3D playback */
#define SHOUT_USAGE_4D (0x2000U) /* The Stream contains information for 4D/XD playback */

#define SHOUT_PROTOCOL_HTTP ( 0)
#define SHOUT_PROTOCOL_XAUDIOCAST ( 1) /* Deprecated. May be removed in future versions. Do not use. */
#define SHOUT_PROTOCOL_ICY ( 2)
Expand Down Expand Up @@ -214,6 +230,9 @@ unsigned int shout_get_public(shout_t *self);
int shout_set_format(shout_t *self, unsigned int format);
unsigned int shout_get_format(shout_t *self);

int shout_set_content_format(shout_t *self, unsigned int format, unsigned int usage, const char *codecs);
int shout_get_content_format(shout_t *self, unsigned int *format, unsigned int *usage, const char **codecs);

/* takes a SHOUT_PROTOCOL_xxxxx argument */
int shout_set_protocol(shout_t *self, unsigned int protocol);
unsigned int shout_get_protocol(shout_t *self);
Expand Down
25 changes: 4 additions & 21 deletions src/proto_http.c
Expand Up @@ -91,27 +91,10 @@ static shout_connection_return_state_t shout_create_http_request_source(shout_t
const char *mimetype;
char *mount = NULL;

switch (self->format) {
case SHOUT_FORMAT_OGG:
mimetype = "application/ogg";
break;

case SHOUT_FORMAT_MP3:
mimetype = "audio/mpeg";
break;

case SHOUT_FORMAT_WEBM:
mimetype = "video/webm";
break;

case SHOUT_FORMAT_WEBMAUDIO:
mimetype = "audio/webm";
break;

default:
shout_connection_set_error(connection, SHOUTERR_INSANE);
return SHOUT_RS_ERROR;
break;
mimetype = shout_get_mimetype_from_self(self);
if (!mimetype) {
shout_connection_set_error(connection, SHOUTERR_INSANE);
return SHOUT_RS_ERROR;
}

/* this is lazy code that relies on the only error from queue_* being
Expand Down
131 changes: 126 additions & 5 deletions src/shout.c
Expand Up @@ -131,6 +131,7 @@ shout_t *shout_new(void)

self->port = LIBSHOUT_DEFAULT_PORT;
self->format = LIBSHOUT_DEFAULT_FORMAT;
self->usage = LIBSHOUT_DEFAULT_USAGE;
self->protocol = LIBSHOUT_DEFAULT_PROTOCOL;

return self;
Expand Down Expand Up @@ -811,22 +812,142 @@ int shout_set_format(shout_t *self, unsigned int format)
if (self->connection)
return self->error = SHOUTERR_CONNECTED;

if (format != SHOUT_FORMAT_OGG && format != SHOUT_FORMAT_MP3 &&
format != SHOUT_FORMAT_WEBM && format != SHOUT_FORMAT_WEBMAUDIO) {
switch (format) {
case SHOUT_FORMAT_OGG:
return shout_set_content_format(self, SHOUT_FORMAT_OGG, SHOUT_USAGE_UNKNOWN, NULL);
break;
case SHOUT_FORMAT_MP3:
return shout_set_content_format(self, SHOUT_FORMAT_MP3, SHOUT_USAGE_AUDIO, NULL);
break;
case SHOUT_FORMAT_WEBM:
return shout_set_content_format(self, SHOUT_FORMAT_WEBM, SHOUT_USAGE_AUDIO|SHOUT_USAGE_VISUAL, NULL);
break;
case SHOUT_FORMAT_WEBMAUDIO:
return shout_set_content_format(self, SHOUT_FORMAT_WEBM, SHOUT_USAGE_AUDIO, NULL);
break;
}

return self->error = SHOUTERR_UNSUPPORTED;
}

unsigned int shout_get_format(shout_t* self)
{
if (!self)
return 0;

if (self->format == SHOUT_FORMAT_WEBM && self->usage == SHOUT_USAGE_AUDIO) {
return SHOUT_FORMAT_WEBMAUDIO;
}

return self->format;
}

static inline unsigned int remove_bits(unsigned int value, unsigned int to_remove)
{
value |= to_remove;
value -= to_remove;

return value;
}

static inline int is_audio(unsigned int usage)
{
if (!(usage & SHOUT_USAGE_AUDIO))
return 0;

if (remove_bits(usage, SHOUT_USAGE_AUDIO|SHOUT_USAGE_SUBTITLE))
return 0;

return 1;
}

static inline int is_video(unsigned int usage)
{
if (!(usage & SHOUT_USAGE_VISUAL))
return 0;

if (remove_bits(usage, SHOUT_USAGE_VISUAL|SHOUT_USAGE_AUDIO|SHOUT_USAGE_SUBTITLE|SHOUT_USAGE_3D|SHOUT_USAGE_4D))
return 0;

return 1;
}

static const char *shout_get_mimetype(unsigned int format, unsigned int usage, const char *codecs)
{
if (codecs)
return NULL;

switch (format) {
case SHOUT_FORMAT_OGG:
if (is_audio(usage)) {
return "audio/ogg";
} else if (is_video(usage)) {
return "video/ogg";
} else {
return "application/ogg";
}
break;

case SHOUT_FORMAT_MP3:
/* MP3 *ONLY* support Audio. So all other values are outright invalid */
if (usage == SHOUT_USAGE_AUDIO) {
return "audio/mpeg";
}
break;
case SHOUT_FORMAT_WEBM:
if (is_audio(usage)) {
return "audio/webm";
} else if (is_video(usage)) {
return "video/webm";
}
break;
}

return NULL;
}

const char *shout_get_mimetype_from_self(shout_t *self)
{
return shout_get_mimetype(self->format, self->usage, NULL);
}

int shout_set_content_format(shout_t *self, unsigned int format, unsigned int usage, const char *codecs)
{
if (!self)
return SHOUTERR_INSANE;

if (self->connection)
return self->error = SHOUTERR_CONNECTED;

if (codecs) {
return self->error = SHOUTERR_UNSUPPORTED;
}

if (!shout_get_mimetype(format, usage, codecs)) {
return self->error = SHOUTERR_UNSUPPORTED;
}

self->format = format;
self->usage = usage;

return self->error = SHOUTERR_SUCCESS;
}

unsigned int shout_get_format(shout_t* self)
int shout_get_content_format(shout_t *self, unsigned int *format, unsigned int *usage, const char **codecs)
{
if (!self)
return 0;
return SHOUTERR_INSANE;

return self->format;
if (format)
*format = self->format;

if (usage)
*usage = self->usage;

if (codecs)
*codecs = NULL;

return self->error = SHOUTERR_SUCCESS;
}

int shout_set_protocol(shout_t *self, unsigned int protocol)
Expand Down
4 changes: 4 additions & 0 deletions src/shout_private.h
Expand Up @@ -48,6 +48,7 @@
#define LIBSHOUT_DEFAULT_HOST "localhost"
#define LIBSHOUT_DEFAULT_PORT 8000
#define LIBSHOUT_DEFAULT_FORMAT SHOUT_FORMAT_OGG
#define LIBSHOUT_DEFAULT_USAGE SHOUT_USAGE_UNKNOWN
#define LIBSHOUT_DEFAULT_PROTOCOL SHOUT_PROTOCOL_HTTP
#define LIBSHOUT_DEFAULT_USER "source"
#define LIBSHOUT_DEFAULT_USERAGENT "libshout/" VERSION
Expand Down Expand Up @@ -214,6 +215,7 @@ struct shout {
unsigned int protocol;
/* type of data being sent */
unsigned int format;
unsigned int usage;
/* audio encoding parameters */
util_dict *audio_info;

Expand Down Expand Up @@ -263,6 +265,8 @@ struct shout {
};

/* helper functions */
const char *shout_get_mimetype_from_self(shout_t *self);

int shout_queue_data(shout_queue_t *queue, const unsigned char *data, size_t len);
int shout_queue_str(shout_connection_t *self, const char *str);
int shout_queue_printf(shout_connection_t *self, const char *fmt, ...);
Expand Down

0 comments on commit 0ac03fd

Please sign in to comment.