diff options
-rw-r--r-- | udpreceive~.c | 805 | ||||
-rw-r--r-- | udpsend~-help.pd | 173 | ||||
-rw-r--r-- | udpsend~.c | 701 | ||||
-rw-r--r-- | udpsend~.h | 102 |
4 files changed, 0 insertions, 1781 deletions
diff --git a/udpreceive~.c b/udpreceive~.c deleted file mode 100644 index 42bf7c7..0000000 --- a/udpreceive~.c +++ /dev/null @@ -1,805 +0,0 @@ -/* udpreceive~ started 20100110 by Martin Peach based on netreceive~: */ -/* ------------------------ netreceive~ --------------------------------------- */ -/* */ -/* Tilde object to receive uncompressed audio data from netsend~. */ -/* Written by Olaf Matthes <olaf.matthes@gmx.de>. */ -/* Based on streamin~ by Guenter Geiger. */ -/* Get source at http://www.akustische-kunst.org/ */ -/* */ -/* This program is free software; you can redistribute it and/or */ -/* modify it under the terms of the GNU General Public License */ -/* as published by the Free Software Foundation; either version 2 */ -/* of the License, or (at your option) any later version. */ -/* */ -/* See file LICENSE for further informations on licensing terms. */ -/* */ -/* This program 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 General Public License for more details. */ -/* */ -/* You should have received a copy of the GNU General Public License */ -/* along with this program; 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. */ -/* */ -/* This project was commissioned by the Society for Arts and Technology [SAT], */ -/* Montreal, Quebec, Canada, http://www.sat.qc.ca/. */ -/* */ -/* ---------------------------------------------------------------------------- */ - - -#include "m_pd.h" - -#include "udpsend~.h" - -#include <sys/types.h> -#include <string.h> -#if defined(UNIX) || defined(unix) -#include <sys/socket.h> -#include <errno.h> -#include <netinet/in.h> -#include <netinet/tcp.h> -#include <arpa/inet.h> -#include <netdb.h> -#include <sys/time.h> -#include <unistd.h> -#include <fcntl.h> -#include <stdio.h> -#define SOCKET_ERROR -1 -#endif -#ifdef _WIN32 -#include <winsock2.h> -#include <ws2tcpip.h> /* for socklen_t */ -#endif - -#ifndef SOL_IP -#define SOL_IP IPPROTO_IP -#endif - -#define DEFAULT_AUDIO_BUFFER_FRAMES 16 /* a small circ. buffer for 16 frames */ -#define DEFAULT_AVERAGE_NUMBER 10 /* number of values we store for average history */ -#define DEFAULT_NETWORK_POLLTIME 1 /* interval in ms for polling for input data (Max/MSP only) */ -#define DEFAULT_QUEUE_LENGTH 3 /* min. number of buffers that can be used reliably on your hardware */ - -#if defined(UNIX) || defined(unix) -#define CLOSESOCKET(fd) close(fd) -#endif -#ifdef _WIN32 -#define CLOSESOCKET(fd) closesocket(fd) -#endif - -/* ------------------------ udpreceive~ ----------------------------- */ - -typedef struct _udpreceive_tilde -{ - t_object x_obj; - t_outlet *x_outlet1; - t_outlet *x_outlet2; - t_outlet *x_addrout; - t_clock *x_clock; - t_atom x_addrbytes[5]; - int x_socket; - int x_connectsocket; - int x_nconnections; - long x_addr; - unsigned short x_port; - t_symbol *x_hostname; - int x_error; - int x_buffering; - char x_msg[256]; - - /* buffering */ - int x_framein;// index of next empty frame in x_frames[] - int x_frameout;// index of next frame to play back from x_frames[] - t_frame x_frames[DEFAULT_AUDIO_BUFFER_FRAMES]; - int x_maxframes; - long x_tag_errors; - int x_sync;// zero if we didn't receive a tag when we expected one - int x_blocksize; - int x_blocksperrecv; - int x_blockssincerecv; - - int x_nbytes; - int x_counter;// count of received frames - int x_average[DEFAULT_AVERAGE_NUMBER]; - int x_averagecur; - int x_underflow; - int x_overflow; - int x_valid; - long x_samplerate; - int x_noutlets; - int x_vecsize; - t_int **x_myvec; /* vector we pass on to the DSP routine */ -} t_udpreceive_tilde; - -/* function prototypes */ -static void udpreceive_tilde_closesocket(t_udpreceive_tilde* x); -static void udpreceive_tilde_reset(t_udpreceive_tilde* x, t_floatarg buffer); -static void udpreceive_tilde_datapoll(t_udpreceive_tilde *x); -static void udpreceive_tilde_connectpoll(t_udpreceive_tilde *x); -static int udpreceive_tilde_createsocket(t_udpreceive_tilde* x, int portno); -static t_int *udpreceive_tilde_perform(t_int *w); -static void udpreceive_tilde_dsp(t_udpreceive_tilde *x, t_signal **sp); -static void udpreceive_tilde_info(t_udpreceive_tilde *x); -static void udpreceive_tilde_tick(t_udpreceive_tilde *x); -static void *udpreceive_tilde_new(t_floatarg fportno, t_floatarg outlets, t_floatarg blocksize); -static void udpreceive_tilde_free(t_udpreceive_tilde *x); -void udpreceive_tilde_setup(void); -static int udpreceive_tilde_sockerror(char *s); -static int udpreceive_tilde_setsocketoptions(int sockfd); -/* these would require to include some headers that are different - between pd 0.36 and later, so it's easier to do it like this! */ -EXTERN void sys_rmpollfn(int fd); -EXTERN void sys_addpollfn(int fd, void* fn, void *ptr); - -static t_class *udpreceive_tilde_class; -static t_symbol *ps_format, *ps_channels, *ps_framesize, *ps_overflow, *ps_underflow, *ps_packets, - *ps_queuesize, *ps_average, *ps_sf_float, *ps_sf_16bit, *ps_sf_8bit, - *ps_sf_mp3, *ps_sf_aac, *ps_sf_unknown, *ps_bitrate, *ps_hostname, *ps_nothing, - *ps_tag_errors; - -/* remove all pollfunctions and close socket */ -static void udpreceive_tilde_closesocket(t_udpreceive_tilde* x) -{ - sys_rmpollfn(x->x_socket); - outlet_float(x->x_outlet1, 0); - CLOSESOCKET(x->x_socket); - x->x_socket = -1; -} - -static void udpreceive_tilde_reset(t_udpreceive_tilde* x, t_floatarg buffer) -{ - int i; - - x->x_counter = 0; - x->x_nbytes = 0; - x->x_framein = 0; - x->x_frameout = 0; - x->x_blockssincerecv = 0; - x->x_blocksperrecv = x->x_blocksize / x->x_vecsize; - x->x_tag_errors = 0; - - for (i = 0; i < DEFAULT_AVERAGE_NUMBER; i++) - x->x_average[i] = x->x_maxframes; - x->x_averagecur = 0; - - i = (int)buffer; - if ((i > 0)&&(i < DEFAULT_AUDIO_BUFFER_FRAMES)) - { - x->x_maxframes = i; - post("udpreceive~: set buffer to %d frames)", x->x_maxframes); - } - else if (i != 0) /* special case of 0 leaves buffer size unchanged */ - { - post("udpreceive~: buffer must be between 1 and %d frames)", DEFAULT_AUDIO_BUFFER_FRAMES-1); - } - x->x_underflow = 0; - x->x_overflow = 0; - x->x_buffering = 1; -} - -static void udpreceive_tilde_datapoll(t_udpreceive_tilde *x) -{ - int ret; - int n; - long addr; - unsigned short port; - struct sockaddr_in from; - socklen_t fromlen = sizeof(from); - t_tag *tag_ptr; - - n = x->x_nbytes; - - if (x->x_nbytes == 0) /* we ate all the samples and need a new header tag */ - { - tag_ptr = &x->x_frames[x->x_framein].tag; - /* receive header tag */ - ret = recvfrom(x->x_socket, (char*)tag_ptr, sizeof(t_tag), 0, - (struct sockaddr *)&from, &fromlen); - /* get the sender's ip */ - addr = ntohl(from.sin_addr.s_addr); - port = ntohs(from.sin_port); - /* output addr/port only if changed */ - if (!((addr == x->x_addr)&&(port == x->x_port))) - { - x->x_addr = addr; - x->x_port = port; - x->x_addrbytes[0].a_w.w_float = (x->x_addr & 0xFF000000)>>24; - x->x_addrbytes[1].a_w.w_float = (x->x_addr & 0x0FF0000)>>16; - x->x_addrbytes[2].a_w.w_float = (x->x_addr & 0x0FF00)>>8; - x->x_addrbytes[3].a_w.w_float = (x->x_addr & 0x0FF); - x->x_addrbytes[4].a_w.w_float = x->x_port; - outlet_list(x->x_addrout, &s_list, 5L, x->x_addrbytes); - } - if (ret <= 0) /* error */ - { - if (0 == udpreceive_tilde_sockerror("recv tag")) return; - udpreceive_tilde_reset(x, 0); - return; - } - else if (ret != sizeof(t_tag)) - { - /* incomplete header tag: return and try again later */ - /* in the hope that more data will be available */ - error("udpreceive~: got incomplete header tag"); - return; - } - /* make sure this is really a tag */ - if (!((tag_ptr->tag[0] == 'T')&&(tag_ptr->tag[1] == 'A')&&(tag_ptr->tag[2] == 'G')&&(tag_ptr->tag[3] == '!'))) - { - ++x->x_tag_errors; - if (x->x_sync) error("udpreceive~: bad header tag (%d)", x->x_tag_errors); - x->x_sync = 0; - /* tag length is 16 bytes, a multiple of the data frame size, so eventually we should resync on a tag */ - return; - } - /* adjust byte order if necessary */ - tag_ptr->count = ntohl(tag_ptr->count); - tag_ptr->framesize = ntohl(tag_ptr->framesize); - - /* get info from header tag */ - if (tag_ptr->channels > (x->x_noutlets-1)) - { - error("udpreceive~: incoming stream has too many channels (%d)", tag_ptr->channels); - x->x_counter = 0; - return; - } - x->x_nbytes = n = tag_ptr->framesize; - x->x_sync = 1; - } - else /* we already have header tag or some data and need more */ - { - ret = recvfrom(x->x_socket, (char*)x->x_frames[x->x_framein].data + x->x_frames[x->x_framein].tag.framesize - n, - n, 0, (struct sockaddr *)&from, &fromlen); - if (ret > 0) - { - n -= ret; - } - else if (ret < 0) /* error */ - { - if ( 0 == (ret = udpreceive_tilde_sockerror("recv data"))) return; -#ifdef _WIN32 - if ( ret == WSAEFAULT) -#else - if ( ret == EFAULT) -#endif - { - post ("udpreceive~: EFAULT: %p %lu %d", x->x_frames[x->x_framein].data, x->x_frames[x->x_framein].tag.framesize, n); - return; - } - udpreceive_tilde_reset(x, 0); - return; - } - - x->x_nbytes = n; - if (n == 0) /* a complete packet is received */ - { - if (x->x_frames[x->x_framein].tag.format == SF_AAC) - { - error("udpreceive~: don't know how to decode AAC format"); - return; - } - x->x_counter++; - x->x_framein++; - x->x_framein %= DEFAULT_AUDIO_BUFFER_FRAMES; - - /* check for buffer overflow */ - if (x->x_framein == x->x_frameout) - { - x->x_overflow++; - } - } - } -} - -static void udpreceive_tilde_connectpoll(t_udpreceive_tilde *x) -{ - socklen_t sockaddrlen = sizeof(struct sockaddr); - struct sockaddr_in incomer_address; - int fd = accept(x->x_connectsocket, (struct sockaddr*)&incomer_address, &sockaddrlen); - - if (fd < 0) - { - post("udpreceive~: accept failed"); - return; - } - if (x->x_socket != -1) - { - post("udpreceive~: new connection"); - udpreceive_tilde_closesocket(x); - } - - udpreceive_tilde_reset(x, 0); - x->x_socket = fd; - x->x_nbytes = 0; - x->x_hostname = gensym(inet_ntoa(incomer_address.sin_addr)); - sys_addpollfn(fd, udpreceive_tilde_datapoll, x); - outlet_float(x->x_outlet1, 1); -} - -static int udpreceive_tilde_createsocket(t_udpreceive_tilde* x, int portno) -{ - struct sockaddr_in server; - int sockfd; - - /* create a socket */ - sockfd = socket(AF_INET, SOCK_DGRAM, 0); - - if (sockfd < 0) - { - udpreceive_tilde_sockerror("socket"); - return 0; - } - server.sin_family = AF_INET; - server.sin_addr.s_addr = INADDR_ANY; - - /* assign server port number */ - - server.sin_port = htons((u_short)portno); - post("udpreceive~: listening to port number %d", portno); - - udpreceive_tilde_setsocketoptions(sockfd); - - /* name the socket */ - if (bind(sockfd, (struct sockaddr *)&server, sizeof(server)) < 0) - { - udpreceive_tilde_sockerror("bind"); - CLOSESOCKET(sockfd); - return 0; - } - - x->x_socket = sockfd; - x->x_nbytes = 0; - sys_addpollfn(sockfd, udpreceive_tilde_datapoll, x); - return 1; -} - -/* Queue is 1 to 16 frames long */ -#define QUEUESIZE (int)((x->x_framein + DEFAULT_AUDIO_BUFFER_FRAMES - x->x_frameout) % DEFAULT_AUDIO_BUFFER_FRAMES) -/* Block is a set of sample vectors inside a frame, one vector per channel */ -#define BLOCKOFFSET (x->x_blockssincerecv * x->x_vecsize * x->x_frames[x->x_frameout].tag.channels) - -static t_int *udpreceive_tilde_perform(t_int *w) -{ - t_udpreceive_tilde *x = (t_udpreceive_tilde*) (w[1]); - int n = (int)(w[2]); - t_float *out[DEFAULT_AUDIO_CHANNELS]; - const int offset = 3; - const int channels = x->x_frames[x->x_frameout].tag.channels; - int i = 0; - - x->x_valid = 0; - for (i = 0; i < x->x_noutlets; i++) - { - out[i] = (t_float *)(w[offset + i]); - } - - /* set our vector size to the local vector size */ - if (n != x->x_vecsize) - { - x->x_vecsize = n; - x->x_blocksperrecv = x->x_blocksize / x->x_vecsize; - x->x_blockssincerecv = 0; - } - - /* check whether there is enough data in buffer */ - if (x->x_buffering && (x->x_counter < x->x_maxframes)) - { - goto bail; - } - x->x_buffering = 0; - - /* check for buffer underflow */ - if (x->x_framein == x->x_frameout) - { - x->x_underflow++; - goto bail; - } - - x->x_valid = 1; - /* queue balancing */ - x->x_average[x->x_averagecur] = QUEUESIZE; - if (++x->x_averagecur >= DEFAULT_AVERAGE_NUMBER) - x->x_averagecur = 0; - - switch (x->x_frames[x->x_frameout].tag.format) - { - case SF_FLOAT: - { - int32_t* buf = (int32_t *)x->x_frames[x->x_frameout].data + BLOCKOFFSET; - flint fl; - - /* swap bytes if necessary */ - while (n--) - { - for (i = 0; i < channels; i++) - { - fl.i32 = ntohl(*buf++); - *out[i]++ = fl.f32; - } - for (i = channels; i < (x->x_noutlets-1); i++) - { - *out[i]++ = 0.; - } - *out[i]++ = x->x_valid; - } - x->x_error = 0; - break; - } - case SF_16BIT: - { - short* buf = (short *)x->x_frames[x->x_frameout].data + BLOCKOFFSET; - /* swap bytes if necessary */ - while (n--) - { - for (i = 0; i < channels; i++) - { - *out[i]++ = (t_float)((short)(ntohs(*buf++)) * 3.051850e-05); - } - for (i = channels; i < (x->x_noutlets-1); i++) - { - *out[i]++ = 0.; - } - *out[i]++ = x->x_valid; - } - x->x_error = 0; - break; - } - case SF_8BIT: - { - unsigned char* buf = (unsigned char *)x->x_frames[x->x_frameout].data + BLOCKOFFSET; - - while (n--) - { - for (i = 0; i < channels; i++) - { - *out[i]++ = (t_float)((0.0078125 * (*buf++)) - 1.0); - } - for (i = channels; i < (x->x_noutlets-1); i++) - { - *out[i]++ = 0.; - } - *out[i]++ = x->x_valid; - } - x->x_error = 0; - break; - } - case SF_MP3: - { - if (x->x_error != 1) - { - x->x_error = 1; - sprintf(x->x_msg, "udpreceive~: mp3 format not supported"); - clock_delay(x->x_clock, 0); - } - break; - } - case SF_AAC: - { - if (x->x_error != 2) - { - x->x_error = 2; - sprintf(x->x_msg, "udpreceive~: aac format not supported"); - clock_delay(x->x_clock, 0); - } - break; - } - default: - if (x->x_error != 3) - { - x->x_error = 3; - sprintf(x->x_msg, "udpreceive~: unknown format (%d)",x->x_frames[x->x_frameout].tag.format); - clock_delay(x->x_clock, 0); - } - break; - } - - if (!(x->x_blockssincerecv < x->x_blocksperrecv - 1)) - { - x->x_blockssincerecv = 0; - x->x_frameout++; - x->x_frameout %= DEFAULT_AUDIO_BUFFER_FRAMES; - } - else x->x_blockssincerecv++; - - return (w + offset + x->x_noutlets); - -bail: - /* set output to zero */ - while (n--) for (i = 0; i < x->x_noutlets; i++) *(out[i]++) = 0.; - return (w + offset + x->x_noutlets); -} - -static void udpreceive_tilde_dsp(t_udpreceive_tilde *x, t_signal **sp) -{ - int i; - - x->x_myvec[0] = (t_int*)x; - x->x_myvec[1] = (t_int*)sp[0]->s_n; - - x->x_samplerate = (long)sp[0]->s_sr; - - if (x->x_blocksize % sp[0]->s_n) - { - error("udpreceive~: signal vector size too large (needs to be even divisor of %d)", x->x_blocksize); - } - else - { - for (i = 0; i < x->x_noutlets; i++) - { - x->x_myvec[2 + i] = (t_int*)sp[i + 1]->s_vec; - } - dsp_addv(udpreceive_tilde_perform, x->x_noutlets + 2, (t_int*)x->x_myvec); - } -} - -/* send stream info */ -static void udpreceive_tilde_info(t_udpreceive_tilde *x) -{ - t_atom list[2]; - t_symbol *sf_format; - t_float bitrate; - int i, avg = 0; - - for (i = 0; i < DEFAULT_AVERAGE_NUMBER; i++) - avg += x->x_average[i]; - - bitrate = (t_float)((SF_SIZEOF(x->x_frames[x->x_frameout].tag.format) * x->x_samplerate * 8 * x->x_frames[x->x_frameout].tag.channels) / 1000.); - - switch (x->x_frames[x->x_frameout].tag.format) - { - case SF_FLOAT: - { - sf_format = ps_sf_float; - break; - } - case SF_16BIT: - { - sf_format = ps_sf_16bit; - break; - } - case SF_8BIT: - { - sf_format = ps_sf_8bit; - break; - } - case SF_MP3: - { - sf_format = ps_sf_mp3; - break; - } - case SF_AAC: - { - sf_format = ps_sf_aac; - break; - } - default: - { - sf_format = ps_sf_unknown; - break; - } - } - - /* --- stream information (t_tag) --- */ - /* audio format */ - SETSYMBOL(list, (t_symbol *)sf_format); - outlet_anything(x->x_outlet2, ps_format, 1, list); - - /* channels */ - SETFLOAT(list, (t_float)x->x_frames[x->x_frameout].tag.channels); - outlet_anything(x->x_outlet2, ps_channels, 1, list); - - /* framesize */ - SETFLOAT(list, (t_float)x->x_frames[x->x_frameout].tag.framesize); - outlet_anything(x->x_outlet2, ps_framesize, 1, list); - - /* bitrate */ - SETFLOAT(list, (t_float)bitrate); - outlet_anything(x->x_outlet2, ps_bitrate, 1, list); - - /* --- internal info (buffer and network) --- */ - /* overflow */ - SETFLOAT(list, (t_float)x->x_overflow); - outlet_anything(x->x_outlet2, ps_overflow, 1, list); - - /* underflow */ - SETFLOAT(list, (t_float)x->x_underflow); - outlet_anything(x->x_outlet2, ps_underflow, 1, list); - - /* queuesize */ - SETFLOAT(list, (t_float)QUEUESIZE); - outlet_anything(x->x_outlet2, ps_queuesize, 1, list); - - /* average queuesize */ - SETFLOAT(list, (t_float)((t_float)avg / (t_float)DEFAULT_AVERAGE_NUMBER)); - outlet_anything(x->x_outlet2, ps_average, 1, list); - - /* total packets */ - SETFLOAT(list, (t_float)x->x_counter); - outlet_anything(x->x_outlet2, ps_packets, 1, list); - - /* total tag errors */ - SETFLOAT(list, (t_float)x->x_tag_errors); - outlet_anything(x->x_outlet2, ps_tag_errors, 1, list); - - outlet_list(x->x_addrout, &s_list, 5L, x->x_addrbytes); -} - -static void udpreceive_tilde_tick(t_udpreceive_tilde *x) -{ -/* post a message once, outside of perform routine */ - post("%s", x->x_msg); -} - -static void *udpreceive_tilde_new(t_floatarg fportno, t_floatarg outlets, t_floatarg blocksize) -{ - t_udpreceive_tilde *x; - int i; - - if (fportno == 0) fportno = DEFAULT_PORT; - - x = (t_udpreceive_tilde *)pd_new(udpreceive_tilde_class); - if (x) - { - for (i = sizeof(t_object); i < (int)sizeof(t_udpreceive_tilde); i++) - ((char *)x)[i] = 0; - - if ((int)outlets < 1 || (int)outlets > DEFAULT_AUDIO_CHANNELS) - { - error("udpreceive~: Number of channels must be between 1 and %d", DEFAULT_AUDIO_CHANNELS); - return NULL; - } - - x->x_noutlets = (int)outlets + 1; // extra outlet for valid flag - for (i = 0; i < x->x_noutlets; i++) - outlet_new(&x->x_obj, &s_signal); - x->x_outlet2 = outlet_new(&x->x_obj, &s_anything); - x->x_addrout = outlet_new(&x->x_obj, &s_list); - for (i = 0; i < 5; ++i) - { - x->x_addrbytes[i].a_type = A_FLOAT; - x->x_addrbytes[i].a_w.w_float = 0; - } - x->x_addr = 0; - x->x_port = 0; - x->x_myvec = (t_int **)t_getbytes(sizeof(t_int *) * (x->x_noutlets + 3)); - if (!x->x_myvec) - { - error("udpreceive~: out of memory"); - return NULL; - } - - x->x_connectsocket = x->x_socket = -1; - x->x_nconnections = x->x_underflow = x->x_overflow = 0; - x->x_hostname = ps_nothing; -/* allocate space for 16 frames of 1024 X numchannels floats*/ - for (i = 0; i < DEFAULT_AUDIO_BUFFER_FRAMES; i++) - { - x->x_frames[i].data = (char *)t_getbytes(DEFAULT_AUDIO_BUFFER_SIZE * (x->x_noutlets-1) * sizeof(t_float)); - } - x->x_clock = clock_new(&x->x_obj.ob_pd, (t_method)udpreceive_tilde_tick); - - x->x_sync = 1; - x->x_tag_errors = x->x_framein = x->x_frameout = x->x_valid = 0; - x->x_maxframes = DEFAULT_QUEUE_LENGTH; - x->x_vecsize = 64; /* we'll update this later */ - if (blocksize == 0) x->x_blocksize = DEFAULT_AUDIO_BUFFER_SIZE; - else if (DEFAULT_AUDIO_BUFFER_SIZE%(int)blocksize) - { - error("udpreceive~: blocksize must fit snugly in %d", DEFAULT_AUDIO_BUFFER_SIZE); - return NULL; - } - else x->x_blocksize = (int)blocksize; //DEFAULT_AUDIO_BUFFER_SIZE; /* <-- the only place blocksize is set */ - x->x_blockssincerecv = 0; - x->x_blocksperrecv = x->x_blocksize / x->x_vecsize; - x->x_buffering = 1; - - if (!udpreceive_tilde_createsocket(x, (int)fportno)) - { - error("udpreceive~: failed to create listening socket"); - return (NULL); - } - } - return (x); -} - -static void udpreceive_tilde_free(t_udpreceive_tilde *x) -{ - int i; - - if (x->x_connectsocket != -1) - { - sys_rmpollfn(x->x_connectsocket); - CLOSESOCKET(x->x_connectsocket); - } - if (x->x_socket != -1) - { - sys_rmpollfn(x->x_socket); - CLOSESOCKET(x->x_socket); - } - - /* free memory */ - t_freebytes(x->x_myvec, sizeof(t_int *) * (x->x_noutlets + 3)); - for (i = 0; i < DEFAULT_AUDIO_BUFFER_FRAMES; i++) - { - t_freebytes(x->x_frames[i].data, DEFAULT_AUDIO_BUFFER_SIZE * (x->x_noutlets-1) * sizeof(t_float)); - } - clock_free(x->x_clock); -} - -void udpreceive_tilde_setup(void) -{ - udpreceive_tilde_class = class_new(gensym("udpreceive~"), - (t_newmethod) udpreceive_tilde_new, (t_method) udpreceive_tilde_free, - sizeof(t_udpreceive_tilde), 0, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_NULL); - - class_addmethod(udpreceive_tilde_class, nullfn, gensym("signal"), 0); - class_addmethod(udpreceive_tilde_class, (t_method)udpreceive_tilde_info, gensym("info"), 0); - class_addmethod(udpreceive_tilde_class, (t_method)udpreceive_tilde_dsp, gensym("dsp"), 0); - class_addmethod(udpreceive_tilde_class, (t_method)udpreceive_tilde_reset, gensym("reset"), A_DEFFLOAT, 0); - class_addmethod(udpreceive_tilde_class, (t_method)udpreceive_tilde_reset, gensym("buffer"), A_DEFFLOAT, 0); - post("udpreceive~ v%s, (c) 2004 Olaf Matthes, 2010 Martin Peach", VERSION); - - ps_format = gensym("format"); - ps_tag_errors = gensym("tag_errors"); - ps_channels = gensym("channels"); - ps_framesize = gensym("framesize"); - ps_bitrate = gensym("bitrate"); - ps_overflow = gensym("overflow"); - ps_underflow = gensym("underflow"); - ps_queuesize = gensym("queuesize"); - ps_average = gensym("average"); - ps_packets = gensym("packets"); - ps_hostname = gensym("ipaddr"); - ps_sf_float = gensym("_float_"); - ps_sf_16bit = gensym("_16bit_"); - ps_sf_8bit = gensym("_8bit_"); - ps_sf_mp3 = gensym("_mp3_"); - ps_sf_aac = gensym("_aac_"); - ps_sf_unknown = gensym("_unknown_"); - ps_nothing = gensym(""); -} - -/* error handlers */ -static int udpreceive_tilde_sockerror(char *s) -{ -#ifdef _WIN32 - int err = WSAGetLastError(); - if (err == 10054) return 1; - else if (err == 10040) post("udpreceive~: %s: message too long (%d)", s, err); - else if (err == 10053) post("udpreceive~: %s: software caused connection abort (%d)", s, err); - else if (err == 10055) post("udpreceive~: %s: no buffer space available (%d)", s, err); - else if (err == 10060) post("udpreceive~: %s: connection timed out (%d)", s, err); - else if (err == 10061) post("udpreceive~: %s: connection refused (%d)", s, err); - else post("udpreceive~: %s: %s (%d)", s, strerror(err), err); -#else - int err = errno; - post("udpreceive~: %s: %s (%d)", s, strerror(err), err); -#endif -#ifdef _WIN32 - if (err == WSAEWOULDBLOCK) -#endif -#if defined(UNIX) || defined(unix) - if (err == EAGAIN) -#endif - { - return 0; /* recoverable error */ - } - return err; /* indicate non-recoverable error */ -} - -static int udpreceive_tilde_setsocketoptions(int sockfd) -{ - int sockopt = 1; - if (setsockopt(sockfd, SOL_IP, TCP_NODELAY, (const char*)&sockopt, sizeof(int)) < 0) - post("udpreceive~: setsockopt NODELAY failed"); - - sockopt = 1; - if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const char*)&sockopt, sizeof(int)) < 0) - post("udpreceive~: setsockopt REUSEADDR failed"); - return 0; -} - -/* fin udpreceive~.c */ diff --git a/udpsend~-help.pd b/udpsend~-help.pd deleted file mode 100644 index bd03c81..0000000 --- a/udpsend~-help.pd +++ /dev/null @@ -1,173 +0,0 @@ -#N canvas 197 27 785 803 10; -#X obj -178 225 osc~ 440; -#X msg -398 60 disconnect; -#X msg -353 105 format float; -#X msg -332 126 format 16bit; -#X msg -311 147 format 8bit; -#X msg -440 18 connect localhost 8008; -#X text -244 103 float is the most expensive with the best resolution -(32bit) \, default is 16bit; -#X msg -419 39 connect 255.255.255.255 8008; -#X obj 52 687 print udpreceive~; -#X obj 224 369 print udpsend~; -#X obj -178 320 tgl 15 0 empty empty empty 17 7 0 10 -4034 -1 -1 0 -1; -#X symbolatom -97 435 10 0 0 0 - - -; -#X floatatom -44 369 5 0 0 0 - - -; -#X floatatom 10 391 9 0 0 0 - - -; -#X floatatom 63 411 9 0 0 0 - - -; -#X symbolatom 117 390 10 0 0 0 - - -; -#X obj -97 411 prepend set; -#X obj 117 367 prepend set; -#X text -102 368 channels:; -#X text -144 442 format:; -#X text 13 411 bitrate:; -#X text -51 391 framesize:; -#X text 98 389 to:; -#X msg -216 242 info; -#X symbolatom -293 774 10 0 0 0 - - -; -#X floatatom -259 708 5 0 0 0 - - -; -#X floatatom -224 687 7 0 0 0 - - -; -#X floatatom -190 752 9 0 0 0 - - -; -#X obj -293 733 prepend set; -#X text -323 707 channels:; -#X text -339 773 format:; -#X text -239 751 bitrate:; -#X text -288 686 framesize:; -#X floatatom -155 709 9 0 0 0 - - -; -#X floatatom -121 687 9 0 0 0 - - -; -#X floatatom -86 730 5 0 0 0 - - -; -#X floatatom -52 709 5 0 0 0 - - -; -#X text -212 708 overflow:; -#X text -181 686 underflow:; -#X text -147 729 queuesize:; -#X text -100 708 average:; -#X msg -435 478 info; -#X text -237 34 broadcast to everybody on your local subnet listening -on the specified port; -#X msg -455 458 reset; -#X text -402 477 status info to rightmost outlet; -#X text -415 241 status info to rightmost outlet; -#X text -417 457 reset underflow & overflow counters; -#X floatatom -260 589 3 0 0 0 - - -; -#X floatatom -237 589 3 0 0 0 - - -; -#X floatatom -214 589 3 0 0 0 - - -; -#X floatatom -191 589 3 0 0 0 - - -; -#X floatatom -167 589 5 0 0 0 - - -; -#X obj -260 563 unpack 0 0 0 0 0; -#X text -297 588 from:; -#X obj -179 268 *~; -#X floatatom -164 150 5 0 0 0 - - -; -#X text -66 148 Framesize = (blocksize) X (number of channels) X (bytes -per sample); -#X obj -97 339 route format channels framesize bitrate ipaddr vecsize -; -#X floatatom 170 430 9 0 0 0 - - -; -#X text 70 430 dsp vector size:; -#X msg -258 200 channels \$1; -#X obj -412 185 hradio 15 1 0 4 empty empty empty 0 -8 0 10 -4034 -1 --1 0; -#X obj -178 297 udpsend~ 2 512; -#X text -88 296 sends 2 dsp-channels using 512-sample blocks; -#X obj -389 541 udpreceive~ 8008 2 512; -#X obj -388 572 dac~ 1 2; -#X text 68 448 (blocksize must be a multiple of this); -#X text -160 318 1 = transmitting; -#X obj -97 246 noise~; -#X obj -98 268 *~; -#X obj -164 170 / 100; -#X text -455 338 Based on: [netreceive~] and [netsend~]by Olaf Matthes -; -#X floatatom -17 752 9 0 0 0 - - -; -#X text -69 751 packets:; -#X text -50 177 Default blocksize is 2048 The number of samples per -block must be an integer multiple of the number of samples in one signal -vector.; -#X text -28 225 Arguments: (1st required \, 2nd optional) 1:number -of channels to send. 2:blocksize = number of samples per channel per -frame. (Blocksize of sender and receiver must be the same.); -#X text -127 554 To communicate \, a [udpreceive~] and [udpsend~] pair -must have the same number of channels and the same blocksize. Also -[udpsend~] must [connect( to the port on which [udpreceive~] is listening. -; -#X text -329 59 stop transmitting; -#X text -355 76 format defines the resolution of the sent signal and -may be changed on-the-fly; -#X text -450 200 number of channels to transmit; -#X msg -414 499 buffer 2; -#X text -352 498 set number of frames to buffer before playback; -#X text -458 365 [udpsend~] transmits dsp vectors ("audio") via UDP. -UDP is a connectionless protocol \, so [udpsend~] will transmit even -if nothing is receiving.; -#X text -299 18 connect to <hostname> <port> and begin transmitting -; -#X text -456 313 [udpreceive~] and [udpsend~]; -#X text -248 540 receives 2 channels on port 8008 Same blocksize as -udpsend~; -#X floatatom -412 216 5 0 0 0 - - -; -#X obj -288 172 tgl 15 0 empty empty toggle_connection 17 7 0 10 -4034 --1 -1 0 1; -#X obj -293 650 route format channels framesize bitrate overflow underflow -queuesize average packets tag_errors; -#X floatatom 17 730 9 0 0 0 - - -; -#X text -49 729 tag errors:; -#X obj -326 601 env~; -#X floatatom -326 624 9 0 0 0 - - -; -#X text -266 613 The rightmost signal outlet outputs 1 if the stream -is valid \, else 0; -#X text -455 326 Author: Martin Peach 2010/03/22; -#X connect 0 0 54 0; -#X connect 1 0 62 0; -#X connect 2 0 62 0; -#X connect 3 0 62 0; -#X connect 4 0 62 0; -#X connect 5 0 62 0; -#X connect 7 0 62 0; -#X connect 16 0 11 0; -#X connect 17 0 15 0; -#X connect 23 0 62 0; -#X connect 28 0 24 0; -#X connect 41 0 64 0; -#X connect 43 0 64 0; -#X connect 52 0 47 0; -#X connect 52 1 48 0; -#X connect 52 2 49 0; -#X connect 52 3 50 0; -#X connect 52 4 51 0; -#X connect 54 0 62 0; -#X connect 55 0 70 0; -#X connect 57 0 16 0; -#X connect 57 1 12 0; -#X connect 57 2 13 0; -#X connect 57 3 14 0; -#X connect 57 4 17 0; -#X connect 57 5 58 0; -#X connect 57 6 9 0; -#X connect 60 0 62 0; -#X connect 61 0 60 0; -#X connect 61 0 86 0; -#X connect 62 0 10 0; -#X connect 62 1 57 0; -#X connect 64 0 65 0; -#X connect 64 1 65 1; -#X connect 64 2 91 0; -#X connect 64 3 88 0; -#X connect 64 4 52 0; -#X connect 68 0 69 0; -#X connect 69 0 62 1; -#X connect 70 0 54 1; -#X connect 70 0 69 1; -#X connect 80 0 64 0; -#X connect 87 0 62 0; -#X connect 88 0 28 0; -#X connect 88 1 25 0; -#X connect 88 2 26 0; -#X connect 88 3 27 0; -#X connect 88 4 33 0; -#X connect 88 5 34 0; -#X connect 88 6 35 0; -#X connect 88 7 36 0; -#X connect 88 8 72 0; -#X connect 88 9 89 0; -#X connect 88 10 8 0; -#X connect 91 0 92 0; diff --git a/udpsend~.c b/udpsend~.c deleted file mode 100644 index aa556c7..0000000 --- a/udpsend~.c +++ /dev/null @@ -1,701 +0,0 @@ -/* udpsend~ started by Martin Peach on 20100110, based on netsend~ */ -/* udpsend~ sends audio via udp only.*/ -/* It is a PD external, all Max stuff has been removed from the source */ -/* ------------------------ netsend~ ------------------------------------------ */ -/* */ -/* Tilde object to send uncompressed audio data to netreceive~. */ -/* Written by Olaf Matthes <olaf.matthes@gmx.de>. */ -/* Based on streamout~ by Guenter Geiger. */ -/* Get source at http://www.akustische-kunst.org/ */ -/* */ -/* This program is free software; you can redistribute it and/or */ -/* modify it under the terms of the GNU General Public License */ -/* as published by the Free Software Foundation; either version 2 */ -/* of the License, or (at your option) any later version. */ -/* */ -/* See file LICENSE for further informations on licensing terms. */ -/* */ -/* This program 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 General Public License for more details. */ -/* */ -/* You should have received a copy of the GNU General Public License */ -/* along with this program; 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. */ -/* */ -/* This project was commissioned by the Society for Arts and Technology [SAT], */ -/* Montreal, Quebec, Canada, http://www.sat.qc.ca/. */ -/* */ -/* ---------------------------------------------------------------------------- */ - -#include "m_pd.h" - -#include "udpsend~.h" - -#include <sys/types.h> -#include <string.h> -#include <stdlib.h> -#include <math.h> -#if defined(UNIX) || defined(unix) -#include <sys/socket.h> -#include <errno.h> -#include <netinet/in.h> -#include <netinet/tcp.h> -#include <arpa/inet.h> -#include <netdb.h> -#include <sys/time.h> -#include <signal.h> -#include <unistd.h> -#include <fcntl.h> -#include <stdio.h> -#include <pthread.h> -#define SOCKET_ERROR -1 -#endif -#ifdef _WIN32 -#include <winsock2.h> -#include "pthread.h" -#endif - -#ifdef MSG_NOSIGNAL -#define SEND_FLAGS /*MSG_DONTWAIT|*/MSG_NOSIGNAL -#else -#define SEND_FLAGS 0 -#endif - -#ifndef SOL_IP -#define SOL_IP IPPROTO_IP -#endif - - -/* ------------------------ udpsend~ ----------------------------- */ - -static t_class *udpsend_tilde_class; - -static t_symbol *ps_nothing, *ps_localhost, *ps_vecsize; -static t_symbol *ps_format, *ps_channels, *ps_framesize; -static t_symbol *ps_sf_float, *ps_sf_16bit, *ps_sf_8bit; -static t_symbol *ps_sf_unknown, *ps_bitrate, *ps_hostname; - -typedef struct _udpsend_tilde -{ - t_object x_obj; - t_outlet *x_outlet; - t_outlet *x_outlet2; - t_clock *x_clock; - int x_fd; - t_tag x_tag; - t_symbol* x_hostname; - int x_portno; - int x_connectstate; - char *x_cbuf; - int x_cbufsize; - int x_blocksize; /* set to DEFAULT_AUDIO_BUFFER_SIZE or user-supplied argument 3 in udpsend_tilde_new() */ - int x_blockspersend; /* set to x->x_blocksize / x->x_vecsize in udpsend_tilde_perform() */ - int x_blockssincesend; - - long x_samplerate; /* samplerate we're running at */ - int x_vecsize; /* current DSP signal vector size */ - int x_ninlets; /* number of inlets */ - int x_channels; /* number of channels we want to stream */ - int x_format; /* format of streamed audio data */ - int x_count; /* total number of audio frames */ - t_int **x_myvec; /* vector we pass on in the DSP routine */ - - pthread_mutex_t x_mutex; - pthread_t x_childthread; /* a thread to initiate a connection to the remote port */ - pthread_attr_t x_childthread_attr; /* child thread should have detached attribute so it can be cleaned up after it exits. */ - int x_childthread_result; /* result from pthread_create. Zero if x_childthread represents a valid thread. */ -} t_udpsend_tilde; - -#define NO_CHILDTHREAD 1 /* not zero */ - -/* function prototypes */ -static int udpsend_tilde_sockerror(char *s); -static void udpsend_tilde_closesocket(int fd); -static void udpsend_tilde_notify(t_udpsend_tilde *x); -static void udpsend_tilde_disconnect(t_udpsend_tilde *x); -static void *udpsend_tilde_doconnect(void *zz); -static void udpsend_tilde_connect(t_udpsend_tilde *x, t_symbol *host, t_floatarg fportno); -static t_int *udpsend_tilde_perform(t_int *w); -static void udpsend_tilde_dsp(t_udpsend_tilde *x, t_signal **sp); -static void udpsend_tilde_channels(t_udpsend_tilde *x, t_floatarg channels); -static void udpsend_tilde_format(t_udpsend_tilde *x, t_symbol* form, t_floatarg bitrate); -static void udpsend_tilde_float(t_udpsend_tilde* x, t_floatarg arg); -static void udpsend_tilde_info(t_udpsend_tilde *x); -static void *udpsend_tilde_new(t_floatarg inlets, t_floatarg blocksize); -static void udpsend_tilde_free(t_udpsend_tilde* x); -void udpsend_tilde_setup(void); - -/* functions */ -static void udpsend_tilde_notify(t_udpsend_tilde *x) -{ - pthread_mutex_lock(&x->x_mutex); - x->x_childthread_result = NO_CHILDTHREAD; /* connection thread has ended */ - outlet_float(x->x_outlet, x->x_connectstate); /* we should be connected */ - pthread_mutex_unlock(&x->x_mutex); -} - -static void udpsend_tilde_disconnect(t_udpsend_tilde *x) -{ - pthread_mutex_lock(&x->x_mutex); - if (x->x_fd != -1) - { - udpsend_tilde_closesocket(x->x_fd); - x->x_fd = -1; - x->x_connectstate = 0; - outlet_float(x->x_outlet, 0); - } - pthread_mutex_unlock(&x->x_mutex); -} - -/* udpsend_tilde_doconnect runs in the child thread, which terminates as soon as a connection is */ -static void *udpsend_tilde_doconnect(void *zz) -{ - t_udpsend_tilde *x = (t_udpsend_tilde *)zz; - struct sockaddr_in server; - struct hostent *hp; - int intarg = 1; - int sockfd; - int portno; - int broadcast = 1;/* nonzero is true */ - t_symbol *hostname; - - pthread_mutex_lock(&x->x_mutex); - hostname = x->x_hostname; - portno = x->x_portno; - pthread_mutex_unlock(&x->x_mutex); - - /* create a socket */ - sockfd = socket(AF_INET, SOCK_DGRAM, 0); - if (sockfd < 0) - { - post("udpsend~: connection to %s on port %d failed", hostname->s_name,portno); - udpsend_tilde_sockerror("socket"); - x->x_childthread_result = NO_CHILDTHREAD; - return (0); - } - -#ifdef SO_BROADCAST - if( 0 != setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, (const void *)&broadcast, sizeof(broadcast))) - { - udpsend_tilde_sockerror("setting SO_BROADCAST"); - } -#endif /* SO_BROADCAST */ - - /* connect socket using hostname provided in command line */ - server.sin_family = AF_INET; - hp = gethostbyname(x->x_hostname->s_name); - if (hp == 0) - { - post("udpsend~: bad host?"); - x->x_childthread_result = NO_CHILDTHREAD; - return (0); - } - -#ifdef SO_PRIORITY - /* set high priority, LINUX only */ - intarg = 6; /* select a priority between 0 and 7 */ - if (setsockopt(sockfd, SOL_SOCKET, SO_PRIORITY, (const char*)&intarg, sizeof(int)) < 0) - { - udpsend_tilde_sockerror("setting SO_PRIORITY"); - } -#endif - - 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 */ - if (connect(sockfd, (struct sockaddr *) &server, sizeof (server)) < 0) - { - udpsend_tilde_sockerror("connecting stream socket"); - udpsend_tilde_closesocket(sockfd); - x->x_childthread_result = NO_CHILDTHREAD; - return (0); - } - - post("udpsend~: connected host %s on port %d", hostname->s_name, portno); - - pthread_mutex_lock(&x->x_mutex); - x->x_fd = sockfd; - x->x_connectstate = 1; - clock_delay(x->x_clock, 0);/* udpsend_tilde_notify is called in next clock tick */ - pthread_mutex_unlock(&x->x_mutex); - return (0); -} - -static void udpsend_tilde_connect(t_udpsend_tilde *x, t_symbol *host, t_floatarg fportno) -{ - pthread_mutex_lock(&x->x_mutex); - if (x->x_childthread_result == 0) - { - pthread_mutex_unlock(&x->x_mutex); - post("udpsend~: already trying to connect"); - return; - } - if (x->x_fd != -1) - { - pthread_mutex_unlock(&x->x_mutex); - post("udpsend~: already connected"); - return; - } - - if (host != ps_nothing) - x->x_hostname = host; - else - x->x_hostname = ps_localhost; /* default host */ - - if (!fportno) - x->x_portno = DEFAULT_PORT; - else - x->x_portno = (int)fportno; - x->x_count = 0; - - /* start child thread to connect */ - /* sender thread should start out detached so its resouces will be freed when it is done */ - if (0!= (x->x_childthread_result = pthread_attr_init(&x->x_childthread_attr))) - { - pthread_mutex_unlock(&x->x_mutex); - post("udpsend~: pthread_attr_init failed: %d", x->x_childthread_result); - return; - } - if(0!= (x->x_childthread_result = pthread_attr_setdetachstate(&x->x_childthread_attr, PTHREAD_CREATE_DETACHED))) - { - pthread_mutex_unlock(&x->x_mutex); - post("udpsend~: pthread_attr_setdetachstate failed: %d", x->x_childthread_result); - return; - } - if (0 != (x->x_childthread_result = pthread_create(&x->x_childthread, &x->x_childthread_attr, udpsend_tilde_doconnect, x))) - { - pthread_mutex_unlock(&x->x_mutex); - post("udpsend~: couldn't create sender thread (%d)", x->x_childthread_result); - return; - } - pthread_mutex_unlock(&x->x_mutex); -} - -static t_int *udpsend_tilde_perform(t_int *w) -{ - t_udpsend_tilde* x = (t_udpsend_tilde*) (w[1]); - int n = (int)(w[2]); - t_float *in[DEFAULT_AUDIO_CHANNELS]; - const int offset = 3; - char* bp = NULL; - int i, length = x->x_blocksize * SF_SIZEOF(x->x_tag.format) * x->x_tag.channels; - int sent = 0; - - pthread_mutex_lock(&x->x_mutex); - - for (i = 0; i < x->x_ninlets; i++) - in[i] = (t_float *)(w[offset + i]); - - if (n != x->x_vecsize) /* resize buffer */ - { - x->x_vecsize = n; - x->x_blockspersend = x->x_blocksize / x->x_vecsize; - x->x_blockssincesend = 0; - length = x->x_blocksize * SF_SIZEOF(x->x_tag.format) * x->x_tag.channels; - } - - /* format the buffer */ - switch (x->x_tag.format) - { - case SF_FLOAT: - { - int32_t* fbuf = (int32_t *)x->x_cbuf + (x->x_blockssincesend * x->x_vecsize * x->x_tag.channels); - flint fl; - - while (n--) - for (i = 0; i < x->x_tag.channels; i++) - { - fl.f32 = *(in[i]++); - *fbuf++ = htonl(fl.i32); - } - break; - } - case SF_16BIT: - { - short* cibuf = (short *)x->x_cbuf + (x->x_blockssincesend * x->x_vecsize * x->x_tag.channels); - - while (n--) - for (i = 0; i < x->x_tag.channels; i++) - *cibuf++ = htons((short)floor(32767.5 * *(in[i]++)));/* signed binary */ - break; - } - case SF_8BIT: - { - unsigned char* cbuf = (unsigned char*)x->x_cbuf + (x->x_blockssincesend * x->x_vecsize * x->x_tag.channels); - - while (n--) - for (i = 0; i < x->x_tag.channels; i++) - *cbuf++ = (unsigned char)floor(128. * (1.0 + *(in[i]++))); /* offset binary */ - break; - } - default: - break; - } - - if (!(x->x_blockssincesend < x->x_blockspersend - 1)) /* time to send the buffer */ - { - x->x_blockssincesend = 0; - x->x_count++; /* count data packet we're going to send */ - - if (x->x_fd != -1) - { - bp = (char *)x->x_cbuf; - /* fill in the header tag */ - x->x_tag.tag[0] = 'T'; - x->x_tag.tag[1] = 'A'; - x->x_tag.tag[2] = 'G'; - x->x_tag.tag[3] = '!'; - x->x_tag.framesize = htonl(length); - x->x_tag.count = htonl(x->x_count); - /* send the format tag */ - if (send(x->x_fd, (char*)&x->x_tag, sizeof(t_tag), SEND_FLAGS) < 0) - { - udpsend_tilde_sockerror("send tag"); - pthread_mutex_unlock(&x->x_mutex); - udpsend_tilde_disconnect(x); - return (w + offset + x->x_ninlets); - } - if (length != 0) -/* UDP: max. packet size is 64k (incl. headers) so we have to split */ - { -#ifdef __APPLE__ - /* WARNING: due to a 'bug' (maybe Apple would call it a feature?) in OS X - send calls with data packets larger than 16k fail with error number 40! - Thus we have to split the data packets into several packets that are - 16k in size. The other side will reassemble them again. */ - int size = DEFAULT_UDP_PACKT_SIZE; - if (length < size) /* maybe data fits into one packet? */ - size = length; - /* send the buffer */ - for (sent = 0; sent < length;) - { - int ret = 0; - ret = send(x->x_fd, bp, size, SEND_FLAGS); - if (ret <= 0) - { - udpsend_tilde_sockerror("send data"); - pthread_mutex_unlock(&x->x_mutex); - udpsend_tilde_disconnect(x); - return (w + offset + x->x_ninlets); - } - else - { - bp += ret; - sent += ret; - if ((length - sent) < size) - size = length - sent; - } - } -#else - /* If there is any data, send the buffer, the OS might segment it into smaller packets */ - int ret = send(x->x_fd, bp, length, SEND_FLAGS); - if (ret <= 0) - { - post ("udpsend~: sending length %ld", length); - udpsend_tilde_sockerror("send data"); - pthread_mutex_unlock(&x->x_mutex); - udpsend_tilde_disconnect(x); - return (w + offset + x->x_ninlets); - } -#endif - } - } - -/* check whether user has updated any parameters */ - if (x->x_tag.channels != x->x_channels) - { - x->x_tag.channels = x->x_channels; - } - if (x->x_tag.format != x->x_format) - { - x->x_tag.format = x->x_format; - } - } - else - { - x->x_blockssincesend++; - } - pthread_mutex_unlock(&x->x_mutex); - return (w + offset + x->x_ninlets); -} - -static void udpsend_tilde_dsp(t_udpsend_tilde *x, t_signal **sp) -{ - int i; - - pthread_mutex_lock(&x->x_mutex); - - x->x_myvec[0] = (t_int*)x; - x->x_myvec[1] = (t_int*)sp[0]->s_n; - - x->x_samplerate = sp[0]->s_sr; - - for (i = 0; i < x->x_ninlets; i++) - { - x->x_myvec[2 + i] = (t_int*)sp[i]->s_vec; - } - - pthread_mutex_unlock(&x->x_mutex); - - if (DEFAULT_AUDIO_BUFFER_SIZE % sp[0]->s_n) - { - error("udpsend~: signal vector size too large (needs to be even divisor of %d)", DEFAULT_AUDIO_BUFFER_SIZE); - } - else - { - dsp_addv(udpsend_tilde_perform, x->x_ninlets + 2, (t_int*)x->x_myvec); - } -} - -static void udpsend_tilde_channels(t_udpsend_tilde *x, t_floatarg channels) -{ - pthread_mutex_lock(&x->x_mutex); - if (channels >= 0 && channels <= x->x_ninlets) - { - x->x_channels = (int)channels; - post("udpsend~: channels set to %d", (int)channels); - } - else post ("udpsend~ number of channels must be between 0 and %d", x->x_ninlets); - pthread_mutex_unlock(&x->x_mutex); -} - -static void udpsend_tilde_format(t_udpsend_tilde *x, t_symbol* form, t_floatarg bitrate) -{ - pthread_mutex_lock(&x->x_mutex); - if (!strncmp(form->s_name,"float", 5) && x->x_tag.format != SF_FLOAT) - { - x->x_format = (int)SF_FLOAT; - } - else if (!strncmp(form->s_name,"16bit", 5) && x->x_tag.format != SF_16BIT) - { - x->x_format = (int)SF_16BIT; - } - else if (!strncmp(form->s_name,"8bit", 4) && x->x_tag.format != SF_8BIT) - { - x->x_format = (int)SF_8BIT; - } - - post("udpsend~: format set to %s", form->s_name); - pthread_mutex_unlock(&x->x_mutex); -} - -static void udpsend_tilde_float(t_udpsend_tilde* x, t_floatarg arg) -{ - if (arg == 0.0) - udpsend_tilde_disconnect(x); - else - udpsend_tilde_connect(x,x->x_hostname,(float) x->x_portno); -} - -/* send stream info */ -static void udpsend_tilde_info(t_udpsend_tilde *x) -{ - t_atom list[2]; - t_symbol *sf_format; - t_float bitrate; - - bitrate = (t_float)((SF_SIZEOF(x->x_tag.format) * x->x_samplerate * 8 * x->x_tag.channels) / 1000.); - - switch (x->x_tag.format) - { - case SF_FLOAT: - { - sf_format = ps_sf_float; - break; - } - case SF_16BIT: - { - sf_format = ps_sf_16bit; - break; - } - case SF_8BIT: - { - sf_format = ps_sf_8bit; - break; - } - default: - { - sf_format = ps_sf_unknown; - break; - } - } - - /* --- stream information (t_tag) --- */ - - /* audio format */ - SETSYMBOL(list, (t_symbol *)sf_format); - outlet_anything(x->x_outlet2, ps_format, 1, list); - - /* channels */ - SETFLOAT(list, (t_float)x->x_tag.channels); - outlet_anything(x->x_outlet2, ps_channels, 1, list); - - /* current signal vector size */ - SETFLOAT(list, (t_float)x->x_vecsize); - outlet_anything(x->x_outlet2, ps_vecsize, 1, list); - - /* framesize */ - SETFLOAT(list, (t_float)(ntohl(x->x_tag.framesize))); - outlet_anything(x->x_outlet2, ps_framesize, 1, list); - - /* bitrate */ - SETFLOAT(list, (t_float)bitrate); - outlet_anything(x->x_outlet2, ps_bitrate, 1, list); - - /* IP address */ - SETSYMBOL(list, (t_symbol *)x->x_hostname); - outlet_anything(x->x_outlet2, ps_hostname, 1, list); -} - -static void *udpsend_tilde_new(t_floatarg inlets, t_floatarg blocksize) -{ - int i; - - t_udpsend_tilde *x = (t_udpsend_tilde *)pd_new(udpsend_tilde_class); - if (x) - { - for (i = sizeof(t_object); i < (int)sizeof(t_udpsend_tilde); i++) - ((char *)x)[i] = 0; - - if ((int)inlets < 1 || (int)inlets > DEFAULT_AUDIO_CHANNELS) - { - error("udpsend~: Number of channels must be between 1 and %d", DEFAULT_AUDIO_CHANNELS); - return NULL; - } - x->x_ninlets = (int)inlets; - for (i = 1; i < x->x_ninlets; i++) - inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal); - - x->x_outlet = outlet_new(&x->x_obj, &s_float); - x->x_outlet2 = outlet_new(&x->x_obj, &s_list); - x->x_clock = clock_new(x, (t_method)udpsend_tilde_notify); - - x->x_myvec = (t_int **)t_getbytes(sizeof(t_int *) * (x->x_ninlets + 3)); - if (!x->x_myvec) - { - error("udpsend~: out of memory"); - return NULL; - } - - pthread_mutex_init(&x->x_mutex, 0); - - x->x_hostname = ps_localhost; - x->x_portno = DEFAULT_PORT; - x->x_connectstate = 0; - x->x_childthread_result = NO_CHILDTHREAD; - x->x_fd = -1; - - x->x_tag.format = x->x_format = SF_FLOAT; - x->x_tag.channels = x->x_channels = x->x_ninlets; - x->x_vecsize = 64; /* this is updated in the perform routine udpsend_tilde_perform */ - x->x_cbuf = NULL; - if (blocksize == 0) x->x_blocksize = DEFAULT_AUDIO_BUFFER_SIZE; - else if (DEFAULT_AUDIO_BUFFER_SIZE%(int)blocksize) - { - error("udpsend~: blocksize must fit snugly in %d", DEFAULT_AUDIO_BUFFER_SIZE); - return NULL; - } - else x->x_blocksize = (int)blocksize; //DEFAULT_AUDIO_BUFFER_SIZE; /* <-- the only place blocksize is set */ - x->x_blockspersend = x->x_blocksize / x->x_vecsize; /* 1024/64 = 16 blocks */ - x->x_blockssincesend = 0; - x->x_cbufsize = x->x_blocksize * sizeof(t_float) * x->x_ninlets; - x->x_cbuf = (char *)t_getbytes(x->x_cbufsize); - -#if defined(UNIX) || defined(unix) - /* we don't want to get signaled in case send() fails */ - signal(SIGPIPE, SIG_IGN); -#endif - } - - return (x); -} - -static void udpsend_tilde_free(t_udpsend_tilde* x) -{ - udpsend_tilde_disconnect(x); - - /* free the memory */ - if (x->x_cbuf)t_freebytes(x->x_cbuf, x->x_cbufsize); - if (x->x_myvec)t_freebytes(x->x_myvec, sizeof(t_int) * (x->x_ninlets + 3)); - - clock_free(x->x_clock); - - pthread_mutex_destroy(&x->x_mutex); -} - -void udpsend_tilde_setup(void) -{ - udpsend_tilde_class = class_new(gensym("udpsend~"), (t_newmethod)udpsend_tilde_new, (t_method)udpsend_tilde_free, - sizeof(t_udpsend_tilde), 0, A_DEFFLOAT, A_DEFFLOAT, A_NULL); - class_addmethod(udpsend_tilde_class, nullfn, gensym("signal"), 0); - class_addmethod(udpsend_tilde_class, (t_method)udpsend_tilde_dsp, gensym("dsp"), 0); - class_addfloat(udpsend_tilde_class, udpsend_tilde_float); - class_addmethod(udpsend_tilde_class, (t_method)udpsend_tilde_info, gensym("info"), 0); - class_addmethod(udpsend_tilde_class, (t_method)udpsend_tilde_connect, gensym("connect"), A_DEFSYM, A_DEFFLOAT, 0); - class_addmethod(udpsend_tilde_class, (t_method)udpsend_tilde_disconnect, gensym("disconnect"), 0); - class_addmethod(udpsend_tilde_class, (t_method)udpsend_tilde_channels, gensym("channels"), A_FLOAT, 0); - class_addmethod(udpsend_tilde_class, (t_method)udpsend_tilde_format, gensym("format"), A_SYMBOL, A_DEFFLOAT, 0); - class_sethelpsymbol(udpsend_tilde_class, gensym("udpsend~")); - post("udpsend~ v%s, (c) 2004-2005 Olaf Matthes, 2010 Martin Peach", VERSION); - post("udpsend~ Default blocksize is %d", DEFAULT_AUDIO_BUFFER_SIZE); - - ps_nothing = gensym(""); - ps_localhost = gensym("localhost"); - ps_hostname = gensym("ipaddr"); - ps_format = gensym("format"); - ps_channels = gensym("channels"); - ps_vecsize = gensym("vecsize"); - ps_framesize = gensym("framesize"); - ps_bitrate = gensym("bitrate"); - ps_sf_float = gensym("_float_"); - ps_sf_16bit = gensym("_16bit_"); - ps_sf_8bit = gensym("_8bit_"); - ps_sf_unknown = gensym("_unknown_"); -} - -/* Utility functions */ - -static int udpsend_tilde_sockerror(char *s) -{ -#ifdef _WIN32 - int err = WSAGetLastError(); - if (err == 10054) return 1; - else if (err == 10053) post("udpsend~: %s: software caused connection abort (%d)", s, err); - else if (err == 10055) post("udpsend~: %s: no buffer space available (%d)", s, err); - else if (err == 10060) post("udpsend~: %s: connection timed out (%d)", s, err); - else if (err == 10061) post("udpsend~: %s: connection refused (%d)", s, err); - else post("udpsend~: %s: %s (%d)", s, strerror(err), err); -#else - int err = errno; - post("udpsend~: %s: %s (%d)", s, strerror(err), err); -#endif -#ifdef _WIN32 - if (err == WSAEWOULDBLOCK) -#endif -#if defined(UNIX) || defined(unix) - if (err == EAGAIN) -#endif - { - return 1; /* recoverable error */ - } - return 0; /* indicate non-recoverable error */ -} - -static void udpsend_tilde_closesocket(int fd) -{ -#if defined(UNIX) || defined(unix) - close(fd); -#endif -#ifdef _WIN32 - closesocket(fd); -#endif -} - -/* fin udpsend~.c */ diff --git a/udpsend~.h b/udpsend~.h deleted file mode 100644 index 386b363..0000000 --- a/udpsend~.h +++ /dev/null @@ -1,102 +0,0 @@ -/* udpsend~.h modified by Martin Peach from netsend~.h: */ -/* ------------------------ netsend~ ------------------------------------------ */ -/* */ -/* Tilde object to send uncompressed audio data to netreceive~. */ -/* Written by Olaf Matthes <olaf.matthes@gmx.de>. */ -/* Based on streamout~ by Guenter Geiger. */ -/* Get source at http://www.akustische-kunst.org/ */ -/* */ -/* This program is free software; you can redistribute it and/or */ -/* modify it under the terms of the GNU General Public License */ -/* as published by the Free Software Foundation; either version 2 */ -/* of the License, or (at your option) any later version. */ -/* */ -/* See file LICENSE for further informations on licensing terms. */ -/* */ -/* This program 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 General Public License for more details. */ -/* */ -/* You should have received a copy of the GNU General Public License */ -/* along with this program; 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. */ -/* */ -/* This project was commissioned by the Society for Arts and Technology [SAT], */ -/* Montreal, Quebec, Canada, http://www.sat.qc.ca/. */ -/* */ -/* ---------------------------------------------------------------------------- */ - - -/* This file is based on and inspired by stream.h (C) Guenter Geiger 1999. */ -/* Some enhancements have been made with the goal of keeping compatibility */ -/* between the stream formats of streamout~/in~ and netsend~/receive~. */ - -#define VERSION "0.34" - -#define DEFAULT_AUDIO_CHANNELS 32 /* nax. number of audio channels we support */ -#define DEFAULT_AUDIO_BUFFER_SIZE 2048 /*1024*/ /* number of samples in one audio block */ -#define DEFAULT_UDP_PACKT_SIZE 8192 /* number of bytes we send in one UDP datagram (OS X only) */ -#define DEFAULT_PORT 8000 /* default network port number */ - -#ifdef _WIN32 -#ifndef HAVE_INT32_T -typedef int int32_t; -#define HAVE_INT32_T -#endif -#ifndef HAVE_INT16_T -typedef short int16_t; -#define HAVE_INT16_T -#endif -#ifndef HAVE_U_INT32_T -typedef unsigned int u_int32_t; -#define HAVE_U_INT32_T -#endif -#ifndef HAVE_U_INT16_T -typedef unsigned short u_int16_t; -#define HAVE_U_INT16_T -#endif -#endif - -typedef union _flint -{ - int i32; - t_float f32; -} flint; - -/* format specific stuff */ - -#define SF_FLOAT 1 -#define SF_DOUBLE 2 /* not implemented */ -#define SF_8BIT 10 -#define SF_16BIT 11 -#define SF_32BIT 12 /* not implemented */ -#define SF_ALAW 20 /* not implemented */ -#define SF_MP3 30 /* not implemented */ -#define SF_AAC 31 /* AAC encoding using FAAC */ -#define SF_VORBIS 40 /* not implemented */ -#define SF_FLAC 50 /* not implemented */ - -#define SF_SIZEOF(a) (a == SF_FLOAT ? sizeof(t_float) : \ - a == SF_16BIT ? sizeof(short) : 1) - -typedef struct _tag -{ /* size (bytes) */ - char tag[4]; /* 4 */ /*"TAG!"*/ - char format; /* 1 */ - long count; /* 4 */ - char channels; /* 1 */ - long framesize; /* 4 */ - char reserved[2]; /* 2 */ /* pad to 16 bytes */ -} t_tag; /*-----*/ - /* 16 */ - -typedef struct _frame -{ - t_tag tag; - char *data; -} t_frame; - -/* fin udpsend~.h */ |