[xiph-cvs] cvs commit: libshout/src mp3.c shout_private.h util.c util.h vorbis.c Makefile.am shout.c

Jack Moffitt jack at xiph.org
Tue Jan 22 19:08:41 PST 2002



jack        02/01/22 19:08:40

  Modified:    .        configure.in
               examples example.c
               include/shout shout.h
               src      Makefile.am shout.c
  Added:       examples Makefile.am
               src      mp3.c shout_private.h util.c util.h vorbis.c
  Removed:     examples Makefile
  Log:
  First cut of the big libshout2 merge.  Brendan did all the heavy lifting
  on this, and it's been sitting on my todo list for some time.  This will
  now support _both_ mp3 and ogg datatypes and 3 protocols (ICE, ICY, and
  XAUDIOCAST).  Consider libshout1 now deprecated :)

Revision  Changes    Path
1.5       +27 -10    libshout/configure.in

Index: configure.in
===================================================================
RCS file: /usr/local/cvsroot/libshout/configure.in,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- configure.in	2001/10/29 16:04:19	1.4
+++ configure.in	2002/01/23 03:08:38	1.5
@@ -15,7 +15,7 @@
                 CFLAGS="-O2 -w -signed"
                 PROFILE="-p -g3 -O2 -signed"
                 ;;
-        *-*-solaris*)
+        sparc-sun-solaris*)
                 DEBUG="-v -g"
                 CFLAGS="-xO4 -fast -w -fsimple -native -xcg92"
                 PROFILE="-v -xpg -g -xO4 -fast -native -fsimple -xcg92 -Dsuncc"
@@ -33,16 +33,11 @@
                 CFLAGS="-Wall -W -O20 -ffast-math -fsigned-char -D_REENTRANT"
                 PROFILE="-Wall -W -pg -g -O20 -ffast-math -fsigned-char -D_REENTRANT"
                 ;;
-        sparc-sun-solaris*)
+        sparc-sun-*)
                 DEBUG="-g -Wall -fsigned-char -mv8"
                 CFLAGS="-O20 -ffast-math -fsigned-char -mv8"
                 PROFILE="-pg -g -O20 -fsigned-char -mv8" 
                 ;;
-        *-pc-solaris*)
-                DEBUG="-g -Wall -fsigned-char"
-                CFLAGS="-O20 -ffast-math -fsigned-char"
-                PROFILE="-pg -g -O20 -fsigned-char" 
-		;;
         *)
                 DEBUG="-g -Wall -fsigned-char"
                 CFLAGS="-O20 -fsigned-char"
@@ -58,12 +53,34 @@
 dnl Checks for header files.
 AC_HEADER_STDC
 
-AC_CHECK_HEADER(stdint.h, AC_DEFINE(HAVE_STDINT_H, 1),,)
-
 dnl Checks for typedefs, structures, and compiler characteristics.
 AC_C_CONST
 
 dnl Check for types
+AC_CHECK_HEADERS(stdint.h inttypes.h)
+AC_MSG_CHECKING(for C99 integer types)
+dnl This is from autoconf-2.50's AC_CHECK_TYPE macro
+AC_TRY_COMPILE([
+#include <sys/types.h>
+#ifdef HAVE_STDINT_H
+#  include <stdint.h>
+#elif defined (HAVE_INTTYPES_H)
+#  include <inttypes.h>
+#endif], [
+if ((uint32_t *) 0)
+  return 0;
+if (sizeof (uint32_t))
+  return 0;
+], [
+  AC_DEFINE(HAVE_C99_INTTYPES, 1, [Define if you have the C99 integer types])
+  AC_MSG_RESULT(yes)
+], [
+  AC_MSG_RESULT(no)
+  AC_CHECK_SIZEOF(short)
+  AC_CHECK_SIZEOF(int)
+  AC_CHECK_SIZEOF(long)
+  AC_CHECK_SIZEOF(long long)
+])
 
 dnl Checks for library functions.
 
@@ -76,4 +93,4 @@
 AC_SUBST(CFLAGS)
 AC_SUBST(PROFILE)
 
-AC_OUTPUT(Makefile include/Makefile include/shout/Makefile src/Makefile src/net/Makefile src/timing/Makefile)
+AC_OUTPUT(Makefile include/Makefile include/shout/Makefile src/Makefile src/net/Makefile src/timing/Makefile examples/Makefile)

<p><p>1.2       +28 -15    libshout/examples/example.c

