diff options
Diffstat (limited to 'oggcast~')
-rw-r--r-- | oggcast~/HISTORY | 151 | ||||
-rw-r--r-- | oggcast~/codec.h | 466 | ||||
-rw-r--r-- | oggcast~/help-oggcast~.pd | 130 | ||||
-rw-r--r-- | oggcast~/oggcast~.c | 2879 | ||||
-rw-r--r-- | oggcast~/readme | 230 | ||||
-rw-r--r-- | oggcast~/vorbisenc.h | 186 |
6 files changed, 2032 insertions, 2010 deletions
diff --git a/oggcast~/HISTORY b/oggcast~/HISTORY index cc7c6f5..04a7528 100644 --- a/oggcast~/HISTORY +++ b/oggcast~/HISTORY @@ -1,70 +1,83 @@ -Version history of oggcast~ external for pure-data - -v 0.2h (27th March 2003): -- added HTTP base auth login for (alpha) Icecast2 server: - message 'server 1' switches to Icecast2, 'server 0' back - top JRoar and PeerCast compatibility (which is the default) - -v 0.2g (3rd August 2002): -- finally fixed the bug that made oggcast~ crash after a - while. seems to be realted with output from child thread - using t_clocks but couldn't proove that - -v 0.2f (20st july 2002): -- recompiled with the final 1.0 release of Ogg Vorbis -- changed the URL to the new akustische-kunst.org domain - -v 0.2e (5th july 2002): -- added simple downsampling to stream at lower sample rates - -v 0.2d (21st june 2002 - stable release!): -- cleaned up code a bit -- now clean disconnect in case server dies or closes - socket - -v 0.2c (13th june 2002): -- fixed some small bugs -- buffer size now in kbytes per channel -- some more info-printout - -v 0.2b (12th june 2002): -- completetly rewritten multithreaded version, first - sort-of-stable release -- KNOWN BUG: eats too much CPU power - -v 0.1g (23rd feb. 2002, not for public use!): -- added multithreading functionality: now sending data - to server in a second thread -- now included the static ogg vorbis libraries - no dll's - needed under win any longer -- fixed a bug that sometimes made pd crash - -v 0.1f (11th feb. 2002): -- converted ringbuffer to simple buffer of fixed size - -v 0.1e (10th feb. 2002): -- now really fixed the bug that made pd die when server - disconnected - -v 0.1d (9th feb. 2002): -- fixed a bug in the "vorbis" setting that made on-the-run - changes impossible -- introduced a function to check writeability of the socket -- fixed the bug that crashed pd due to an access violation - in vorbis.dll when send() returned an error (more of a - fast workaround) -- corrected bitrate setting, now it really is _k_bps - - -v 0.1c (9th feb. 2002): -- added support for setting / changing the comment tags in - the ogg/vorbis header, spaces have to be replaced by '=' -- fixed a bug in oggcast_stream() that made Pd crash - now - it's vorbis.dll that makes Pd crash... ;-( - -v 0.1b (not released): -- added support for changing encoder settings when stream - is running (no need to disconnect), seems to be unstable - on linux (with JRoar) - +Version history of oggcast~ external for pure-data
+
+v 0.2k (29th Sept. 2003):
+- fixed a bug in multichannel support
+- fixed a memory leak in Icecast2 login
+
+v 0.2i (13th September 2003):
+- updated login scheme to work with latest Icecast2 server
+ from CVS (tested on Windows and Debian Linux)
+- changed handling of comment tags: it's no longer necessarry
+ to replace spaces with underscores! Just use spaces for spaces.
+- fixed (no: avoided!) the bug that deleted underscores from
+ the Pd patch
+- made Icecast2 login the default scheme
+
+v 0.2h (27th March 2003):
+- added HTTP base auth login for (alpha) Icecast2 server:
+ message 'server 1' switches to Icecast2, 'server 0' back
+ top JRoar and PeerCast compatibility (which is the default)
+
+v 0.2g (3rd August 2002):
+- finally fixed the bug that made oggcast~ crash after a
+ while. seems to be realted with output from child thread
+ using t_clocks but couldn't proove that
+
+v 0.2f (20st july 2002):
+- recompiled with the final 1.0 release of Ogg Vorbis
+- changed the URL to the new akustische-kunst.org domain
+
+v 0.2e (5th july 2002):
+- added simple downsampling to stream at lower sample rates
+
+v 0.2d (21st june 2002 - stable release!):
+- cleaned up code a bit
+- now clean disconnect in case server dies or closes
+ socket
+
+v 0.2c (13th june 2002):
+- fixed some small bugs
+- buffer size now in kbytes per channel
+- some more info-printout
+
+v 0.2b (12th june 2002):
+- completetly rewritten multithreaded version, first
+ sort-of-stable release
+- KNOWN BUG: eats too much CPU power
+
+v 0.1g (23rd feb. 2002, not for public use!):
+- added multithreading functionality: now sending data
+ to server in a second thread
+- now included the static ogg vorbis libraries - no dll's
+ needed under win any longer
+- fixed a bug that sometimes made pd crash
+
+v 0.1f (11th feb. 2002):
+- converted ringbuffer to simple buffer of fixed size
+
+v 0.1e (10th feb. 2002):
+- now really fixed the bug that made pd die when server
+ disconnected
+
+v 0.1d (9th feb. 2002):
+- fixed a bug in the "vorbis" setting that made on-the-run
+ changes impossible
+- introduced a function to check writeability of the socket
+- fixed the bug that crashed pd due to an access violation
+ in vorbis.dll when send() returned an error (more of a
+ fast workaround)
+- corrected bitrate setting, now it really is _k_bps
+
+
+v 0.1c (9th feb. 2002):
+- added support for setting / changing the comment tags in
+ the ogg/vorbis header, spaces have to be replaced by '='
+- fixed a bug in oggcast_stream() that made Pd crash - now
+ it's vorbis.dll that makes Pd crash... ;-(
+
+v 0.1b (not released):
+- added support for changing encoder settings when stream
+ is running (no need to disconnect), seems to be unstable
+ on linux (with JRoar)
+
v 0.1: first public release
\ No newline at end of file diff --git a/oggcast~/codec.h b/oggcast~/codec.h index d986a9b..964a067 100644 --- a/oggcast~/codec.h +++ b/oggcast~/codec.h @@ -1,233 +1,233 @@ -/******************************************************************** - * * - * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * - * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * - * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * - * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * - * * - * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2001 * - * by the XIPHOPHORUS Company http://www.xiph.org/ * - - ******************************************************************** - - function: libvorbis codec headers - last mod: $Id: codec.h,v 1.2 2003-04-23 10:36:25 xovo Exp $ - - ********************************************************************/ - -#ifndef _vorbis_codec_h_ -#define _vorbis_codec_h_ - -#ifdef __cplusplus -extern "C" -{ -#endif /* __cplusplus */ - -#include <ogg/ogg.h> - -typedef struct vorbis_info{ - int version; - int channels; - long rate; - - /* The below bitrate declarations are *hints*. - Combinations of the three values carry the following implications: - - all three set to the same value: - implies a fixed rate bitstream - only nominal set: - implies a VBR stream that averages the nominal bitrate. No hard - upper/lower limit - upper and or lower set: - implies a VBR bitstream that obeys the bitrate limits. nominal - may also be set to give a nominal rate. - none set: - the coder does not care to speculate. - */ - - long bitrate_upper; - long bitrate_nominal; - long bitrate_lower; - long bitrate_window; - - void *codec_setup; -} vorbis_info; - -/* vorbis_dsp_state buffers the current vorbis audio - analysis/synthesis state. The DSP state belongs to a specific - logical bitstream ****************************************************/ -typedef struct vorbis_dsp_state{ - int analysisp; - vorbis_info *vi; - - float **pcm; - float **pcmret; - int pcm_storage; - int pcm_current; - int pcm_returned; - - int preextrapolate; - int eofflag; - - long lW; - long W; - long nW; - long centerW; - - ogg_int64_t granulepos; - ogg_int64_t sequence; - - ogg_int64_t glue_bits; - ogg_int64_t time_bits; - ogg_int64_t floor_bits; - ogg_int64_t res_bits; - - void *backend_state; -} vorbis_dsp_state; - -typedef struct vorbis_block{ - /* necessary stream state for linking to the framing abstraction */ - float **pcm; /* this is a pointer into local storage */ - oggpack_buffer opb; - - long lW; - long W; - long nW; - int pcmend; - int mode; - - int eofflag; - ogg_int64_t granulepos; - ogg_int64_t sequence; - vorbis_dsp_state *vd; /* For read-only access of configuration */ - - /* local storage to avoid remallocing; it's up to the mapping to - structure it */ - void *localstore; - long localtop; - long localalloc; - long totaluse; - struct alloc_chain *reap; - - /* bitmetrics for the frame */ - long glue_bits; - long time_bits; - long floor_bits; - long res_bits; - - void *internal; - -} vorbis_block; - -/* vorbis_block is a single block of data to be processed as part of -the analysis/synthesis stream; it belongs to a specific logical -bitstream, but is independant from other vorbis_blocks belonging to -that logical bitstream. *************************************************/ - -struct alloc_chain{ - void *ptr; - struct alloc_chain *next; -}; - -/* vorbis_info contains all the setup information specific to the - specific compression/decompression mode in progress (eg, - psychoacoustic settings, channel setup, options, codebook - etc). vorbis_info and substructures are in backends.h. -*********************************************************************/ - -/* the comments are not part of vorbis_info so that vorbis_info can be - static storage */ -typedef struct vorbis_comment{ - /* unlimited user comment fields. libvorbis writes 'libvorbis' - whatever vendor is set to in encode */ - char **user_comments; - int *comment_lengths; - int comments; - char *vendor; - -} vorbis_comment; - - -/* libvorbis encodes in two abstraction layers; first we perform DSP - and produce a packet (see docs/analysis.txt). The packet is then - coded into a framed OggSquish bitstream by the second layer (see - docs/framing.txt). Decode is the reverse process; we sync/frame - the bitstream and extract individual packets, then decode the - packet back into PCM audio. - - The extra framing/packetizing is used in streaming formats, such as - files. Over the net (such as with UDP), the framing and - packetization aren't necessary as they're provided by the transport - and the streaming layer is not used */ - -/* Vorbis PRIMITIVES: general ***************************************/ - -extern void vorbis_info_init(vorbis_info *vi); -extern void vorbis_info_clear(vorbis_info *vi); -extern int vorbis_info_blocksize(vorbis_info *vi,int zo); -extern void vorbis_comment_init(vorbis_comment *vc); -extern void vorbis_comment_add(vorbis_comment *vc, char *comment); -extern void vorbis_comment_add_tag(vorbis_comment *vc, - char *tag, char *contents); -extern char *vorbis_comment_query(vorbis_comment *vc, char *tag, int count); -extern int vorbis_comment_query_count(vorbis_comment *vc, char *tag); -extern void vorbis_comment_clear(vorbis_comment *vc); - -extern int vorbis_block_init(vorbis_dsp_state *v, vorbis_block *vb); -extern int vorbis_block_clear(vorbis_block *vb); -extern void vorbis_dsp_clear(vorbis_dsp_state *v); - -/* Vorbis PRIMITIVES: analysis/DSP layer ****************************/ - -extern int vorbis_analysis_init(vorbis_dsp_state *v,vorbis_info *vi); -extern int vorbis_commentheader_out(vorbis_comment *vc, ogg_packet *op); -extern int vorbis_analysis_headerout(vorbis_dsp_state *v, - vorbis_comment *vc, - ogg_packet *op, - ogg_packet *op_comm, - ogg_packet *op_code); -extern float **vorbis_analysis_buffer(vorbis_dsp_state *v,int vals); -extern int vorbis_analysis_wrote(vorbis_dsp_state *v,int vals); -extern int vorbis_analysis_blockout(vorbis_dsp_state *v,vorbis_block *vb); -extern int vorbis_analysis(vorbis_block *vb,ogg_packet *op); - -extern int vorbis_bitrate_addblock(vorbis_block *vb); -extern int vorbis_bitrate_flushpacket(vorbis_dsp_state *vd, - ogg_packet *op); - -/* Vorbis PRIMITIVES: synthesis layer *******************************/ -extern int vorbis_synthesis_headerin(vorbis_info *vi,vorbis_comment *vc, - ogg_packet *op); - -extern int vorbis_synthesis_init(vorbis_dsp_state *v,vorbis_info *vi); -extern int vorbis_synthesis(vorbis_block *vb,ogg_packet *op); -extern int vorbis_synthesis_trackonly(vorbis_block *vb,ogg_packet *op); -extern int vorbis_synthesis_blockin(vorbis_dsp_state *v,vorbis_block *vb); -extern int vorbis_synthesis_pcmout(vorbis_dsp_state *v,float ***pcm); -extern int vorbis_synthesis_read(vorbis_dsp_state *v,int samples); -extern long vorbis_packet_blocksize(vorbis_info *vi,ogg_packet *op); - -/* Vorbis ERRORS and return codes ***********************************/ - -#define OV_FALSE -1 -#define OV_EOF -2 -#define OV_HOLE -3 - -#define OV_EREAD -128 -#define OV_EFAULT -129 -#define OV_EIMPL -130 -#define OV_EINVAL -131 -#define OV_ENOTVORBIS -132 -#define OV_EBADHEADER -133 -#define OV_EVERSION -134 -#define OV_ENOTAUDIO -135 -#define OV_EBADPACKET -136 -#define OV_EBADLINK -137 -#define OV_ENOSEEK -138 - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif - +/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2001 *
+ * by the XIPHOPHORUS Company http://www.xiph.org/ *
+
+ ********************************************************************
+
+ function: libvorbis codec headers
+ last mod: $Id: codec.h,v 1.3 2004-01-04 12:16:07 x75 Exp $
+
+ ********************************************************************/
+
+#ifndef _vorbis_codec_h_
+#define _vorbis_codec_h_
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+#include <ogg/ogg.h>
+
+typedef struct vorbis_info{
+ int version;
+ int channels;
+ long rate;
+
+ /* The below bitrate declarations are *hints*.
+ Combinations of the three values carry the following implications:
+
+ all three set to the same value:
+ implies a fixed rate bitstream
+ only nominal set:
+ implies a VBR stream that averages the nominal bitrate. No hard
+ upper/lower limit
+ upper and or lower set:
+ implies a VBR bitstream that obeys the bitrate limits. nominal
+ may also be set to give a nominal rate.
+ none set:
+ the coder does not care to speculate.
+ */
+
+ long bitrate_upper;
+ long bitrate_nominal;
+ long bitrate_lower;
+ long bitrate_window;
+
+ void *codec_setup;
+} vorbis_info;
+
+/* vorbis_dsp_state buffers the current vorbis audio
+ analysis/synthesis state. The DSP state belongs to a specific
+ logical bitstream ****************************************************/
+typedef struct vorbis_dsp_state{
+ int analysisp;
+ vorbis_info *vi;
+
+ float **pcm;
+ float **pcmret;
+ int pcm_storage;
+ int pcm_current;
+ int pcm_returned;
+
+ int preextrapolate;
+ int eofflag;
+
+ long lW;
+ long W;
+ long nW;
+ long centerW;
+
+ ogg_int64_t granulepos;
+ ogg_int64_t sequence;
+
+ ogg_int64_t glue_bits;
+ ogg_int64_t time_bits;
+ ogg_int64_t floor_bits;
+ ogg_int64_t res_bits;
+
+ void *backend_state;
+} vorbis_dsp_state;
+
+typedef struct vorbis_block{
+ /* necessary stream state for linking to the framing abstraction */
+ float **pcm; /* this is a pointer into local storage */
+ oggpack_buffer opb;
+
+ long lW;
+ long W;
+ long nW;
+ int pcmend;
+ int mode;
+
+ int eofflag;
+ ogg_int64_t granulepos;
+ ogg_int64_t sequence;
+ vorbis_dsp_state *vd; /* For read-only access of configuration */
+
+ /* local storage to avoid remallocing; it's up to the mapping to
+ structure it */
+ void *localstore;
+ long localtop;
+ long localalloc;
+ long totaluse;
+ struct alloc_chain *reap;
+
+ /* bitmetrics for the frame */
+ long glue_bits;
+ long time_bits;
+ long floor_bits;
+ long res_bits;
+
+ void *internal;
+
+} vorbis_block;
+
+/* vorbis_block is a single block of data to be processed as part of
+the analysis/synthesis stream; it belongs to a specific logical
+bitstream, but is independant from other vorbis_blocks belonging to
+that logical bitstream. *************************************************/
+
+struct alloc_chain{
+ void *ptr;
+ struct alloc_chain *next;
+};
+
+/* vorbis_info contains all the setup information specific to the
+ specific compression/decompression mode in progress (eg,
+ psychoacoustic settings, channel setup, options, codebook
+ etc). vorbis_info and substructures are in backends.h.
+*********************************************************************/
+
+/* the comments are not part of vorbis_info so that vorbis_info can be
+ static storage */
+typedef struct vorbis_comment{
+ /* unlimited user comment fields. libvorbis writes 'libvorbis'
+ whatever vendor is set to in encode */
+ char **user_comments;
+ int *comment_lengths;
+ int comments;
+ char *vendor;
+
+} vorbis_comment;
+
+
+/* libvorbis encodes in two abstraction layers; first we perform DSP
+ and produce a packet (see docs/analysis.txt). The packet is then
+ coded into a framed OggSquish bitstream by the second layer (see
+ docs/framing.txt). Decode is the reverse process; we sync/frame
+ the bitstream and extract individual packets, then decode the
+ packet back into PCM audio.
+
+ The extra framing/packetizing is used in streaming formats, such as
+ files. Over the net (such as with UDP), the framing and
+ packetization aren't necessary as they're provided by the transport
+ and the streaming layer is not used */
+
+/* Vorbis PRIMITIVES: general ***************************************/
+
+extern void vorbis_info_init(vorbis_info *vi);
+extern void vorbis_info_clear(vorbis_info *vi);
+extern int vorbis_info_blocksize(vorbis_info *vi,int zo);
+extern void vorbis_comment_init(vorbis_comment *vc);
+extern void vorbis_comment_add(vorbis_comment *vc, char *comment);
+extern void vorbis_comment_add_tag(vorbis_comment *vc,
+ char *tag, char *contents);
+extern char *vorbis_comment_query(vorbis_comment *vc, char *tag, int count);
+extern int vorbis_comment_query_count(vorbis_comment *vc, char *tag);
+extern void vorbis_comment_clear(vorbis_comment *vc);
+
+extern int vorbis_block_init(vorbis_dsp_state *v, vorbis_block *vb);
+extern int vorbis_block_clear(vorbis_block *vb);
+extern void vorbis_dsp_clear(vorbis_dsp_state *v);
+
+/* Vorbis PRIMITIVES: analysis/DSP layer ****************************/
+
+extern int vorbis_analysis_init(vorbis_dsp_state *v,vorbis_info *vi);
+extern int vorbis_commentheader_out(vorbis_comment *vc, ogg_packet *op);
+extern int vorbis_analysis_headerout(vorbis_dsp_state *v,
+ vorbis_comment *vc,
+ ogg_packet *op,
+ ogg_packet *op_comm,
+ ogg_packet *op_code);
+extern float **vorbis_analysis_buffer(vorbis_dsp_state *v,int vals);
+extern int vorbis_analysis_wrote(vorbis_dsp_state *v,int vals);
+extern int vorbis_analysis_blockout(vorbis_dsp_state *v,vorbis_block *vb);
+extern int vorbis_analysis(vorbis_block *vb,ogg_packet *op);
+
+extern int vorbis_bitrate_addblock(vorbis_block *vb);
+extern int vorbis_bitrate_flushpacket(vorbis_dsp_state *vd,
+ ogg_packet *op);
+
+/* Vorbis PRIMITIVES: synthesis layer *******************************/
+extern int vorbis_synthesis_headerin(vorbis_info *vi,vorbis_comment *vc,
+ ogg_packet *op);
+
+extern int vorbis_synthesis_init(vorbis_dsp_state *v,vorbis_info *vi);
+extern int vorbis_synthesis(vorbis_block *vb,ogg_packet *op);
+extern int vorbis_synthesis_trackonly(vorbis_block *vb,ogg_packet *op);
+extern int vorbis_synthesis_blockin(vorbis_dsp_state *v,vorbis_block *vb);
+extern int vorbis_synthesis_pcmout(vorbis_dsp_state *v,float ***pcm);
+extern int vorbis_synthesis_read(vorbis_dsp_state *v,int samples);
+extern long vorbis_packet_blocksize(vorbis_info *vi,ogg_packet *op);
+
+/* Vorbis ERRORS and return codes ***********************************/
+
+#define OV_FALSE -1
+#define OV_EOF -2
+#define OV_HOLE -3
+
+#define OV_EREAD -128
+#define OV_EFAULT -129
+#define OV_EIMPL -130
+#define OV_EINVAL -131
+#define OV_ENOTVORBIS -132
+#define OV_EBADHEADER -133
+#define OV_EVERSION -134
+#define OV_ENOTAUDIO -135
+#define OV_EBADPACKET -136
+#define OV_EBADLINK -137
+#define OV_ENOSEEK -138
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif
+
diff --git a/oggcast~/help-oggcast~.pd b/oggcast~/help-oggcast~.pd index c61a94a..17c0999 100644 --- a/oggcast~/help-oggcast~.pd +++ b/oggcast~/help-oggcast~.pd @@ -1,65 +1,65 @@ -#N canvas 298 121 629 593 10; -#X floatatom 18 36 0 40 16000 0 - - -; -#X msg 468 508 \; pd dsp 1; -#X floatatom 18 524 0 0 0 0 - - -; -#X msg 185 250 disconnect; -#X msg 213 352 print; -#X msg 534 508 \; pd dsp 0; -#X obj 468 482 loadbang; -#X floatatom 97 502 10 0 0 0 - - -; -#X text 131 154 connect <host> <mountpoint> <port>; -#X text 272 45 get latest version at; -#X text 168 502 ogg pages; -#X text 48 527 connection state; -#X text 378 337 channels: 1 or 2 (default); -#X text 210 304 vbr <samplerate> <channels> <quality>; -#X msg 100 57 passwd letmein; -#X obj 18 63 osc~ 440; -#X text 330 326 quality settings: 0 - 1 (low - hi); -#X text 227 412 possible tags: TITLE \, ARTIST \, PERFORMER \, DESCRIPTION -\,; -#X text 316 425 GENRE \, LOCATION \, COPYRIGHT \, CONTACT \, DATE; -#X msg 163 194 connect 141.53.196.149 puredata.ogg 8000; -#X msg 133 172 connect localhost puredata.ogg 8000; -#X msg 170 220 connect 141.53.3.18 musicforfilms.ogg 8100; -#X obj 18 475 oggcast~ 2 512; -#X text 273 34 written by Olaf Matthes <olaf.matthes@gmx.de>; -#X text 252 353 print current settings to console window; -#X text 225 373 comment: <TAG> <content>; -#X msg 225 390 ARTIST your_name; -#X text 228 444 '_' (underline) or '=' (equal sign) will get replaced -with spaces!; -#X text 240 493 default is 2 channels and 512k; -#X text 241 505 bytes buffer size; -#X text 119 475 creation arguments: oggcast~ <channels> <buffer size> -; -#X msg 195 285 vorbis 44100 2 144 128 96; -#X obj 33 110 noise~; -#X text 19 6 oggcast~ 0.2f - send Ogg Vorbis stream to IceCast2 or -JRoar; -#X text 274 59 http://www.akustische-kunst.org/puredata/; -#X text 195 268 vorbis <samplerate> <channels> <max.br> <nom.br> <min.br> -; -#X msg 210 320 vbr 44100 2 0.6; -#X msg 117 95 server 0; -#X msg 129 120 server 1; -#X text 175 94 choose JRoar or old Icecast2 as server type (default) -; -#X text 188 121 choose new Icecast2 (final) as server type; -#X connect 0 0 15 0; -#X connect 3 0 22 0; -#X connect 4 0 22 0; -#X connect 6 0 1 0; -#X connect 14 0 22 0; -#X connect 15 0 22 0; -#X connect 19 0 22 0; -#X connect 20 0 22 0; -#X connect 21 0 22 0; -#X connect 22 0 2 0; -#X connect 22 1 7 0; -#X connect 26 0 22 0; -#X connect 31 0 22 0; -#X connect 32 0 22 1; -#X connect 36 0 22 0; -#X connect 37 0 22 0; -#X connect 38 0 22 0; +#N canvas 298 121 629 593 10;
+#X floatatom 18 36 0 40 16000 0 - - -;
+#X msg 468 508 \; pd dsp 1;
+#X floatatom 18 524 0 0 0 0 - - -;
+#X msg 185 250 disconnect;
+#X msg 213 352 print;
+#X msg 534 508 \; pd dsp 0;
+#X obj 468 482 loadbang;
+#X floatatom 97 502 10 0 0 0 - - -;
+#X text 131 154 connect <host> <mountpoint> <port>;
+#X text 272 45 get latest version at;
+#X text 168 502 ogg pages;
+#X text 48 527 connection state;
+#X text 378 337 channels: 1 or 2 (default);
+#X text 210 304 vbr <samplerate> <channels> <quality>;
+#X msg 100 57 passwd letmein;
+#X obj 18 63 osc~ 440;
+#X text 330 326 quality settings: 0 - 1 (low - hi);
+#X text 227 412 possible tags: TITLE \, ARTIST \, PERFORMER \, DESCRIPTION
+\,;
+#X text 316 425 GENRE \, LOCATION \, COPYRIGHT \, CONTACT \, DATE;
+#X msg 163 194 connect 141.53.196.149 puredata.ogg 8000;
+#X msg 133 172 connect localhost puredata.ogg 8000;
+#X msg 170 220 connect 141.53.3.18 musicforfilms.ogg 8100;
+#X obj 18 475 oggcast~ 2 512;
+#X text 273 34 written by Olaf Matthes <olaf.matthes@gmx.de>;
+#X text 252 353 print current settings to console window;
+#X text 225 373 comment: <TAG> <content>;
+#X msg 225 390 ARTIST your_name;
+#X text 228 444 '_' (underline) or '=' (equal sign) will get replaced
+with spaces!;
+#X text 240 493 default is 2 channels and 512k;
+#X text 241 505 bytes buffer size;
+#X text 119 475 creation arguments: oggcast~ <channels> <buffer size>
+;
+#X msg 195 285 vorbis 44100 2 144 128 96;
+#X obj 33 110 noise~;
+#X text 19 6 oggcast~ 0.2f - send Ogg Vorbis stream to IceCast2 or
+JRoar;
+#X text 274 59 http://www.akustische-kunst.org/puredata/;
+#X text 195 268 vorbis <samplerate> <channels> <max.br> <nom.br> <min.br>
+;
+#X msg 210 320 vbr 44100 2 0.6;
+#X msg 117 95 server 0;
+#X msg 129 120 server 1;
+#X text 175 94 choose JRoar or old Icecast2 as server type (default)
+;
+#X text 188 121 choose new Icecast2 (final) as server type;
+#X connect 0 0 15 0;
+#X connect 3 0 22 0;
+#X connect 4 0 22 0;
+#X connect 6 0 1 0;
+#X connect 14 0 22 0;
+#X connect 15 0 22 0;
+#X connect 19 0 22 0;
+#X connect 20 0 22 0;
+#X connect 21 0 22 0;
+#X connect 22 0 2 0;
+#X connect 22 1 7 0;
+#X connect 26 0 22 0;
+#X connect 31 0 22 0;
+#X connect 32 0 22 1;
+#X connect 36 0 22 0;
+#X connect 37 0 22 0;
+#X connect 38 0 22 0;
diff --git a/oggcast~/oggcast~.c b/oggcast~/oggcast~.c index f27849c..c5dfc5f 100644 --- a/oggcast~/oggcast~.c +++ b/oggcast~/oggcast~.c @@ -1,1435 +1,1444 @@ -/* ------------------------- oggcast~ ----------------------------------------- */ -/* */ -/* Tilde object to send an Ogg Vorbis stream from to IceCast2 server. */ -/* Written by Olaf Matthes (olaf.matthes@gmx.de) */ -/* Get source at http://www.akustische-kunst.org/puredata/pdogg/ */ -/* */ -/* This library is free software; you can redistribute it and/or */ -/* modify it under the terms of the GNU Lesser General Public */ -/* License as published by the Free Software Foundation; either */ -/* version 2 of the License, or (at your option) any later version. */ -/* */ -/* This library is distributed in the hope that it will be useful, */ -/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ -/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU */ -/* Lesser General Public License for more details. */ -/* */ -/* You should have received a copy of the GNU Lesser General Public */ -/* License along with this library; if not, write to the */ -/* Free Software Foundation, Inc., 59 Temple Place - Suite 330, */ -/* Boston, MA 02111-1307, USA. */ -/* */ -/* Based on PureData by Miller Puckette and others. */ -/* Uses the Ogg Vorbis decoding library which can be found at */ -/* http://www.vorbis.com/ */ -/* */ -/* ---------------------------------------------------------------------------- */ - - /* Pd includes */ -#include "m_pd.h" -#include "g_canvas.h" - /* Vorbis includes */ -#include "codec.h" -#include "vorbisenc.h" - -#include <sys/types.h> -#include <string.h> -#include <stdio.h> -#include <errno.h> -#include <fcntl.h> -#include <pthread.h> -#ifdef UNIX -#include <sys/socket.h> -#include <netinet/in.h> -#include <netinet/tcp.h> -#include <arpa/inet.h> -#include <netdb.h> -#include <sys/time.h> -#include <unistd.h> -#define SOCKET_ERROR -1 -#else -#include <io.h> /* for 'write' in pute-function only */ -#include <winsock.h> -#include <winbase.h> -#endif - -#ifdef NT -#pragma warning( disable : 4244 ) -#pragma warning( disable : 4305 ) -#endif - -#ifdef UNIX -#define sys_closesocket close -#endif -#ifdef NT -#define sys_closesocket closesocket -#endif - -/************************* oggcast~ object ******************************/ - -/* Each instance of oggcast~ owns a "child" thread for doing the data -transfer. The parent thread signals the child each time: - (1) a connection wants opening or closing; - (2) we've eaten another 1/16 of the shared buffer (so that the - child thread should check if it's time to receive some more.) -The child signals the parent whenever a receive has completed. Signalling -is done by setting "conditions" and putting data in mutex-controlled common -areas. -*/ - - -#define REQUEST_NOTHING 0 -#define REQUEST_CONNECT 1 -#define REQUEST_CLOSE 2 -#define REQUEST_QUIT 3 -#define REQUEST_BUSY 4 -#define REQUEST_DATA 5 -#define REQUEST_REINIT 6 - -#define STATE_IDLE 0 -#define STATE_STARTUP 1 /* connecting and filling the buffer */ -#define STATE_STREAM 2 /* streaming aund audio output */ - -#define READ 4096 /* amount of data we pass on to encoder */ -#define DEFBUFPERCHAN 262144 /* audio output buffer by default: 256k */ -#define MINBUFSIZE 65536 -#define MAXBUFSIZE 16777216 /* arbitrary; just don't want to hang malloc */ -#define STRBUF_SIZE 1024 /* char received from server on startup */ -#define MAXSTREAMCHANS 2 /* maximum number of channels: restricted to 2 by Ogg specs */ -#define UPDATE_INTERVAL 250 /* time in milliseconds between updates of output values */ - -static char *oggcast_version = "oggcast~: ogg/vorbis streaming client version 0.2i, written by Olaf Matthes"; - -static t_class *oggcast_class; - -typedef struct _oggcast -{ - t_object x_obj; - t_float *x_f; - t_clock *x_clock_connect; - t_clock *x_clock_pages; - t_outlet *x_connection; /* outlet for connection state */ - t_outlet *x_outpages; /* outlet for no. of ogg pages */ - - t_float *x_buf; /* audio data buffer */ - t_int x_bufsize; /* buffer size in bytes */ - t_int x_ninlets; /* number of audio outlets */ - t_sample *(x_outvec[MAXSTREAMCHANS]); /* audio vectors */ - t_int x_vecsize; /* vector size for transfers */ - t_int x_state; /* opened, running, or idle */ - - /* parameters to communicate with subthread */ - t_int x_requestcode; /* pending request from parent to I/O thread */ - t_int x_connecterror; /* slot for "errno" return */ - - /* buffer stuff */ - t_int x_fifosize; /* buffer size appropriately rounded down */ - t_int x_fifohead; /* index of next byte to get from file */ - t_int x_fifotail; /* index of next byte the ugen will read */ - t_int x_sigcountdown; /* counter for signalling child for more data */ - t_int x_sigperiod; /* number of ticks per signal */ - t_int x_siginterval; /* number of times per buffer (depends on data rate) */ - - /* ogg/vorbis related stuff */ - ogg_stream_state x_os; /* take physical pages, weld into a logical stream of packets */ - ogg_page x_og; /* one Ogg bitstream page. Vorbis packets are inside */ - ogg_packet x_op; /* one raw packet of data for decode */ - vorbis_info x_vi; /* struct that stores all the static vorbis bitstream settings */ - vorbis_comment x_vc; /* struct that stores all the user comments */ - vorbis_dsp_state x_vd; /* central working state for the packet->PCM decoder */ - vorbis_block x_vb; /* local working space for packet->PCM decode */ - - t_int x_eos; /* end of stream */ - t_float x_pages; /* number of pages that have been output to server */ - t_float x_lastpages; - - /* ringbuffer stuff */ - t_float *x_buffer; /* data to be buffered (ringbuffer)*/ - t_int x_bytesbuffered; /* number of unprocessed bytes in buffer */ - - /* ogg/vorbis format stuff */ - t_int x_samplerate; /* samplerate of stream (default = getsr() ) */ - t_int x_skip; /* samples from input to skip (for resampling) */ - t_float x_quality; /* desired quality level from 0.0 to 1.0 (lo to hi) */ - t_int x_br_max; /* max. bitrate of ogg/vorbis stream */ - t_int x_br_nom; /* nom. bitrate of ogg/vorbis stream */ - t_int x_br_min; /* min. bitrate of ogg/vorbis stream */ - t_int x_channels; /* number of channels (1 or 2) */ - t_int x_vbr; - - /* IceCast server stuff */ - char* x_passwd; /* password for server */ - char* x_bcname; /* name of broadcast */ - char* x_bcurl; /* url of broadcast */ - char* x_bcgenre; /* genre of broadcast */ - char* x_bcdescription; /* description */ - char* x_bcartist; /* artist */ - char* x_bclocation; - char* x_bccopyright; - char* x_bcperformer; - char* x_bccontact; - char* x_bcdate; /* system date when broadcast started */ - char* x_hostname; /* name or IP of host to connect to */ - char* x_mountpoint; /* mountpoint for IceCast server */ - t_float x_port; /* port number on which the connection is made */ - t_int x_bcpublic; /* do(n't) publish broadcast on www.oggcast.com */ - t_int x_servertype; /* type of server: 0 = JRoar or old Icecast2; 1 = new Icecast2 */ - - - - - t_int x_connectstate; /* indicates to state of socket connection */ - t_int x_outvalue; /* value that has last been output via outlet */ - t_int x_fd; /* the socket number */ - t_resample x_resample; /* resampling unit */ - t_int x_recover; /* indicate how to behave on buffer underruns */ - - /* thread stuff */ - pthread_mutex_t x_mutex; - pthread_cond_t x_requestcondition; - pthread_cond_t x_answercondition; - pthread_t x_childthread; -} t_oggcast; - - -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','+','/', -}; - - /* This isn't efficient, but it doesn't need to be */ -char *oggcast_util_base64_encode(char *data) -{ - int len = strlen(data); - char *out = (char *)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; -} - - /* check server for writeability */ -static int oggcast_checkserver(t_int sock) -{ - fd_set fdset; - struct timeval ztout; - fd_set writeset; - fd_set exceptset; - - FD_ZERO(&writeset); - FD_ZERO(&exceptset); - FD_SET(sock, &writeset ); - FD_SET(sock, &exceptset ); - - if(select(sock+1, NULL, &writeset, &exceptset, &ztout) > 0) - { - if(!FD_ISSET(sock, &writeset)) - { - post("oggcast~: can not write data to the server, quitting"); - return -1; - } - if(FD_ISSET(sock, &exceptset)) - { - post("oggcast~: socket returned an error, quitting"); - return -1; - } - } - return 0; -} - - /* stream ogg/vorbis to IceCast2 server */ -static int oggcast_stream(t_oggcast *x, t_int fd) -{ - int err = -1; /* error return code */ - int pages = 0; - - /* write out pages (if any) */ - while(!x->x_eos) - { - int result=ogg_stream_pageout(&(x->x_os),&(x->x_og)); - if(result==0)break; - err = send(fd, x->x_og.header, x->x_og.header_len, 0); - if(err < 0) - { - error("oggcast~: could not send ogg header to server (%d)", err); - x->x_eos = 1; /* indicate (artificial) end of stream */ - return err; - } - err = send(fd, x->x_og.body, x->x_og.body_len, 0); - if(err < 0) - { - error("oggcast~: could not send ogg body to server (%d)", err); - x->x_eos = 1; /* indicate (artificial) end of stream */ - return err; - } - pages++; /* count number of pages */ - /* there might be more than one pages we have to send */ - if(ogg_page_eos(&(x->x_og)))x->x_eos=1; - } - return (pages); -} - - /* ogg/vorbis decoder setup */ -static int oggcast_vorbis_init(t_oggcast *x) -{ - int err = -1; - - x->x_eos = 0; - x->x_skip = 1; /* assume no resampling */ - /* choose an encoding mode */ - vorbis_info_init(&(x->x_vi)); - - if(x->x_samplerate != sys_getsr()) /* downsampling for Oliver (http://radiostudio.org) */ - { - if(sys_getsr() / x->x_samplerate == 2.0) - { - post("oggcast~: downsampling from %.0f to %d Hz", sys_getsr(), x->x_samplerate); - x->x_skip = 2; - } - else if(sys_getsr() / x->x_samplerate == 4.0) - { - post("oggcast~: downsampling from %.0f to %d Hz", sys_getsr(), x->x_samplerate); - x->x_skip = 4; - } - else if(sys_getsr() / x->x_samplerate == 3.0) - { - post("oggcast~: downsampling from %.0f to %d Hz", sys_getsr(), x->x_samplerate); - x->x_skip = 3; - } else post("oggcast~: warning: resampling from %.0f to %d not supported", sys_getsr(), x->x_samplerate); - } - if(x->x_vbr == 1) - { /* quality based setting */ - if(vorbis_encode_init_vbr(&(x->x_vi), x->x_channels, x->x_samplerate, x->x_quality)) - { - post("oggcast~: ogg/vorbis mode initialisation failed: invalid parameters for quality"); - vorbis_info_clear(&(x->x_vi)); - return (-1); - } - } - else - { /* bitrate based setting */ - if(vorbis_encode_init(&(x->x_vi), x->x_channels, x->x_samplerate, x->x_br_max*1024, x->x_br_nom*1024, x->x_br_min*1024)) - { - post("oggcast~: ogg/vorbis mode initialisation failed: invalid parameters for quality"); - vorbis_info_clear(&(x->x_vi)); - return (-1); - } - } - - /* add a comment */ - vorbis_comment_init(&(x->x_vc)); - vorbis_comment_add_tag(&(x->x_vc),"TITLE", x->x_bcname); - vorbis_comment_add_tag(&(x->x_vc),"ARTIST", x->x_bcartist); - vorbis_comment_add_tag(&(x->x_vc),"GENRE",x->x_bcgenre); - vorbis_comment_add_tag(&(x->x_vc),"DESCRIPTION", x->x_bcdescription); - vorbis_comment_add_tag(&(x->x_vc),"LOCATION",x->x_bclocation); - vorbis_comment_add_tag(&(x->x_vc),"PERFORMER",x->x_bcperformer); - vorbis_comment_add_tag(&(x->x_vc),"COPYRIGHT",x->x_bccopyright); - vorbis_comment_add_tag(&(x->x_vc),"CONTACT",x->x_bccontact); - vorbis_comment_add_tag(&(x->x_vc),"DATE",x->x_bcdate); - vorbis_comment_add_tag(&(x->x_vc),"ENCODER","oggcast~ v0.2 for pure-data"); - - /* set up the analysis state and auxiliary encoding storage */ - vorbis_analysis_init(&(x->x_vd),&(x->x_vi)); - vorbis_block_init(&(x->x_vd),&(x->x_vb)); - - /* set up our packet->stream encoder */ - /* pick a random serial number; that way we can more likely build - chained streams just by concatenation */ - srand(time(NULL)); - ogg_stream_init(&(x->x_os),rand()); - - /* Vorbis streams begin with three headers; the initial header (with - most of the codec setup parameters) which is mandated by the Ogg - bitstream spec. The second header holds any comment fields. The - third header holds the bitstream codebook. We merely need to - make the headers, then pass them to libvorbis one at a time; - libvorbis handles the additional Ogg bitstream constraints */ - - { - ogg_packet header; - ogg_packet header_comm; - ogg_packet header_code; - - vorbis_analysis_headerout(&(x->x_vd),&(x->x_vc),&header,&header_comm,&header_code); - ogg_stream_packetin(&(x->x_os),&header); /* automatically placed in its own page */ - ogg_stream_packetin(&(x->x_os),&header_comm); - ogg_stream_packetin(&(x->x_os),&header_code); - - /* We don't have to write out here, but doing so makes streaming - * much easier, so we do, flushing ALL pages. This ensures the actual - * audio data will start on a new page - * - * IceCast2 server will take this as a first info about our stream - */ - while(!x->x_eos) - { - int result=ogg_stream_flush(&(x->x_os),&(x->x_og)); - if(result==0)break; - err = send(x->x_fd, x->x_og.header, x->x_og.header_len, 0); - if(err < 0) - { - error("oggcast~: could not send ogg header to server (%d)", err); - x->x_eos = 1; /* indicate end of stream */ - return (-1); - } - err = send(x->x_fd, x->x_og.body, x->x_og.body_len, 0); - if(err < 0) - { - error("oggcast~: could not send ogg body to server (%d)", err); - x->x_eos = 1; /* indicate end of stream */ - return (-1); - } - } - } - return (0); -} - - /* deinit the ogg/vorbis decoder */ -static void oggcast_vorbis_deinit(t_oggcast *x) -{ - vorbis_analysis_wrote(&(x->x_vd),0); - /* get rid of remaining data in encoder, if any */ - while(vorbis_analysis_blockout(&(x->x_vd),&(x->x_vb))==1) - { - vorbis_analysis(&(x->x_vb),NULL); - vorbis_bitrate_addblock(&(x->x_vb)); - - while(vorbis_bitrate_flushpacket(&(x->x_vd),&(x->x_op))) - { - ogg_stream_packetin(&(x->x_os),&(x->x_op)); - oggcast_stream(x, x->x_fd); - } - } - /* clean up and exit. vorbis_info_clear() must be called last */ - ogg_stream_clear(&(x->x_os)); - vorbis_block_clear(&(x->x_vb)); - vorbis_dsp_clear(&(x->x_vd)); - vorbis_comment_clear(&(x->x_vc)); - vorbis_info_clear(&(x->x_vi)); -} - - /* encode ogg/vorbis and stream new data */ -static int oggcast_encode(t_oggcast *x, float *buf, int channels, int fifosize, int fd) -{ - unsigned short i, ch; - int err = 0; - int n, pages = 0; - - /* expose the buffer to submit data */ - float **inbuffer=vorbis_analysis_buffer(&(x->x_vd),READ); - - /* read from buffer */ - for(n = 0; n < READ / channels; n++) /* fill encode buffer */ - { - for(ch = 0; ch < channels; ch++) - { - inbuffer[ch][n] = *buf++; - } - } - /* tell the library how much we actually submitted */ - vorbis_analysis_wrote(&(x->x_vd),n); - - /* vorbis does some data preanalysis, then divvies up blocks for - more involved (potentially parallel) processing. Get a single - block for encoding now */ - while(vorbis_analysis_blockout(&(x->x_vd),&(x->x_vb))==1) - { - /* analysis, assume we want to use bitrate management */ - vorbis_analysis(&(x->x_vb),NULL); - vorbis_bitrate_addblock(&(x->x_vb)); - - while(vorbis_bitrate_flushpacket(&(x->x_vd),&(x->x_op))) - { - /* weld the packet into the bitstream */ - ogg_stream_packetin(&(x->x_os),&(x->x_op)); - err = oggcast_stream(x, fd); /* stream packet to server */ - if(err >= 0) - { - pages += err; /* count pages */ - } - else return (err); - } - } - return (pages); -} - - /* connect to icecast2 server */ -static int oggcast_child_connect(char *hostname, char *mountpoint, t_int portno, - char *passwd, char *bcname, char *bcurl, - char *bcgenre, t_int bcpublic, t_int br_nom, t_int servertype) -{ - struct sockaddr_in server; - struct hostent *hp; - - /* variables used for communication with server */ - const char * buf = 0; - char resp[STRBUF_SIZE]; - unsigned int len; - fd_set fdset; - struct timeval tv; - t_int sockfd; /* our internal handle for the socket */ - t_int ret; - - sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - if (sockfd < 0) - { - error("oggcast~: internal error while attempting to open socket"); - return (-1); - } - - /* connect socket using hostname provided in command line */ - server.sin_family = AF_INET; - hp = gethostbyname(hostname); - if (hp == 0) - { - post("oggcast~: bad host?"); - sys_closesocket(sockfd); - return (-1); - } - memcpy((char *)&server.sin_addr, (char *)hp->h_addr, hp->h_length); - - /* assign client port number */ - server.sin_port = htons((unsigned short)portno); - - /* try to connect. */ - post("oggcast~: connecting to port %d", portno); - if (connect(sockfd, (struct sockaddr *) &server, sizeof (server)) < 0) - { - error("oggcast~: connection failed!\n"); - sys_closesocket(sockfd); - return (-1); - } - - /* sheck if we can read/write from/to the socket */ - FD_ZERO( &fdset); - FD_SET( sockfd, &fdset); - tv.tv_sec = 0; /* seconds */ - tv.tv_usec = 500; /* microseconds */ - - ret = select(sockfd + 1, &fdset, NULL, NULL, &tv); - if(ret != 0) - { - error("oggcast~: can not read from socket"); - sys_closesocket(sockfd); - return (-1); - } - - post("oggcast~: logging in to IceCast2 server..."); - /* now try to log in at IceCast2 server using ICE/1.0 scheme */ - if(servertype == 0) - { - /* send the request, a string like: "SOURCE /<mountpoint> ICE/1.0\n" */ - buf = "SOURCE "; - send(sockfd, buf, strlen(buf), 0); - buf = "/"; - send(sockfd, buf, strlen(buf), 0); - buf = mountpoint; - send(sockfd, buf, strlen(buf), 0); - buf = " ICE/1.0"; - send(sockfd, buf, strlen(buf), 0); - /* send the ice headers */ - /* password */ - buf = "\nice-password: "; - send(sockfd, buf, strlen(buf), 0); - buf = passwd; - send(sockfd, buf, strlen(buf), 0); - /* name */ - buf = "\r\nice-name: "; - send(sockfd, buf, strlen(buf), 0); - buf = bcname; - send(sockfd, buf, strlen(buf), 0); - /* url */ - buf = "\r\nice-url: "; - send(sockfd, buf, strlen(buf), 0); - buf = bcurl; - send(sockfd, buf, strlen(buf), 0); - /* genre */ - buf = "\r\nice-genre: "; - send(sockfd, buf, strlen(buf), 0); - buf = bcgenre; - send(sockfd, buf, strlen(buf), 0); - /* public */ - buf = "\r\nice-public: "; - send(sockfd, buf, strlen(buf), 0); - if(bcpublic==0) /* set the public flag for broadcast */ - { - buf = "no"; - } - else - { - buf ="yes"; - } - send(sockfd, buf, strlen(buf), 0); - /* bitrate */ - buf = "\r\nice-bitrate: "; - send(sockfd, buf, strlen(buf), 0); - if(sprintf(resp, "%d", br_nom) == -1) /* convert int to a string */ - { - error("oggcast~: wrong bitrate"); - } - send(sockfd, resp, strlen(resp), 0); - /* description */ - buf = "\r\nice-description: "; - send(sockfd, buf, strlen(buf), 0); - buf = "ogg/vorbis streamed from pure-data with oggcast~"; - send(sockfd, buf, strlen(buf), 0); - /* end of header */ - buf = "\r\n\r\n"; - send(sockfd, buf, strlen(buf), 0); - /* end login for IceCast using ICE/1.0 scheme */ - } - else /* or try to log in at IceCast2 server using HTTP/1.0 base auth scheme */ - { - /* send the request, a string like: "SOURCE /<mountpoint> HTTP/1.0\n\r" */ - buf = "SOURCE /"; - send(sockfd, buf, strlen(buf), 0); - buf = mountpoint; - send(sockfd, buf, strlen(buf), 0); - buf = " HTTP/1.0\r\n"; - send(sockfd, buf, strlen(buf), 0); - /* send basic authorization */ - sprintf(resp, "source:%s", passwd); - buf = oggcast_util_base64_encode(resp); - sprintf(resp, "Authorization: Basic %s\r\n", buf); - send(sockfd, resp, strlen(resp), 0); - /* send content type */ - buf = "Content-Type: application/x-ogg"; - send(sockfd, buf, strlen(buf), 0); - /* send the ice headers */ - /* password */ - buf = "\r\nice-password: "; - send(sockfd, buf, strlen(buf), 0); - buf = passwd; - send(sockfd, buf, strlen(buf), 0); - /* name */ - buf = "\r\nice-name: "; - send(sockfd, buf, strlen(buf), 0); - buf = bcname; - send(sockfd, buf, strlen(buf), 0); - /* url */ - buf = "\r\nice-url: "; - send(sockfd, buf, strlen(buf), 0); - buf = bcurl; - send(sockfd, buf, strlen(buf), 0); - /* genre */ - buf = "\r\nice-genre: "; - send(sockfd, buf, strlen(buf), 0); - buf = bcgenre; - send(sockfd, buf, strlen(buf), 0); - /* public */ - buf = "\r\nice-public: "; - send(sockfd, buf, strlen(buf), 0); - if(bcpublic==0) /* set the public flag for broadcast */ - { - buf = "0"; - } - else - { - buf = "1"; - } - send(sockfd, buf, strlen(buf), 0); - /* bitrate */ - buf = "\r\nice-bitrate: "; - send(sockfd, buf, strlen(buf), 0); - if(sprintf(resp, "%d", br_nom) == -1) /* convert int to a string */ - { - error("oggcast~: wrong bitrate"); - } - send(sockfd, resp, strlen(resp), 0); - /* description */ - buf = "\r\nice-description: "; - send(sockfd, buf, strlen(buf), 0); - buf = "Ogg/Vorbis streamed from Pure Data with oggcast~\r\n"; - send(sockfd, buf, strlen(buf), 0); - /* end of header: write an empty line */ - buf = "\r\n"; - send(sockfd, buf, strlen(buf), 0); - /* end login for IceCast2 using ICE/1.0 scheme */ - } - - /* check if we can write to server */ - if(oggcast_checkserver(sockfd)!= 0) - { - post("oggcast~: error: server refused to receive data"); - return (-1); - } - - post("oggcast~: logged in to http://%s:%d/%s", hp->h_name, portno, mountpoint); - - return (sockfd); -} - - - -static void oggcast_child_disconnect(t_int fd) -{ - sys_closesocket(fd); - post("oggcast~: connection closed"); -} -/************** the child thread which performs data I/O ***********/ - -#if 0 /* set this to 1 to get debugging output */ -static void pute(char *s) /* debug routine */ -{ - write(2, s, strlen(s)); -} -#else -#define pute(x) -#endif - -#if 1 -#define oggcast_cond_wait pthread_cond_wait -#define oggcast_cond_signal pthread_cond_signal -#else -#include <sys/time.h> /* debugging version... */ -#include <sys/types.h> -static void oggcast_fakewait(pthread_mutex_t *b) -{ - struct timeval timout; - timout.tv_sec = 0; - timout.tv_usec = 1000000; - pthread_mutex_unlock(b); - select(0, 0, 0, 0, &timout); - pthread_mutex_lock(b); -} - -void oggcast_banana( void) -{ - struct timeval timout; - timout.tv_sec = 0; - timout.tv_usec = 200000; - pute("banana1\n"); - select(0, 0, 0, 0, &timout); - pute("banana2\n"); -} - - -#define oggcast_cond_wait(a,b) oggcast_fakewait(b) -#define oggcast_cond_signal(a) -#endif - -static void *oggcast_child_main(void *zz) -{ - t_oggcast *x = zz; - time_t now; /* to get the time */ - pute("1\n"); - pthread_mutex_lock(&x->x_mutex); - while (1) - { - int fd, fifotail; - pute("0\n"); - if (x->x_requestcode == REQUEST_NOTHING) - { - pute("wait 2\n"); - oggcast_cond_signal(&x->x_answercondition); - oggcast_cond_wait(&x->x_requestcondition, &x->x_mutex); - pute("3\n"); - } - // connect to Icecast2 server - else if (x->x_requestcode == REQUEST_CONNECT) - { - char boo[100]; - int sysrtn, wantbytes; - - /* copy connect stuff out of the data structure so we can - relinquish the mutex while we're connecting to server. */ - char *hostname = x->x_hostname; - char *mountpoint = x->x_mountpoint; - t_int portno = x->x_port; - char *passwd = x->x_passwd; - char *bcname = x->x_bcname; - char *bcgenre = x->x_bcgenre; - char *bcurl = x->x_bcurl; - t_int bcpublic = x->x_bcpublic; - t_int br_nom = x->x_br_nom; - t_int servertype = x->x_servertype; - /* alter the request code so that an ensuing "open" will get - noticed. */ - pute("4\n"); - x->x_requestcode = REQUEST_BUSY; - x->x_connecterror = 0; - - /* open the socket with the mutex unlocked in case - we're not already connected */ - if(x->x_fd < 0) - { - pthread_mutex_unlock(&x->x_mutex); - fd = oggcast_child_connect(hostname, mountpoint, portno, passwd, bcname, - bcurl, bcgenre, bcpublic, br_nom, servertype); - pthread_mutex_lock(&x->x_mutex); - pute("5\n"); - /* copy back into the instance structure. */ - x->x_connectstate = 1; - clock_delay(x->x_clock_connect, 0); - x->x_fd = fd; - if (fd < 0) - { - x->x_connecterror = fd; - x->x_connectstate = 0; - clock_delay(x->x_clock_connect, 0); - pute("connect failed\n"); - goto lost; - } - else - { - /* get the time for the DATE comment */ - now=time(NULL); - x->x_bcdate = ctime(&now); - x->x_pages = 0; - clock_delay(x->x_clock_pages, 0); - /* initialise the encoder */ - if(oggcast_vorbis_init(x) == 0) - { - post("oggcast~: ogg/vorbis encoder initialised"); - x->x_eos = 0; - x->x_state = STATE_STREAM; - } - else - { - post("oggcast~: could not init encoder"); - oggcast_child_disconnect(fd); - post("oggcast~: connection closed due to initialisation error"); - x->x_fd = -1; - x->x_connectstate = 0; - clock_delay(x->x_clock_connect, 0); - pute("oggcast~: initialisation failed\n"); - goto lost; - } - } - x->x_fifotail = fifotail = 0; - /* set fifosize from bufsize. fifosize must be a - multiple of the number of bytes eaten for each DSP - tick. We pessimistically assume MAXVECSIZE samples - per tick since that could change. There could be a - problem here if the vector size increases while a - stream is being played... */ - x->x_fifosize = x->x_bufsize - (x->x_bufsize % (x->x_channels * READ)); - /* arrange for the "request" condition to be signalled x->x_siginterval - times per buffer */ - sprintf(boo, "fifosize %d\n", x->x_fifosize); - pute(boo); - x->x_sigcountdown = x->x_sigperiod = (x->x_fifosize / (x->x_siginterval * x->x_channels * x->x_vecsize)); - } - /* check if another request has been made; if so, field it */ - if (x->x_requestcode != REQUEST_BUSY) - goto lost; - pute("6\n"); - - while (x->x_requestcode == REQUEST_BUSY) - { - int fifosize = x->x_fifosize, fifotail, channels; - float *buf = x->x_buf; - pute("77\n"); - - /* if the head is < the tail, we can immediately write - from tail to end of fifo to disk; otherwise we hold off - writing until there are at least WRITESIZE bytes in the - buffer */ - if (x->x_fifohead < x->x_fifotail || - x->x_fifohead >= x->x_fifotail + READ - || (x->x_requestcode == REQUEST_CLOSE && - x->x_fifohead != x->x_fifotail)) - { /* encode audio and send to server */ - pute("8\n"); - fifotail = x->x_fifotail; - channels = x->x_channels; - fd = x->x_fd; - pthread_mutex_unlock(&x->x_mutex); - sysrtn = oggcast_encode(x, buf + fifotail, channels, fifosize, fd); - pthread_mutex_lock(&x->x_mutex); - if (x->x_requestcode != REQUEST_BUSY && - x->x_requestcode != REQUEST_CLOSE) - break; - if (sysrtn < 0) - { - post("oggcast~: closing due to error..."); - goto lost; - } - else - { - x->x_fifotail += READ; - x->x_pages += sysrtn; - if (x->x_fifotail >= fifosize) - x->x_fifotail = 0; - } - sprintf(boo, "after: head %d, tail %d, pages %d\n", x->x_fifohead, x->x_fifotail, sysrtn); - pute(boo); - } - else /* just wait... */ - { - pute("wait 7a ...\n"); - oggcast_cond_signal(&x->x_answercondition); - pute("signalled\n"); - oggcast_cond_wait(&x->x_requestcondition, - &x->x_mutex); - pute("7a done\n"); - continue; - } - /* signal parent in case it's waiting for data */ - oggcast_cond_signal(&x->x_answercondition); - } - } - - /* reinit encoder (settings have changed) */ - else if (x->x_requestcode == REQUEST_REINIT) - { - pthread_mutex_unlock(&x->x_mutex); - oggcast_vorbis_deinit(x); - oggcast_vorbis_init(x); - pthread_mutex_lock(&x->x_mutex); - post("oggcast~: ogg/vorbis encoder reinitialised"); - x->x_state = STATE_STREAM; - if (x->x_requestcode == REQUEST_REINIT) - x->x_requestcode = REQUEST_CONNECT; - oggcast_cond_signal(&x->x_answercondition); - } - /* close connection to server (disconnect) */ - else if (x->x_requestcode == REQUEST_CLOSE) - { -lost: - x->x_state = STATE_IDLE; - if (x->x_fd >= 0) - { - fd = x->x_fd; - pthread_mutex_unlock(&x->x_mutex); - oggcast_vorbis_deinit(x); - oggcast_child_disconnect(fd); - pthread_mutex_lock(&x->x_mutex); - x->x_fd = -1; - } - if (x->x_requestcode == REQUEST_CLOSE) - x->x_requestcode = REQUEST_NOTHING; - if (x->x_requestcode == REQUEST_BUSY) /* disconnect due to error */ - x->x_requestcode = REQUEST_NOTHING; - x->x_connectstate = 0; - clock_delay(x->x_clock_connect, 0); - x->x_eos = 1; - oggcast_cond_signal(&x->x_answercondition); - } - // quit everything - else if (x->x_requestcode == REQUEST_QUIT) - { - x->x_state = STATE_IDLE; - if (x->x_fd >= 0) - { - fd = x->x_fd; - pthread_mutex_unlock(&x->x_mutex); - oggcast_vorbis_deinit(x); - oggcast_child_disconnect(fd); - pthread_mutex_lock(&x->x_mutex); - x->x_fd = -1; - } - x->x_connectstate = 0; - clock_delay(x->x_clock_connect, 0); - x->x_requestcode = REQUEST_NOTHING; - oggcast_cond_signal(&x->x_answercondition); - break; - } - else - { - pute("13\n"); - } - } - pute("thread exit\n"); - pthread_mutex_unlock(&x->x_mutex); - return (0); -} - -/******** the object proper runs in the calling (parent) thread ****/ - -static void oggcast_tick_connect(t_oggcast *x) -{ - pthread_mutex_lock(&x->x_mutex); - outlet_float(x->x_connection, x->x_connectstate); - pthread_mutex_unlock(&x->x_mutex); -} - -static void oggcast_tick_pages(t_oggcast *x) -{ - /* output new no. of pages if anything changed */ - t_float pages; - pthread_mutex_lock(&x->x_mutex); - pages = x->x_pages; /* get current value with mutex locked */ - pthread_mutex_unlock(&x->x_mutex); - if(pages != x->x_lastpages) - { - outlet_float(x->x_outpages, pages); - x->x_lastpages = pages; - } - clock_delay(x->x_clock_pages, UPDATE_INTERVAL); /* come back again... */ -} - -static void *oggcast_new(t_floatarg fnchannels, t_floatarg fbufsize) -{ - t_oggcast *x; - int nchannels = fnchannels, bufsize = fbufsize * 1024, i; - float *buf; - - if (nchannels < 1) - nchannels = 2; /* two channels as default */ - else if (nchannels > MAXSTREAMCHANS) - nchannels = MAXSTREAMCHANS; - /* check / set buffer size */ - if (bufsize <= 0) bufsize = DEFBUFPERCHAN * nchannels; - else if (bufsize < MINBUFSIZE) - bufsize = MINBUFSIZE; - else if (bufsize > MAXBUFSIZE) - bufsize = MAXBUFSIZE; - buf = getbytes(bufsize*sizeof(t_float)); - if (!buf) return (0); - - x = (t_oggcast *)pd_new(oggcast_class); - - for (i = 1; i < nchannels; i++) - inlet_new (&x->x_obj, &x->x_obj.ob_pd, gensym ("signal"), gensym ("signal")); - x->x_connection = outlet_new(&x->x_obj, gensym("float")); - x->x_outpages = outlet_new(&x->x_obj, gensym("float")); - x->x_ninlets = nchannels; - - x->x_clock_connect = clock_new(x, (t_method)oggcast_tick_connect); - x->x_clock_pages = clock_new(x, (t_method)oggcast_tick_pages); - - pthread_mutex_init(&x->x_mutex, 0); - pthread_cond_init(&x->x_requestcondition, 0); - pthread_cond_init(&x->x_answercondition, 0); - - x->x_vecsize = 2; - x->x_state = STATE_IDLE; - x->x_buf = buf; - x->x_bufsize = bufsize; - x->x_siginterval = 32; /* signal 32 times per buffer */ - /* I found this to be most efficient on my machine */ - x->x_fifosize = x->x_fifohead = x->x_fifotail = x->x_requestcode = 0; - - x->x_connectstate = 0; /* indicating state of connection */ - x->x_outvalue = 0; /* value at output currently is 0 */ - - x->x_samplerate = sys_getsr(); - x->x_resample.upsample = x->x_resample.downsample = 1; /* don't resample */ - - - x->x_fd = -1; - x->x_eos = 0; - x->x_vbr = 1; /* use the vbr setting by default */ - x->x_passwd = "letmein"; - x->x_samplerate = sys_getsr(); /* default to Pd's sampling rate */ - x->x_skip = 1; /* no resampling supported */ - x->x_quality = 0.4; /* quality 0.4 gives roughly 128kbps VBR stream */ - x->x_channels = nchannels; /* stereo */ - x->x_br_max = 144; - x->x_br_nom = 128; - x->x_br_min = 96; - x->x_pages = x->x_lastpages = 0; - x->x_bcname = "ogg/vorbis stream"; - x->x_bcurl = "http://www.akustische-kunst.org/puredata/"; - x->x_bcgenre = "experimental"; - x->x_bcdescription = "ogg/vorbis stream emitted from pure-data with oggcast~"; - x->x_bcartist = "Pd and oggcast~ v0.2"; - x->x_bclocation = x->x_bcurl; - x->x_bccopyright = ""; - x->x_bcperformer = ""; - x->x_bccontact = ""; - x->x_bcdate = ""; - x->x_bcpublic = 1; - x->x_mountpoint = "puredata.ogg"; - x->x_servertype = 1; /* HTTP/1.0 protocol for Icecast2 */ - - post(oggcast_version); - post("oggcast~: set buffer to %dk bytes", bufsize / 1024); - post("oggcast~: encoding %d channels @ %d Hz", x->x_channels, x->x_samplerate); - - clock_delay(x->x_clock_pages, 0); - pthread_create(&x->x_childthread, 0, oggcast_child_main, x); - return (x); -} - -static t_int *oggcast_perform(t_int *w) -{ - t_oggcast *x = (t_oggcast *)(w[1]); - int vecsize = x->x_vecsize, ninlets = x->x_ninlets, channels = x->x_channels, i, j, skip = x->x_skip; - float *sp = x->x_buf; - pthread_mutex_lock(&x->x_mutex); - if (x->x_state != STATE_IDLE) - { - int wantbytes; - /* get 'wantbytes' bytes from inlet */ - wantbytes = channels * vecsize / skip; /* we'll get vecsize bytes per channel */ - /* check if there is enough space in buffer to write all samples */ - while (x->x_fifotail > x->x_fifohead && - x->x_fifotail < x->x_fifohead + wantbytes + 1) - { - pute("wait...\n"); - oggcast_cond_signal(&x->x_requestcondition); - oggcast_cond_wait(&x->x_answercondition, &x->x_mutex); - pute("done\n"); - } - - /* output audio */ - sp += x->x_fifohead; - - if(ninlets >= channels) - { - for(j = 0; j < vecsize; j += skip) - { - for(i = 0; i < channels; i++) - { - *sp++ = x->x_outvec[i][j]; - } - } - } - else if(channels == ninlets * 2) /* convert mono -> stereo */ - { - for(j = 0; j < vecsize; j += skip) - { - for(i = 0; i < ninlets; i++) - { - *sp++ = x->x_outvec[i][j]; - *sp++ = x->x_outvec[i][j]; - } - } - } - - - x->x_fifohead += wantbytes; - if (x->x_fifohead >= x->x_fifosize) - x->x_fifohead = 0; - /* signal the child thread */ - if ((--x->x_sigcountdown) <= 0) - { - pute("signal 1\n"); - oggcast_cond_signal(&x->x_requestcondition); - x->x_sigcountdown = x->x_sigperiod; - } - } - - pthread_mutex_unlock(&x->x_mutex); - - return (w+2); -} - - -static void oggcast_disconnect(t_oggcast *x) -{ - /* LATER rethink whether you need the mutex just to set a variable? */ - pthread_mutex_lock(&x->x_mutex); - if(x->x_fd >= 0) - { - x->x_state = STATE_IDLE; - x->x_requestcode = REQUEST_CLOSE; - oggcast_cond_signal(&x->x_requestcondition); - } - else post("oggcast~: not connected"); - pthread_mutex_unlock(&x->x_mutex); -} - - - /* connect method. Called as: - connect <hostname or IP> <mountpoint> <portnumber> - */ - -static void oggcast_connect(t_oggcast *x, t_symbol *s, int argc, t_atom *argv) -{ - t_symbol *hostsym = atom_getsymbolarg(0, argc, argv); - t_symbol *mountsym = atom_getsymbolarg(1, argc, argv); - t_float portno = atom_getfloatarg(2, argc, argv); - if (!*hostsym->s_name) /* check for hostname */ - return; - if (!portno) /* check wether the portnumber is specified */ - portno = 8000; /* ...assume port 8000 as standard */ - pthread_mutex_lock(&x->x_mutex); - if(x->x_fd >= 0) - { - post("oggcast~: already connected"); - } - else - { - x->x_requestcode = REQUEST_CONNECT; - x->x_hostname = hostsym->s_name; - x->x_mountpoint = mountsym->s_name; - x->x_port = portno; - - x->x_fifotail = 0; - x->x_fifohead = 0; - // if(x->x_recover != 1)x->x_fifobytes = 0; - - x->x_connecterror = 0; - x->x_state = STATE_STARTUP; - oggcast_cond_signal(&x->x_requestcondition); - } - pthread_mutex_unlock(&x->x_mutex); -} - -static void oggcast_float(t_oggcast *x, t_floatarg f) -{ - if (f != 0) - { - pthread_mutex_lock(&x->x_mutex); - if(x->x_fd >= 0) - { - post("oggcast~: already connected"); - } - else - { - if(x->x_recover != 1) - { - x->x_fifotail = 0; - x->x_fifohead = 0; - } - x->x_requestcode = REQUEST_CONNECT; - - x->x_fifotail = 0; - x->x_fifohead = 0; - - x->x_connecterror = 0; - x->x_state = STATE_STARTUP; - oggcast_cond_signal(&x->x_requestcondition); - } - pthread_mutex_unlock(&x->x_mutex); - } - else oggcast_disconnect(x); -} - -static void oggcast_dsp(t_oggcast *x, t_signal **sp) -{ - int i, ninlets = x->x_ninlets; - pthread_mutex_lock(&x->x_mutex); - x->x_vecsize = sp[0]->s_n; - - x->x_sigperiod = (x->x_fifosize / (x->x_siginterval * ninlets * x->x_vecsize)); - for (i = 0; i < ninlets; i++) - x->x_outvec[i] = sp[i]->s_vec; - pthread_mutex_unlock(&x->x_mutex); - dsp_add(oggcast_perform, 1, x); -} - - /* set password for oggcast server */ -static void oggcast_password(t_oggcast *x, t_symbol *password) -{ - pthread_mutex_lock(&x->x_mutex); - x->x_passwd = password->s_name; - pthread_mutex_unlock(&x->x_mutex); -} - /* set comment fields for header (reads in just anything) */ -static void oggcast_comment(t_oggcast *x, t_symbol *s, t_int argc, t_atom* argv) -{ - t_binbuf *b = binbuf_new(); - char* comment; - int length; - binbuf_add(b, argc, argv); - binbuf_gettext(b, &comment, &length); - - pthread_mutex_lock(&x->x_mutex); - if(strstr(s->s_name, "ARTIST")) - { - strcpy(x->x_bcartist, comment); - post("oggcast~: ARTIST = %s", x->x_bcartist); - } - else if(strstr(s->s_name, "GENRE")) - { - strcpy(x->x_bcgenre, comment); - post("oggcast~: GENRE = %s", x->x_bcgenre); - } - else if(strstr(s->s_name, "TITLE")) - { - strcpy(x->x_bcname, comment); - post("oggcast~: TITLE = %s", x->x_bcname); - } - else if(strstr(s->s_name, "PERFORMER")) - { - strcpy(x->x_bcperformer, comment); - post("oggcast~: PERFORMER = %s", x->x_bcperformer); - } - else if(strstr(s->s_name, "LOCATION")) - { - strcpy(x->x_bclocation, comment); - post("oggcast~: LOCATION = %s", x->x_bclocation); - } - else if(strstr(s->s_name, "COPYRIGHT")) - { - strcpy(x->x_bccopyright, comment); - post("oggcast~: COPYRIGHT = %s", x->x_bccopyright); - } - else if(strstr(s->s_name, "CONTACT")) - { - strcpy(x->x_bccontact, comment); - post("oggcast~: CONTACT = %s", x->x_bccontact); - } - else if(strstr(s->s_name, "DESCRIPTION")) - { - strcpy(x->x_bcdescription, comment); - post("oggcast~: DESCRIPTION = %s", x->x_bcdescription); - } - else if(strstr(s->s_name, "DATE")) - { - strcpy(x->x_bcdate, comment); - post("oggcast~: DATE = %s", x->x_bcdate); - } - else post("oggcast~: no method for %s", s->s_name); - if(x->x_state == STATE_STREAM) - { - x->x_state = STATE_IDLE; - x->x_requestcode = REQUEST_REINIT; - oggcast_cond_signal(&x->x_requestcondition); - } - pthread_mutex_unlock(&x->x_mutex); - freebytes(comment, strlen(comment)); -} - /* settings for variable bitrate encoding */ -static void oggcast_vbr(t_oggcast *x, t_floatarg fsr, t_floatarg fchannels, - t_floatarg fquality) -{ - pthread_mutex_lock(&x->x_mutex); - x->x_vbr = 1; - x->x_samplerate = (t_int)fsr; - x->x_quality = fquality; - x->x_channels = (t_int)fchannels; - post("oggcast~: %d channels @ %d Hz, quality %.2f", x->x_channels, x->x_samplerate, x->x_quality); - if(x->x_state == STATE_STREAM) - { - x->x_state = STATE_IDLE; - x->x_requestcode = REQUEST_REINIT; - oggcast_cond_signal(&x->x_requestcondition); - } - pthread_mutex_unlock(&x->x_mutex); -} - - /* settings for bitrate-based vbr encoding */ -static void oggcast_vorbis(t_oggcast *x, t_floatarg fsr, t_floatarg fchannels, - t_floatarg fmax, t_floatarg fnom, t_floatarg fmin) -{ - pthread_mutex_lock(&x->x_mutex); - x->x_vbr = 0; - x->x_samplerate = (t_int)fsr; - x->x_channels = (t_int)fchannels; - x->x_br_max = (t_int)fmax; - x->x_br_nom = (t_int)fnom; - x->x_br_min = (t_int)fmin; - post("oggcast~: %d channels @ %d Hz, bitrates: max. %d / nom. %d / min. %d", - x->x_channels, x->x_samplerate, x->x_br_max, x->x_br_nom, x->x_br_min); - if(x->x_state == STATE_STREAM) - { - x->x_state = STATE_IDLE; - x->x_requestcode = REQUEST_REINIT; - oggcast_cond_signal(&x->x_requestcondition); - } - pthread_mutex_unlock(&x->x_mutex); -} - /* select server type */ -static void oggcast_server(t_oggcast *x, t_floatarg f) -{ - pthread_mutex_lock(&x->x_mutex); - if(f) - { - x->x_servertype = 1; - post("oggcast~: set server type to new Icecast2 (HTTP/1.0 scheme)"); - } - else - { - x->x_servertype = 0; - post("oggcast~: set server type to JRoar (ICE/1.0 scheme)"); - } - pthread_mutex_unlock(&x->x_mutex); -} - /* print settings to pd's console window */ -static void oggcast_print(t_oggcast *x) -{ - pthread_mutex_lock(&x->x_mutex); - if(x->x_servertype) - post("oggcast~: server type is Icecast2"); - else - post("oggcast~: server type is JRoar"); - post("oggcast~: mountpoint at Icecast2: %s", x->x_mountpoint); - if(x->x_vbr == 1) - { - post("oggcast~: Ogg Vorbis encoder: %d channels @ %d Hz, quality %.2f", x->x_channels, x->x_samplerate, x->x_quality); - } - else - { - post("oggcast~: Ogg Vorbis encoder: %d channels @ %d Hz, bitrates: max. %d, nom. %d, min. %d", - x->x_channels, x->x_samplerate, x->x_br_max, x->x_br_nom, x->x_br_min); - } - post("oggcast~: Ogg Vorbis comments:"); - post(" TITLE = %s", x->x_bcname); - post(" ARTIST = %s", x->x_bcartist); - post(" PERFORMER = %s", x->x_bcperformer); - post(" GENRE = %s", x->x_bcgenre); - post(" LOCATION = %s", x->x_bclocation); - post(" COPYRIGHT = %s", x->x_bccopyright); - post(" CONTACT = %s", x->x_bccontact); - post(" DESCRIPTION = %s", x->x_bcdescription); - post(" DATE = %s", x->x_bcdate); - pthread_mutex_unlock(&x->x_mutex); -} - - -static void oggcast_free(t_oggcast *x) -{ - /* request QUIT and wait for acknowledge */ - void *threadrtn; - pthread_mutex_lock(&x->x_mutex); - x->x_requestcode = REQUEST_QUIT; - post("stopping oggcast thread..."); - oggcast_cond_signal(&x->x_requestcondition); - while (x->x_requestcode != REQUEST_NOTHING) - { - post("signalling..."); - oggcast_cond_signal(&x->x_requestcondition); - oggcast_cond_wait(&x->x_answercondition, &x->x_mutex); - } - pthread_mutex_unlock(&x->x_mutex); - if (pthread_join(x->x_childthread, &threadrtn)) - error("oggcast_free: join failed"); - post("... done."); - - pthread_cond_destroy(&x->x_requestcondition); - pthread_cond_destroy(&x->x_answercondition); - pthread_mutex_destroy(&x->x_mutex); - freebytes(x->x_buf, x->x_bufsize*sizeof(t_float)); - clock_free(x->x_clock_connect); - clock_free(x->x_clock_pages); -} - -void oggcast_tilde_setup(void) -{ - oggcast_class = class_new(gensym("oggcast~"), (t_newmethod)oggcast_new, - (t_method)oggcast_free, sizeof(t_oggcast), 0, A_DEFFLOAT, A_DEFFLOAT, 0); - CLASS_MAINSIGNALIN(oggcast_class, t_oggcast, x_f ); - class_addfloat(oggcast_class, (t_method)oggcast_float); - class_addmethod(oggcast_class, (t_method)oggcast_disconnect, gensym("disconnect"), 0); - class_addmethod(oggcast_class, (t_method)oggcast_dsp, gensym("dsp"), 0); - class_addmethod(oggcast_class, (t_method)oggcast_connect, gensym("connect"), A_GIMME, 0); - class_addmethod(oggcast_class, (t_method)oggcast_print, gensym("print"), 0); - class_addmethod(oggcast_class, (t_method)oggcast_password, gensym("passwd"), A_SYMBOL, 0); - class_addmethod(oggcast_class, (t_method)oggcast_vorbis, gensym("vorbis"), A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0); - class_addmethod(oggcast_class, (t_method)oggcast_vbr, gensym("vbr"), A_FLOAT, A_FLOAT, A_FLOAT, 0); - class_addmethod(oggcast_class, (t_method)oggcast_server, gensym("server"), A_FLOAT, 0); - class_addanything(oggcast_class, oggcast_comment); - class_sethelpsymbol(oggcast_class, gensym("help-oggcast~.pd")); -} +/* ------------------------- oggcast~ ----------------------------------------- */
+/* */
+/* Tilde object to send an Ogg Vorbis stream from to IceCast2 server. */
+/* Written by Olaf Matthes (olaf.matthes@gmx.de) */
+/* Get source at http://www.akustische-kunst.org/puredata/pdogg/ */
+/* */
+/* This library is free software; you can redistribute it and/or */
+/* modify it under the terms of the GNU Lesser General Public */
+/* License as published by the Free Software Foundation; either */
+/* version 2 of the License, or (at your option) any later version. */
+/* */
+/* This library is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU */
+/* Lesser General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU Lesser General Public */
+/* License along with this library; if not, write to the */
+/* Free Software Foundation, Inc., 59 Temple Place - Suite 330, */
+/* Boston, MA 02111-1307, USA. */
+/* */
+/* Based on PureData by Miller Puckette and others. */
+/* Uses the Ogg Vorbis decoding library which can be found at */
+/* http://www.vorbis.com/ */
+/* */
+/* ---------------------------------------------------------------------------- */
+
+ /* Pd includes */
+#include "m_pd.h"
+#include "g_canvas.h"
+ /* Vorbis includes */
+#include "codec.h"
+#include "vorbisenc.h"
+
+#include <sys/types.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#ifdef UNIX
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <sys/time.h>
+#include <unistd.h>
+#define SOCKET_ERROR -1
+#else
+#include <io.h> /* for 'write' in pute-function only */
+#include <winsock.h>
+#include <winbase.h>
+#endif
+
+#ifdef NT
+#pragma warning( disable : 4244 )
+#pragma warning( disable : 4305 )
+#endif
+
+#ifdef UNIX
+#define sys_closesocket close
+#endif
+#ifdef NT
+#define sys_closesocket closesocket
+#endif
+
+/************************* oggcast~ object ******************************/
+
+/* Each instance of oggcast~ owns a "child" thread for doing the data
+transfer. The parent thread signals the child each time:
+ (1) a connection wants opening or closing;
+ (2) we've eaten another 1/16 of the shared buffer (so that the
+ child thread should check if it's time to receive some more.)
+The child signals the parent whenever a receive has completed. Signalling
+is done by setting "conditions" and putting data in mutex-controlled common
+areas.
+*/
+
+
+#define REQUEST_NOTHING 0
+#define REQUEST_CONNECT 1
+#define REQUEST_CLOSE 2
+#define REQUEST_QUIT 3
+#define REQUEST_BUSY 4
+#define REQUEST_DATA 5
+#define REQUEST_REINIT 6
+
+#define STATE_IDLE 0
+#define STATE_STARTUP 1 /* connecting and filling the buffer */
+#define STATE_STREAM 2 /* streaming aund audio output */
+
+#define READ 4096 /* amount of data we pass on to encoder */
+#define DEFBUFPERCHAN 262144 /* audio output buffer by default: 256k */
+#define MINBUFSIZE 65536
+#define MAXBUFSIZE 16777216 /* arbitrary; just don't want to hang malloc */
+#define STRBUF_SIZE 1024 /* char received from server on startup */
+#define MAXSTREAMCHANS 256 /* maximum number of channels: restricted by Pd? */
+#define UPDATE_INTERVAL 250 /* time in milliseconds between updates of output values */
+
+#ifdef __linux__ // 'real' linux only, not for OS X !
+#define SEND_OPT MSG_DONTWAIT|MSG_NOSIGNAL
+#else
+#define SEND_OPT 0
+#endif
+
+
+static char *oggcast_version = "oggcast~: ogg/vorbis streaming client version 0.2k, written by Olaf Matthes";
+
+static t_class *oggcast_class;
+
+typedef struct _oggcast
+{
+ t_object x_obj;
+ t_float *x_f;
+ t_clock *x_clock_connect;
+ t_clock *x_clock_pages;
+ t_outlet *x_connection; /* outlet for connection state */
+ t_outlet *x_outpages; /* outlet for no. of ogg pages */
+
+ t_float *x_buf; /* audio data buffer */
+ t_int x_bufsize; /* buffer size in bytes */
+ t_int x_ninlets; /* number of audio outlets */
+ t_sample **x_outvec; /* audio vectors */
+ t_int x_vecsize; /* vector size for transfers */
+ t_int x_state; /* opened, running, or idle */
+
+ /* parameters to communicate with subthread */
+ t_int x_requestcode; /* pending request from parent to I/O thread */
+ t_int x_connecterror; /* slot for "errno" return */
+
+ /* buffer stuff */
+ t_int x_fifosize; /* buffer size appropriately rounded down */
+ t_int x_fifohead; /* index of next byte to get from file */
+ t_int x_fifotail; /* index of next byte the ugen will read */
+ t_int x_sigcountdown; /* counter for signalling child for more data */
+ t_int x_sigperiod; /* number of ticks per signal */
+ t_int x_siginterval; /* number of times per buffer (depends on data rate) */
+
+ /* ogg/vorbis related stuff */
+ ogg_stream_state x_os; /* take physical pages, weld into a logical stream of packets */
+ ogg_page x_og; /* one Ogg bitstream page. Vorbis packets are inside */
+ ogg_packet x_op; /* one raw packet of data for decode */
+ vorbis_info x_vi; /* struct that stores all the static vorbis bitstream settings */
+ vorbis_comment x_vc; /* struct that stores all the user comments */
+ vorbis_dsp_state x_vd; /* central working state for the packet->PCM decoder */
+ vorbis_block x_vb; /* local working space for packet->PCM decode */
+
+ t_int x_eos; /* end of stream */
+ t_float x_pages; /* number of pages that have been output to server */
+ t_float x_lastpages;
+
+ /* ringbuffer stuff */
+ t_float *x_buffer; /* data to be buffered (ringbuffer)*/
+ t_int x_bytesbuffered; /* number of unprocessed bytes in buffer */
+
+ /* ogg/vorbis format stuff */
+ t_int x_samplerate; /* samplerate of stream (default = getsr() ) */
+ t_int x_skip; /* samples from input to skip (for resampling) */
+ t_float x_quality; /* desired quality level from 0.0 to 1.0 (lo to hi) */
+ t_int x_br_max; /* max. bitrate of ogg/vorbis stream */
+ t_int x_br_nom; /* nom. bitrate of ogg/vorbis stream */
+ t_int x_br_min; /* min. bitrate of ogg/vorbis stream */
+ t_int x_channels; /* number of channels (1 or 2) */
+ t_int x_vbr;
+
+ /* IceCast server stuff */
+ char* x_passwd; /* password for server */
+ char* x_bcname; /* name of broadcast */
+ char* x_bcurl; /* url of broadcast */
+ char* x_bcgenre; /* genre of broadcast */
+ char* x_bcdescription; /* description */
+ char* x_bcartist; /* artist */
+ char* x_bclocation;
+ char* x_bccopyright;
+ char* x_bcperformer;
+ char* x_bccontact;
+ char* x_bcdate; /* system date when broadcast started */
+ char* x_hostname; /* name or IP of host to connect to */
+ char* x_mountpoint; /* mountpoint for IceCast server */
+ t_float x_port; /* port number on which the connection is made */
+ t_int x_bcpublic; /* do(n't) publish broadcast on www.oggcast.com */
+ t_int x_servertype; /* type of server: 0 = JRoar or old Icecast2; 1 = new Icecast2 */
+
+
+
+
+ t_int x_connectstate; /* indicates to state of socket connection */
+ t_int x_outvalue; /* value that has last been output via outlet */
+ t_int x_fd; /* the socket number */
+ t_resample x_resample; /* resampling unit */
+ t_int x_recover; /* indicate how to behave on buffer underruns */
+
+ /* thread stuff */
+ pthread_mutex_t x_mutex;
+ pthread_cond_t x_requestcondition;
+ pthread_cond_t x_answercondition;
+ pthread_t x_childthread;
+} t_oggcast;
+
+
+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','+','/',
+};
+
+ /* This isn't efficient, but it doesn't need to be */
+char *oggcast_util_base64_encode(char *data)
+{
+ int len = strlen(data);
+ char *out = (char *)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;
+}
+
+ /* check server for writeability */
+static int oggcast_checkserver(t_int sock)
+{
+ fd_set fdset;
+ struct timeval ztout;
+ fd_set writeset;
+ fd_set exceptset;
+
+ FD_ZERO(&writeset);
+ FD_ZERO(&exceptset);
+ FD_SET(sock, &writeset );
+ FD_SET(sock, &exceptset );
+
+ if(select(sock+1, NULL, &writeset, &exceptset, &ztout) > 0)
+ {
+ if(!FD_ISSET(sock, &writeset))
+ {
+ post("oggcast~: can not write data to the server, quitting");
+ return -1;
+ }
+ if(FD_ISSET(sock, &exceptset))
+ {
+ post("oggcast~: socket returned an error, quitting");
+ return -1;
+ }
+ }
+ return 0;
+}
+
+ /* stream ogg/vorbis to IceCast2 server */
+static int oggcast_stream(t_oggcast *x, t_int fd)
+{
+ int err = -1; /* error return code */
+ int pages = 0;
+
+ /* write out pages (if any) */
+ while(!x->x_eos)
+ {
+ int result=ogg_stream_pageout(&(x->x_os),&(x->x_og));
+ if(result==0)break;
+ err = send(fd, x->x_og.header, x->x_og.header_len, SEND_OPT);
+ if(err < 0)
+ {
+ error("oggcast~: could not send ogg header to server (%d)", err);
+ x->x_eos = 1; /* indicate (artificial) end of stream */
+ return err;
+ }
+ err = send(fd, x->x_og.body, x->x_og.body_len, SEND_OPT);
+ if(err < 0)
+ {
+ error("oggcast~: could not send ogg body to server (%d)", err);
+ x->x_eos = 1; /* indicate (artificial) end of stream */
+ return err;
+ }
+ pages++; /* count number of pages */
+ /* there might be more than one pages we have to send */
+ if(ogg_page_eos(&(x->x_og)))x->x_eos=1;
+ }
+ return (pages);
+}
+
+ /* ogg/vorbis decoder setup */
+static int oggcast_vorbis_init(t_oggcast *x)
+{
+ int err = -1;
+
+ x->x_eos = 0;
+ x->x_skip = 1; /* assume no resampling */
+ /* choose an encoding mode */
+ vorbis_info_init(&(x->x_vi));
+
+ if(x->x_samplerate != sys_getsr()) /* downsampling for Oliver (http://radiostudio.org) */
+ {
+ if(sys_getsr() / x->x_samplerate == 2.0)
+ {
+ post("oggcast~: downsampling from %.0f to %d Hz", sys_getsr(), x->x_samplerate);
+ x->x_skip = 2;
+ }
+ else if(sys_getsr() / x->x_samplerate == 4.0)
+ {
+ post("oggcast~: downsampling from %.0f to %d Hz", sys_getsr(), x->x_samplerate);
+ x->x_skip = 4;
+ }
+ else if(sys_getsr() / x->x_samplerate == 3.0)
+ {
+ post("oggcast~: downsampling from %.0f to %d Hz", sys_getsr(), x->x_samplerate);
+ x->x_skip = 3;
+ } else post("oggcast~: warning: resampling from %.0f to %d not supported", sys_getsr(), x->x_samplerate);
+ }
+ if(x->x_vbr == 1)
+ { /* quality based setting */
+ if(vorbis_encode_init_vbr(&(x->x_vi), x->x_channels, x->x_samplerate, x->x_quality))
+ {
+ post("oggcast~: ogg/vorbis mode initialisation failed: invalid parameters for quality");
+ vorbis_info_clear(&(x->x_vi));
+ return (-1);
+ }
+ }
+ else
+ { /* bitrate based setting */
+ if(vorbis_encode_init(&(x->x_vi), x->x_channels, x->x_samplerate, x->x_br_max*1024, x->x_br_nom*1024, x->x_br_min*1024))
+ {
+ post("oggcast~: ogg/vorbis mode initialisation failed: invalid parameters for quality");
+ vorbis_info_clear(&(x->x_vi));
+ return (-1);
+ }
+ }
+
+ /* add a comment */
+ vorbis_comment_init(&(x->x_vc));
+ vorbis_comment_add_tag(&(x->x_vc),"TITLE", x->x_bcname);
+ vorbis_comment_add_tag(&(x->x_vc),"ARTIST", x->x_bcartist);
+ vorbis_comment_add_tag(&(x->x_vc),"GENRE",x->x_bcgenre);
+ vorbis_comment_add_tag(&(x->x_vc),"DESCRIPTION", x->x_bcdescription);
+ vorbis_comment_add_tag(&(x->x_vc),"LOCATION",x->x_bclocation);
+ vorbis_comment_add_tag(&(x->x_vc),"PERFORMER",x->x_bcperformer);
+ vorbis_comment_add_tag(&(x->x_vc),"COPYRIGHT",x->x_bccopyright);
+ vorbis_comment_add_tag(&(x->x_vc),"CONTACT",x->x_bccontact);
+ vorbis_comment_add_tag(&(x->x_vc),"DATE",x->x_bcdate);
+ vorbis_comment_add_tag(&(x->x_vc),"ENCODER","oggcast~ v0.2 for pure-data");
+
+ /* set up the analysis state and auxiliary encoding storage */
+ vorbis_analysis_init(&(x->x_vd),&(x->x_vi));
+ vorbis_block_init(&(x->x_vd),&(x->x_vb));
+
+ /* set up our packet->stream encoder */
+ /* pick a random serial number; that way we can more likely build
+ chained streams just by concatenation */
+ srand(time(NULL));
+ ogg_stream_init(&(x->x_os),rand());
+
+ /* Vorbis streams begin with three headers; the initial header (with
+ most of the codec setup parameters) which is mandated by the Ogg
+ bitstream spec. The second header holds any comment fields. The
+ third header holds the bitstream codebook. We merely need to
+ make the headers, then pass them to libvorbis one at a time;
+ libvorbis handles the additional Ogg bitstream constraints */
+
+ {
+ ogg_packet header;
+ ogg_packet header_comm;
+ ogg_packet header_code;
+
+ vorbis_analysis_headerout(&(x->x_vd),&(x->x_vc),&header,&header_comm,&header_code);
+ ogg_stream_packetin(&(x->x_os),&header); /* automatically placed in its own page */
+ ogg_stream_packetin(&(x->x_os),&header_comm);
+ ogg_stream_packetin(&(x->x_os),&header_code);
+
+ /* We don't have to write out here, but doing so makes streaming
+ * much easier, so we do, flushing ALL pages. This ensures the actual
+ * audio data will start on a new page
+ *
+ * IceCast2 server will take this as a first info about our stream
+ */
+ while(!x->x_eos)
+ {
+ int result=ogg_stream_flush(&(x->x_os),&(x->x_og));
+ if(result==0)break;
+ err = send(x->x_fd, x->x_og.header, x->x_og.header_len, SEND_OPT);
+ if(err < 0)
+ {
+ error("oggcast~: could not send ogg header to server (%d)", err);
+ x->x_eos = 1; /* indicate end of stream */
+ return (-1);
+ }
+ err = send(x->x_fd, x->x_og.body, x->x_og.body_len, SEND_OPT);
+ if(err < 0)
+ {
+ error("oggcast~: could not send ogg body to server (%d)", err);
+ x->x_eos = 1; /* indicate end of stream */
+ return (-1);
+ }
+ }
+ }
+ return (0);
+}
+
+ /* deinit the ogg/vorbis decoder */
+static void oggcast_vorbis_deinit(t_oggcast *x)
+{
+ vorbis_analysis_wrote(&(x->x_vd),0);
+ /* get rid of remaining data in encoder, if any */
+ while(vorbis_analysis_blockout(&(x->x_vd),&(x->x_vb))==1)
+ {
+ vorbis_analysis(&(x->x_vb),NULL);
+ vorbis_bitrate_addblock(&(x->x_vb));
+
+ while(vorbis_bitrate_flushpacket(&(x->x_vd),&(x->x_op)))
+ {
+ ogg_stream_packetin(&(x->x_os),&(x->x_op));
+ oggcast_stream(x, x->x_fd);
+ }
+ }
+ /* clean up and exit. vorbis_info_clear() must be called last */
+ ogg_stream_clear(&(x->x_os));
+ vorbis_block_clear(&(x->x_vb));
+ vorbis_dsp_clear(&(x->x_vd));
+ vorbis_comment_clear(&(x->x_vc));
+ vorbis_info_clear(&(x->x_vi));
+}
+
+ /* encode ogg/vorbis and stream new data */
+static int oggcast_encode(t_oggcast *x, float *buf, int channels, int fifosize, int fd)
+{
+ unsigned short i, ch;
+ int err = 0;
+ int n, pages = 0;
+
+ /* expose the buffer to submit data */
+ float **inbuffer=vorbis_analysis_buffer(&(x->x_vd),READ * channels);
+
+ /* read from buffer */
+ for(n = 0; n < READ; n++) /* fill encode buffer */
+ {
+ for(ch = 0; ch < channels; ch++)
+ {
+ inbuffer[ch][n] = *buf++;
+ }
+ }
+ /* tell the library how much we actually submitted */
+ vorbis_analysis_wrote(&(x->x_vd),n);
+
+ /* vorbis does some data preanalysis, then divvies up blocks for
+ more involved (potentially parallel) processing. Get a single
+ block for encoding now */
+ while(vorbis_analysis_blockout(&(x->x_vd),&(x->x_vb))==1)
+ {
+ /* analysis, assume we want to use bitrate management */
+ vorbis_analysis(&(x->x_vb),NULL);
+ vorbis_bitrate_addblock(&(x->x_vb));
+
+ while(vorbis_bitrate_flushpacket(&(x->x_vd),&(x->x_op)))
+ {
+ /* weld the packet into the bitstream */
+ ogg_stream_packetin(&(x->x_os),&(x->x_op));
+ err = oggcast_stream(x, fd); /* stream packet to server */
+ if(err >= 0)
+ {
+ pages += err; /* count pages */
+ }
+ else return (err);
+ }
+ }
+ return (pages);
+}
+
+ /* connect to icecast2 server */
+static int oggcast_child_connect(char *hostname, char *mountpoint, t_int portno,
+ char *passwd, char *bcname, char *bcurl,
+ char *bcgenre, t_int bcpublic, t_int br_nom, t_int servertype)
+{
+ struct sockaddr_in server;
+ struct hostent *hp;
+
+ /* variables used for communication with server */
+ const char * buf = 0;
+ char resp[STRBUF_SIZE];
+ unsigned int len;
+ fd_set fdset;
+ struct timeval tv;
+ t_int sockfd; /* our internal handle for the socket */
+ t_int ret;
+
+ sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (sockfd < 0)
+ {
+ error("oggcast~: internal error while attempting to open socket");
+ return (-1);
+ }
+
+ /* connect socket using hostname provided in command line */
+ server.sin_family = AF_INET;
+ hp = gethostbyname(hostname);
+ if (hp == 0)
+ {
+ post("oggcast~: bad host?");
+ sys_closesocket(sockfd);
+ return (-1);
+ }
+ memcpy((char *)&server.sin_addr, (char *)hp->h_addr, hp->h_length);
+
+ /* assign client port number */
+ server.sin_port = htons((unsigned short)portno);
+
+ /* try to connect. */
+ post("oggcast~: connecting to port %d", portno);
+ if (connect(sockfd, (struct sockaddr *) &server, sizeof (server)) < 0)
+ {
+ error("oggcast~: connection failed!\n");
+ sys_closesocket(sockfd);
+ return (-1);
+ }
+
+ /* sheck if we can read/write from/to the socket */
+ FD_ZERO( &fdset);
+ FD_SET( sockfd, &fdset);
+ tv.tv_sec = 0; /* seconds */
+ tv.tv_usec = 500; /* microseconds */
+
+ ret = select(sockfd + 1, &fdset, NULL, NULL, &tv);
+ if(ret != 0)
+ {
+ error("oggcast~: can not read from socket");
+ sys_closesocket(sockfd);
+ return (-1);
+ }
+
+ post("oggcast~: logging in to IceCast2 server...");
+ /* now try to log in at IceCast2 server using ICE/1.0 scheme */
+ if(servertype == 0)
+ {
+ /* send the request, a string like: "SOURCE /<mountpoint> ICE/1.0\n" */
+ buf = "SOURCE ";
+ send(sockfd, buf, strlen(buf), SEND_OPT);
+ buf = "/";
+ send(sockfd, buf, strlen(buf), SEND_OPT);
+ buf = mountpoint;
+ send(sockfd, buf, strlen(buf), SEND_OPT);
+ buf = " ICE/1.0";
+ send(sockfd, buf, strlen(buf), SEND_OPT);
+ /* send the ice headers */
+ /* password */
+ buf = "\nice-password: ";
+ send(sockfd, buf, strlen(buf), SEND_OPT);
+ buf = passwd;
+ send(sockfd, buf, strlen(buf), SEND_OPT);
+ /* name */
+ buf = "\r\nice-name: ";
+ send(sockfd, buf, strlen(buf), SEND_OPT);
+ buf = bcname;
+ send(sockfd, buf, strlen(buf), SEND_OPT);
+ /* url */
+ buf = "\r\nice-url: ";
+ send(sockfd, buf, strlen(buf), SEND_OPT);
+ buf = bcurl;
+ send(sockfd, buf, strlen(buf), SEND_OPT);
+ /* genre */
+ buf = "\r\nice-genre: ";
+ send(sockfd, buf, strlen(buf), SEND_OPT);
+ buf = bcgenre;
+ send(sockfd, buf, strlen(buf), SEND_OPT);
+ /* public */
+ buf = "\r\nice-public: ";
+ send(sockfd, buf, strlen(buf), SEND_OPT);
+ if(bcpublic==0) /* set the public flag for broadcast */
+ {
+ buf = "no";
+ }
+ else
+ {
+ buf ="yes";
+ }
+ send(sockfd, buf, strlen(buf), SEND_OPT);
+ /* bitrate */
+ buf = "\r\nice-bitrate: ";
+ send(sockfd, buf, strlen(buf), SEND_OPT);
+ if(sprintf(resp, "%d", br_nom) == -1) /* convert int to a string */
+ {
+ error("oggcast~: wrong bitrate");
+ }
+ send(sockfd, resp, strlen(resp), SEND_OPT);
+ /* description */
+ buf = "\r\nice-description: ";
+ send(sockfd, buf, strlen(buf), SEND_OPT);
+ buf = "ogg/vorbis streamed from pure-data with oggcast~";
+ send(sockfd, buf, strlen(buf), SEND_OPT);
+ /* end of header */
+ buf = "\r\n\r\n";
+ send(sockfd, buf, strlen(buf), SEND_OPT);
+ /* end login for IceCast using ICE/1.0 scheme */
+ }
+ else /* or try to log in at IceCast2 server using HTTP/1.0 base auth scheme */
+ {
+ /* send the request, a string like: "SOURCE /<mountpoint> HTTP/1.0\n\r" */
+ buf = "SOURCE /";
+ send(sockfd, buf, strlen(buf), SEND_OPT);
+ buf = mountpoint;
+ send(sockfd, buf, strlen(buf), SEND_OPT);
+ buf = " HTTP/1.0\r\n";
+ send(sockfd, buf, strlen(buf), SEND_OPT);
+ /* send basic authorization */
+ sprintf(resp, "source:%s", passwd);
+ buf = oggcast_util_base64_encode(resp);
+ sprintf(resp, "Authorization: Basic %s\r\n", buf);
+ send(sockfd, resp, strlen(resp), SEND_OPT);
+ /* send content type */
+ buf = "Content-Type: application/x-ogg";
+ send(sockfd, buf, strlen(buf), SEND_OPT);
+ /* send the ice headers */
+ /* password */
+ buf = "\r\nice-password: ";
+ send(sockfd, buf, strlen(buf), SEND_OPT);
+ buf = passwd;
+ send(sockfd, buf, strlen(buf), SEND_OPT);
+ /* name */
+ buf = "\r\nice-name: ";
+ send(sockfd, buf, strlen(buf), SEND_OPT);
+ buf = bcname;
+ send(sockfd, buf, strlen(buf), SEND_OPT);
+ /* url */
+ buf = "\r\nice-url: ";
+ send(sockfd, buf, strlen(buf), SEND_OPT);
+ buf = bcurl;
+ send(sockfd, buf, strlen(buf), SEND_OPT);
+ /* genre */
+ buf = "\r\nice-genre: ";
+ send(sockfd, buf, strlen(buf), SEND_OPT);
+ buf = bcgenre;
+ send(sockfd, buf, strlen(buf), SEND_OPT);
+ /* public */
+ buf = "\r\nice-public: ";
+ send(sockfd, buf, strlen(buf), SEND_OPT);
+ if(bcpublic==0) /* set the public flag for broadcast */
+ {
+ buf = "0";
+ }
+ else
+ {
+ buf = "1";
+ }
+ send(sockfd, buf, strlen(buf), SEND_OPT);
+ /* bitrate */
+ buf = "\r\nice-bitrate: ";
+ send(sockfd, buf, strlen(buf), SEND_OPT);
+ if(sprintf(resp, "%d", br_nom) == -1) /* convert int to a string */
+ {
+ error("oggcast~: wrong bitrate");
+ }
+ send(sockfd, resp, strlen(resp), SEND_OPT);
+ /* description */
+ buf = "\r\nice-description: ";
+ send(sockfd, buf, strlen(buf), SEND_OPT);
+ buf = "Ogg/Vorbis streamed from PureData with oggcast~\r\n";
+ send(sockfd, buf, strlen(buf), SEND_OPT);
+ /* end of header: write an empty line */
+ buf = "\r\n";
+ send(sockfd, buf, strlen(buf), SEND_OPT);
+ /* end login for IceCast2 using ICE/1.0 scheme */
+ }
+
+ /* check if we can write to server */
+ if(oggcast_checkserver(sockfd)!= 0)
+ {
+ post("oggcast~: error: server refused to receive data");
+ return (-1);
+ }
+
+ post("oggcast~: logged in to http://%s:%d/%s", hp->h_name, portno, mountpoint);
+
+ return (sockfd);
+}
+
+
+
+static void oggcast_child_disconnect(t_int fd)
+{
+ sys_closesocket(fd);
+ post("oggcast~: connection closed");
+}
+/************** the child thread which performs data I/O ***********/
+
+#if 0 /* set this to 1 to get debugging output */
+static void pute(char *s) /* debug routine */
+{
+ write(2, s, strlen(s));
+}
+#else
+#define pute(x)
+#endif
+
+#if 1
+#define oggcast_cond_wait pthread_cond_wait
+#define oggcast_cond_signal pthread_cond_signal
+#else
+#include <sys/time.h> /* debugging version... */
+#include <sys/types.h>
+static void oggcast_fakewait(pthread_mutex_t *b)
+{
+ struct timeval timout;
+ timout.tv_sec = 0;
+ timout.tv_usec = 1000000;
+ pthread_mutex_unlock(b);
+ select(0, 0, 0, 0, &timout);
+ pthread_mutex_lock(b);
+}
+
+void oggcast_banana( void)
+{
+ struct timeval timout;
+ timout.tv_sec = 0;
+ timout.tv_usec = 200000;
+ pute("banana1\n");
+ select(0, 0, 0, 0, &timout);
+ pute("banana2\n");
+}
+
+
+#define oggcast_cond_wait(a,b) oggcast_fakewait(b)
+#define oggcast_cond_signal(a)
+#endif
+
+static void *oggcast_child_main(void *zz)
+{
+ t_oggcast *x = zz;
+ time_t now; /* to get the time */
+ pute("1\n");
+ pthread_mutex_lock(&x->x_mutex);
+ while (1)
+ {
+ int fd, fifotail;
+ pute("0\n");
+ if (x->x_requestcode == REQUEST_NOTHING)
+ {
+ pute("wait 2\n");
+ oggcast_cond_signal(&x->x_answercondition);
+ oggcast_cond_wait(&x->x_requestcondition, &x->x_mutex);
+ pute("3\n");
+ }
+ // connect to Icecast2 server
+ else if (x->x_requestcode == REQUEST_CONNECT)
+ {
+ char boo[100];
+ int sysrtn, wantbytes;
+
+ /* copy connect stuff out of the data structure so we can
+ relinquish the mutex while we're connecting to server. */
+ char *hostname = x->x_hostname;
+ char *mountpoint = x->x_mountpoint;
+ t_int portno = x->x_port;
+ char *passwd = x->x_passwd;
+ char *bcname = x->x_bcname;
+ char *bcgenre = x->x_bcgenre;
+ char *bcurl = x->x_bcurl;
+ t_int bcpublic = x->x_bcpublic;
+ t_int br_nom = x->x_br_nom;
+ t_int servertype = x->x_servertype;
+ /* alter the request code so that an ensuing "open" will get
+ noticed. */
+ pute("4\n");
+ x->x_requestcode = REQUEST_BUSY;
+ x->x_connecterror = 0;
+
+ /* open the socket with the mutex unlocked in case
+ we're not already connected */
+ if(x->x_fd < 0)
+ {
+ pthread_mutex_unlock(&x->x_mutex);
+ fd = oggcast_child_connect(hostname, mountpoint, portno, passwd, bcname,
+ bcurl, bcgenre, bcpublic, br_nom, servertype);
+ pthread_mutex_lock(&x->x_mutex);
+ pute("5\n");
+ /* copy back into the instance structure. */
+ x->x_connectstate = 1;
+ clock_delay(x->x_clock_connect, 0);
+ x->x_fd = fd;
+ if (fd < 0)
+ {
+ x->x_connecterror = fd;
+ x->x_connectstate = 0;
+ clock_delay(x->x_clock_connect, 0);
+ pute("connect failed\n");
+ goto lost;
+ }
+ else
+ {
+ /* get the time for the DATE comment */
+ now=time(NULL);
+ x->x_bcdate = ctime(&now);
+ x->x_pages = 0;
+ clock_delay(x->x_clock_pages, 0);
+ /* initialise the encoder */
+ if(oggcast_vorbis_init(x) == 0)
+ {
+ post("oggcast~: ogg/vorbis encoder initialised");
+ x->x_eos = 0;
+ x->x_state = STATE_STREAM;
+ }
+ else
+ {
+ post("oggcast~: could not init encoder");
+ oggcast_child_disconnect(fd);
+ post("oggcast~: connection closed due to initialisation error");
+ x->x_fd = -1;
+ x->x_connectstate = 0;
+ clock_delay(x->x_clock_connect, 0);
+ pute("oggcast~: initialisation failed\n");
+ goto lost;
+ }
+ }
+ x->x_fifotail = fifotail = 0;
+ /* set fifosize from bufsize. fifosize must be a
+ multiple of the number of bytes eaten for each DSP
+ tick. We pessimistically assume MAXVECSIZE samples
+ per tick since that could change. There could be a
+ problem here if the vector size increases while a
+ stream is being played... */
+ x->x_fifosize = x->x_bufsize - (x->x_bufsize % (x->x_channels * READ));
+ /* arrange for the "request" condition to be signalled x->x_siginterval
+ times per buffer */
+ sprintf(boo, "fifosize %d\n", x->x_fifosize);
+ pute(boo);
+ x->x_sigcountdown = x->x_sigperiod = (x->x_fifosize / (x->x_siginterval * x->x_channels * x->x_vecsize));
+ }
+ /* check if another request has been made; if so, field it */
+ if (x->x_requestcode != REQUEST_BUSY)
+ goto lost;
+ pute("6\n");
+
+ while (x->x_requestcode == REQUEST_BUSY)
+ {
+ int fifosize = x->x_fifosize, fifotail, channels;
+ float *buf = x->x_buf;
+ pute("77\n");
+
+ /* if the head is < the tail, we can immediately write
+ from tail to end of fifo to disk; otherwise we hold off
+ writing until there are at least WRITESIZE bytes in the
+ buffer */
+ if (x->x_fifohead < x->x_fifotail ||
+ x->x_fifohead >= x->x_fifotail + (READ * x->x_channels)
+ || (x->x_requestcode == REQUEST_CLOSE &&
+ x->x_fifohead != x->x_fifotail))
+ { /* encode audio and send to server */
+ pute("8\n");
+ fifotail = x->x_fifotail;
+ channels = x->x_channels;
+ fd = x->x_fd;
+ pthread_mutex_unlock(&x->x_mutex);
+ sysrtn = oggcast_encode(x, buf + fifotail, channels, fifosize, fd);
+ pthread_mutex_lock(&x->x_mutex);
+ if (x->x_requestcode != REQUEST_BUSY &&
+ x->x_requestcode != REQUEST_CLOSE)
+ break;
+ if (sysrtn < 0)
+ {
+ post("oggcast~: closing due to error...");
+ goto lost;
+ }
+ else
+ {
+ x->x_fifotail += (READ * x->x_channels);
+ x->x_pages += sysrtn;
+ if (x->x_fifotail >= fifosize)
+ x->x_fifotail = 0;
+ }
+ sprintf(boo, "after: head %d, tail %d, pages %d\n", x->x_fifohead, x->x_fifotail, sysrtn);
+ pute(boo);
+ }
+ else /* just wait... */
+ {
+ pute("wait 7a ...\n");
+ oggcast_cond_signal(&x->x_answercondition);
+ pute("signalled\n");
+ oggcast_cond_wait(&x->x_requestcondition,
+ &x->x_mutex);
+ pute("7a done\n");
+ continue;
+ }
+ /* signal parent in case it's waiting for data */
+ oggcast_cond_signal(&x->x_answercondition);
+ }
+ }
+
+ /* reinit encoder (settings have changed) */
+ else if (x->x_requestcode == REQUEST_REINIT)
+ {
+ pthread_mutex_unlock(&x->x_mutex);
+ oggcast_vorbis_deinit(x);
+ oggcast_vorbis_init(x);
+ pthread_mutex_lock(&x->x_mutex);
+ post("oggcast~: ogg/vorbis encoder reinitialised");
+ x->x_state = STATE_STREAM;
+ if (x->x_requestcode == REQUEST_REINIT)
+ x->x_requestcode = REQUEST_CONNECT;
+ oggcast_cond_signal(&x->x_answercondition);
+ }
+ /* close connection to server (disconnect) */
+ else if (x->x_requestcode == REQUEST_CLOSE)
+ {
+lost:
+ x->x_state = STATE_IDLE;
+ if (x->x_fd >= 0)
+ {
+ fd = x->x_fd;
+ pthread_mutex_unlock(&x->x_mutex);
+ oggcast_vorbis_deinit(x);
+ oggcast_child_disconnect(fd);
+ pthread_mutex_lock(&x->x_mutex);
+ x->x_fd = -1;
+ }
+ if (x->x_requestcode == REQUEST_CLOSE)
+ x->x_requestcode = REQUEST_NOTHING;
+ if (x->x_requestcode == REQUEST_BUSY) /* disconnect due to error */
+ x->x_requestcode = REQUEST_NOTHING;
+ x->x_connectstate = 0;
+ clock_delay(x->x_clock_connect, 0);
+ x->x_eos = 1;
+ oggcast_cond_signal(&x->x_answercondition);
+ }
+ // quit everything
+ else if (x->x_requestcode == REQUEST_QUIT)
+ {
+ x->x_state = STATE_IDLE;
+ if (x->x_fd >= 0)
+ {
+ fd = x->x_fd;
+ pthread_mutex_unlock(&x->x_mutex);
+ oggcast_vorbis_deinit(x);
+ oggcast_child_disconnect(fd);
+ pthread_mutex_lock(&x->x_mutex);
+ x->x_fd = -1;
+ }
+ x->x_connectstate = 0;
+ clock_delay(x->x_clock_connect, 0);
+ x->x_requestcode = REQUEST_NOTHING;
+ oggcast_cond_signal(&x->x_answercondition);
+ break;
+ }
+ else
+ {
+ pute("13\n");
+ }
+ }
+ pute("thread exit\n");
+ pthread_mutex_unlock(&x->x_mutex);
+ return (0);
+}
+
+/******** the object proper runs in the calling (parent) thread ****/
+
+static void oggcast_tick_connect(t_oggcast *x)
+{
+ pthread_mutex_lock(&x->x_mutex);
+ outlet_float(x->x_connection, x->x_connectstate);
+ pthread_mutex_unlock(&x->x_mutex);
+}
+
+static void oggcast_tick_pages(t_oggcast *x)
+{
+ /* output new no. of pages if anything changed */
+ t_float pages;
+ pthread_mutex_lock(&x->x_mutex);
+ pages = x->x_pages; /* get current value with mutex locked */
+ pthread_mutex_unlock(&x->x_mutex);
+ if(pages != x->x_lastpages)
+ {
+ outlet_float(x->x_outpages, pages);
+ x->x_lastpages = pages;
+ }
+ clock_delay(x->x_clock_pages, UPDATE_INTERVAL); /* come back again... */
+}
+
+static void *oggcast_new(t_floatarg fnchannels, t_floatarg fbufsize)
+{
+ t_oggcast *x;
+ int nchannels = fnchannels, bufsize = fbufsize * 1024, i;
+ float *buf;
+
+ if (nchannels < 1)
+ nchannels = 2; /* two channels as default */
+ else if (nchannels > MAXSTREAMCHANS)
+ nchannels = MAXSTREAMCHANS;
+ /* check / set buffer size */
+ if (bufsize <= 0) bufsize = DEFBUFPERCHAN * nchannels;
+ else if (bufsize < MINBUFSIZE)
+ bufsize = MINBUFSIZE;
+ else if (bufsize > MAXBUFSIZE)
+ bufsize = MAXBUFSIZE;
+ buf = getbytes(bufsize*sizeof(t_float));
+ if (!buf) return (0);
+
+ x = (t_oggcast *)pd_new(oggcast_class);
+
+ for (i = 1; i < nchannels; i++)
+ inlet_new (&x->x_obj, &x->x_obj.ob_pd, gensym ("signal"), gensym ("signal"));
+ x->x_connection = outlet_new(&x->x_obj, gensym("float"));
+ x->x_outpages = outlet_new(&x->x_obj, gensym("float"));
+ x->x_ninlets = nchannels;
+ x->x_outvec = getbytes(nchannels*sizeof(t_sample *));
+ x->x_clock_connect = clock_new(x, (t_method)oggcast_tick_connect);
+ x->x_clock_pages = clock_new(x, (t_method)oggcast_tick_pages);
+
+ pthread_mutex_init(&x->x_mutex, 0);
+ pthread_cond_init(&x->x_requestcondition, 0);
+ pthread_cond_init(&x->x_answercondition, 0);
+
+ x->x_vecsize = 2;
+ x->x_state = STATE_IDLE;
+ x->x_buf = buf;
+ x->x_bufsize = bufsize;
+ x->x_siginterval = 32; /* signal 32 times per buffer */
+ /* I found this to be most efficient on my machine */
+ x->x_fifosize = x->x_fifohead = x->x_fifotail = x->x_requestcode = 0;
+
+ x->x_connectstate = 0; /* indicating state of connection */
+ x->x_outvalue = 0; /* value at output currently is 0 */
+
+ x->x_samplerate = sys_getsr();
+ x->x_resample.upsample = x->x_resample.downsample = 1; /* don't resample */
+
+
+ x->x_fd = -1;
+ x->x_eos = 0;
+ x->x_vbr = 1; /* use the vbr setting by default */
+ x->x_passwd = "letmein";
+ x->x_samplerate = sys_getsr(); /* default to Pd's sampling rate */
+ x->x_skip = 1; /* no resampling supported */
+ x->x_quality = 0.4; /* quality 0.4 gives roughly 128kbps VBR stream */
+ x->x_channels = nchannels; /* stereo */
+ x->x_br_max = 144;
+ x->x_br_nom = 128;
+ x->x_br_min = 96;
+ x->x_pages = x->x_lastpages = 0;
+ x->x_bcname = "ogg/vorbis stream";
+ x->x_bcurl = "http://www.akustische-kunst.org/puredata/";
+ x->x_bcgenre = "experimental";
+ x->x_bcdescription = "ogg/vorbis stream emitted from pure-data with oggcast~";
+ x->x_bcartist = "Pd and oggcast~ v0.2";
+ x->x_bclocation = x->x_bcurl;
+ x->x_bccopyright = "";
+ x->x_bcperformer = "";
+ x->x_bccontact = "";
+ x->x_bcdate = "";
+ x->x_bcpublic = 1;
+ x->x_mountpoint = "puredata.ogg";
+ x->x_servertype = 1; /* HTTP/1.0 protocol for Icecast2 */
+
+ post(oggcast_version);
+ post("oggcast~: set buffer to %dk bytes", bufsize / 1024);
+ post("oggcast~: encoding %d channels @ %d Hz", x->x_channels, x->x_samplerate);
+
+ clock_delay(x->x_clock_pages, 0);
+ pthread_create(&x->x_childthread, 0, oggcast_child_main, x);
+ return (x);
+}
+
+static t_int *oggcast_perform(t_int *w)
+{
+ t_oggcast *x = (t_oggcast *)(w[1]);
+ int vecsize = x->x_vecsize, ninlets = x->x_ninlets, channels = x->x_channels, i, j, skip = x->x_skip;
+ float *sp = x->x_buf;
+ pthread_mutex_lock(&x->x_mutex);
+ if (x->x_state != STATE_IDLE)
+ {
+ int wantbytes;
+ /* get 'wantbytes' bytes from inlet */
+ wantbytes = channels * vecsize / skip; /* we'll get vecsize bytes per channel */
+ /* check if there is enough space in buffer to write all samples */
+ while (x->x_fifotail > x->x_fifohead &&
+ x->x_fifotail < x->x_fifohead + wantbytes + 1)
+ {
+ pute("wait...\n");
+ oggcast_cond_signal(&x->x_requestcondition);
+ oggcast_cond_wait(&x->x_answercondition, &x->x_mutex);
+ pute("done\n");
+ }
+
+ /* output audio */
+ sp += x->x_fifohead;
+
+ if(ninlets >= channels)
+ {
+ for(j = 0; j < vecsize; j += skip)
+ {
+ for(i = 0; i < channels; i++)
+ {
+ *sp++ = x->x_outvec[i][j];
+ }
+ }
+ }
+ else if(channels == ninlets * 2) /* convert mono -> stereo */
+ {
+ for(j = 0; j < vecsize; j += skip)
+ {
+ for(i = 0; i < ninlets; i++)
+ {
+ *sp++ = x->x_outvec[i][j];
+ *sp++ = x->x_outvec[i][j];
+ }
+ }
+ }
+
+
+ x->x_fifohead += wantbytes;
+ if (x->x_fifohead >= x->x_fifosize)
+ x->x_fifohead = 0;
+ /* signal the child thread */
+ if ((--x->x_sigcountdown) <= 0)
+ {
+ pute("signal 1\n");
+ oggcast_cond_signal(&x->x_requestcondition);
+ x->x_sigcountdown = x->x_sigperiod;
+ }
+ }
+
+ pthread_mutex_unlock(&x->x_mutex);
+
+ return (w+2);
+}
+
+
+static void oggcast_disconnect(t_oggcast *x)
+{
+ /* LATER rethink whether you need the mutex just to set a variable? */
+ pthread_mutex_lock(&x->x_mutex);
+ if(x->x_fd >= 0)
+ {
+ x->x_state = STATE_IDLE;
+ x->x_requestcode = REQUEST_CLOSE;
+ oggcast_cond_signal(&x->x_requestcondition);
+ }
+ else post("oggcast~: not connected");
+ pthread_mutex_unlock(&x->x_mutex);
+}
+
+
+ /* connect method. Called as:
+ connect <hostname or IP> <mountpoint> <portnumber>
+ */
+
+static void oggcast_connect(t_oggcast *x, t_symbol *s, int argc, t_atom *argv)
+{
+ t_symbol *hostsym = atom_getsymbolarg(0, argc, argv);
+ t_symbol *mountsym = atom_getsymbolarg(1, argc, argv);
+ t_float portno = atom_getfloatarg(2, argc, argv);
+ if (!*hostsym->s_name) /* check for hostname */
+ return;
+ if (!portno) /* check wether the portnumber is specified */
+ portno = 8000; /* ...assume port 8000 as standard */
+ pthread_mutex_lock(&x->x_mutex);
+ if(x->x_fd >= 0)
+ {
+ post("oggcast~: already connected");
+ }
+ else
+ {
+ x->x_requestcode = REQUEST_CONNECT;
+ x->x_hostname = hostsym->s_name;
+ x->x_mountpoint = mountsym->s_name;
+ x->x_port = portno;
+
+ x->x_fifotail = 0;
+ x->x_fifohead = 0;
+ // if(x->x_recover != 1)x->x_fifobytes = 0;
+
+ x->x_connecterror = 0;
+ x->x_state = STATE_STARTUP;
+ oggcast_cond_signal(&x->x_requestcondition);
+ }
+ pthread_mutex_unlock(&x->x_mutex);
+}
+
+static void oggcast_float(t_oggcast *x, t_floatarg f)
+{
+ if (f != 0)
+ {
+ pthread_mutex_lock(&x->x_mutex);
+ if(x->x_fd >= 0)
+ {
+ post("oggcast~: already connected");
+ }
+ else
+ {
+ if(x->x_recover != 1)
+ {
+ x->x_fifotail = 0;
+ x->x_fifohead = 0;
+ }
+ x->x_requestcode = REQUEST_CONNECT;
+
+ x->x_fifotail = 0;
+ x->x_fifohead = 0;
+
+ x->x_connecterror = 0;
+ x->x_state = STATE_STARTUP;
+ oggcast_cond_signal(&x->x_requestcondition);
+ }
+ pthread_mutex_unlock(&x->x_mutex);
+ }
+ else oggcast_disconnect(x);
+}
+
+static void oggcast_dsp(t_oggcast *x, t_signal **sp)
+{
+ int i, ninlets = x->x_ninlets;
+ pthread_mutex_lock(&x->x_mutex);
+ x->x_vecsize = sp[0]->s_n;
+
+ x->x_sigperiod = (x->x_fifosize / (x->x_siginterval * ninlets * x->x_vecsize));
+ for (i = 0; i < ninlets; i++)
+ x->x_outvec[i] = sp[i]->s_vec;
+ pthread_mutex_unlock(&x->x_mutex);
+ dsp_add(oggcast_perform, 1, x);
+}
+
+ /* set password for oggcast server */
+static void oggcast_password(t_oggcast *x, t_symbol *password)
+{
+ pthread_mutex_lock(&x->x_mutex);
+ x->x_passwd = password->s_name;
+ pthread_mutex_unlock(&x->x_mutex);
+}
+ /* set comment fields for header (reads in just anything) */
+static void oggcast_comment(t_oggcast *x, t_symbol *s, t_int argc, t_atom* argv)
+{
+ t_binbuf *b = binbuf_new();
+ char* comment;
+ int length;
+ binbuf_add(b, argc, argv);
+ binbuf_gettext(b, &comment, &length);
+
+ pthread_mutex_lock(&x->x_mutex);
+ if(strstr(s->s_name, "ARTIST"))
+ {
+ strcpy(x->x_bcartist, comment);
+ post("oggcast~: ARTIST = %s", x->x_bcartist);
+ }
+ else if(strstr(s->s_name, "GENRE"))
+ {
+ strcpy(x->x_bcgenre, comment);
+ post("oggcast~: GENRE = %s", x->x_bcgenre);
+ }
+ else if(strstr(s->s_name, "TITLE"))
+ {
+ strcpy(x->x_bcname, comment);
+ post("oggcast~: TITLE = %s", x->x_bcname);
+ }
+ else if(strstr(s->s_name, "PERFORMER"))
+ {
+ strcpy(x->x_bcperformer, comment);
+ post("oggcast~: PERFORMER = %s", x->x_bcperformer);
+ }
+ else if(strstr(s->s_name, "LOCATION"))
+ {
+ strcpy(x->x_bclocation, comment);
+ post("oggcast~: LOCATION = %s", x->x_bclocation);
+ }
+ else if(strstr(s->s_name, "COPYRIGHT"))
+ {
+ strcpy(x->x_bccopyright, comment);
+ post("oggcast~: COPYRIGHT = %s", x->x_bccopyright);
+ }
+ else if(strstr(s->s_name, "CONTACT"))
+ {
+ strcpy(x->x_bccontact, comment);
+ post("oggcast~: CONTACT = %s", x->x_bccontact);
+ }
+ else if(strstr(s->s_name, "DESCRIPTION"))
+ {
+ strcpy(x->x_bcdescription, comment);
+ post("oggcast~: DESCRIPTION = %s", x->x_bcdescription);
+ }
+ else if(strstr(s->s_name, "DATE"))
+ {
+ strcpy(x->x_bcdate, comment);
+ post("oggcast~: DATE = %s", x->x_bcdate);
+ }
+ else post("oggcast~: no method for %s", s->s_name);
+ if(x->x_state == STATE_STREAM)
+ {
+ x->x_state = STATE_IDLE;
+ x->x_requestcode = REQUEST_REINIT;
+ oggcast_cond_signal(&x->x_requestcondition);
+ }
+ pthread_mutex_unlock(&x->x_mutex);
+ freebytes(comment, strlen(comment));
+ binbuf_free(b);
+}
+ /* settings for variable bitrate encoding */
+static void oggcast_vbr(t_oggcast *x, t_floatarg fsr, t_floatarg fchannels,
+ t_floatarg fquality)
+{
+ pthread_mutex_lock(&x->x_mutex);
+ x->x_vbr = 1;
+ x->x_samplerate = (t_int)fsr;
+ x->x_quality = fquality;
+ x->x_channels = (t_int)fchannels;
+ post("oggcast~: %d channels @ %d Hz, quality %.2f", x->x_channels, x->x_samplerate, x->x_quality);
+ if(x->x_state == STATE_STREAM)
+ {
+ x->x_state = STATE_IDLE;
+ x->x_requestcode = REQUEST_REINIT;
+ oggcast_cond_signal(&x->x_requestcondition);
+ }
+ pthread_mutex_unlock(&x->x_mutex);
+}
+
+ /* settings for bitrate-based vbr encoding */
+static void oggcast_vorbis(t_oggcast *x, t_floatarg fsr, t_floatarg fchannels,
+ t_floatarg fmax, t_floatarg fnom, t_floatarg fmin)
+{
+ pthread_mutex_lock(&x->x_mutex);
+ x->x_vbr = 0;
+ x->x_samplerate = (t_int)fsr;
+ x->x_channels = (t_int)fchannels;
+ x->x_br_max = (t_int)fmax;
+ x->x_br_nom = (t_int)fnom;
+ x->x_br_min = (t_int)fmin;
+ post("oggcast~: %d channels @ %d Hz, bitrates: max. %d / nom. %d / min. %d",
+ x->x_channels, x->x_samplerate, x->x_br_max, x->x_br_nom, x->x_br_min);
+ if(x->x_state == STATE_STREAM)
+ {
+ x->x_state = STATE_IDLE;
+ x->x_requestcode = REQUEST_REINIT;
+ oggcast_cond_signal(&x->x_requestcondition);
+ }
+ pthread_mutex_unlock(&x->x_mutex);
+}
+ /* select server type */
+static void oggcast_server(t_oggcast *x, t_floatarg f)
+{
+ pthread_mutex_lock(&x->x_mutex);
+ if(f)
+ {
+ x->x_servertype = 1;
+ post("oggcast~: set server type to new Icecast2 (HTTP/1.0 scheme)");
+ }
+ else
+ {
+ x->x_servertype = 0;
+ post("oggcast~: set server type to JRoar (ICE/1.0 scheme)");
+ }
+ pthread_mutex_unlock(&x->x_mutex);
+}
+ /* print settings to pd's console window */
+static void oggcast_print(t_oggcast *x)
+{
+ pthread_mutex_lock(&x->x_mutex);
+ if(x->x_servertype)
+ post("oggcast~: server type is Icecast2");
+ else
+ post("oggcast~: server type is JRoar");
+ post("oggcast~: mountpoint at Icecast2: %s", x->x_mountpoint);
+ if(x->x_vbr == 1)
+ {
+ post("oggcast~: Ogg Vorbis encoder: %d channels @ %d Hz, quality %.2f", x->x_channels, x->x_samplerate, x->x_quality);
+ }
+ else
+ {
+ post("oggcast~: Ogg Vorbis encoder: %d channels @ %d Hz, bitrates: max. %d, nom. %d, min. %d",
+ x->x_channels, x->x_samplerate, x->x_br_max, x->x_br_nom, x->x_br_min);
+ }
+ post("oggcast~: Ogg Vorbis comments:");
+ post(" TITLE = %s", x->x_bcname);
+ post(" ARTIST = %s", x->x_bcartist);
+ post(" PERFORMER = %s", x->x_bcperformer);
+ post(" GENRE = %s", x->x_bcgenre);
+ post(" LOCATION = %s", x->x_bclocation);
+ post(" COPYRIGHT = %s", x->x_bccopyright);
+ post(" CONTACT = %s", x->x_bccontact);
+ post(" DESCRIPTION = %s", x->x_bcdescription);
+ post(" DATE = %s", x->x_bcdate);
+ pthread_mutex_unlock(&x->x_mutex);
+}
+
+
+static void oggcast_free(t_oggcast *x)
+{
+ /* request QUIT and wait for acknowledge */
+ void *threadrtn;
+ pthread_mutex_lock(&x->x_mutex);
+ x->x_requestcode = REQUEST_QUIT;
+ post("stopping oggcast thread...");
+ oggcast_cond_signal(&x->x_requestcondition);
+ while (x->x_requestcode != REQUEST_NOTHING)
+ {
+ post("signalling...");
+ oggcast_cond_signal(&x->x_requestcondition);
+ oggcast_cond_wait(&x->x_answercondition, &x->x_mutex);
+ }
+ pthread_mutex_unlock(&x->x_mutex);
+ if (pthread_join(x->x_childthread, &threadrtn))
+ error("oggcast_free: join failed");
+ post("... done.");
+
+ pthread_cond_destroy(&x->x_requestcondition);
+ pthread_cond_destroy(&x->x_answercondition);
+ pthread_mutex_destroy(&x->x_mutex);
+ freebytes(x->x_buf, x->x_bufsize*sizeof(t_float));
+ freebytes(x->x_outvec, x->x_ninlets*sizeof(t_sample *));
+ clock_free(x->x_clock_connect);
+ clock_free(x->x_clock_pages);
+}
+
+void oggcast_tilde_setup(void)
+{
+ oggcast_class = class_new(gensym("oggcast~"), (t_newmethod)oggcast_new,
+ (t_method)oggcast_free, sizeof(t_oggcast), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
+ CLASS_MAINSIGNALIN(oggcast_class, t_oggcast, x_f );
+ class_addfloat(oggcast_class, (t_method)oggcast_float);
+ class_addmethod(oggcast_class, (t_method)oggcast_disconnect, gensym("disconnect"), 0);
+ class_addmethod(oggcast_class, (t_method)oggcast_dsp, gensym("dsp"), 0);
+ class_addmethod(oggcast_class, (t_method)oggcast_connect, gensym("connect"), A_GIMME, 0);
+ class_addmethod(oggcast_class, (t_method)oggcast_print, gensym("print"), 0);
+ class_addmethod(oggcast_class, (t_method)oggcast_password, gensym("passwd"), A_SYMBOL, 0);
+ class_addmethod(oggcast_class, (t_method)oggcast_vorbis, gensym("vorbis"), A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
+ class_addmethod(oggcast_class, (t_method)oggcast_vbr, gensym("vbr"), A_FLOAT, A_FLOAT, A_FLOAT, 0);
+ class_addmethod(oggcast_class, (t_method)oggcast_server, gensym("server"), A_FLOAT, 0);
+ class_addanything(oggcast_class, oggcast_comment);
+ class_sethelpsymbol(oggcast_class, gensym("help-oggcast~.pd"));
+}
\ No newline at end of file diff --git a/oggcast~/readme b/oggcast~/readme index 0f6b84b..b3090ec 100644 --- a/oggcast~/readme +++ b/oggcast~/readme @@ -1,116 +1,116 @@ -Version 0.2 -copyright (c) 2002 by Olaf Matthes - -oggcast~ is a ogg/vorbis streaming external for pd (by Miller -Puckette) that connects to an IceCast2 server. - - -To run oggcast~ place the file oggcast~.dll for win or oggcast~.pd_linux -in the directory of our patch or start pd with '-lib oggcast~' flag. - -To compile oggcast~ on Linux get the ogg/vorbice library from -http://www.vorbis.com/. -You have to modify the makefile to make it point to the place where the -ogg/vorbis library is. - - -This software is published under LGPL terms. - -This is software with ABSOLUTELY NO WARRANTY. -Use it at your OWN RISK. It's possible to damage e.g. hardware or your hearing -due to a bug or for other reasons. - -***************************************************************************** - -oggcast~ uses the ogg/vorbice library to encode audio data. -The latest version of ogg/vorbis can be found at http://www.vorbice.com/ - -Below is the original copyright information taken from the ogg/vorbis library: - - -Copyright (c) 2001, Xiphophorus - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - -- Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - -- Redistributions in binary form must reproduce the above copyright -notice, this list of conditions and the following disclaimer in the -documentation and/or other materials provided with the distribution. - -- Neither the name of the Xiphophorus nor the names of its contributors -may be used to endorse or promote products derived from this software -without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR -CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -***************************************************************************** - -Usage: - -Use message "vbr <samplerate> <channels> <quality>" to set the vorbis -encoding parameters. Resampling is currently not supported, so 'samplerate' -should be the one pd is running at. 'channels' specyfies the number of channels -to stream. This can be set to 2 (default) or 1 which means mono stream taking -the leftmost audio input only. 'quality' can be a value between 0.0 and 1.0 -giving the quality of the stream. 0.4 (default) results in a stream that's -about 128kbps. - -Since Vorbis uses VBR encoding, bitrates vary depending on the type of audio -signal to be encoded. A pure sine [osc~] results in the smalest stream, com- -plex audio signals will increase this value significantly. To test the maximum -bitrate that might occur for a quality setting use noise~ as signal input. - -Use message "vorbis <samplerate> <channels> <maximum bitrate> <nominal bit- -rate> <minimal bitrate>" to set encoding quality on the basis of bitrates. -When setting all three bitrate parameters to the same value one gets a -constant bitrate stream. Values are in kbps! - -Message "connect <host> <mountpoint> <port>" connects to the IceCast2 server. -Note that no response about succesfull connection is send by the server. All -messages in the pd console window about connection status depend on the ability -to send data to the server. -The mountpoint should end with '.ogg' to indiocate to the player/client that -it is an ogg/vorbis encoded stream. - -Use "passwd <passwort>" to set your password (default is 'letmein') and -"disconnect" to disconnect from the server. "print" prints out the current -vorbis encoder settings. - -To set the comment tags in the ogg/vorbis header (which can be displayed by -the receiving client) use message "<NAMEOFTAG> <comment>". Supported tags are: -TITLE, ARTIST, GENRE, PERFORMER, LOCATION, COPYRIGHT, CONTACT, DESCRIPTION and -DATE (which is automatically set to the date/time the broadcast started). To -get spaces use '=' or '_' instead. Note that under Win2k '=' sometimes get lost -from the patch after saving!!! - - -Listening to it: - -To listen to ogg/vorbis encoded livestreams many player need an extra plug-in. -Have a look at http://www.vorbis.com/ to find the appropiate plug-in for your -player. -To play back the stream just open lacation http://<server>:<port>/<mountpoint>. - -Note that changing encoding parameters or header comments while oggcast~ is -streaming to the server might result in audible dropouts. - - - -Latest version can be found at: -http://www.akustische-kunst.de/puredata/ - +Version 0.2
+copyright (c) 2002 by Olaf Matthes
+
+oggcast~ is a ogg/vorbis streaming external for pd (by Miller
+Puckette) that connects to an IceCast2 server.
+
+
+To run oggcast~ place the file oggcast~.dll for win or oggcast~.pd_linux
+in the directory of our patch or start pd with '-lib oggcast~' flag.
+
+To compile oggcast~ on Linux get the ogg/vorbice library from
+http://www.vorbis.com/.
+You have to modify the makefile to make it point to the place where the
+ogg/vorbis library is.
+
+
+This software is published under LGPL terms.
+
+This is software with ABSOLUTELY NO WARRANTY.
+Use it at your OWN RISK. It's possible to damage e.g. hardware or your hearing
+due to a bug or for other reasons.
+
+*****************************************************************************
+
+oggcast~ uses the ogg/vorbice library to encode audio data.
+The latest version of ogg/vorbis can be found at http://www.vorbice.com/
+
+Below is the original copyright information taken from the ogg/vorbis library:
+
+
+Copyright (c) 2001, Xiphophorus
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+- Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+
+- Neither the name of the Xiphophorus nor the names of its contributors
+may be used to endorse or promote products derived from this software
+without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*****************************************************************************
+
+Usage:
+
+Use message "vbr <samplerate> <channels> <quality>" to set the vorbis
+encoding parameters. Resampling is currently not supported, so 'samplerate'
+should be the one pd is running at. 'channels' specyfies the number of channels
+to stream. This can be set to 2 (default) or 1 which means mono stream taking
+the leftmost audio input only. 'quality' can be a value between 0.0 and 1.0
+giving the quality of the stream. 0.4 (default) results in a stream that's
+about 128kbps.
+
+Since Vorbis uses VBR encoding, bitrates vary depending on the type of audio
+signal to be encoded. A pure sine [osc~] results in the smalest stream, com-
+plex audio signals will increase this value significantly. To test the maximum
+bitrate that might occur for a quality setting use noise~ as signal input.
+
+Use message "vorbis <samplerate> <channels> <maximum bitrate> <nominal bit-
+rate> <minimal bitrate>" to set encoding quality on the basis of bitrates.
+When setting all three bitrate parameters to the same value one gets a
+constant bitrate stream. Values are in kbps!
+
+Message "connect <host> <mountpoint> <port>" connects to the IceCast2 server.
+Note that no response about succesfull connection is send by the server. All
+messages in the pd console window about connection status depend on the ability
+to send data to the server.
+The mountpoint should end with '.ogg' to indiocate to the player/client that
+it is an ogg/vorbis encoded stream.
+
+Use "passwd <passwort>" to set your password (default is 'letmein') and
+"disconnect" to disconnect from the server. "print" prints out the current
+vorbis encoder settings.
+
+To set the comment tags in the ogg/vorbis header (which can be displayed by
+the receiving client) use message "<NAMEOFTAG> <comment>". Supported tags are:
+TITLE, ARTIST, GENRE, PERFORMER, LOCATION, COPYRIGHT, CONTACT, DESCRIPTION and
+DATE (which is automatically set to the date/time the broadcast started). To
+get spaces use '=' or '_' instead. Note that under Win2k '=' sometimes get lost
+from the patch after saving!!!
+
+
+Listening to it:
+
+To listen to ogg/vorbis encoded livestreams many player need an extra plug-in.
+Have a look at http://www.vorbis.com/ to find the appropiate plug-in for your
+player.
+To play back the stream just open lacation http://<server>:<port>/<mountpoint>.
+
+Note that changing encoding parameters or header comments while oggcast~ is
+streaming to the server might result in audible dropouts.
+
+
+
+Latest version can be found at:
+http://www.akustische-kunst.de/puredata/
+
Please report any bugs to olaf.matthes@gmx.de!
\ No newline at end of file diff --git a/oggcast~/vorbisenc.h b/oggcast~/vorbisenc.h index 1fc8913..dce0f38 100644 --- a/oggcast~/vorbisenc.h +++ b/oggcast~/vorbisenc.h @@ -1,93 +1,93 @@ -/******************************************************************** - * * - * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * - * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * - * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * - * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * - * * - * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2001 * - * by the XIPHOPHORUS Company http://www.xiph.org/ * - * * - ******************************************************************** - - function: vorbis encode-engine setup - last mod: $Id: vorbisenc.h,v 1.2 2003-04-23 10:36:25 xovo Exp $ - - ********************************************************************/ - -#ifndef _OV_ENC_H_ -#define _OV_ENC_H_ - -#ifdef __cplusplus -extern "C" -{ -#endif /* __cplusplus */ - -#include "codec.h" - -extern int vorbis_encode_init(vorbis_info *vi, - long channels, - long rate, - - long max_bitrate, - long nominal_bitrate, - long min_bitrate); - -extern int vorbis_encode_setup_managed(vorbis_info *vi, - long channels, - long rate, - - long max_bitrate, - long nominal_bitrate, - long min_bitrate); - -extern int vorbis_encode_setup_vbr(vorbis_info *vi, - long channels, - long rate, - - float /* quality level from 0. (lo) to 1. (hi) */ - ); - -extern int vorbis_encode_init_vbr(vorbis_info *vi, - long channels, - long rate, - - float base_quality /* quality level from 0. (lo) to 1. (hi) */ - ); - -extern int vorbis_encode_setup_init(vorbis_info *vi); - -extern int vorbis_encode_ctl(vorbis_info *vi,int number,void *arg); - -#define OV_ECTL_RATEMANAGE_GET 0x10 - -#define OV_ECTL_RATEMANAGE_SET 0x11 -#define OV_ECTL_RATEMANAGE_AVG 0x12 -#define OV_ECTL_RATEMANAGE_HARD 0x13 - -#define OV_ECTL_LOWPASS_GET 0x20 -#define OV_ECTL_LOWPASS_SET 0x21 - -#define OV_ECTL_IBLOCK_GET 0x30 -#define OV_ECTL_IBLOCK_SET 0x31 - -struct ovectl_ratemanage_arg { - int management_active; - - long bitrate_hard_min; - long bitrate_hard_max; - double bitrate_hard_window; - - long bitrate_av_lo; - long bitrate_av_hi; - double bitrate_av_window; - double bitrate_av_window_center; -}; - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif - - +/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2001 *
+ * by the XIPHOPHORUS Company http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: vorbis encode-engine setup
+ last mod: $Id: vorbisenc.h,v 1.3 2004-01-04 12:16:07 x75 Exp $
+
+ ********************************************************************/
+
+#ifndef _OV_ENC_H_
+#define _OV_ENC_H_
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+#include "codec.h"
+
+extern int vorbis_encode_init(vorbis_info *vi,
+ long channels,
+ long rate,
+
+ long max_bitrate,
+ long nominal_bitrate,
+ long min_bitrate);
+
+extern int vorbis_encode_setup_managed(vorbis_info *vi,
+ long channels,
+ long rate,
+
+ long max_bitrate,
+ long nominal_bitrate,
+ long min_bitrate);
+
+extern int vorbis_encode_setup_vbr(vorbis_info *vi,
+ long channels,
+ long rate,
+
+ float /* quality level from 0. (lo) to 1. (hi) */
+ );
+
+extern int vorbis_encode_init_vbr(vorbis_info *vi,
+ long channels,
+ long rate,
+
+ float base_quality /* quality level from 0. (lo) to 1. (hi) */
+ );
+
+extern int vorbis_encode_setup_init(vorbis_info *vi);
+
+extern int vorbis_encode_ctl(vorbis_info *vi,int number,void *arg);
+
+#define OV_ECTL_RATEMANAGE_GET 0x10
+
+#define OV_ECTL_RATEMANAGE_SET 0x11
+#define OV_ECTL_RATEMANAGE_AVG 0x12
+#define OV_ECTL_RATEMANAGE_HARD 0x13
+
+#define OV_ECTL_LOWPASS_GET 0x20
+#define OV_ECTL_LOWPASS_SET 0x21
+
+#define OV_ECTL_IBLOCK_GET 0x30
+#define OV_ECTL_IBLOCK_SET 0x31
+
+struct ovectl_ratemanage_arg {
+ int management_active;
+
+ long bitrate_hard_min;
+ long bitrate_hard_max;
+ double bitrate_hard_window;
+
+ long bitrate_av_lo;
+ long bitrate_av_hi;
+ double bitrate_av_window;
+ double bitrate_av_window_center;
+};
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif
+
+
|