PageRenderTime 87ms CodeModel.GetById 18ms app.highlight 62ms RepoModel.GetById 1ms app.codeStats 1ms

/src/externals/mrpeach/udpsend~.c

http://github.com/danomatika/robotcowboy
C | 701 lines | 552 code | 83 blank | 66 comment | 100 complexity | 0faf8e2b445bef78bf8fe1ebf8b39a86 MD5 | raw file
  1/* udpsend~ started by Martin Peach on 20100110, based on netsend~              */
  2/* udpsend~ sends audio via udp only.*/
  3/* It is a PD external, all Max stuff has been removed from the source */
  4/* ------------------------ netsend~ ------------------------------------------ */
  5/*                                                                              */
  6/* Tilde object to send uncompressed audio data to netreceive~.                 */
  7/* Written by Olaf Matthes <olaf.matthes@gmx.de>.                               */
  8/* Based on streamout~ by Guenter Geiger.                                       */
  9/* Get source at http://www.akustische-kunst.org/                               */
 10/*                                                                              */
 11/* This program is free software; you can redistribute it and/or                */
 12/* modify it under the terms of the GNU General Public License                  */
 13/* as published by the Free Software Foundation; either version 2               */
 14/* of the License, or (at your option) any later version.                       */
 15/*                                                                              */
 16/* See file LICENSE for further informations on licensing terms.                */
 17/*                                                                              */
 18/* This program is distributed in the hope that it will be useful,              */
 19/* but WITHOUT ANY WARRANTY; without even the implied warranty of               */
 20/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                */
 21/* GNU General Public License for more details.                                 */
 22/*                                                                              */
 23/* You should have received a copy of the GNU General Public License            */
 24/* along with this program; if not, write to the Free Software                  */
 25/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.  */
 26/*                                                                              */
 27/* Based on PureData by Miller Puckette and others.                             */
 28/*                                                                              */
 29/* This project was commissioned by the Society for Arts and Technology [SAT],  */
 30/* Montreal, Quebec, Canada, http://www.sat.qc.ca/.                             */
 31/*                                                                              */
 32/* ---------------------------------------------------------------------------- */
 33
 34#include "m_pd.h"
 35
 36#include "udpsend~.h"
 37
 38#include <sys/types.h>
 39#include <string.h>
 40#include <stdlib.h>
 41#include <math.h>
 42#if defined(UNIX) || defined(unix)
 43#include <sys/socket.h>
 44#include <errno.h>
 45#include <netinet/in.h>
 46#include <netinet/tcp.h>
 47#include <arpa/inet.h>
 48#include <netdb.h>
 49#include <sys/time.h>
 50#include <signal.h>
 51#include <unistd.h>
 52#include <fcntl.h>
 53#include <stdio.h>
 54#include <pthread.h>
 55#define SOCKET_ERROR -1
 56#endif
 57#ifdef _WIN32
 58#include <winsock2.h>
 59#include "pthread.h"
 60#endif
 61
 62#ifdef MSG_NOSIGNAL
 63#define SEND_FLAGS /*MSG_DONTWAIT|*/MSG_NOSIGNAL
 64#else
 65#define SEND_FLAGS 0
 66#endif
 67
 68#ifndef SOL_IP
 69#define SOL_IP IPPROTO_IP
 70#endif
 71
 72
 73/* ------------------------ udpsend~ ----------------------------- */
 74
 75static t_class *udpsend_tilde_class;
 76
 77static t_symbol *ps_nothing, *ps_localhost, *ps_vecsize;
 78static t_symbol *ps_format, *ps_channels, *ps_framesize;
 79static t_symbol *ps_sf_float, *ps_sf_16bit, *ps_sf_8bit;
 80static t_symbol *ps_sf_unknown, *ps_bitrate, *ps_hostname;
 81
 82typedef struct _udpsend_tilde
 83{
 84    t_object        x_obj;
 85    t_outlet        *x_outlet;
 86    t_outlet        *x_outlet2;
 87    t_clock         *x_clock;
 88    int             x_fd;
 89    t_tag           x_tag;
 90    t_symbol*       x_hostname;
 91    int             x_portno;
 92    int             x_connectstate;
 93    char            *x_cbuf;
 94    int             x_cbufsize;
 95    int             x_blocksize; /* set to DEFAULT_AUDIO_BUFFER_SIZE or user-supplied argument 3 in udpsend_tilde_new() */
 96    int             x_blockspersend; /* set to x->x_blocksize / x->x_vecsize in udpsend_tilde_perform() */
 97    int             x_blockssincesend;
 98
 99    long            x_samplerate; /* samplerate we're running at */
100    int             x_vecsize; /* current DSP signal vector size */
101    int             x_ninlets; /* number of inlets */
102    int             x_channels; /* number of channels we want to stream */
103    int             x_format; /* format of streamed audio data */
104    int             x_count; /* total number of audio frames */
105    t_int           **x_myvec; /* vector we pass on in the DSP routine */
106
107    pthread_mutex_t x_mutex;
108    pthread_t       x_childthread; /* a thread to initiate a connection to the remote port */
109    pthread_attr_t  x_childthread_attr; /* child thread should have detached attribute so it can be cleaned up after it exits. */
110    int             x_childthread_result; /* result from pthread_create. Zero if x_childthread represents a valid thread. */
111} t_udpsend_tilde;
112
113#define NO_CHILDTHREAD 1 /* not zero */
114
115/* function prototypes */
116static int udpsend_tilde_sockerror(char *s);
117static void udpsend_tilde_closesocket(int fd);
118static void udpsend_tilde_notify(t_udpsend_tilde *x);
119static void udpsend_tilde_disconnect(t_udpsend_tilde *x);
120static void *udpsend_tilde_doconnect(void *zz);
121static void udpsend_tilde_connect(t_udpsend_tilde *x, t_symbol *host, t_floatarg fportno);
122static t_int *udpsend_tilde_perform(t_int *w);
123static void udpsend_tilde_dsp(t_udpsend_tilde *x, t_signal **sp);
124static void udpsend_tilde_channels(t_udpsend_tilde *x, t_floatarg channels);
125static void udpsend_tilde_format(t_udpsend_tilde *x, t_symbol* form, t_floatarg bitrate);
126static void udpsend_tilde_float(t_udpsend_tilde* x, t_floatarg arg);
127static void udpsend_tilde_info(t_udpsend_tilde *x);
128static void *udpsend_tilde_new(t_floatarg inlets, t_floatarg blocksize);
129static void udpsend_tilde_free(t_udpsend_tilde* x);
130void udpsend_tilde_setup(void);
131
132/* functions */
133static void udpsend_tilde_notify(t_udpsend_tilde *x)
134{
135    pthread_mutex_lock(&x->x_mutex);
136    x->x_childthread_result = NO_CHILDTHREAD; /* connection thread has ended */
137    outlet_float(x->x_outlet, x->x_connectstate); /* we should be connected */
138    pthread_mutex_unlock(&x->x_mutex);
139}
140
141static void udpsend_tilde_disconnect(t_udpsend_tilde *x)
142{
143    pthread_mutex_lock(&x->x_mutex);
144    if (x->x_fd != -1)
145    {
146        udpsend_tilde_closesocket(x->x_fd);
147        x->x_fd = -1;
148        x->x_connectstate = 0;
149        outlet_float(x->x_outlet, 0);
150    }
151    pthread_mutex_unlock(&x->x_mutex);
152}
153
154/* udpsend_tilde_doconnect runs in the child thread, which terminates as soon as a connection is  */
155static void *udpsend_tilde_doconnect(void *zz)
156{
157    t_udpsend_tilde     *x = (t_udpsend_tilde *)zz;
158    struct sockaddr_in  server;
159    struct hostent      *hp;
160    int                 intarg = 1;
161    int                 sockfd;
162    int                 portno;
163    int                 broadcast = 1;/* nonzero is true */
164    t_symbol            *hostname;
165
166    pthread_mutex_lock(&x->x_mutex);
167    hostname = x->x_hostname;
168    portno = x->x_portno;
169    pthread_mutex_unlock(&x->x_mutex);
170
171    /* create a socket */
172    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
173    if (sockfd < 0)
174    {
175         post("udpsend~: connection to %s on port %d failed", hostname->s_name,portno); 
176         udpsend_tilde_sockerror("socket");
177         x->x_childthread_result = NO_CHILDTHREAD;
178         return (0);
179    }
180
181#ifdef SO_BROADCAST
182    if( 0 != setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, (const void *)&broadcast, sizeof(broadcast)))
183    {
184        udpsend_tilde_sockerror("setting SO_BROADCAST");
185    }
186#endif /* SO_BROADCAST */
187
188    /* connect socket using hostname provided in command line */
189    server.sin_family = AF_INET;
190    hp = gethostbyname(x->x_hostname->s_name);
191    if (hp == 0)
192    {
193        post("udpsend~: bad host?");
194        x->x_childthread_result = NO_CHILDTHREAD;
195        return (0);
196    }
197
198#ifdef SO_PRIORITY
199    /* set high priority, LINUX only */
200    intarg = 6;	/* select a priority between 0 and 7 */
201    if (setsockopt(sockfd, SOL_SOCKET, SO_PRIORITY, (const char*)&intarg, sizeof(int)) < 0)
202    {
203        udpsend_tilde_sockerror("setting SO_PRIORITY");
204    }
205#endif
206
207    memcpy((char *)&server.sin_addr, (char *)hp->h_addr, hp->h_length);
208
209    /* assign client port number */
210    server.sin_port = htons((unsigned short)portno);
211
212    /* try to connect */
213    if (connect(sockfd, (struct sockaddr *) &server, sizeof (server)) < 0)
214    {
215        udpsend_tilde_sockerror("connecting stream socket");
216        udpsend_tilde_closesocket(sockfd);
217        x->x_childthread_result = NO_CHILDTHREAD;
218        return (0);
219    }
220
221    post("udpsend~: connected host %s on port %d", hostname->s_name, portno);
222
223    pthread_mutex_lock(&x->x_mutex);
224    x->x_fd = sockfd;
225    x->x_connectstate = 1;
226    clock_delay(x->x_clock, 0);/* udpsend_tilde_notify is called in next clock tick */
227    pthread_mutex_unlock(&x->x_mutex);
228    return (0);
229}
230
231static void udpsend_tilde_connect(t_udpsend_tilde *x, t_symbol *host, t_floatarg fportno)
232{
233    pthread_mutex_lock(&x->x_mutex);
234    if (x->x_childthread_result == 0)
235    {
236        pthread_mutex_unlock(&x->x_mutex);
237        post("udpsend~: already trying to connect");
238        return;
239    }
240    if (x->x_fd != -1)
241    {
242        pthread_mutex_unlock(&x->x_mutex);
243        post("udpsend~: already connected");
244        return;
245    }
246
247    if (host != ps_nothing)
248        x->x_hostname = host;
249    else
250        x->x_hostname = ps_localhost; /* default host */
251
252    if (!fportno)
253        x->x_portno = DEFAULT_PORT;
254    else
255        x->x_portno = (int)fportno;
256    x->x_count = 0;
257
258    /* start child thread to connect */
259    /* sender thread should start out detached so its resouces will be freed when it is done */
260    if (0!= (x->x_childthread_result = pthread_attr_init(&x->x_childthread_attr)))
261    {
262        pthread_mutex_unlock(&x->x_mutex);
263        post("udpsend~: pthread_attr_init failed: %d", x->x_childthread_result);
264        return;
265    }
266    if(0!= (x->x_childthread_result = pthread_attr_setdetachstate(&x->x_childthread_attr, PTHREAD_CREATE_DETACHED)))
267    {
268        pthread_mutex_unlock(&x->x_mutex);
269        post("udpsend~: pthread_attr_setdetachstate failed: %d", x->x_childthread_result);
270        return;
271    }
272    if (0 != (x->x_childthread_result = pthread_create(&x->x_childthread, &x->x_childthread_attr, udpsend_tilde_doconnect, x)))
273    {
274        pthread_mutex_unlock(&x->x_mutex);
275        post("udpsend~: couldn't create sender thread (%d)", x->x_childthread_result);
276        return;
277    }
278    pthread_mutex_unlock(&x->x_mutex);
279}
280
281static t_int *udpsend_tilde_perform(t_int *w)
282{
283    t_udpsend_tilde* x = (t_udpsend_tilde*) (w[1]);
284    int n = (int)(w[2]);
285    t_float *in[DEFAULT_AUDIO_CHANNELS];
286    const int offset = 3;
287    char* bp = NULL;
288    int i, length = x->x_blocksize * SF_SIZEOF(x->x_tag.format) * x->x_tag.channels;
289    int sent = 0;
290
291    pthread_mutex_lock(&x->x_mutex);
292
293    for (i = 0; i < x->x_ninlets; i++)
294        in[i] = (t_float *)(w[offset + i]);
295
296    if (n != x->x_vecsize)	/* resize buffer */
297    {
298        x->x_vecsize = n;
299        x->x_blockspersend = x->x_blocksize / x->x_vecsize;
300        x->x_blockssincesend = 0;
301        length = x->x_blocksize * SF_SIZEOF(x->x_tag.format) * x->x_tag.channels;
302    }
303
304    /* format the buffer */
305    switch (x->x_tag.format)
306    {
307        case SF_FLOAT:
308        {
309            int32_t* fbuf = (int32_t *)x->x_cbuf + (x->x_blockssincesend * x->x_vecsize * x->x_tag.channels);
310            flint fl;
311
312            while (n--)
313                for (i = 0; i < x->x_tag.channels; i++)
314                {
315                    fl.f32 = *(in[i]++);
316                    *fbuf++ = htonl(fl.i32);
317                }
318            break;
319        }
320        case SF_16BIT:
321        {
322            short* cibuf = (short *)x->x_cbuf + (x->x_blockssincesend * x->x_vecsize * x->x_tag.channels);
323
324            while (n--) 
325                for (i = 0; i < x->x_tag.channels; i++)
326                    *cibuf++ = htons((short)floor(32767.5 * *(in[i]++)));/* signed binary */
327            break;
328        }
329        case SF_8BIT:
330        {
331            unsigned char* cbuf = (unsigned char*)x->x_cbuf + (x->x_blockssincesend * x->x_vecsize * x->x_tag.channels);
332
333            while (n--) 
334                for (i = 0; i < x->x_tag.channels; i++)
335                    *cbuf++ = (unsigned char)floor(128. * (1.0 + *(in[i]++))); /* offset binary */
336            break;
337        }
338        default:
339            break;
340    }
341
342    if (!(x->x_blockssincesend < x->x_blockspersend - 1))	/* time to send the buffer */
343    {
344        x->x_blockssincesend = 0;
345        x->x_count++;	/* count data packet we're going to send */
346
347        if (x->x_fd != -1)
348        {
349            bp = (char *)x->x_cbuf;
350            /* fill in the header tag */
351            x->x_tag.tag[0] = 'T';
352            x->x_tag.tag[1] = 'A';
353            x->x_tag.tag[2] = 'G';
354            x->x_tag.tag[3] = '!';
355            x->x_tag.framesize = htonl(length);
356            x->x_tag.count = htonl(x->x_count);
357            /* send the format tag */
358            if (send(x->x_fd, (char*)&x->x_tag, sizeof(t_tag), SEND_FLAGS) < 0)
359            {
360                udpsend_tilde_sockerror("send tag");
361                pthread_mutex_unlock(&x->x_mutex);
362                udpsend_tilde_disconnect(x);
363                return (w + offset + x->x_ninlets);
364            }
365            if (length != 0)
366/* UDP: max. packet size is 64k (incl. headers) so we have to split */
367            {
368#ifdef __APPLE__
369                /* WARNING: due to a 'bug' (maybe Apple would call it a feature?) in OS X
370                    send calls with data packets larger than 16k fail with error number 40!
371                    Thus we have to split the data packets into several packets that are 
372                    16k in size. The other side will reassemble them again. */
373                int size = DEFAULT_UDP_PACKT_SIZE;
374                if (length < size)  /* maybe data fits into one packet? */
375                    size = length;
376                /* send the buffer */
377                for (sent = 0; sent < length;)
378                {
379                    int ret = 0;
380                    ret = send(x->x_fd, bp, size, SEND_FLAGS);
381                    if (ret <= 0)
382                    {
383                        udpsend_tilde_sockerror("send data");
384                        pthread_mutex_unlock(&x->x_mutex);
385                        udpsend_tilde_disconnect(x);
386                        return (w + offset + x->x_ninlets);
387                    }
388                    else
389                    {
390                        bp += ret;
391                        sent += ret;
392                        if ((length - sent) < size)
393                            size = length - sent;
394                    }
395                }
396#else
397                /* If there is any data, send the buffer, the OS might segment it into smaller packets */
398                int ret = send(x->x_fd, bp, length, SEND_FLAGS);
399                if (ret <= 0)
400                {
401                    post ("udpsend~: sending length %ld", length);
402                    udpsend_tilde_sockerror("send data");
403                    pthread_mutex_unlock(&x->x_mutex);
404                    udpsend_tilde_disconnect(x);
405                    return (w + offset + x->x_ninlets);
406                }
407#endif
408            }
409        }
410
411/* check whether user has updated any parameters */
412        if (x->x_tag.channels != x->x_channels)
413        {
414            x->x_tag.channels = x->x_channels;
415        }
416        if (x->x_tag.format != x->x_format)
417        {
418            x->x_tag.format = x->x_format;
419        }
420    }
421    else
422    {
423        x->x_blockssincesend++;
424    }
425    pthread_mutex_unlock(&x->x_mutex);
426    return (w + offset + x->x_ninlets);
427}
428
429static void udpsend_tilde_dsp(t_udpsend_tilde *x, t_signal **sp)
430{
431    int i;
432
433    pthread_mutex_lock(&x->x_mutex);
434
435    x->x_myvec[0] = (t_int*)x;
436    x->x_myvec[1] = (t_int*)sp[0]->s_n;
437
438    x->x_samplerate = sp[0]->s_sr;
439
440    for (i = 0; i < x->x_ninlets; i++)
441    {
442        x->x_myvec[2 + i] = (t_int*)sp[i]->s_vec;
443    }
444
445    pthread_mutex_unlock(&x->x_mutex);
446
447    if (DEFAULT_AUDIO_BUFFER_SIZE % sp[0]->s_n)
448    {
449        error("udpsend~: signal vector size too large (needs to be even divisor of %d)", DEFAULT_AUDIO_BUFFER_SIZE);
450    }
451    else
452    {
453        dsp_addv(udpsend_tilde_perform, x->x_ninlets + 2, (t_int*)x->x_myvec);
454    }
455}
456
457static void udpsend_tilde_channels(t_udpsend_tilde *x, t_floatarg channels)
458{
459    pthread_mutex_lock(&x->x_mutex);
460    if (channels >= 0 && channels <= x->x_ninlets)
461    {
462        x->x_channels = (int)channels;
463        post("udpsend~: channels set to %d", (int)channels);
464    }
465    else post ("udpsend~ number of channels must be between 0 and %d", x->x_ninlets);
466    pthread_mutex_unlock(&x->x_mutex);
467}
468
469static void udpsend_tilde_format(t_udpsend_tilde *x, t_symbol* form, t_floatarg bitrate)
470{
471    pthread_mutex_lock(&x->x_mutex);
472    if (!strncmp(form->s_name,"float", 5) && x->x_tag.format != SF_FLOAT)
473    {
474        x->x_format = (int)SF_FLOAT;
475    }
476    else if (!strncmp(form->s_name,"16bit", 5) && x->x_tag.format != SF_16BIT)
477    {
478        x->x_format = (int)SF_16BIT;
479    }
480    else if (!strncmp(form->s_name,"8bit", 4) && x->x_tag.format != SF_8BIT)
481    {
482        x->x_format = (int)SF_8BIT;
483    }
484
485    post("udpsend~: format set to %s", form->s_name);
486    pthread_mutex_unlock(&x->x_mutex);
487}
488
489static void udpsend_tilde_float(t_udpsend_tilde* x, t_floatarg arg)
490{
491    if (arg == 0.0)
492        udpsend_tilde_disconnect(x);
493    else
494        udpsend_tilde_connect(x,x->x_hostname,(float) x->x_portno);
495}
496
497/* send stream info */
498static void udpsend_tilde_info(t_udpsend_tilde *x)
499{
500    t_atom list[2];
501    t_symbol *sf_format;
502    t_float bitrate;
503
504    bitrate = (t_float)((SF_SIZEOF(x->x_tag.format) * x->x_samplerate * 8 * x->x_tag.channels) / 1000.);
505
506    switch (x->x_tag.format)
507    {
508        case SF_FLOAT:
509        {
510            sf_format = ps_sf_float;
511            break;
512        }
513        case SF_16BIT:
514        {
515            sf_format = ps_sf_16bit;
516            break;
517        }
518        case SF_8BIT:
519        {
520            sf_format = ps_sf_8bit;
521            break;
522        }
523        default:
524        {
525            sf_format = ps_sf_unknown;
526            break;
527        }
528    }
529
530    /* --- stream information (t_tag) --- */
531
532    /* audio format */
533    SETSYMBOL(list, (t_symbol *)sf_format);
534    outlet_anything(x->x_outlet2, ps_format, 1, list);
535
536    /* channels */
537    SETFLOAT(list, (t_float)x->x_tag.channels);
538    outlet_anything(x->x_outlet2, ps_channels, 1, list);
539
540    /* current signal vector size */
541    SETFLOAT(list, (t_float)x->x_vecsize);
542    outlet_anything(x->x_outlet2, ps_vecsize, 1, list);
543
544    /* framesize */
545    SETFLOAT(list, (t_float)(ntohl(x->x_tag.framesize)));
546    outlet_anything(x->x_outlet2, ps_framesize, 1, list);
547
548    /* bitrate */
549    SETFLOAT(list, (t_float)bitrate);
550    outlet_anything(x->x_outlet2, ps_bitrate, 1, list);
551
552    /* IP address */
553    SETSYMBOL(list, (t_symbol *)x->x_hostname);
554    outlet_anything(x->x_outlet2, ps_hostname, 1, list);
555}
556
557static void *udpsend_tilde_new(t_floatarg inlets, t_floatarg blocksize)
558{
559    int i;
560
561    t_udpsend_tilde *x = (t_udpsend_tilde *)pd_new(udpsend_tilde_class);
562    if (x)
563    {
564        for (i = sizeof(t_object); i < (int)sizeof(t_udpsend_tilde); i++)
565            ((char *)x)[i] = 0; 
566
567        if ((int)inlets < 1 || (int)inlets > DEFAULT_AUDIO_CHANNELS)
568        {
569            error("udpsend~: Number of channels must be between 1 and %d", DEFAULT_AUDIO_CHANNELS);
570            return NULL;
571        }
572        x->x_ninlets = (int)inlets;
573        for (i = 1; i < x->x_ninlets; i++)
574            inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
575 
576        x->x_outlet = outlet_new(&x->x_obj, &s_float);
577        x->x_outlet2 = outlet_new(&x->x_obj, &s_list);
578        x->x_clock = clock_new(x, (t_method)udpsend_tilde_notify);
579
580        x->x_myvec = (t_int **)t_getbytes(sizeof(t_int *) * (x->x_ninlets + 3));
581        if (!x->x_myvec)
582        {
583            error("udpsend~: out of memory");
584            return NULL;
585        }
586
587        pthread_mutex_init(&x->x_mutex, 0);
588
589        x->x_hostname = ps_localhost;
590        x->x_portno = DEFAULT_PORT;
591        x->x_connectstate = 0;
592        x->x_childthread_result = NO_CHILDTHREAD;
593        x->x_fd = -1;
594
595        x->x_tag.format = x->x_format = SF_FLOAT;
596        x->x_tag.channels = x->x_channels = x->x_ninlets;
597        x->x_vecsize = 64; /* this is updated in the perform routine udpsend_tilde_perform */
598        x->x_cbuf = NULL;
599        if (blocksize == 0) x->x_blocksize = DEFAULT_AUDIO_BUFFER_SIZE; 
600        else if (DEFAULT_AUDIO_BUFFER_SIZE%(int)blocksize)
601        {
602            error("udpsend~: blocksize must fit snugly in %d", DEFAULT_AUDIO_BUFFER_SIZE);
603            return NULL;
604        } 
605        else x->x_blocksize = (int)blocksize; //DEFAULT_AUDIO_BUFFER_SIZE; /* <-- the only place blocksize is set */
606        x->x_blockspersend = x->x_blocksize / x->x_vecsize; /* 1024/64 = 16 blocks */
607        x->x_blockssincesend = 0;
608        x->x_cbufsize = x->x_blocksize * sizeof(t_float) * x->x_ninlets;
609        x->x_cbuf = (char *)t_getbytes(x->x_cbufsize);
610
611#if defined(UNIX) || defined(unix)
612        /* we don't want to get signaled in case send() fails */
613        signal(SIGPIPE, SIG_IGN);
614#endif
615    }
616
617    return (x);
618}
619
620static void udpsend_tilde_free(t_udpsend_tilde* x)
621{
622    udpsend_tilde_disconnect(x);
623
624    /* free the memory */
625    if (x->x_cbuf)t_freebytes(x->x_cbuf, x->x_cbufsize);
626    if (x->x_myvec)t_freebytes(x->x_myvec, sizeof(t_int) * (x->x_ninlets + 3));
627
628    clock_free(x->x_clock);
629
630    pthread_mutex_destroy(&x->x_mutex);
631}
632
633void udpsend_tilde_setup(void)
634{
635    udpsend_tilde_class = class_new(gensym("udpsend~"), (t_newmethod)udpsend_tilde_new, (t_method)udpsend_tilde_free,
636        sizeof(t_udpsend_tilde), 0, A_DEFFLOAT, A_DEFFLOAT, A_NULL);
637    class_addmethod(udpsend_tilde_class, nullfn, gensym("signal"), 0);
638    class_addmethod(udpsend_tilde_class, (t_method)udpsend_tilde_dsp, gensym("dsp"), 0);
639    class_addfloat(udpsend_tilde_class, udpsend_tilde_float);
640    class_addmethod(udpsend_tilde_class, (t_method)udpsend_tilde_info, gensym("info"), 0);
641    class_addmethod(udpsend_tilde_class, (t_method)udpsend_tilde_connect, gensym("connect"), A_DEFSYM, A_DEFFLOAT, 0);
642    class_addmethod(udpsend_tilde_class, (t_method)udpsend_tilde_disconnect, gensym("disconnect"), 0);
643    class_addmethod(udpsend_tilde_class, (t_method)udpsend_tilde_channels, gensym("channels"), A_FLOAT, 0);
644    class_addmethod(udpsend_tilde_class, (t_method)udpsend_tilde_format, gensym("format"), A_SYMBOL, A_DEFFLOAT, 0);
645    class_sethelpsymbol(udpsend_tilde_class, gensym("udpsend~"));
646    post("udpsend~ v%s, (c) 2004-2005 Olaf Matthes, 2010 Martin Peach", VERSION);
647    post("udpsend~ Default blocksize is %d", DEFAULT_AUDIO_BUFFER_SIZE);
648
649    ps_nothing = gensym("");
650    ps_localhost = gensym("localhost");
651    ps_hostname = gensym("ipaddr");
652    ps_format = gensym("format");
653    ps_channels = gensym("channels");
654    ps_vecsize = gensym("vecsize");
655    ps_framesize = gensym("framesize");
656    ps_bitrate = gensym("bitrate");
657    ps_sf_float = gensym("_float_");
658    ps_sf_16bit = gensym("_16bit_");
659    ps_sf_8bit = gensym("_8bit_");
660    ps_sf_unknown = gensym("_unknown_");
661}
662
663/* Utility functions */
664
665static int udpsend_tilde_sockerror(char *s)
666{
667#ifdef _WIN32
668    int err = WSAGetLastError();
669    if (err == 10054) return 1;
670    else if (err == 10053) post("udpsend~: %s: software caused connection abort (%d)", s, err);
671    else if (err == 10055) post("udpsend~: %s: no buffer space available (%d)", s, err);
672    else if (err == 10060) post("udpsend~: %s: connection timed out (%d)", s, err);
673    else if (err == 10061) post("udpsend~: %s: connection refused (%d)", s, err);
674    else post("udpsend~: %s: %s (%d)", s, strerror(err), err);
675#else
676    int err = errno;
677    post("udpsend~: %s: %s (%d)", s, strerror(err), err);
678#endif
679#ifdef _WIN32
680    if (err == WSAEWOULDBLOCK)
681#endif
682#if defined(UNIX) || defined(unix)
683    if (err == EAGAIN)
684#endif
685    {
686        return 1;	/* recoverable error */
687    }
688    return 0;	/* indicate non-recoverable error */
689}
690
691static void udpsend_tilde_closesocket(int fd)
692{
693#if defined(UNIX) || defined(unix)
694    close(fd);
695#endif
696#ifdef _WIN32
697    closesocket(fd);
698#endif
699}
700
701/* fin udpsend~.c */