Index: example.c
===================================================================
RCS file: /usr/local/cvsroot/libshout/examples/example.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- example.c	2001/09/10 02:24:40	1.1
+++ example.c	2002/01/23 03:08:38	1.2
@@ -1,4 +1,4 @@
-#include <stdio.h>
+/* example.c: Demonstration of the libshout API. */
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -8,41 +8,54 @@
 
 int main()
 {
-	shout_conn_t conn;
+	shout_t *shout;
         char buff[4096];
         long read, ret, total;
 
-	shout_init_connection(&conn);
+	if (!(shout = shout_new())) {
+		printf("Could not allocate shout_t\n");
+		return 1;
+	}
 
-	conn.ip = "127.0.0.1";
-	conn.port = 8765;
-	conn.password = "hackme";
-	conn.mount = "/example";
+	if (shout_set_host(shout, "127.0.0.1") != SHOUTERR_SUCCESS) {
+		printf("Error setting hostname: %s\n", shout_get_error(shout));
+		return 1;
+	}
+	shout_set_port(shout, 8000);
+	if (shout_set_password(shout, "hackme") != SHOUTERR_SUCCESS) {
+		printf("Error setting password: %s\n", shout_get_error(shout));
+		return 1;
+	}
+	if (shout_set_mount(shout, "/example.ogg") != SHOUTERR_SUCCESS) {
+		printf("Error setting mount: %s\n", shout_get_error(shout));
+		return 1;
+	}
+	shout_set_format(shout, SHOUT_FORMAT_MP3);
 
-	if (shout_connect(&conn)) {
+	if (shout_open(shout) == SHOUTERR_SUCCESS) {
                 printf("Connected to server...\n");
                 total = 0;
                 while (1) {
-			read = fread(buff, 1, 4096, stdin);
+			read = fread(buff, 1, sizeof(buff), stdin);
                         total = total + read;
 
                         if (read > 0) {
-				ret = shout_send_data(&conn, buff, read);
-				if (!ret) {
-					printf("DEBUG: Send error: %i...\n", conn.error);
+				ret = shout_send(shout, buff, read);
+				if (ret != SHOUTERR_SUCCESS) {
+					printf("DEBUG: Send error: %s\n", shout_get_error(shout));
                                         break;
                                 }
                         } else {
                                 break;
                         }
 
-			shout_sleep(&conn);
+			shout_sync(shout);
                 }
         } else {
-		printf("Couldn't connect...%i\n", conn.error);
+		printf("Error connecting: %s\n", shout_get_error(shout));
         }
 
-	shout_disconnect(&conn);
+	shout_close(shout);
 
         return 0;
 }

<p><p>1.1                  libshout/examples/Makefile.am

Index: Makefile.am
===================================================================
## Process this file with automake to create Makefile.in

AUTOMAKE_OPTIONS = foreign

noinst_PROGRAMS = example

example_SOURCES = example.c
example_LDADD = ../src/libshout.la -logg -lvorbis

INCLUDES = -I$(top_srcdir)/include

<p><p>1.5       +101 -92   libshout/include/shout/shout.h

Index: shout.h
===================================================================
RCS file: /usr/local/cvsroot/libshout/include/shout/shout.h,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- shout.h	2001/10/20 22:34:57	1.4
+++ shout.h	2002/01/23 03:08:39	1.5
@@ -5,104 +5,113 @@
 #ifndef __LIBSHOUT_SHOUT_H__
 #define __LIBSHOUT_SHOUT_H__
 
-#ifdef _WIN32
-typedef __int64 int64_t;
-typedef unsigned __int64 uint64_t;
-#else
-# ifdef __GLIBC__
-#  include <stdint.h>
-# endif
-#endif
-
-#include <sys/types.h>
+#define SHOUTERR_SUCCESS	(0)
+#define SHOUTERR_INSANE		(1)
+#define SHOUTERR_NOCONNECT	(2)
+#define SHOUTERR_NOLOGIN	(3)
+#define SHOUTERR_SOCKET		(4)
+#define SHOUTERR_MALLOC		(5)
+#define SHOUTERR_METADATA	(6)
+#define SHOUTERR_CONNECTED	(7)
+#define SHOUTERR_UNCONNECTED	(8)
+#define SHOUTERR_UNSUPPORTED	(9)
+
+#define SHOUT_FORMAT_VORBIS	(0)
+#define SHOUT_FORMAT_MP3	(1)
+
+#define SHOUT_PROTOCOL_ICE		(0)
+#define SHOUT_PROTOCOL_XAUDIOCAST	(1)
+#define SHOUT_PROTOCOL_ICY		(2)
 
-#include <ogg/ogg.h>
+typedef struct shout shout_t;
+typedef struct shout_metadata shout_metadata_t;
 
 #ifdef __cplusplus
 extern "C" {
 #endif
+
+/* returns a static version string.  Non-null parameters will be set to the
+ * value of the library major, minor, and patch levels, respectively */
+const char *shout_version(int *major, int *minor, int *patch);
+
+/* Allocates and sets up a new shout_t.  Returns NULL if it can't get enough
+ * memory.  The returns shout_t must be disposed of with shout_free. */
+shout_t *shout_new(void);
+
+/* Free all memory allocated by a shout_t */
+void shout_free(shout_t *self);
+
+/* Returns a statically allocated string describing the last shout error
+ * to occur.  Only valid until the next libshout call on this shout_t */
+const char *shout_get_error(shout_t *self);
+
+/* Parameter manipulation functions.  libshout makes copies of all parameters,
+ * the caller may free its copies after giving them to libshout.  May return
+ * SHOUTERR_MALLOC */
+
+int shout_set_host(shout_t *self, const char *host);
+const char *shout_get_host(shout_t *self);
+
+int shout_set_port(shout_t *self, unsigned short port);
+const char *shout_get_port(shout_t *self);
+
+int shout_set_password(shout_t *, const char *password);
+const char *shout_get_password(shout_t *self);
+
+int shout_set_mount(shout_t *self, const char *mount);
+const char *shout_get_mount(shout_t *self);
+
+int shout_set_name(shout_t *self, const char *name);
+const char *shout_get_name(shout_t *self);
+
+int shout_set_url(shout_t *self, const char *url);
+const char *shout_get_url(shout_t *self);
+
+int shout_set_genre(shout_t *self, const char *genre);
+const char *shout_set_genre(shout_t *self);
+
+int shout_set_description(shout_t *self, const char *description);
+const char *shout_get_description(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);
+
+/* takes a SHOUT_FORMAT_xxxx argument */
+int shout_set_format(shout_t *self, unsigned int format);
+unsigned int shout_get_format(shout_t *self);
+
+/* takes a SHOUT_PROTOCOL_xxxxx argument */
+int shout_set_protocol(shout_t *self, unsigned int protocol);
+unsigned int shout_get_protocol(shout_t *self);
+
+/* Opens a connection to the server.  All parameters must already be set */
+int shout_open(shout_t *self);
+
+/* Closes a connection to the server */
+int shout_close(shout_t *self);
+
+/* Send data to the server, parsing it for format specific timing info */
+int shout_send(shout_t *self, const unsigned char *data, size_t len);
+
+/* Send unparsed data to the server.  Do not use this unless you know
+ * what you are doing. */
+ssize_t shout_send_raw(shout_t *self, const unsigned char *data, size_t len);
+
+/* Puts caller to sleep until it is time to send more data to the server */
+void shout_sync(shout_t *self);
+
+/* Sets MP3 metadata */
+int shout_set_metadata(shout_t *self, shout_metadata_t *metadata);
+
+/* Allocates a new metadata structure.  Must be freed by shout_metadata_free */
+shout_metadata_t *shout_metadata_new(void);
+
+/* Free resources allocated by shout_metadata_t */
+void shout_metadata_free(shout_metadata_t *self);
 
-#define SHOUTERR_INSANE		1
-#define SHOUTERR_NOCONNECT	2
-#define SHOUTERR_NOLOGIN	3
-#define SHOUTERR_SOCKET		4
-#define SHOUTERR_MALLOC		5
-#define SHOUTERR_METADATA	6
-
-typedef struct {
-	char *ip;		/* ip of the icecast server (NOT A HOSTNAME) */
-	int port;		/* port of the icecast server */
-	char *mount;		/* mountpoint for this stream */
-
-	int connected;		/* are we connected to a server? */
-	int _socket;		/* internal - socket the connection is on */
-
-	char *password;		/* login password for the server */
-	char *name;		/* name of the stream */
-	char *url;		/* homepage of the stream */
-	char *genre;		/* genre of the stream */
-	char *description;	/* description of the stream */
-	int bitrate;		/* bitrate of this stream */
-	int ispublic;		/* is this stream private? */
-	int error;
-	int pages;		/* total pages broadcasted */
-
-	uint64_t _starttime;	/* start of this period's timeclock */
-	uint64_t _senttime;	/* amout of data we've sent (in milliseconds) */
-	int _samples;	        /* the number of samples for the current page */
-	int _oldsamples;
-	int _samplerate;  	/* the samplerate of the stream */
-
-	ogg_sync_state _oy;
-	long _serialno;
-} shout_conn_t;
-
-
-/*
-** shout_init_connection
-**
-** initializes the shout_conn_t structure
-*/
-void shout_init_connection(shout_conn_t *self);
-
-/*
-** shout_connect
-**  
-** opens a connection to an icecast server, and logs in
-*/
-int shout_connect(shout_conn_t *self);
-
-/*
-** shout_disconnect
-**
-** closes a connection to an icecast server
-*/
-int shout_disconnect(shout_conn_t *self);
-
-/*
-** shout_send_data
-** 
-** sends a block of data (buffsize bytes in buff) to the icecast
-** server at the correct rate (calculated by the bitrate in the mp3
-** frame headers
-*/
-int shout_send_data(shout_conn_t *self, unsigned char *buff, unsigned long len);
-
-/*
-** shout_sleep
-**
-** sleeps if need be
-**
-*/
-void shout_sleep(shout_conn_t *self);
-
-/*
-** shout_strerror
-**
-** Formats the error code to a user readable string, like strerror()
-** Returns pointer to namespace.
-*/
-char *shout_strerror(int error);
+/* Add a parameter to the metadata structure */
+int shout_metadata_add(shout_metadata_t *self, const char *name, const char *value);
 
 #ifdef __cplusplus
 }

<p><p>1.2       +2 -5      libshout/src/Makefile.am

Index: Makefile.am
===================================================================
RCS file: /usr/local/cvsroot/libshout/src/Makefile.am,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- Makefile.am	2001/09/10 02:24:40	1.1
+++ Makefile.am	2002/01/23 03:08:39	1.2
@@ -7,14 +7,11 @@
 lib_LTLIBRARIES = libshout.la
 
 noinst_HEADERS = 
-libshout_la_SOURCES = shout.c
+libshout_la_SOURCES = shout.c util.c vorbis.c mp3.c
 
 libshout_la_LIBADD = net/libicenet.la timing/libicetiming.la
 
-INCLUDES = -I../include/shout -Inet -Itiming
-
-# SCCS stuff (for BitKeeper)
-GET = true
+INCLUDES = -I$(top_srcdir)/include/shout -I$(srcdir)/net -I$(srcdir)/timing
 
 debug:
         $(MAKE) all CFLAGS="@DEBUG@"

<p><p>1.4       +540 -119  libshout/src/shout.c

Index: shout.c
===================================================================
RCS file: /usr/local/cvsroot/libshout/src/shout.c,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- shout.c	2001/10/20 21:47:00	1.3
+++ shout.c	2002/01/23 03:08:39	1.4
@@ -1,174 +1,188 @@
+/* shout.c: Implementation of public libshout interface shout.h */
+
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 
-#include <ogg/ogg.h>
-#include <vorbis/codec.h>
+#include "shout.h"
+#include "shout_private.h"
 
 #include "sock.h"
-
-#include "shout.h"
 #include "timing.h"
-
-int _login(shout_conn_t *self)
-{
-	int res;
-
-	res = sock_write(self->_socket, "SOURCE %s ICE/1.0\n", self->mount);
-	if (!res) return 0;
+#include "util.h"
 
-	res = sock_write(self->_socket, "ice-password: %s\n", self->password);
-	if (!res) return 0;
+/* -- local prototypes -- */
+static int login_ice(shout_t *self);
+static int login_xaudiocast(shout_t *self);
+static int login_icy(shout_t *self);
 
-	res = sock_write(self->_socket, "ice-name: %s\n", self->name != NULL ? self->name : "no name");
-	if (!res) return 0;
+/* -- public functions -- */
 
-	if (self->url) {
-		res = sock_write(self->_socket, "ice-url: %s\n", self->url);
-		if (!res) return 0;
-	}
+shout_t *shout_new(void)
+{
+	shout_t *self;
 
-	if (self->genre) {
-		res = sock_write(self->_socket, "ice-genre: %s\n", self->genre);
-		if (!res) return 0;
+	if (!(self = (struct shout *)calloc(1, sizeof(shout_t)))) {
+		return NULL;
         }
 
-	res = sock_write(self->_socket, "ice-bitrate: %d\n", self->bitrate);
-	if (!res) return 0;
-
-	res = sock_write(self->_socket, "ice-public: %d\n", self->ispublic);
-	if (!res) return 0;
-
-	if (self->description) {
-		res = sock_write(self->_socket, "ice-description: %s\n", self->description);
-		if (!res) return 0;
+	if (!(self->host = util_strdup(LIBSHOUT_DEFAULT_HOST))) {
+		free(self);
+		return NULL;
         }
 
-	res = sock_write(self->_socket, "\n");
-	if (!res) return 0;
+	self->port = LIBSHOUT_DEFAULT_PORT;
+	self->format = LIBSHOUT_DEFAULT_FORMAT;
+	self->protocol = LIBSHOUT_DEFAULT_PROTOCOL;
 
-	return 1;
+	return self;
 }
 
-void shout_init_connection(shout_conn_t *self)
+void shout_free(shout_t *self)
 {
-	memset(self, 0, sizeof(shout_conn_t));
+	if (!self) return;
+
+	if (self->host) free(self->host);
+	if (self->password) free(self->password);
+	if (self->mount) free(self->mount);
+	if (self->name) free(self->name);
+	if (self->url) free(self->url);
+	if (self->genre) free(self->genre);
+	if (self->description) free(self->description);
+
+	free(self);
 }
 
-int shout_connect(shout_conn_t *self)
+int shout_open(shout_t *self)
 {
         /* sanity check */
-	if ((self->ip == NULL) || (self->password == NULL) || (self->port <= 0) || self->connected) {
-		self->error = SHOUTERR_INSANE;
-		return 0;
-	}
+	if (!self)
+		return SHOUTERR_INSANE;
 
-	self->_socket = sock_connect(self->ip, self->port);
-	if (self->_socket <= 0) {
-		self->error = SHOUTERR_NOCONNECT;
-		return 0;
-	}
+	if (!self->host || !self->password || !self->port || self->connected)
+		return self->error = SHOUTERR_INSANE;
+
+	if (self->format == SHOUT_FORMAT_VORBIS && self->protocol != SHOUT_PROTOCOL_ICE)
+		return self->error = SHOUTERR_UNSUPPORTED;
 
-	if (_login(self)) {
-		self->connected = 1;
-		ogg_sync_init(&self->_oy);
-		return 1;
+	self->socket = sock_connect(self->host, self->port);
+	if (self->socket <= 0)
+		return self->error = SHOUTERR_NOCONNECT;
+
+	if (self->protocol == SHOUT_PROTOCOL_ICE) {
+		if ((self->error = login_ice(self)) != SHOUTERR_SUCCESS) {
+			sock_close(self->socket);
+			return self->error;
+		}
+	} else if (self->protocol == SHOUT_PROTOCOL_XAUDIOCAST) {
+		if ((self->error = login_xaudiocast(self)) != SHOUTERR_SUCCESS) {
+			sock_close(self->socket);
+			return self->error;
+		}
+	} else if (self->protocol == SHOUT_PROTOCOL_ICY) {
+		if ((self->error = login_icy(self)) != SHOUTERR_SUCCESS) {
+			sock_close(self->socket);
+			return self->error;
+		}
+		
+	} else
+		return self->error = SHOUTERR_INSANE;
+  
+	if (self->format == SHOUT_FORMAT_VORBIS) {
+		if ((self->error = shout_open_vorbis(self)) != SHOUTERR_SUCCESS) {
+			sock_close(self->socket);
+			return self->error;
+		}
+	} else if (self->format == SHOUT_FORMAT_MP3) {
+		if ((self->error = shout_open_mp3(self)) != SHOUTERR_SUCCESS) {
+			sock_close(self->socket);
+			return self->error;
+		}
+	} else {
+		sock_close(self->socket);
+		return self->error = SHOUTERR_INSANE;
         }
 
-	self->error = SHOUTERR_NOLOGIN;
-	return 0;
+	self->connected = 1;
+
+	return self->error;
 }
+
 
-int shout_disconnect(shout_conn_t *self)
+int shout_close(shout_t *self)
 {
-	if (!sock_valid_socket(self->_socket)) {
-		self->error = SHOUTERR_INSANE;
-		return 0;
-	}
+	if (!self)
+		return SHOUTERR_INSANE;
 
-	ogg_sync_clear(&self->_oy);
+	if (!self->connected)
+		return self->error = SHOUTERR_UNCONNECTED;
 
+	if (self->close)
+		self->close(self);
+
+	sock_close(self->socket);
         self->connected = 0;
-	sock_close(self->_socket);
 
-	return 1;
+	return self->error = SHOUTERR_SUCCESS;
 }
 
-int shout_send_data(shout_conn_t *self, unsigned char *buff, unsigned long len)
+int shout_send(shout_t *self, const unsigned char *data, size_t len)
 {
-	int ret;
-	char *buffer;
-	ogg_stream_state os;
-	ogg_page og;
-	ogg_packet op;
-	vorbis_info vi;
-	vorbis_comment vc;
-
-	if (self->_starttime == 0) 
-		self->_starttime = timing_get_time();
-
-	buffer = ogg_sync_buffer(&self->_oy, len);
-	memcpy(buffer, buff, len);
-	ogg_sync_wrote(&self->_oy, len);
-
-	while (ogg_sync_pageout(&self->_oy, &og) == 1) {
-		if (self->_serialno != ogg_page_serialno(&og)) {
-			self->_serialno = ogg_page_serialno(&og);
-			
-			self->_oldsamples = 0;
-			
-			ogg_stream_init(&os, self->_serialno);
-			ogg_stream_pagein(&os, &og);
-			ogg_stream_packetout(&os, &op);
-
-			vorbis_info_init(&vi);
-			vorbis_comment_init(&vc);
-			vorbis_synthesis_headerin(&vi, &vc, &op);
-			
-			self->_samplerate = vi.rate;
-			
-			vorbis_comment_clear(&vc);
-			vorbis_info_clear(&vi);
-			ogg_stream_clear(&os);
-		}
+	if (!self)
+		return SHOUTERR_INSANE;
 
-		self->_samples = ogg_page_granulepos(&og) - self->_oldsamples;
-		self->_oldsamples = ogg_page_granulepos(&og);
+	if (!self->connected)
+		return self->error = SHOUTERR_UNCONNECTED;
 
-		
-		self->_senttime += ((double)self->_samples * 1000000 / (double)self->_samplerate);
-		
-		ret = sock_write_bytes(self->_socket, og.header, og.header_len);
-		if (ret != og.header_len) {
-			self->error = SHOUTERR_SOCKET;
-			return 0;
-		}
-		
-		ret = sock_write_bytes(self->_socket, og.body, og.body_len);
-		if (ret != og.body_len) {
+	if (self->starttime <= 0)
+		self->starttime = timing_get_time();
+
+	return self->send(self, buff, len);
+}
+
+ssize_t shout_send_raw(shout_t *self, const unsigned char *data, size_t len)
+{
+	ssize_t ret;
+
+	if (!self)
+		return SHOUTERR_INSANE;
+
+	if (len) {
+		ret = sock_write_bytes(self->socket, buff, len);
+		if (ret < 0 || (size_t)ret != len) {
                         self->error = SHOUTERR_SOCKET;
-			return 0;
+			return ret;
                 }
-		
-		self->pages++;
         }
 
-	return 1;
+	self->error = SHOUTERR_SUCCESS;
+	return len;
 }
 
-void shout_sleep(shout_conn_t *self)
+void shout_sync(shout_t *self)
 {
         uint64_t sleep;
+
+	if (!self)
+		return;
 
-	if (self->_senttime == 0) return;
+	if (self->senttime == 0)
+		return;
 
-	sleep = ((double)self->_senttime / 1000) - (timing_get_time() - self->_starttime);
+	sleep = ((double)self->senttime / 1000) - (timing_get_time() - self->starttime);
 
-	if (sleep > 0) timing_sleep(sleep);
+	if (sleep > 0)
+		timing_sleep(sleep);
 }
 
-char *shout_strerror(int error)
+const char *shout_get_error(shout_t *self)
 {
-	switch (error) {
+	if (!self)
+		return "Invalid shout_t";
+
+	switch (self->error) {
+	case SHOUTERR_SUCCESS:
+		return "No error";
         case SHOUTERR_INSANE:
                 return "Nonsensical arguments";
         case SHOUTERR_NOCONNECT:
@@ -179,7 +193,414 @@
                 return "Socket error";
         case SHOUTERR_MALLOC:
                 return "Out of memory";
+	case SHOUTERR_CONNECTED:
+		return "Cannot set parameter while connected";
+	case SHOUTERR_UNCONNECTED:
+		return "Not connected";
+	case SHOUTERR_UNSUPPORTED:
+		return "This libshout doesn't support the requested option";
         default:
                 return "Unknown error";
         }
+}
+
+int shout_set_host(shout_t *self, const char *host)
+{
+	if (!self)
+		return SHOUTERR_INSANE;
+
+	if (self->connected)
+		return self->error = SHOUTERR_CONNECTED;
+
+	if (self->host)
+		free(self->host);
+
+	if (!(self->host = util_strdup(host)))
+		return self->error = SHOUTERR_MALLOC;
+
+	return self->error = SHOUTERR_SUCCESS;
+}
+
+const char *shout_get_host(shout_t *self)
+{
+	if (!self)
+		return NULL;
+
+	return self->host;
+}
+
+int shout_set_port(shout_t *self, unsigned short port)
+{
+	if (!self)
+		return SHOUTERR_INSANE;
+
+	if (self->connected)
+		return self->error = SHOUTERR_CONNECTED;
+
+	self->port = port;
+
+	return self->error = SHOUTERR_SUCCESS;
+}
+
+unsigned short shout_get_port(shout_t *self)
+{
+	if (!self)
+		return 0;
+
+	return self->port;
+}
+
+int shout_set_password(shout_t *self, const char *password)
+{
+	if (!self)
+		return SHOUTERR_INSANE;
+
+	if (self->connected)
+		return self->error = SHOUTERR_CONNECTED;
+
+	if (self->password)
+		free (self->password);
+
+	if (!(self->password = util_strdup(password)))
+		return self->error = SHOUTERR_MALLOC;
+
+	return self->error = SHOUTERR_SUCCESS;
+}
+
+const char* shout_get_password(shout_t *self)
+{
+	if (!self)
+		return NULL;
+
+	return self->password;
+}
+
+int shout_set_mount(shout_t *self, const char *mount)
+{
+	if (!self)
+		return SHOUTERR_INSANE;
+
+	if (self->connected)
+		return self->error = SHOUTERR_CONNECTED;
+
+	if (self->mount)
+		free(self->mount);
+
+	if (!(self->mount = util_strdup(mount)))
+		return self->error = SHOUTERR_MALLOC;
+
+	return self->error = SHOUTERR_SUCCESS;
+}
+
+const char *shout_get_mount(shout_t *self)
+{
+	if (!self)
+		return NULL;
+
+	return self->mount;
+}
+
+int shout_set_name(shout_t *self, const char *name)
+{
+	if (!self)
+		return SHOUTERR_INSANE;
+
+	if (self->connected)
+		return self->error = SHOUTERR_CONNECTED;
+
+	if (self->name)
+		free(self->name);
+
+	if (!(self->name = util_strdup(name)))
+		return self->error = SHOUTERR_MALLOC;
+
+	return self->error = SHOUTERR_SUCCESS;
+}
+
+const char *shout_get_name(shout_t *self)
+{
+	if (!self)
+		return NULL;
+
+	return self->name;
+}
+
+int shout_set_url(shout_t *self, const char *url)
+{
+	if (!self)
+		return SHOUTERR_INSANE;
+
+	if (self->connected)
+		return self->error = SHOUTERR_CONNECTED;
+
+	if (self->url)
+		free(self->url);
+
+	if (!(self->url = util_strdup(url)))
+		return self->error = SHOUTERR_MALLOC;
+
+	return self->error = SHOUTERR_SUCCESS;
+}
+
+const char *shout_get_url(shout_t *self)
+{
+	if (!self)
+		return NULL;
+
+	return self->url;
+}
+
+int shout_set_genre(shout_t *self, const char *genre)
+{
+	if (!self)
+		return SHOUTERR_INSANE;
+
+	if (self->connected)
+		return self->error = SHOUTERR_CONNECTED;
+
+	if (self->genre)
+		free(self->genre);
+
+	if (! (self->genre = util_strdup (genre)))
+		return self->error = SHOUTERR_MALLOC;
+
+	return self->error = SHOUTERR_SUCCESS;
+}
+
+const char *shout_get_genre(shout_t *self)
+{
+	if (!self)
+		return NULL;
+
+	return self->genre;
+}
+
+int shout_set_description(shout_t *self, const char *description)
+{
+	if (!self)
+		return SHOUTERR_INSANE;
+
+	if (self->connected)
+		return self->error = SHOUTERR_CONNECTED;
+
+	if (self->description)
+		free(self->description);
+
+	if (! (self->description = util_strdup (description)))
+		return self->error = SHOUTERR_MALLOC;
+
+	return self->error = SHOUTERR_SUCCESS;
+}
+
+const char *shout_get_description(shout_t *self)
+{
+	if (!self)
+		return NULL;
+
+	return self->description;
+}
+
+int shout_set_bitrate(shout_t *self, unsigned int bitrate)
+{
+	if (!self)
+		return SHOUTERR_INSANE;
+
+	if (self->connected)
+		return self->error = SHOUTERR_CONNECTED;
+
+	self->bitrate = bitrate;
+
+	return self->error = SHOUTERR_SUCCESS;
+}
+
+unsigned int shout_get_bitrate(shout_t *self)
+{
+	if (!self)
+		return 0;
+
+	return self->bitrate;
+}
+
+int shout_set_public(shout_t *self, unsigned int public)
+{
+	if (!self || (public != 0 && public != 1))
+		return SHOUTERR_INSANE;
+
+	if (self->connected)
+		return self->error = SHOUTERR_CONNECTED;
+
+	self->public = public;
+
+	return self->error = SHOUTERR_SUCCESS;
+}
+
+unsigned int shout_get_public(shout_t *self)
+{
+	if (!self)
+		return 0;
+
+	return self->public;
+}
+
+int shout_set_format(shout_t *self, unsigned int format)
+{
+	if (!self)
+		return SHOUTERR_INSANE;
+
+	if (self->connected)
+		return self->error = SHOUTERR_CONNECTED;
+
+	if (format != SHOUT_FORMAT_VORBIS && format != SHOUT_FORMAT_MP3)
+		return self->error = SHOUTERR_UNSUPPORTED;
+
+	self->format = format;
+
+	return self->error = SHOUTERR_SUCCESS;
+}
+
+unsigned int shout_get_format(shout_t* self)
+{
+	if (!self)
+		return 0;
+
+	return self->format;
+}
+
+int shout_set_protocol(shout_t *self, unsigned int protocol)
+{
+	if (!self)
+		return SHOUTERR_INSANE;
+
+	if (self->connected)
+		return self->error = SHOUTERR_CONNECTED;
+
+	if (protocol != SHOUT_PROTOCOL_ICE &&
+	    protocol != SHOUT_PROTOCOL_XAUDIOCAST &&
+	    protocol != SHOUT_PROTOCOL_ICY)
+		return self->error = SHOUTERR_UNSUPPORTED;
+
+	self->protocol = protocol;
+
+	return self->error = SHOUTERR_SUCCESS;
+}
+
+unsigned int shout_get_protocol(shout_t *self)
+{
+	if (!self)
+		return 0;
+
+	return self->protocol;
+}
+
+/* -- static function definitions -- */
+
+static int login_ice(shout_t *self)
+{
+	self->error = SHOUTERR_SOCKET;
+
+	if (!sock_write(self->socket, "SOURCE %s ICE/1.0\n", self->mount))
+		return SHOUTERR_SOCKET;
+	if (!sock_write(self->socket, "ice-password: %s\n", self->password))
+		return SHOUTERR_SOCKET;
+	if (!sock_write(self->socket, "ice-name: %s\n", self->name != NULL ? self->name : "no name"))
+		return SHOUTERR_SOCKET;
+	if (self->url) {
+		if (!sock_write(self->socket, "ice-url: %s\n", self->url))
+			return SHOUTERR_SOCKET;
+	}
+	if (self->genre) {
+		if (!sock_write(self->socket, "ice-genre: %s\n", self->genre))
+			return SHOUTERR_SOCKET;
+	}
+	if (!sock_write(self->socket, "ice-bitrate: %d\n", self->bitrate))
+		return SHOUTERR_SOCKET;
+	if (!sock_write(self->socket, "ice-public: %d\n", self->public))
+		return SHOUTERR_SOCKET;
+	if (self->description) {
+		if (!sock_write(self->socket, "ice-description: %s\n", self->description))
+			return SHOUTERR_SOCKET;
+	}
+	if (self->format == SHOUT_FORMAT_VORBIS) {
+		if (!sock_write(self->socket, "Content-Type: application/x-ogg\n"))
+			return SHOUTERR_SOCKET;
+	} else if (self->format == SHOUT_FORMAT_MP3) {
+		if (!sock_write(self->socket, "Content-Type: audio/mpeg\n"))
+			return SHOUTERR_SOCKET;
+	}
+
+	if (!sock_write(self->socket, "\n"))
+		return SHOUTERR_SOCKET;
+
+	return SHOUTERR_SUCCESS;
+}
+
+static int login_xaudiocast(shout_t *self)
+{
+	char response[4096];
+
+	if (!sock_write(self->socket, "SOURCE %s %s\n", self->password, self->mount))
+		return SHOUTERR_SOCKET;
+	if (!sock_write(self->socket, "x-audiocast-name: %s\n", self->name != NULL ? self->name : "unnamed"))
+		return SHOUTERR_SOCKET;
+	if (!sock_write(self->socket, "x-audiocast-url: %s\n", self->url != NULL ? self->url : "http://www.icecast.org/"))
+		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))
+		return SHOUTERR_SOCKET;
+	if (!sock_write(self->socket, "x-audiocast-public: %i\n", self->public))
+		return SHOUTERR_SOCKET;
+	if (!sock_write(self->socket, "x-audiocast-description: %s\n", self->description != NULL ? self->description : "Broadcasting with the icecast streaming media server!"))
+		return SHOUTERR_SOCKET;
+
+	if (!sock_write(self->socket, "\n"))
+		return SHOUTERR_SOCKET;
+
+	if (!sock_read_line(self->socket, response, sizeof(response)))
+		return SHOUTERR_SOCKET;
+
+	if (!strstr(response, "OK"))
+		return SHOUTERR_NOLOGIN;
+
+	return SHOUTERR_SUCCESS;
+}
+
+int login_icy(shout_t *self)
+{
+	char response[4096];
+
+	if (!sock_write(self->socket, "%s\n", self->password))
+		return SHOUTERR_SOCKET;
+	if (!sock_write(self->socket, "icy-name:%s\n", self->name != NULL ? self->name : "unnamed"))
+		return SHOUTERR_SOCKET;
+	if (!sock_write(self->socket, "icy-url:%s\n", self->url != NULL ? self->url : "http://www.icecast.org/"))
+		return SHOUTERR_SOCKET;
+
+#if 0
+	/* Fields we don't use */
+	if (!sock_write(self->socket, "icy-irc:%s\n", self->irc != NULL ? self->irc : ""))
+		return SHOUTERR_SOCKET;
+	if (!sock_write(self->socket, "icy-aim:%s\n", self->aim != NULL ? self->aim : ""))
+		return SHOUTERR_SOCKET;
+	if (!sock_write(self->socket, "icy-icq:%s\n", self->icq != NULL ? self->icq : ""))
+		return SHOUTERR_SOCKET;
+	if (!sock_write(self->socket, "icy-pub:%i\n", self->ispublic))
+		return SHOUTERR_SOCKET;
+#endif
+
+	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))
+		return SHOUTERR_SOCKET;
+
+	if (!sock_write(self->socket, "\n"))
+		return SHOUTERR_SOCKET;
+
+	if (!sock_read_line(self->socket, response, sizeof(response)))
+		return SHOUTERR_SOCKET;
+
+	if (!strstr(response, "OK"))
+		return SHOUTERR_NOLOGIN;
+
+	return SHOUTERR_SUCCESS;
 }

<p><p>1.1                  libshout/src/mp3.c

Index: mp3.c
===================================================================
/* mp3.c: libshout MP3 format handler */

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>

#include "shout.h"
#include "shout_private.h"

/*
 * MP3 Frame handling curtesy of Scott Manley - may he always be Manley.
 */

#define MPEG_MODE_MONO 3

/* -- local datatypes -- */
typedef struct {
        unsigned int frames;
        /* the number of samples for the current frame */
        int frame_samples;
        /* the samplerate of the current frame */
        int frame_samplerate;
        /* how many bytes for the rest of this frame */
        unsigned int frame_left;
        /* is the header bridged?? */
        int header_bridges;
        /* put part of header here if it spans a boundary */
        unsigned char header_bridge[3];
} mp3_data_t;

typedef struct {
        int syncword;
        int layer;
        int version;
        int error_protection;
        int bitrate_index;
        int samplerate_index;
        int padding;
        int extension;
        int mode;
        int mode_ext;
        int copyright;
        int original;
        int emphasis;
        int stereo;
        int bitrate;
        unsigned int samplerate;
        unsigned int samples;
        unsigned int framesize;
} mp3_header_t;

/* -- const data -- */
const unsigned int bitrate[3][3][16] =
{
        {
                { 0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 0 },
                { 0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 0 },
                { 0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 0 }
        }, {
                { 0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, 0 },
                { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0 },
                { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0 }
        }, {
                { 0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, 0 },
                { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0 },
                { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0 }
        }
};

const unsigned int samplerate[3][4] =
{
        { 44100, 48000, 32000, 0 },
        { 22050, 24000, 16000, 0 },
        { 11025, 8000, 8000, 0 }
};

/* -- static prototypes -- */
static int send_mp3(shout_t *self, const unsigned char *data, size_t len);
static void close_mp3(shout_t *self);

tatic void parse_header(mp3_header_t *mh, uint32_t header);
static int mp3_header(uint32_t head, mp3_header_t *mh);

int shout_open_mp3(shout_t *self)
{
        mp3_data_t *mp3_data;

        if (!(mp3_data = (mp3_data_t *)calloc(1, sizeof(mp3_data_t))))
                return SHOUTERR_MALLOC;
        self->format_data = mp3_data;

        self->send = send_mp3;
        self->close = close_mp3;

        return SHOUTERR_SUCCESS;
}

tatic int send_mp3(shout_t* self, const unsigned char* buff, size_t len)
{
        mp3_data_t* mp3_data = (mp3_data_t*) self->format_data;
        unsigned long pos;
        uint32_t head;
        int ret, count;
        int start, end, error, i;
        unsigned char *bridge_buff;
        mp3_header_t mh;

        bridge_buff = NULL;
        pos = 0;
        start = 0;
        error = 0;
        end = len - 1;
        memset(&mh, 0, sizeof(mh));

        /* finish the previous frame */
        if (mp3_data->frame_left > 0) {
                /* is the rest of the frame here? */
                if (mp3_data->frame_left <= len) {
                        self->senttime += ((double)mp3_data->frame_samples / (double)mp3_data->frame_samplerate * 1000000);
                        mp3_data->frames++;
                        pos += mp3_data->frame_left;
                        mp3_data->frame_left = 0;
                } else {
                        mp3_data->frame_left -= len;
                        pos = len;
                }
        }

        /* header was over the boundary, so build a new build a new buffer */
        if (mp3_data->header_bridges) {
                bridge_buff = (unsigned char *)malloc(len + mp3_data->header_bridges);
                if (bridge_buff == NULL) {
                        return self->error = SHOUTERR_MALLOC;
                }

                bridge_buff[0] = mp3_data->header_bridge[0];
                bridge_buff[1] = mp3_data->header_bridge[1];
                bridge_buff[2] = mp3_data->header_bridge[2];

                memcpy(&bridge_buff[mp3_data->header_bridges], buff, len);

                buff = bridge_buff;
                len += mp3_data->header_bridges;
                end = len - 1;

                mp3_data->header_bridges = 0;
        }

        /** this is the main loop
        *** we handle everything but the last 4 bytes...
        **/
        while (pos <= (len - 4)) {
                /* find mp3 header */
                head = (buff[pos] << 24) | 
                        (buff[pos + 1] << 16) |
                        (buff[pos + 2] << 8) |
                        (buff[pos + 3]);

                /* is this a valid header? */
                if (mp3_header(head, &mh)) {
                        if (error) {
                                start = pos;
                                end = len - 1;
                                error = 0;
                        }

                        mp3_data->frame_samples = mh.samples;
                        mp3_data->frame_samplerate = mh.samplerate;

                        /* do we have a complete frame in this buffer? */
                        if (len - pos >= mh.framesize) {
                                self->senttime += ((double)mp3_data->frame_samples / (double)mp3_data->frame_samplerate * 1000000);
                                mp3_data->frames++;
                                pos += mh.framesize;
                        } else {
                                mp3_data->frame_left = mh.framesize - (len - pos);
                                pos = len;
                        }
                } else {
                        /* there was an error
                        ** so we send all the valid data up to this point 
                        */
                        if (!error) {
                                error = 1;
                                end = pos - 1;
                                count = end - start + 1;
                                if (count > 0)
                                        ret = sock_write_bytes(self->socket, (char *)&buff[start], count);
                                else
                                        ret = 0;

                                if (ret != count) {
                                        if (bridge_buff != NULL)
                                                free(bridge_buff);
                                        return self->error = SHOUTERR_SOCKET;
                                }
                        }
                        pos++;
                }
        }

        /* catch the tail if there is one */
        if ((pos > (len - 4)) && (pos < len)) {
                end = pos - 1;

                i = 0;
                while (pos < len) {
                        mp3_data->header_bridge[i] = buff[pos];
                        pos++;
                        i++;
                } 
                mp3_data->header_bridges = i;
        }

        if (!error) {
                /* if there's no errors, lets send the frames */
                count = end - start + 1;
                if (count > 0)
                        ret = sock_write_bytes(self->socket, (char *)&buff[start], count);
                else
                        ret = 0;

                if (bridge_buff != NULL)
                        free(bridge_buff);

                if (ret == count) {
                        return self->error = SHOUTERR_SUCCESS;
                } else {
                        return self->error = SHOUTERR_SOCKET;
                }
        }

        if (bridge_buff != NULL)
                free(bridge_buff);

        return self->error = SHOUTERR_SUCCESS;
}

tatic void parse_header(mp3_header_t *mh, uint32_t header)
{
        mh->syncword = (header >> 20) & 0x0fff;
        mh->version = ((header >> 19) & 0x01) ? 0 : 1;
        if ((mh->syncword & 0x01) == 0)
                mh->version = 2;
        mh->layer = 3 - ((header >> 17) & 0x03);
        mh->error_protection = ((header >> 16) & 0x01) ? 0 : 1;
        mh->bitrate_index = (header >> 12) & 0x0F;
        mh->samplerate_index = (header >> 10) & 0x03;
        mh->padding = (header >> 9) & 0x01;
        mh->extension = (header >> 8) & 0x01;
        mh->mode = (header >> 6) & 0x03;
        mh->mode_ext = (header >> 4) & 0x03;
        mh->copyright = (header >> 3) & 0x01;
        mh->original = (header >> 2) & 0x01;
        mh->emphasis = header & 0x03;

        mh->stereo = (mh->mode == MPEG_MODE_MONO) ? 1 : 2;
        mh->bitrate = bitrate[mh->version][mh->layer][mh->bitrate_index];
        mh->samplerate = samplerate[mh->version][mh->samplerate_index];

        if (mh->version == 0)
                mh->samples = 1152;
        else
                mh->samples = 576;

        if(mh->samplerate)
                mh->framesize = ((float)mh->samples * mh->bitrate * 1000 / (float)mh->samplerate) / 8 + mh->padding;
}

/* mp3 frame parsing stuff */
static int mp3_header(uint32_t head, mp3_header_t *mh)
{
        /* fill out the header struct */
        parse_header(mh, head);

        /* check for syncword */
        if ((mh->syncword & 0x0ffe) != 0x0ffe)
                return 0;

        /* check for the right layer */
        if (mh->layer != 2)
                return 0;

        /* make sure bitrate is sane */
        if (mh->bitrate == 0)
                return 0;

        /* make sure samplerate is sane */
        if (mh->samplerate == 0)
                return 0;

        return 1;
}

tatic void close_mp3(shout_t *self)
{
        mp3_data_t *mp3_data = (mp3_data_t *)self->format_data;

        free(mp3_data);
}

<p><p>1.1                  libshout/src/shout_private.h

Index: shout_private.h
===================================================================
/* shout.h: Private libshout data structures and declarations */

#ifndef __LIBSHOUT_SHOUT_PRIVATE_H__
#define __LIBSHOUT_SHOUT_PRIVATE_H__

#include "shout.h"
#include "sock.h"
#include "timing.h"

#include <sys/types.h>
#ifdef HAVE_STDINT_H
#  include <stdint.h>
#elif defined (HAVE_INTTYPES_H)
#  include <inttypes.h>
#endif

#ifndef HAVE_C99_INTTYPES
#  if SIZEOF_SHORT == 4
typedef unsigned short uint32_t;
#  elif SIZEOF_INT == 4
typedef unsigned int uint32_t;
#  elif SIZEOF_LONG == 4
typedef unsigned long uint32_t;
#  endif
#  if SIZEOF_INT == 8
typedef unsigned int uint64_t;
#  elif SIZEOF_LONG == 8
typedef unsigned long uint64_t;
#  elif SIZEOF_LONG_LONG == 8
typedef unsigned long long uint64_t;
#  endif
#endif

#define LIBSHOUT_DEFAULT_HOST "localhost"
#define LIBSHOUT_DEFAULT_PORT 8000
#define LIBSHOUT_DEFAULT_FORMAT SHOUT_FORMAT_VORBIS
#define LIBSHOUT_DEFAULT_PROTOCOL SHOUT_PROTOCOL_ICE

truct shout {
        /* hostname or IP of icecast server */
        char *host;
        /* port of the icecast server */
        int port;
        /* login password for the server */
        char *password;
        /* server protocol to use */
        unsigned int protocol;
        /* type of data being sent */
        unsigned int format;

        /* mountpoint for this stream */
        char *mount;
        /* name of the stream */
        char *name;
        /* homepage of the stream */
        char *url;
        /* genre of the stream */
        char *genre;
        /* description of the stream */
        char *description;
        /* bitrate of this stream */
        int bitrate;
        /* is this stream private? */
        int public;

        /* are we connected to a server? */
        int connected;
        /* socket the connection is on */
        sock_t socket;

        void *format_data;
        int (*send)(shout_t* self, const unsigned char* buff, size_t len);
        void (*close)(shout_t* self);

        /* start of this period's timeclock */
        uint64_t starttime;
        /* amout of data we've sent (in milliseconds) */
        uint64_t senttime;

        int error;
};

truct shout_metadata {
        char *name;
        char *value;
        shout_metadata_t *next;
};

int shout_open_vorbis(shout_t *self);
int shout_open_mp3(shout_t *self);

#endif /* __LIBSHOUT_SHOUT_PRIVATE_H__ */

<p><p>1.1                  libshout/src/util.c

Index: util.c
===================================================================
/* util.c: libshout utility/portability functions */

#include <stdio.h>
#include <string.h>

#include "util.h"

char *util_strdup(const char *s)
{
        if (!s) return NULL;
        return strdup(s);
}

<p><p>1.1                  libshout/src/util.h

Index: util.h
===================================================================
/* util.h: libshout utility/portability functions */

#ifndef __LIBSHOUT_UTIL_H__
#define __LIBSHOUT_UTIL_H__

char *util_strdup(const char *s);

#endif /* __LIBSHOUT_UTIL_H__ */

<p><p>1.1                  libshout/src/vorbis.c

Index: vorbis.c
===================================================================
/* vorbis.c: Ogg Vorbis data handlers for libshout */

#include <stdlib.h>

#include <ogg/ogg.h>
#include <vorbis/codec.h>

#include "shout.h"
#include "shout_private.h"

/* -- local datatypes -- */
typedef struct {
        /* total pages broadcasted */
        unsigned int pages;
        /* the number of samples for the current page */
        unsigned int samples;

        unsigned int oldsamples;
        unsigned int samplerate;
        ogg_sync_state oy;
        long serialno;
} vorbis_data_t;

/* -- static prototypes -- */
static int send_vorbis(shout_t *self, const unsigned char *data, size_t len);
static void close_vorbis(shout_t *self);

int shout_open_vorbis(shout_t *self)
{
        vorbis_data_t *vorbis_data;

        if (!(vorbis_data = (vorbis_data_t *)calloc(1, sizeof(vorbis_data_t))))
                return SHOUTERR_MALLOC;
        self->format_data = vorbis_data;

        ogg_sync_init(&vorbis_data->oy);

        self->send = send_vorbis;
        self->close = close_vorbis;

        return SHOUTERR_SUCCESS;
}

tatic int send_vorbis(shout_t *self, const unsigned char *data, size_t len)
{
        vorbis_data_t *vorbis_data = (vorbis_data_t *)self->format_data;
        int ret;
        char *buffer;
        ogg_stream_state os;
        ogg_page og;
        ogg_packet op;
        vorbis_info vi;
        vorbis_comment vc;

        buffer = ogg_sync_buffer(&vorbis_data->oy, len);
        memcpy(buffer, buff, len);
        ogg_sync_wrote(&vorbis_data->oy, len);

        while (ogg_sync_pageout(&vorbis_data->oy, &og) == 1) {
                if (vorbis_data->serialno != ogg_page_serialno(&og)) {
                        vorbis_data->serialno = ogg_page_serialno(&og);

                        vorbis_data->oldsamples = 0;

                        ogg_stream_init(&os, vorbis_data->serialno);
                        ogg_stream_pagein(&os, &og);
                        ogg_stream_packetout(&os, &op);

                        vorbis_info_init(&vi);
                        vorbis_comment_init(&vc);
                        vorbis_synthesis_headerin(&vi, &vc, &op);

                        vorbis_data->samplerate = vi.rate;

                        vorbis_comment_clear(&vc);
                        vorbis_info_clear(&vi);
                        ogg_stream_clear(&os);
                }

                vorbis_data->samples = ogg_page_granulepos(&og) - vorbis_data->oldsamples;
                vorbis_data->oldsamples = ogg_page_granulepos(&og);

                self->senttime += ((double)vorbis_data->samples * 1000000 / (double)vorbis_data->samplerate);

                ret = sock_write_bytes(self->socket, og.header, og.header_len);
                if (ret != og.header_len)
                        return self->error = SHOUTERR_SOCKET;

                ret = sock_write_bytes(self->socket, og.body, og.body_len);
                if (ret != og.body_len)
                        return self->error = SHOUTERR_SOCKET;

                vorbis_data->pages++;
        }

        return self->error = SHOUTERR_SUCCESS;
}

tatic void close_vorbis(shout_t *self)
{
        vorbis_data_t *vorbis_data = (vorbis_data_t *)self->format_data;
        ogg_sync_clear(&vorbis_data->oy);
        free(vorbis_data);
}

<p><p><p>--- >8 ----
List archives:  http://www.xiph.org/archives/
Ogg project homepage: http://www.xiph.org/ogg/
To unsubscribe from this list, send a message to 'cvs-request at xiph.org'
containing only the word 'unsubscribe' in the body.  No subject is needed.
Unsubscribe messages sent to the list will be ignored/filtered.



More information about the commits mailing list