/* (C) Guenter Geiger */ #include #include "stream.h" #include #include #include #ifdef unix #include #include #include #include #define SOCKET_ERROR -1 #else #include #endif /* Utility functions */ static void sys_sockerror(char *s) { #ifdef unix int err = errno; #else int err = WSAGetLastError(); if (err == 10054) return; #endif post("%s: %s (%d)\n", s, strerror(err), err); } static void sys_closesocket(int fd) { #ifdef UNIX close(fd); /* shutdown() ?? */ #endif #ifdef NT closesocket(fd); #endif } /* ------------------------ streamout~ ----------------------------- */ static t_class *streamout_class; typedef struct _streamout { t_object x_obj; int x_fd; int x_protocol; t_tag x_tag; t_symbol* hostname; int portno; short* cbuf; int nsamples; int tbufsize; } t_streamout; static void streamout_tempbuf(t_streamout *x,int size) { if (x->cbuf && x->tbufsize) freebytes(x->cbuf,x->tbufsize); x->tbufsize=size*sizeof(float)*x->x_tag.channels; if (!x->cbuf) x->cbuf = getbytes(x->tbufsize); x->nsamples = size; } static void streamout_disconnect(t_streamout *x) { if (x->x_fd >= 0) { sys_closesocket(x->x_fd); x->x_fd = -1; outlet_float(x->x_obj.ob_outlet, 0); } } static void streamout_connect(t_streamout *x, t_symbol *hostname, t_floatarg fportno) { struct sockaddr_in server; struct hostent *hp; int sockfd; int portno = fportno; x->hostname = hostname; if (!fportno) x->portno = 4267; else x->portno = (int) fportno; x->x_tag.count = 0; if (x->x_fd >= 0) { post("streamout~: already connected"); return; } /* create a socket */ sockfd = socket(AF_INET, x->x_protocol, 0); if (sockfd < 0) { post("streamout: Connection to %s on port %d failed",hostname->s_name,portno); sys_sockerror("socket"); return; } /* connect socket using hostname provided in command line */ server.sin_family = AF_INET; hp = gethostbyname(x->hostname->s_name); if (hp == 0) { post("bad host?\n"); return; } memcpy((char *)&server.sin_addr, (char *)hp->h_addr, hp->h_length); /* assign client port number */ server.sin_port = htons((u_short)portno); /* try to connect. LATER make a separate thread to do this because it might block */ if (connect(sockfd, (struct sockaddr *) &server, sizeof (server)) < 0) { sys_sockerror("connecting stream socket"); sys_closesocket(sockfd); return; } post("connected host %s on port %d",hostname->s_name, portno); x->x_fd = sockfd; outlet_float(x->x_obj.ob_outlet, 1); } static t_int *streamout_perform(t_int *w) { t_streamout* x = (t_streamout*) (w[1]); t_float *in[4]; char* bp; int n; int length; int sent = 0; int i; int chans = x->x_tag.channels; for (i=0;ix_tag.format)*chans; if (n != x->nsamples) streamout_tempbuf(x,n); x->x_tag.framesize=length; x->x_tag.count++; /* format the buffer */ switch (x->x_tag.format) { case SF_FLOAT: { float* cibuf =(float*) x->cbuf; bp = (char*) x->cbuf; for (i=0;icbuf; bp = (char*) x->cbuf; for (i=0;icbuf; bp = (char*) x->cbuf; for (i=0;ix_fd > 0) { /* send the format tag */ #ifdef unix if (send(x->x_fd,(char*)&x->x_tag,sizeof(t_tag),/*MSG_DONTWAIT|*/MSG_NOSIGNAL) < 0) #else if (send(x->x_fd,(char*)&x->x_tag,sizeof(t_tag),0) < 0) #endif { sys_sockerror("streamout"); streamout_disconnect(x); return (w+4); } /* send the buffer */ for (sent = 0; sent < length;) { int res = 0; #ifdef unix res = send(x->x_fd, bp, length-sent, /*MSG_DONTWAIT|*/MSG_NOSIGNAL); #else res = send(x->x_fd, bp, length-sent, 0); #endif if (res <= 0) { sys_sockerror("streamout"); streamout_disconnect(x); break; } else { sent += res; bp += res; } } } return (w+3+chans); } static void streamout_dsp(t_streamout *x, t_signal **sp) { switch (x->x_tag.channels) { case 1: dsp_add(streamout_perform, 3, x,sp[0]->s_vec, sp[0]->s_n); post("one channel mode"); break; case 2: dsp_add(streamout_perform, 4, x,sp[0]->s_vec, sp[1]->s_vec,sp[0]->s_n); post("two channel mode"); break; case 4: dsp_add(streamout_perform, 6, x,sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec,sp[3]->s_vec,sp[0]->s_n); post("four channel mode"); break; default: post("streamout: %d channels not supported",x->x_tag.channels); } } static void streamout_format(t_streamout *x,t_symbol* form) { if (!strncmp(form->s_name,"float",5)) x->x_tag.format = (int) SF_FLOAT; if (!strncmp(form->s_name,"16bit",5)) x->x_tag.format = (int) SF_16BIT; if (!strncmp(form->s_name,"8bit",4)) x->x_tag.format = (int) SF_8BIT; post ("format set to %s", form->s_name); } static void streamout_host(t_streamout *x,t_symbol* host) { if (host != &s_) x->hostname = host; if (x->x_fd >= 0) { streamout_connect(x,x->hostname,(float) x->portno); } } static void streamout_float(t_streamout* x,t_float arg) { if (arg == 0.0) streamout_disconnect(x); else streamout_connect(x,x->hostname,(float) x->portno); } static void *streamout_new(t_symbol* prot,float channels) { t_streamout *x = (t_streamout *)pd_new(streamout_class); outlet_new(&x->x_obj, &s_float); if (channels == 0) channels = 1; x->hostname = gensym("localhost"); x->portno = 3000; x->x_fd = -1; x->x_protocol = SOCK_STREAM; if (prot != &s_) if (!strncmp(prot->s_name,"udp",3)) x->x_protocol = SOCK_DGRAM; x->x_tag.format = SF_FLOAT; x->x_tag.channels = channels; x->x_tag.version = 1; x->cbuf = NULL; streamout_tempbuf(x,64); return (x); } static void streamout_free(t_streamout* x) { if (x->cbuf && x->tbufsize) freebytes(x->cbuf,x->tbufsize); } void streamout_tilde_setup(void) { streamout_class = class_new(gensym("streamout~"), (t_newmethod) streamout_new, (t_method) streamout_free, sizeof(t_streamout), 0, A_DEFSYM,A_DEFFLOAT, 0); class_addmethod(streamout_class, (t_method) streamout_connect, gensym("connect"), A_SYMBOL, A_DEFFLOAT, 0); class_addmethod(streamout_class, (t_method) streamout_disconnect, gensym("disconnect"), 0); class_addfloat(streamout_class,streamout_float); class_addmethod(streamout_class, nullfn, gensym("signal"), 0); class_addmethod(streamout_class, (t_method) streamout_dsp, gensym("dsp"), 0); class_addmethod(streamout_class, (t_method)streamout_format,gensym("format"),A_SYMBOL,0); class_addmethod(streamout_class, (t_method)streamout_host,gensym("host"),A_DEFSYM,0); }