diff options
-rw-r--r-- | mp3cast~/CHANGES.LOG | 6 | ||||
-rw-r--r-- | mp3cast~/Makefile | 2 | ||||
-rw-r--r-- | mp3cast~/mp3cast~-help.pd | 101 | ||||
-rw-r--r-- | mp3cast~/mp3cast~.c | 781 |
4 files changed, 613 insertions, 277 deletions
diff --git a/mp3cast~/CHANGES.LOG b/mp3cast~/CHANGES.LOG index 7418ad7..3d088ed 100644 --- a/mp3cast~/CHANGES.LOG +++ b/mp3cast~/CHANGES.LOG @@ -1,3 +1,9 @@ +0.5 (by rama) + changed "ispublic" option to true as default + added messages handling for setting stream info: url, genre, description, isPublic + (all was tested using icecast2) +0.4 + added icecast 2 compatibility 0.3 renamed it to mp3cast 0.2 diff --git a/mp3cast~/Makefile b/mp3cast~/Makefile index 799788e..610423e 100644 --- a/mp3cast~/Makefile +++ b/mp3cast~/Makefile @@ -61,7 +61,7 @@ pd_linux: $(NAME).pd_linux .SUFFIXES: .pd_linux
LINUXCFLAGS = -DPD -DUNIX -DICECAST -O2 -funroll-loops -fomit-frame-pointer \
- -Wall -W -Wshadow -Wstrict-prototypes -Werror \
+ -Wall -W -Wshadow -Wstrict-prototypes \
-Wno-unused -Wno-parentheses -Wno-switch
LINUXINCLUDE = -I../../src
diff --git a/mp3cast~/mp3cast~-help.pd b/mp3cast~/mp3cast~-help.pd index c7d8e72..243570a 100644 --- a/mp3cast~/mp3cast~-help.pd +++ b/mp3cast~/mp3cast~-help.pd @@ -1,50 +1,65 @@ -#N canvas 52 75 741 425 10; -#X floatatom 53 24 0 40 16000; -#X msg 30 378 \; pd dsp 1; -#X obj 61 242 mp3cast~; -#X floatatom 61 280 0 0 0; +#N canvas 1180 63 687 606 10; +#X floatatom 53 24 0 40 16000 0 - - -; +#X msg 351 547 \; pd dsp 1; +#X floatatom 48 537 0 0 0 0 - - -; #X msg 181 88 disconnect; -#X msg 151 44 connect localhost 8000; #X text 266 63 <-- your password for the server; #X text 317 75 (default passwd is "pd"); #X text 257 87 <-- close connection; -#X text 411 21 <-- host and port; -#X text 292 215 <-- settings for mp3 stream; -#X text 315 245 bitrate: bitrate of stream \, def. 224kbit/s; -#X text 352 269 1 = joint stereo (default); -#X text 312 307 quality: 1 = high \, 9 = low; -#X text 313 227 (samplerate \, bitrate \, mode \, quality); -#X text 316 257 mode: 0 = stereo; -#X text 352 281 2 = dual channel; -#X text 352 294 3 = mono; -#X msg 13 145 print; -#X msg 96 378 \; pd dsp 0; -#X msg 203 141 icecast; -#X text 259 116 <-- choose type of server; +#X text 313 45 <-- host and port; +#X text 349 218 <-- settings for mp3 stream; +#X text 372 248 bitrate: bitrate of stream \, def. 224kbit/s; +#X text 409 272 1 = joint stereo (default); +#X text 369 310 quality: 1 = high \, 9 = low; +#X text 370 230 (samplerate \, bitrate \, mode \, quality); +#X text 373 260 mode: 0 = stereo; +#X text 409 284 2 = dual channel; +#X text 409 297 3 = mono; +#X msg 6 439 print; +#X msg 417 547 \; pd dsp 0; +#X msg 204 129 icecast; #X obj 53 51 osc~ 440; -#X msg 163 66 passwd letmein; -#X msg 154 239 mpeg 8000 8 3 5; -#X msg 155 215 mpeg 44100 128 1 4; -#X msg 209 170 mountpoint pd; -#X obj 29 349 loadbang; -#X text 293 374 Author : Yves Degoyon ( ydegoyon@free.fr ); -#X msg 190 118 shoutcast; -#X msg 116 23 connect college-invisible.dyndns.org 8000; +#X msg 211 242 mpeg 8000 8 3 5; +#X msg 212 218 mpeg 44100 128 1 4; +#X obj 350 518 loadbang; +#X text 313 477 Author : Yves Degoyon ( ydegoyon@free.fr ); +#X msg 191 109 shoutcast; #X msg 212 194 name mystream; #X text 322 195 name of the stream; -#X connect 0 0 22 0; -#X connect 2 0 3 0; -#X connect 4 0 2 0; -#X connect 5 0 2 0; -#X connect 18 0 2 0; -#X connect 20 0 2 0; -#X connect 22 0 2 0; -#X connect 22 0 2 1; -#X connect 23 0 2 0; -#X connect 24 0 2 0; -#X connect 25 0 2 0; -#X connect 26 0 2 0; -#X connect 27 0 1 0; -#X connect 29 0 2 0; -#X connect 30 0 2 0; -#X connect 31 0 2 0; +#X text 260 107 <-- choose type of server ( default = icecast ); +#X msg 209 148 icecast2; +#X msg 180 365 isPublic 0; +#X msg 181 387 isPublic 1; +#X text 385 421 <-- stream description; +#X text 265 380 <-- publish stream info in the yellow pages; +#X text 269 438 <-- stream genre; +#X text 338 344 <-- stream url; +#X msg 164 66 passwd pd; +#X msg 151 45 connect localhost 8000; +#X msg 212 172 mountpoint live.mp3; +#X msg 179 343 url http://localhost; +#X msg 180 415 description hardcore; +#X msg 180 439 genre other; +#X text 313 490 Contributor : Ramiro Consentino; +#X obj 48 499 mp3cast~; +#X connect 0 0 19 0; +#X connect 3 0 42 0; +#X connect 16 0 42 0; +#X connect 18 0 42 0; +#X connect 19 0 42 0; +#X connect 19 0 42 1; +#X connect 20 0 42 0; +#X connect 21 0 42 0; +#X connect 22 0 1 0; +#X connect 24 0 42 0; +#X connect 25 0 42 0; +#X connect 28 0 42 0; +#X connect 29 0 42 0; +#X connect 30 0 42 0; +#X connect 35 0 42 0; +#X connect 36 0 42 0; +#X connect 37 0 42 0; +#X connect 38 0 42 0; +#X connect 39 0 42 0; +#X connect 40 0 42 0; +#X connect 42 0 2 0; diff --git a/mp3cast~/mp3cast~.c b/mp3cast~/mp3cast~.c index 11c3d19..1d6d4be 100644 --- a/mp3cast~/mp3cast~.c +++ b/mp3cast~/mp3cast~.c @@ -26,6 +26,13 @@ /* */
/* ---------------------------------------------------------------------------- */
+
+
+#ifdef NT
+#pragma warning( disable : 4244 )
+#pragma warning( disable : 4305 )
+#endif
+
#include "m_pd.h" /* standard pd stuff */
#include <sys/types.h>
@@ -35,7 +42,7 @@ #include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>
-#ifndef __APPLE__
+#ifndef MACOSX
#include <malloc.h>
#endif
#include <ctype.h>
@@ -46,15 +53,17 @@ #include <netdb.h>
#include <time.h>
#include <sys/time.h>
+#include <lame/lame.h> /* lame encoder stuff */
+#include "mpg123.h"
#define SOCKET_ERROR -1
#else
#include <io.h>
#include <windows.h>
#include <winsock.h>
#include <windef.h>
+#include "lame_enc.h" /* lame encoder stuff */
#endif
-#include <lame/lame.h>
-#include "mpg123.h"
+
#define MY_MP3_MALLOC_IN_SIZE 65536
/* max size taken from lame readme */
@@ -63,7 +72,24 @@ #define MAXDATARATE 320 /* maximum mp3 data rate is 320kbit/s */
#define STRBUF_SIZE 32
-static char *mp3cast_version = "mp3cast~: mp3 streamer version 0.3, written by Yves Degoyon";
+static char *mp3cast_version = "mp3cast~: mp3 streamer version 0.5, written by Yves Degoyon";
+
+#ifndef UNIX
+static HINSTANCE dll = NULL;
+static BEINITSTREAM initStream = NULL;
+static BEENCODECHUNK encodeChunk = NULL;
+static BEDEINITSTREAM deinitStream = NULL;
+static BECLOSESTREAM closeStream = NULL;
+static BEVERSION dllVersion = NULL;
+static BEWRITEVBRHEADER writeVBRHeader = NULL;
+#endif
+
+static char base64table[65] = {
+ 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
+ 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
+ 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
+ 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/',
+};
static t_class *mp3cast_class;
@@ -95,13 +121,19 @@ typedef struct _mp3cast int x_fd; /* info about connection status */
char* x_passwd; /* password for server */
int x_icecast; /* tells if we use a IceCast server or SHOUTcast */
- /* special IceCast server stuff */
+ /* special IceCast server stuff */
char* x_mountpoint;
char* x_name;
+ char* x_url;
+ char* x_genre;
+ char* x_description;
+ int x_isPublic;
t_float x_f; /* float needed for signal input */
+#ifdef UNIX
lame_global_flags *lgfp; /* lame encoder configuration */
+#endif
} t_mp3cast;
@@ -142,41 +174,52 @@ static void mp3cast_encode(t_mp3cast *x) i = MY_MP3_MALLOC_IN_SIZE - x->x_outp;
- /* read from buffer */
- if(x->x_lamechunk <= i)
- {
- /* enough data until end of buffer */
- for(n = 0; n < x->x_lamechunk; n++) /* fill encode buffer */
- {
- x->x_mp3inbuf[n] = x->x_buffer[n + x->x_outp];
- }
- x->x_outp += x->x_lamechunk;
- }
- else /* split data */
- {
- for(wp = 0; wp < i; wp++) /* data at end of buffer */
- {
- x->x_mp3inbuf[wp] = x->x_buffer[wp + x->x_outp];
- }
-
- for(wp = i; wp < x->x_lamechunk; wp++) /* write rest of data at beginning of buffer */
- {
- x->x_mp3inbuf[wp] = x->x_buffer[wp - i];
- }
- x->x_outp = x->x_lamechunk - i;
- }
+ /* read from buffer */
+ if(x->x_lamechunk <= i)
+ {
+ /* enough data until end of buffer */
+ for(n = 0; n < x->x_lamechunk; n++) /* fill encode buffer */
+ {
+ x->x_mp3inbuf[n] = x->x_buffer[n + x->x_outp];
+ }
+ x->x_outp += x->x_lamechunk;
+ }
+ else /* split data */
+ {
+ for(wp = 0; wp < i; wp++) /* data at end of buffer */
+ {
+ x->x_mp3inbuf[wp] = x->x_buffer[wp + x->x_outp];
+ }
+
+ for(wp = i; wp < x->x_lamechunk; wp++) /* write rest of data at beginning of buffer */
+ {
+ x->x_mp3inbuf[wp] = x->x_buffer[wp - i];
+ }
+ x->x_outp = x->x_lamechunk - i;
+ }
/* encode mp3 data */
+#ifndef UNIX
+ err = encodeChunk(x->x_lame, x->x_lamechunk, x->x_mp3inbuf, x->x_mp3outbuf, &x->x_mp3size);
+#else
x->x_mp3size = lame_encode_buffer_interleaved(x->lgfp, x->x_mp3inbuf,
x->x_lamechunk/lame_get_num_channels(x->lgfp),
x->x_mp3outbuf, MY_MP3_MALLOC_OUT_SIZE);
// post( "mp3cast~ : encoding returned %d frames", x->x_mp3size );
+#endif
/* check result */
+#ifndef UNIX
+ if(err != BE_ERR_SUCCESSFUL)
+ {
+ closeStream(x->x_lame);
+ error("mp3cast~: lameEncodeChunk() failed (%lu)", err);
+#else
if(x->x_mp3size<0)
{
lame_close( x->lgfp );
error("mp3cast~: lame_encode_buffer_interleaved failed (%d)", x->x_mp3size);
+#endif
x->x_lame = -1;
}
}
@@ -192,7 +235,11 @@ static void mp3cast_stream(t_mp3cast *x) if(err < 0)
{
error("mp3cast~: could not send encoded data to server (%d)", err);
+#ifndef UNIX
+ closeStream(x->x_lame);
+#else
lame_close( x->lgfp );
+#endif
x->x_lame = -1;
#ifndef UNIX
closesocket(x->x_fd);
@@ -219,65 +266,65 @@ static t_int *mp3cast_perform(t_int *w) /* copy the data into the buffer */
i = MY_MP3_MALLOC_IN_SIZE - x->x_inp; /* space left at the end of buffer */
- n *= 2; /* two channels go into one buffer */
+ n *= 2; /* two channels go into one buffer */
if( n <= i )
{
- /* the place between inp and MY_MP3_MALLOC_IN_SIZE */
- /* is big enough to hold the data */
-
- for(wp = 0; wp < n; wp++)
- {
- if(wp%2)
- {
- in = *(in2++); /* right channel / inlet */
- }
- else
- {
- in = *(in1++); /* left channel / inlet */
- }
- if (in > 1.0) { in = 1.0; }
- if (in < -1.0) { in = -1.0; }
- x->x_buffer[wp + x->x_inp] = (short) (32767.0 * in);
- }
- x->x_inp += n; /* n more samples written to buffer */
+ /* the place between inp and MY_MP3_MALLOC_IN_SIZE */
+ /* is big enough to hold the data */
+
+ for(wp = 0; wp < n; wp++)
+ {
+ if(wp%2)
+ {
+ in = *(in2++); /* right channel / inlet */
+ }
+ else
+ {
+ in = *(in1++); /* left channel / inlet */
+ }
+ if (in > 1.0) { in = 1.0; }
+ if (in < -1.0) { in = -1.0; }
+ x->x_buffer[wp + x->x_inp] = (short) (32767.0 * in);
+ }
+ x->x_inp += n; /* n more samples written to buffer */
}
else
{
- /* the place between inp and MY_MP3_MALLOC_IN_SIZE is not */
- /* big enough to hold the data */
- /* writing will take place in two turns, one from */
- /* x->x_inp -> MY_MP3_MALLOC_IN_SIZE, then from 0 on */
-
- for(wp = 0; wp < i; wp++) /* fill up to end of buffer */
- {
- if(wp%2)
- {
- in = *(in2++);
- }
- else
- {
- in = *(in1++);
- }
- if (in > 1.0) { in = 1.0; }
- if (in < -1.0) { in = -1.0; }
- x->x_buffer[wp + x->x_inp] = (short) (32767.0 * in);
- }
- for(wp = i; wp < n; wp++) /* write rest at start of buffer */
- {
- if(wp%2)
- {
- in = *(in2++);
- }
- else
- {
- in = *(in1++);
- }
- if (in > 1.0) { in = 1.0; }
- if (in < -1.0) { in = -1.0; }
- x->x_buffer[wp - i] = (short) (32767.0 * in);
- }
- x->x_inp = n - i; /* new writeposition in buffer */
+ /* the place between inp and MY_MP3_MALLOC_IN_SIZE is not */
+ /* big enough to hold the data */
+ /* writing will take place in two turns, one from */
+ /* x->x_inp -> MY_MP3_MALLOC_IN_SIZE, then from 0 on */
+
+ for(wp = 0; wp < i; wp++) /* fill up to end of buffer */
+ {
+ if(wp%2)
+ {
+ in = *(in2++);
+ }
+ else
+ {
+ in = *(in1++);
+ }
+ if (in > 1.0) { in = 1.0; }
+ if (in < -1.0) { in = -1.0; }
+ x->x_buffer[wp + x->x_inp] = (short) (32767.0 * in);
+ }
+ for(wp = i; wp < n; wp++) /* write rest at start of buffer */
+ {
+ if(wp%2)
+ {
+ in = *(in2++);
+ }
+ else
+ {
+ in = *(in1++);
+ }
+ if (in > 1.0) { in = 1.0; }
+ if (in < -1.0) { in = -1.0; }
+ x->x_buffer[wp - i] = (short) (32767.0 * in);
+ }
+ x->x_inp = n - i; /* new writeposition in buffer */
}
if((x->x_fd >= 0)&&(x->x_lame >= 0))
@@ -308,14 +355,21 @@ static void mp3cast_dsp(t_mp3cast *x, t_signal **sp) /* initialize the lame library */
static void mp3cast_tilde_lame_init(t_mp3cast *x)
{
+#ifndef UNIX
+ /* encoder related stuff (calculating buffer size) */
+ BE_VERSION lameVersion = {0,}; /* version number of LAME */
+ BE_CONFIG lameConfig = {0,}; /* config structure of LAME */
+ unsigned int ret;
+#else
int ret;
x->lgfp = lame_init(); /* set default parameters for now */
+#endif
#ifndef UNIX
/* load lame_enc.dll library */
- HINSTANCE dll;
- dll = LoadLibrary("lame_enc.dll");
- if(!dll)
+
+ dll=LoadLibrary("lame_enc.dll");
+ if(dll==NULL)
{
error("mp3cast~: error loading lame_enc.dll");
closesocket(x->x_fd);
@@ -324,12 +378,75 @@ static void mp3cast_tilde_lame_init(t_mp3cast *x) post("mp3cast~: connection closed");
return;
}
-#endif
+ /* get Interface functions */
+ initStream = (BEINITSTREAM) GetProcAddress(dll, TEXT_BEINITSTREAM);
+ encodeChunk = (BEENCODECHUNK) GetProcAddress(dll, TEXT_BEENCODECHUNK);
+ deinitStream = (BEDEINITSTREAM) GetProcAddress(dll, TEXT_BEDEINITSTREAM);
+ closeStream = (BECLOSESTREAM) GetProcAddress(dll, TEXT_BECLOSESTREAM);
+ dllVersion = (BEVERSION) GetProcAddress(dll, TEXT_BEVERSION);
+ writeVBRHeader = (BEWRITEVBRHEADER) GetProcAddress(dll,TEXT_BEWRITEVBRHEADER);
+
+ /* check if all interfaces are present */
+ if(!initStream || !encodeChunk || !deinitStream || !closeStream || !dllVersion || !writeVBRHeader)
+ {
+
+ error("mp3cast~: unable to get LAME interfaces");
+ closesocket(x->x_fd);
+ x->x_fd = -1;
+ outlet_float(x->x_obj.ob_outlet, 0);
+ post("mp3cast~: connection closed");
+ return;
+ }
+
+ /* get LAME version number */
+ dllVersion(&lameVersion);
+
+ post( "mp3cast~: lame_enc.dll version %u.%02u (%u/%u/%u)\n"
+ " lame_enc engine %u.%02u",
+ lameVersion.byDLLMajorVersion, lameVersion.byDLLMinorVersion,
+ lameVersion.byDay, lameVersion.byMonth, lameVersion.wYear,
+ lameVersion.byMajorVersion, lameVersion.byMinorVersion);
+
+ memset(&lameConfig,0,sizeof(lameConfig)); /* clear all fields */
+#else
{
const char *lameVersion = get_lame_version();
post( "mp3cast~ : using lame version : %s", lameVersion );
}
+#endif
+
+#ifndef UNIX
+
+ /* use the LAME config structure */
+ lameConfig.dwConfig = BE_CONFIG_LAME;
+
+ /* set the mpeg format flags */
+ lameConfig.format.LHV1.dwStructVersion = 1;
+ lameConfig.format.LHV1.dwStructSize = sizeof(lameConfig);
+ lameConfig.format.LHV1.dwSampleRate = (int)sys_getsr(); /* input frequency - pd's sample rate */
+ lameConfig.format.LHV1.dwReSampleRate = x->x_samplerate; /* output s/r - resample if necessary */
+ lameConfig.format.LHV1.nMode = x->x_mp3mode; /* output mode */
+ lameConfig.format.LHV1.dwBitrate = x->x_bitrate; /* mp3 bitrate */
+ lameConfig.format.LHV1.nPreset = x->x_mp3quality; /* mp3 encoding quality */
+ lameConfig.format.LHV1.dwMpegVersion = MPEG1; /* use MPEG1 */
+ lameConfig.format.LHV1.dwPsyModel = 0; /* USE DEFAULT PSYCHOACOUSTIC MODEL */
+ lameConfig.format.LHV1.dwEmphasis = 0; /* NO EMPHASIS TURNED ON */
+ lameConfig.format.LHV1.bOriginal = TRUE; /* SET ORIGINAL FLAG */
+ lameConfig.format.LHV1.bCopyright = TRUE; /* SET COPYRIGHT FLAG */
+ lameConfig.format.LHV1.bNoRes = TRUE; /* no bit resorvoir */
+
+ /* init the MP3 stream */
+ ret = initStream(&lameConfig, &x->x_lamechunk, &x->x_mp3size, &x->x_lame);
+
+ /* check result */
+ if(ret != BE_ERR_SUCCESSFUL)
+ {
+ post("mp3cast~: error opening encoding stream (%lu)", ret);
+ return;
+ }
+
+#else
/* setting lame parameters */
lame_set_num_channels( x->lgfp, 2);
lame_set_in_samplerate( x->lgfp, sys_getsr() );
@@ -353,9 +470,46 @@ static void mp3cast_tilde_lame_init(t_mp3cast *x) post( "mp3cast~ : lame initialization done. (%d)", x->x_lame );
}
lame_init_bitstream( x->lgfp );
+#endif
+
+
+}
+
+char *mp3cast_base64_encode(char *data)
+{
+ int len = strlen(data);
+ char *out = t_getbytes(len*4/3 + 4);
+ char *result = out;
+ int chunk;
+
+ while(len > 0) {
+ chunk = (len >3)?3:len;
+ *out++ = base64table[(*data & 0xFC)>>2];
+ *out++ = base64table[((*data & 0x03)<<4) | ((*(data+1) & 0xF0) >> 4)];
+
+ switch(chunk) {
+ case 3:
+ *out++ = base64table[((*(data+1) & 0x0F)<<2) | ((*(data+2) & 0xC0)>>6)];
+ *out++ = base64table[(*(data+2)) & 0x3F];
+ break;
+ case 2:
+ *out++ = base64table[((*(data+1) & 0x0F)<<2)];
+ *out++ = '=';
+ break;
+ case 1:
+ *out++ = '=';
+ *out++ = '=';
+ break;
+ }
+ data += chunk;
+ len -= chunk;
+ }
+ *out = 0;
+
+ return result;
}
- /* connect to SHOUTcast server */
+ /* connect to server */
static void mp3cast_connect(t_mp3cast *x, t_symbol *hostname, t_floatarg fportno)
{
struct sockaddr_in server;
@@ -364,13 +518,14 @@ static void mp3cast_connect(t_mp3cast *x, t_symbol *hostname, t_floatarg fportno /* information about this broadcast to be send to the server */
const char *name = x->x_name; /* name of broadcast */
- const char *url = "http://guess.where.i.am"; /* url of broadcast */
- const char *genre = "abstract break"; /* genre of broadcast */
+ const char *url = x->x_url; /* url of broadcast */
+ const char *genre = x->x_genre; /* genre of broadcast */
+ const char *description = x->x_description; /* description of broadcast */
const char *aim = "N/A"; /* aim of broadcast */
const char *irc = "#mp3cast"; /* ??? what's this ??? */
const char *icq = ""; /* icq id of broadcaster */
const char *mountpoint = x->x_mountpoint; /* mountpoint for IceCast server */
- int isPublic = 0; /* don't publish broadcast on www.shoutcast.com */
+ int isPublic = x->x_isPublic; /* don't publish broadcast on www.shoutcast.com */
/* variables used for communication with server */
const char * buf = 0;
@@ -379,9 +534,14 @@ static void mp3cast_connect(t_mp3cast *x, t_symbol *hostname, t_floatarg fportno fd_set fdset;
struct timeval tv;
int sockfd;
+
+#ifndef UNIX
+ unsigned int ret;
+#else
int ret;
+#endif
- if(x->x_icecast == 0)portno++; /* use SHOUTcast, portno is one higher */
+ if(x->x_icecast == 0)portno++; /* use SHOUTcast, portno is one higher */
if (x->x_fd >= 0)
{
@@ -434,7 +594,6 @@ static void mp3cast_connect(t_mp3cast *x, t_symbol *hostname, t_floatarg fportno tv.tv_usec = 500; /* microseconds */
ret = select(sockfd + 1, &fdset, NULL, NULL, &tv);
-
if(ret < 0)
{
error("mp3cast~: can not read from socket");
@@ -445,134 +604,216 @@ static void mp3cast_connect(t_mp3cast *x, t_symbol *hostname, t_floatarg fportno #endif
return;
}
-#ifndef NT
ret = select(sockfd + 1, NULL, &fdset, NULL, &tv);
if(ret < 0)
{
error("mp3cast~: can not write to socket");
+#ifndef UNIX
+ closesocket(sockfd);
+#else
close(sockfd);
+#endif
return;
}
-#endif
- if(x->x_icecast == 0) /* SHOUTCAST */
- {
- /* now try to log in at SHOUTcast server */
- post("mp3cast~: logging in to SHOUTcast server...");
-
- /* first line is the passwd */
- buf = x->x_passwd;
- send(sockfd, buf, strlen(buf), 0);
- buf = "\n";
- send(sockfd, buf, strlen(buf), 0);
-
- /* header for SHOUTcast server */
- buf = "icy-name:"; /* name of broadcast */
- send(sockfd, buf, strlen(buf), 0);
- buf = name;
- send(sockfd, buf, strlen(buf), 0);
- buf = "\nicy-url:"; /* URL of broadcast */
- send(sockfd, buf, strlen(buf), 0);
- buf = url;
- send(sockfd, buf, strlen(buf), 0);
- buf = "\nicy-genre:"; /* genre of broadcast */
- send(sockfd, buf, strlen(buf), 0);
- buf = genre;
- send(sockfd, buf, strlen(buf), 0);
- buf = "\nicy-irc:";
- send(sockfd, buf, strlen(buf), 0);
- buf = irc;
- send(sockfd, buf, strlen(buf), 0);
- buf = "\nicy-aim:";
- send(sockfd, buf, strlen(buf), 0);
- buf = aim;
- send(sockfd, buf, strlen(buf), 0);
- buf = "\nicy-icq:";
- send(sockfd, buf, strlen(buf), 0);
- buf = icq;
- send(sockfd, buf, strlen(buf), 0);
- buf = "\nicy-br:";
- send(sockfd, buf, strlen(buf), 0);
- if(sprintf(resp, "%d", x->x_bitrate) == -1) /* convert int to a string */
- {
- error("mp3cast~: wrong bitrate");
- }
- send(sockfd, resp, strlen(resp), 0);
- buf = "\nicy-pub:";
- send(sockfd, buf, strlen(buf), 0);
- if(isPublic==0) /* set the public flag for broadcast */
- {
- buf = "no";
- }
- else
- {
- buf ="yes";
- }
- send(sockfd, buf, strlen(buf), 0);
- buf = "\n\n";
- send(sockfd, buf, strlen(buf), 0);
- }
- else /* IceCast */
- {
- /* now try to log in at IceCast server */
- post("mp3cast~: logging in to IceCast server...");
-
- /* send the request, a string like:
- * "SOURCE <password> /<mountpoint>\n" */
- buf = "SOURCE ";
- send(sockfd, buf, strlen(buf), 0);
- buf = x->x_passwd;
- send(sockfd, buf, strlen(buf), 0);
- buf = " /";
- send(sockfd, buf, strlen(buf), 0);
- buf = mountpoint;
- send(sockfd, buf, strlen(buf), 0);
-
- /* send the x-audiocast headers */
- buf = "\nx-audiocast-bitrate: ";
- send(sockfd, buf, strlen(buf), 0);
- if(sprintf(resp, "%d", x->x_bitrate) == -1) /* convert int to a string */
- {
- error("mp3cast~: wrong bitrate");
- }
- send(sockfd, resp, strlen(resp), 0);
-
- buf = "\nx-audiocast-public: ";
- send(sockfd, buf, strlen(buf), 0);
- if(isPublic==0) /* set the public flag for broadcast */
- {
- buf = "no";
- }
- else
- {
- buf ="yes";
- }
- send(sockfd, buf, strlen(buf), 0);
-
- buf = "\nx-audiocast-name: ";
- send(sockfd, buf, strlen(buf), 0);
- buf = name;
- send(sockfd, buf, strlen(buf), 0);
-
- buf = "\nx-audiocast-url: ";
- send(sockfd, buf, strlen(buf), 0);
- buf = url;
- send(sockfd, buf, strlen(buf), 0);
-
- buf = "\nx-audiocast-genre: ";
- send(sockfd, buf, strlen(buf), 0);
- buf = genre;
- send(sockfd, buf, strlen(buf), 0);
-
- buf = "\n\n";
- send(sockfd, buf, strlen(buf), 0);
- /* end login for IceCast */
- }
+
+ if(x->x_icecast == 0) /* SHOUTCAST */
+ {
+ /* now try to log in at SHOUTcast server */
+ post("mp3cast~: logging in to SHOUTcast server...");
+
+ /* first line is the passwd */
+ buf = x->x_passwd;
+ send(sockfd, buf, strlen(buf), 0);
+ buf = "\n";
+ send(sockfd, buf, strlen(buf), 0);
+
+ /* header for SHOUTcast server */
+ buf = "icy-name:"; /* name of broadcast */
+ send(sockfd, buf, strlen(buf), 0);
+ buf = name;
+ send(sockfd, buf, strlen(buf), 0);
+ buf = "\nicy-url:"; /* URL of broadcast */
+ send(sockfd, buf, strlen(buf), 0);
+ buf = url;
+ send(sockfd, buf, strlen(buf), 0);
+
+ buf = "\nicy-genre:"; /* genre of broadcast */
+ send(sockfd, buf, strlen(buf), 0);
+ buf = genre;
+ send(sockfd, buf, strlen(buf), 0);
+
+ buf = "\nicy-description:"; /* description of broadcast */
+ send(sockfd, buf, strlen(buf), 0);
+ buf = description;
+ send(sockfd, buf, strlen(buf), 0);
+
+ buf = "\nicy-irc:";
+ send(sockfd, buf, strlen(buf), 0);
+ buf = irc;
+ send(sockfd, buf, strlen(buf), 0);
+ buf = "\nicy-aim:";
+ send(sockfd, buf, strlen(buf), 0);
+ buf = aim;
+ send(sockfd, buf, strlen(buf), 0);
+ buf = "\nicy-icq:";
+ send(sockfd, buf, strlen(buf), 0);
+ buf = icq;
+ send(sockfd, buf, strlen(buf), 0);
+ buf = "\nicy-br:";
+ send(sockfd, buf, strlen(buf), 0);
+ if(sprintf(resp, "%d", x->x_bitrate) == -1) /* convert int to a string */
+ {
+ error("mp3cast~: wrong bitrate");
+ }
+ send(sockfd, resp, strlen(resp), 0);
+ buf = "\nicy-pub:";
+ send(sockfd, buf, strlen(buf), 0);
+ if(isPublic==0) /* set the public flag for broadcast */
+ {
+ buf = "no";
+ }
+ else
+ {
+ buf ="yes";
+ }
+ send(sockfd, buf, strlen(buf), 0);
+ buf = "\n\n";
+ send(sockfd, buf, strlen(buf), 0);
+ }
+ else if ( x->x_icecast == 1 ) /* IceCast */
+ {
+ /* now try to log in at IceCast server */
+ post("mp3cast~: logging in to IceCast server...");
+
+ /* send the request, a string like:
+ * "SOURCE <password> /<mountpoint>\n" */
+ buf = "SOURCE ";
+ send(sockfd, buf, strlen(buf), 0);
+ buf = x->x_passwd;
+ send(sockfd, buf, strlen(buf), 0);
+ buf = " /";
+ send(sockfd, buf, strlen(buf), 0);
+ buf = mountpoint;
+ send(sockfd, buf, strlen(buf), 0);
+
+ /* send the x-audiocast headers */
+ buf = "\nx-audiocast-bitrate: ";
+ send(sockfd, buf, strlen(buf), 0);
+ if(sprintf(resp, "%d", x->x_bitrate) == -1) /* convert int to a string */
+ {
+ error("mp3cast~: wrong bitrate");
+ }
+ send(sockfd, resp, strlen(resp), 0);
+
+ buf = "\nx-audiocast-public: ";
+ send(sockfd, buf, strlen(buf), 0);
+ if(isPublic==0) /* set the public flag for broadcast */
+ {
+ buf = "no";
+ }
+ else
+ {
+ buf ="yes";
+ }
+ send(sockfd, buf, strlen(buf), 0);
+
+ buf = "\nx-audiocast-name: ";
+ send(sockfd, buf, strlen(buf), 0);
+ buf = name;
+ send(sockfd, buf, strlen(buf), 0);
+
+ buf = "\nx-audiocast-url: ";
+ send(sockfd, buf, strlen(buf), 0);
+ buf = url;
+ send(sockfd, buf, strlen(buf), 0);
+
+ buf = "\nx-audiocast-genre: ";
+ send(sockfd, buf, strlen(buf), 0);
+ buf = genre;
+ send(sockfd, buf, strlen(buf), 0);
+
+ buf = "\nx-audiocast-description: ";
+ send(sockfd, buf, strlen(buf), 0);
+ buf = description;
+ send(sockfd, buf, strlen(buf), 0);
+
+ buf = "\n\n";
+ send(sockfd, buf, strlen(buf), 0);
+ /* end login for IceCast */
+ }
+ else if ( x->x_icecast == 2 ) /* Icecast 2 */
+ {
+ char *base64; /* buffer to hold 64bit encoded strings */
+ /* send the request, a string like: "SOURCE /<mountpoint> HTTP/1.0\r\n" */
+ buf = "SOURCE /";
+ send(sockfd, buf, strlen(buf), 0);
+ buf = x->x_mountpoint;
+ send(sockfd, buf, strlen(buf), 0);
+ buf = " HTTP/1.0\r\n";
+ send(sockfd, buf, strlen(buf), 0);
+ /* send basic authorization as base64 encoded string */
+ sprintf(resp, "source:%s", x->x_passwd);
+ len = strlen(resp);
+ base64 = mp3cast_base64_encode(resp);
+ sprintf(resp, "Authorization: Basic %s\r\n", base64);
+ send(sockfd, resp, strlen(resp), 0);
+ t_freebytes(base64, len*4/3 + 4);
+ /* send application name */
+ buf = "User-Agent: mp3cast~";
+ send(sockfd, buf, strlen(buf), 0);
+ /* send content type: mpeg */
+ buf = "\r\nContent-Type: audio/mpeg";
+ send(sockfd, buf, strlen(buf), 0);
+ /* send the ice headers */
+ /* name */
+ buf = "\r\nice-name: ";
+ send(sockfd, buf, strlen(buf), 0);
+ buf = x->x_name;
+ send(sockfd, buf, strlen(buf), 0);
+ /* url */
+ buf = "\r\nice-url: ";
+ send(sockfd, buf, strlen(buf), 0);
+ buf = x->x_url;
+ send(sockfd, buf, strlen(buf), 0);
+ /* genre */
+ buf = "\r\nice-genre: ";
+ send(sockfd, buf, strlen(buf), 0);
+ buf = genre;
+ send(sockfd, buf, strlen(buf), 0);
+ /* public */
+ buf = "\r\nice-public: ";
+ send(sockfd, buf, strlen(buf), 0);
+ if(isPublic==0)
+ {
+ buf = "0";
+ }
+ else
+ {
+ buf = "1";
+ }
+ send(sockfd, buf, strlen(buf), 0);
+ /* bitrate */
+ if(sprintf(resp, "\r\nice-audio-info: bitrate=%d", x->x_bitrate) == -1)
+ {
+ error("shoutcast~: could not create audio-info");
+ }
+ send(sockfd, resp, strlen(resp), 0);
+ /* description */
+ buf = "\r\nice-description: ";
+ send(sockfd, buf, strlen(buf), 0);
+ buf = description;
+ send(sockfd, buf, strlen(buf), 0);
+ /* end of header: write an empty line */
+ buf = "\r\n\r\n";
+ send(sockfd, buf, strlen(buf), 0);
+ }
/* read the anticipated response: "OK" */
len = recv(sockfd, resp, STRBUF_SIZE, 0);
- if ( len < 2 || resp[0] != 'O' || resp[1] != 'K' )
+ if ( strstr( resp, "OK" ) == NULL )
{
post("mp3cast~: login failed!");
+ if ( len>0 ) post("mp3cast~: server answered : %s", resp);
#ifndef UNIX
closesocket(sockfd);
#else
@@ -580,11 +821,11 @@ static void mp3cast_connect(t_mp3cast *x, t_symbol *hostname, t_floatarg fportno #endif
return;
}
-
+
/* suck anything that the other side has to say */
// while (len = recv(sockfd, resp, STRBUF_SIZE,0))
// {
- ; /* do nothing, just wait ! */
+ // post("mp3cast~: server answered : %s", resp);
// }
x->x_fd = sockfd;
@@ -601,12 +842,23 @@ static void mp3cast_disconnect(t_mp3cast *x) int err = -1;
if(x->x_lame >= 0)
{
+#ifndef UNIX
+ /* deinit the stream */
+ err = deinitStream(x->x_lame, x->x_mp3outbuf, &x->x_mp3size);
+
+ /* check result */
+ if(err != BE_ERR_SUCCESSFUL)
+ {
+ error("exiting mp3 stream failed (%lu)", err);
+ }
+ closeStream(x->x_lame); /* close mp3 encoder stream */
+#else
/* ignore remaining bytes */
if ( x->x_mp3size = lame_encode_flush( x->lgfp, x->x_mp3outbuf, 0) < 0 ) {
post( "mp3cast~ : warning : remaining encoded bytes" );
}
lame_close( x->lgfp );
-
+#endif
x->x_lame = -1;
post("mp3cast~: encoder stream closed");
}
@@ -673,54 +925,108 @@ static void mp3cast_print(t_mp3cast *x) }
post(" mode: %s\n"
" quality: %d", buf, x->x_mp3quality);
+#ifndef UNIX
+ if(x->x_lamechunk!=0)post(" calculated mp3 chunk size: %d", x->x_lamechunk);
+#else
post(" mp3 chunk size: %d", x->x_lamechunk);
+#endif
if(x->x_samplerate!=sys_getsr())
{
post(" resampling from %d to %d Hz!", (int)sys_getsr(), x->x_samplerate);
}
- if(x->x_icecast == 0)
- {
- post(" server type is SHOUTcast");
- }
- else
- {
- post(" server type is IceCast");
- }
+
+ if ( x->x_icecast == 0)
+ {
+ post(" server type is SHOUTcast");
+ }
+ else if ( x->x_icecast == 1 )
+ {
+ post(" server type is IceCast");
+ }
+ else if ( x->x_icecast == 2 )
+ {
+ post(" server type is IceCast 2");
+ }
}
- /* we use iceCast server */
static void mp3cast_icecast(t_mp3cast *x)
{
- x->x_icecast = 1;
- post("mp3cast~: set server type to IceCast");
+ x->x_icecast = 1;
+ post("mp3cast~: set server type to IceCast");
+}
+
+static void mp3cast_icecast2(t_mp3cast *x)
+{
+ x->x_icecast = 2;
+ post("mp3cast~: set server type to IceCast 2");
}
- /* we use SHOUTcast server (default) */
static void mp3cast_shoutcast(t_mp3cast *x)
{
- x->x_icecast = 0;
- post("mp3cast~: set server type to SHOUTcast");
+ x->x_icecast = 0;
+ post("mp3cast~: set server type to SHOUTcast");
}
- /* set mountpoint for IceCast server */
+ /* set mountpoint for IceCast server */
static void mp3cast_mountpoint(t_mp3cast *x, t_symbol *mount)
{
- x->x_mountpoint = mount->s_name;
- post("mp3cast~: mountpoint set to %s", x->x_mountpoint);
+ x->x_mountpoint = mount->s_name;
+ post("mp3cast~: mountpoint set to %s", x->x_mountpoint);
}
- /* set namle for IceCast server */
+ /* set namle for IceCast server */
static void mp3cast_name(t_mp3cast *x, t_symbol *name)
{
- x->x_name = name->s_name;
- post("mp3cast~: name set to %s", x->x_name);
+ x->x_name = name->s_name;
+ post("mp3cast~: name set to %s", x->x_name);
}
- /* clean up */
+ /* set url for IceCast server */
+static void mp3cast_url(t_mp3cast *x, t_symbol *url)
+{
+ x->x_url = url->s_name;
+ post("mp3cast~: url set to %s", x->x_url);
+}
+
+ /* set genre for IceCast server */
+static void mp3cast_genre(t_mp3cast *x, t_symbol *genre)
+{
+ x->x_genre = genre->s_name;
+ post("mp3cast~: genre set to %s", x->x_genre);
+}
+
+ /* set isPublic for IceCast server */
+static void mp3cast_isPublic(t_mp3cast *x, t_floatarg isPublic)
+{
+ x->x_isPublic = isPublic;
+ char* isPublicStr;
+ if(isPublic==0)
+ {
+ isPublicStr = "no";
+ }
+ else
+ {
+ isPublicStr = "yes";
+ }
+ post("mp3cast~: isPublic set to %s", isPublicStr);
+}
+
+ /* set description for IceCast server */
+static void mp3cast_description(t_mp3cast *x, t_symbol *description)
+{
+ x->x_description = description->s_name;
+ post("mp3cast~: description set to %s", x->x_description);
+}
+
+ /* clean up */
static void mp3cast_free(t_mp3cast *x)
{
if(x->x_lame >= 0)
- lame_close( x->lgfp );
+#ifndef UNIX
+ closeStream(x->x_lame);
+#else
+ lame_close( x->lgfp );
+#endif
if(x->x_fd >= 0)
#ifndef UNIX
closesocket(x->x_fd);
@@ -756,9 +1062,13 @@ static void *mp3cast_new(void) x->x_outp = 0;
x->lgfp = NULL;
x->x_start = -1;
- x->x_icecast = 0;
+ x->x_icecast = 1;
x->x_mountpoint = "puredata";
x->x_name = "puredata";
+ x->x_url = "http://puredata.info";
+ x->x_genre = "experimental sound";
+ x->x_isPublic = 1;
+ x->x_description = "playing with my patches";
return(x);
}
@@ -775,8 +1085,13 @@ void mp3cast_tilde_setup(void) class_addmethod(mp3cast_class, (t_method)mp3cast_mpeg, gensym("mpeg"), A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
class_addmethod(mp3cast_class, (t_method)mp3cast_print, gensym("print"), 0);
class_addmethod(mp3cast_class, (t_method)mp3cast_icecast, gensym("icecast"), 0);
+ class_addmethod(mp3cast_class, (t_method)mp3cast_icecast2, gensym("icecast2"), 0);
class_addmethod(mp3cast_class, (t_method)mp3cast_shoutcast, gensym("shoutcast"), 0);
class_addmethod(mp3cast_class, (t_method)mp3cast_mountpoint, gensym("mountpoint"), A_SYMBOL, 0);
class_addmethod(mp3cast_class, (t_method)mp3cast_name, gensym("name"), A_SYMBOL, 0);
+ class_addmethod(mp3cast_class, (t_method)mp3cast_url, gensym("url"), A_SYMBOL, 0);
+ class_addmethod(mp3cast_class, (t_method)mp3cast_genre, gensym("genre"), A_SYMBOL, 0);
+ class_addmethod(mp3cast_class, (t_method)mp3cast_isPublic, gensym("isPublic"), A_FLOAT, 0);
+ class_addmethod(mp3cast_class, (t_method)mp3cast_description, gensym("description"), A_SYMBOL, 0);
}
|