From 9bfd11451d5fa6512aec0619c3791d66b3b1fcb7 Mon Sep 17 00:00:00 2001 From: Martin Peach Date: Wed, 13 Jan 2010 21:54:30 +0000 Subject: Fixed header files for _WIN32 svn path=/trunk/externals/mrpeach/; revision=12985 --- net/udpreceive~.c | 1487 +++++++++++++++++++++++++++-------------------------- net/udpsend~.c | 1306 +++++++++++++++++++++++----------------------- 2 files changed, 1397 insertions(+), 1396 deletions(-) diff --git a/net/udpreceive~.c b/net/udpreceive~.c index 353f1a6..85f9bf1 100644 --- a/net/udpreceive~.c +++ b/net/udpreceive~.c @@ -1,189 +1,190 @@ -/* udpreceive~ started 20100110 by Martin Peach based on netreceive~: */ -/* ------------------------ netreceive~ --------------------------------------- */ -/* */ -/* Tilde object to receive uncompressed audio data from netsend~. */ -/* Written by Olaf Matthes . */ -/* 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 -#include -#if defined(UNIX) || defined(unix) -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#define SOCKET_ERROR -1 -#endif -#ifdef _WIN32 -#include -#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; +/* udpreceive~ started 20100110 by Martin Peach based on netreceive~: */ +/* ------------------------ netreceive~ --------------------------------------- */ +/* */ +/* Tilde object to receive uncompressed audio data from netsend~. */ +/* Written by Olaf Matthes . */ +/* 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 +#include +#if defined(UNIX) || defined(unix) +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define SOCKET_ERROR -1 +#endif +#ifdef _WIN32 +#include +#include /* 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_atom x_addrbytes[5]; - int x_socket; - int x_connectsocket; - int x_nconnections; - int x_ndrops; - int x_tcp; - t_symbol *x_hostname; - - /* buffering */ - int x_framein; - int x_frameout; - t_frame x_frames[DEFAULT_AUDIO_BUFFER_FRAMES]; - int x_maxframes; - long x_framecount; - int x_blocksize; - int x_blocksperrecv; - int x_blockssincerecv; - - int x_nbytes; - int x_counter; - int x_average[DEFAULT_AVERAGE_NUMBER]; - int x_averagecur; - int x_underflow; - int x_overflow; - - 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_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; - -/* 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; - - for (i = 0; i < DEFAULT_AVERAGE_NUMBER; i++) - x->x_average[i] = x->x_maxframes; - x->x_averagecur = 0; - + int x_socket; + int x_connectsocket; + int x_nconnections; + int x_ndrops; + int x_tcp; + t_symbol *x_hostname; + + /* buffering */ + int x_framein; + int x_frameout; + t_frame x_frames[DEFAULT_AUDIO_BUFFER_FRAMES]; + int x_maxframes; + long x_framecount; + int x_blocksize; + int x_blocksperrecv; + int x_blockssincerecv; + + int x_nbytes; + int x_counter; + int x_average[DEFAULT_AVERAGE_NUMBER]; + int x_averagecur; + int x_underflow; + int x_overflow; + + 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_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; + +/* 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; + + 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)) + 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 */ + 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; -} - -static void udpreceive_tilde_datapoll(t_udpreceive_tilde *x) -{ - int ret; - int n; + post("udpreceive~: buffer must be between 1 and %d frames)", DEFAULT_AUDIO_BUFFER_FRAMES-1); + } + x->x_underflow = 0; + x->x_overflow = 0; +} + +static void udpreceive_tilde_datapoll(t_udpreceive_tilde *x) +{ + int ret; + int n; struct sockaddr_in from; socklen_t fromlen = sizeof(from); long addr; unsigned short port; - - n = x->x_nbytes; - - if (x->x_nbytes == 0) /* we ate all the samples and need a new header tag */ - { - /* receive header tag */ + + n = x->x_nbytes; + + if (x->x_nbytes == 0) /* we ate all the samples and need a new header tag */ + { + /* receive header tag */ ret = recvfrom(x->x_socket, (char*)&x->x_frames[x->x_framein].tag, sizeof(t_tag), 0, (struct sockaddr *)&from, &fromlen); /* get the sender's ip */ @@ -197,579 +198,579 @@ static void udpreceive_tilde_datapoll(t_udpreceive_tilde *x) x->x_addrbytes[4].a_w.w_float = port; outlet_list(x->x_addrout, &s_list, 5L, x->x_addrbytes); - if (ret <= 0) /* error */ - { - if (udpreceive_tilde_sockerror("recv tag")) - goto bail; - udpreceive_tilde_reset(x, 0); - x->x_counter = 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; - } - /* adjust byte order if neccessarry */ - if (x->x_frames[x->x_framein].tag.version != SF_BYTE_NATIVE) - { - x->x_frames[x->x_framein].tag.count = netsend_long(x->x_frames[x->x_framein].tag.count); - x->x_frames[x->x_framein].tag.framesize = netsend_long(x->x_frames[x->x_framein].tag.framesize); - } - /* get info from header tag */ - if (x->x_frames[x->x_framein].tag.channels > x->x_noutlets) - { - error("udpreceive~: incoming stream has too many channels (%d)", x->x_frames[x->x_framein].tag.channels); - x->x_counter = 0; - return; - } - x->x_nbytes = n = x->x_frames[x->x_framein].tag.framesize; - } - else /* we already have header tag or some data and need more */ - { + if (ret <= 0) /* error */ + { + if (udpreceive_tilde_sockerror("recv tag")) + goto bail; + udpreceive_tilde_reset(x, 0); + x->x_counter = 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; + } + /* adjust byte order if neccessarry */ + if (x->x_frames[x->x_framein].tag.version != SF_BYTE_NATIVE) + { + x->x_frames[x->x_framein].tag.count = netsend_long(x->x_frames[x->x_framein].tag.count); + x->x_frames[x->x_framein].tag.framesize = netsend_long(x->x_frames[x->x_framein].tag.framesize); + } + /* get info from header tag */ + if (x->x_frames[x->x_framein].tag.channels > x->x_noutlets) + { + error("udpreceive~: incoming stream has too many channels (%d)", x->x_frames[x->x_framein].tag.channels); + x->x_counter = 0; + return; + } + x->x_nbytes = n = x->x_frames[x->x_framein].tag.framesize; + } + 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 (udpreceive_tilde_sockerror("recv data")) - goto bail; - udpreceive_tilde_reset(x, 0); - x->x_counter = 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++; - } - } - } -bail: -; -} - -static void udpreceive_tilde_connectpoll(t_udpreceive_tilde *x) -{ - int sockaddrl = (int)sizeof(struct sockaddr); - struct sockaddr_in incomer_address; - int fd = accept(x->x_connectsocket, (struct sockaddr*)&incomer_address, &sockaddrl); - - if (fd < 0) - { - post("udpreceive~: accept failed"); - return; - } -#ifdef O_NONBLOCK - fcntl(fd, F_SETFL, O_NONBLOCK); -#endif - 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("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; - - 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_counter < x->x_maxframes) - { - goto bail; - } - - /* check for buffer underflow */ - if (x->x_framein == x->x_frameout) - { - x->x_underflow++; - goto bail; - } - - /* 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: - { - t_float* buf = (t_float *)x->x_frames[x->x_frameout].data + BLOCKOFFSET; - - if (x->x_frames[x->x_frameout].tag.version == SF_BYTE_NATIVE) - { - while (n--) - { - for (i = 0; i < channels; i++) - { - *out[i]++ = *buf++; - } - for (i = channels; i < x->x_noutlets; i++) - { - *out[i]++ = 0.; - } - } - } - else /* swap bytes */ - { - while (n--) - { - for (i = 0; i < channels; i++) - { - *out[i]++ = netsend_float(*buf++); - } - for (i = channels; i < x->x_noutlets; i++) - { - *out[i]++ = 0.; - } - } - } - break; - } - case SF_16BIT: - { - short* buf = (short *)x->x_frames[x->x_frameout].data + BLOCKOFFSET; - - if (x->x_frames[x->x_frameout].tag.version == SF_BYTE_NATIVE) - { - while (n--) - { - for (i = 0; i < channels; i++) - { - *out[i]++ = (t_float)(*buf++ * 3.051850e-05); - } - for (i = channels; i < x->x_noutlets; i++) - { - *out[i]++ = 0.; - } - } - } - else /* swap bytes */ - { - while (n--) - { - for (i = 0; i < channels; i++) - { - *out[i]++ = (t_float)(netsend_short(*buf++) * 3.051850e-05); - } - for (i = channels; i < x->x_noutlets; i++) - { - *out[i]++ = 0.; - } - } - } - break; - } - case SF_8BIT: - { - unsigned char* buf = (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; i++) - { - *out[i]++ = 0.; - } - } - break; - } - case SF_MP3: - { - post("udpreceive~: mp3 format not supported"); - } - case SF_AAC: - { - post("udpreceive~: aac format not supported"); - break; - } - default: - post("udpreceive~: unknown format (%d)",x->x_frames[x->x_frameout].tag.format); - 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("netsend~: 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); -} - -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; - - x->x_noutlets = CLIP((int)outlets, 1, DEFAULT_AUDIO_CHANNELS); - 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); + n, 0, (struct sockaddr *)&from, &fromlen); + if (ret > 0) + { + n -= ret; + } + else if (ret < 0) /* error */ + { + if (udpreceive_tilde_sockerror("recv data")) + goto bail; + udpreceive_tilde_reset(x, 0); + x->x_counter = 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++; + } + } + } +bail: +; +} + +static void udpreceive_tilde_connectpoll(t_udpreceive_tilde *x) +{ + int sockaddrl = (int)sizeof(struct sockaddr); + struct sockaddr_in incomer_address; + int fd = accept(x->x_connectsocket, (struct sockaddr*)&incomer_address, &sockaddrl); + + if (fd < 0) + { + post("udpreceive~: accept failed"); + return; + } +#ifdef O_NONBLOCK + fcntl(fd, F_SETFL, O_NONBLOCK); +#endif + 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("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; + + 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_counter < x->x_maxframes) + { + goto bail; + } + + /* check for buffer underflow */ + if (x->x_framein == x->x_frameout) + { + x->x_underflow++; + goto bail; + } + + /* 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: + { + t_float* buf = (t_float *)x->x_frames[x->x_frameout].data + BLOCKOFFSET; + + if (x->x_frames[x->x_frameout].tag.version == SF_BYTE_NATIVE) + { + while (n--) + { + for (i = 0; i < channels; i++) + { + *out[i]++ = *buf++; + } + for (i = channels; i < x->x_noutlets; i++) + { + *out[i]++ = 0.; + } + } + } + else /* swap bytes */ + { + while (n--) + { + for (i = 0; i < channels; i++) + { + *out[i]++ = netsend_float(*buf++); + } + for (i = channels; i < x->x_noutlets; i++) + { + *out[i]++ = 0.; + } + } + } + break; + } + case SF_16BIT: + { + short* buf = (short *)x->x_frames[x->x_frameout].data + BLOCKOFFSET; + + if (x->x_frames[x->x_frameout].tag.version == SF_BYTE_NATIVE) + { + while (n--) + { + for (i = 0; i < channels; i++) + { + *out[i]++ = (t_float)(*buf++ * 3.051850e-05); + } + for (i = channels; i < x->x_noutlets; i++) + { + *out[i]++ = 0.; + } + } + } + else /* swap bytes */ + { + while (n--) + { + for (i = 0; i < channels; i++) + { + *out[i]++ = (t_float)(netsend_short(*buf++) * 3.051850e-05); + } + for (i = channels; i < x->x_noutlets; i++) + { + *out[i]++ = 0.; + } + } + } + break; + } + case SF_8BIT: + { + unsigned char* buf = (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; i++) + { + *out[i]++ = 0.; + } + } + break; + } + case SF_MP3: + { + post("udpreceive~: mp3 format not supported"); + } + case SF_AAC: + { + post("udpreceive~: aac format not supported"); + break; + } + default: + post("udpreceive~: unknown format (%d)",x->x_frames[x->x_frameout].tag.format); + 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("netsend~: 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); +} + +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; + + x->x_noutlets = CLIP((int)outlets, 1, DEFAULT_AUDIO_CHANNELS); + 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_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 = -1; - x->x_socket = -1; - x->x_nconnections = 0; - x->x_ndrops = 0; - x->x_underflow = 0; - 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 * sizeof(t_float)); - } - x->x_framein = 0; - x->x_frameout = 0; - x->x_maxframes = DEFAULT_QUEUE_LENGTH; - x->x_vecsize = 64; /* we'll update this later */ + 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 = -1; + x->x_socket = -1; + x->x_nconnections = 0; + x->x_ndrops = 0; + x->x_underflow = 0; + 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 * sizeof(t_float)); + } + x->x_framein = 0; + x->x_frameout = 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; - - 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 * sizeof(t_float)); - } -} - -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_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("netsend~: %s: message too long (%d)", s, err); - else if (err == 10053) post("netsend~: %s: software caused connection abort (%d)", s, err); - else if (err == 10055) post("netsend~: %s: no buffer space available (%d)", s, err); - else if (err == 10060) post("netsend~: %s: connection timed out (%d)", s, err); - else if (err == 10061) post("netsend~: %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 1; /* recoverable error */ - } - return 0; /* 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("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 */ + 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; + + 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 * sizeof(t_float)); + } +} + +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_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("netsend~: %s: message too long (%d)", s, err); + else if (err == 10053) post("netsend~: %s: software caused connection abort (%d)", s, err); + else if (err == 10055) post("netsend~: %s: no buffer space available (%d)", s, err); + else if (err == 10060) post("netsend~: %s: connection timed out (%d)", s, err); + else if (err == 10061) post("netsend~: %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 1; /* recoverable error */ + } + return 0; /* 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("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/net/udpsend~.c b/net/udpsend~.c index 2abf288..291891e 100644 --- a/net/udpsend~.c +++ b/net/udpsend~.c @@ -1,669 +1,669 @@ -/* 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 . */ -/* 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 "float_cast.h" /* tools for fast conversion from float to int */ - -#include -#include -#include +/* 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 . */ +/* 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 "float_cast.h" /* tools for fast conversion from float to int */ + +#include +#include +#include #if defined(UNIX) || defined(unix) -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include -#include -#define SOCKET_ERROR -1 -#endif -#ifdef _WIN32 -#include -#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, *ps_overflow, *ps_underflow; -static t_symbol *ps_queuesize, *ps_average, *ps_sf_float, *ps_sf_16bit, *ps_sf_8bit; -static t_symbol *ps_sf_mp3, *ps_sf_aac, *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 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_bitrate; /* specifies bitrate for compressed formats */ - 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_cond_t x_requestcondition; - pthread_cond_t x_answercondition; - pthread_t x_childthread; -} t_udpsend_tilde; - -/* 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 = 0; - outlet_float(x->x_outlet, x->x_connectstate); - 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); -} - -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; - 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 = 0; - return (0); - } - - /* 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 = 0; - 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) - { - error("udpsend~: setsockopt(SO_PRIORITY) failed"); - } -#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 = 0; - 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); - 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 != 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 */ - pthread_create(&x->x_childthread, 0, udpsend_tilde_doconnect, x); - 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: - { - t_float* fbuf = (t_float *)x->x_cbuf + (x->x_blockssincesend * x->x_vecsize * x->x_tag.channels); - while (n--) - for (i = 0; i < x->x_tag.channels; i++) - *fbuf++ = *(in[i]++); - 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++ = (short)lrint(32767.0 * *(in[i]++)); - 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)(128. * (1.0 + *(in[i]++))); - 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.framesize = length; - x->x_tag.count = 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); +#include +#define SOCKET_ERROR -1 +#endif +#ifdef _WIN32 +#include +#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, *ps_overflow, *ps_underflow; +static t_symbol *ps_queuesize, *ps_average, *ps_sf_float, *ps_sf_16bit, *ps_sf_8bit; +static t_symbol *ps_sf_mp3, *ps_sf_aac, *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 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_bitrate; /* specifies bitrate for compressed formats */ + 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_cond_t x_requestcondition; + pthread_cond_t x_answercondition; + pthread_t x_childthread; +} t_udpsend_tilde; + +/* 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 = 0; + outlet_float(x->x_outlet, x->x_connectstate); + 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); +} + +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; + 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 = 0; + return (0); + } + + /* 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 = 0; + 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) + { + error("udpsend~: setsockopt(SO_PRIORITY) failed"); + } +#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 = 0; + 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); + 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 != 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 */ + pthread_create(&x->x_childthread, 0, udpsend_tilde_doconnect, x); + 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: + { + t_float* fbuf = (t_float *)x->x_cbuf + (x->x_blockssincesend * x->x_vecsize * x->x_tag.channels); + while (n--) + for (i = 0; i < x->x_tag.channels; i++) + *fbuf++ = *(in[i]++); + 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++ = (short)lrint(32767.0 * *(in[i]++)); + 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)(128. * (1.0 + *(in[i]++))); + 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.framesize = length; + x->x_tag.count = 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) +/* 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 ("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); - } + post ("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); - + 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)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; + SETFLOAT(list, (t_float)x->x_vecsize); + outlet_anything(x->x_outlet2, ps_vecsize, 1, list); + + /* framesize */ + SETFLOAT(list, (t_float)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); - pthread_cond_init(&x->x_requestcondition, 0); - pthread_cond_init(&x->x_answercondition, 0); - - x->x_hostname = ps_localhost; - x->x_portno = DEFAULT_PORT; - x->x_connectstate = 0; - x->x_childthread = 0; - 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_tag.version = SF_BYTE_NATIVE; /* native endianness */ - x->x_vecsize = 64; /* this is updated in the perform routine udpsend_tilde_perform */ - x->x_bitrate = 0; /* not specified, use default */ + 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); + pthread_cond_init(&x->x_requestcondition, 0); + pthread_cond_init(&x->x_answercondition, 0); + + x->x_hostname = ps_localhost; + x->x_portno = DEFAULT_PORT; + x->x_connectstate = 0; + x->x_childthread = 0; + 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_tag.version = SF_BYTE_NATIVE; /* native endianness */ + x->x_vecsize = 64; /* this is updated in the perform routine udpsend_tilde_perform */ + x->x_bitrate = 0; /* not specified, use default */ 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_cond_destroy(&x->x_requestcondition); - pthread_cond_destroy(&x->x_answercondition); - 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"); + 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_cond_destroy(&x->x_requestcondition); + pthread_cond_destroy(&x->x_answercondition); + 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 */ + 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 */ -- cgit v1.2.1