[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