*** empty log message ***
[chuck-blob.git] / v2 / ulib_net.cpp
blobc6625453a12e412817935e3eaa28399a1b6908cb
1 /*----------------------------------------------------------------------------
2 ChucK Concurrent, On-the-fly Audio Programming Language
3 Compiler and Virtual Machine
5 Copyright (c) 2004 Ge Wang and Perry R. Cook. All rights reserved.
6 http://chuck.cs.princeton.edu/
7 http://soundlab.cs.princeton.edu/
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22 U.S.A.
23 -----------------------------------------------------------------------------*/
25 //-----------------------------------------------------------------------------
26 // file: ulib_net.cpp
27 // desc: ...
29 // author: Ge Wang (gewang@cs.princeton.edu)
30 // Perry R. Cook (prc@cs.princeton.edu)
31 // date: Spring 2004
32 //-----------------------------------------------------------------------------
33 #include "ulib_net.h"
34 #include "util_network.h"
35 #include <iostream>
36 using namespace std;
41 //-----------------------------------------------------------------------------
42 // name: net_query()
43 // desc: ...
44 //-----------------------------------------------------------------------------
45 DLL_QUERY net_query( Chuck_DL_Query * QUERY )
48 //! \sectionMain network
49 /*! \nameinfo
50 ChucK's network ugens
51 */
53 // add netout
54 //! UDP-based network audio transmitter
55 QUERY->ugen_add( QUERY, "netout", NULL );
56 // set funcs
57 QUERY->ugen_func( QUERY, netout_ctor, netout_dtor, netout_tick, NULL );
58 // ctrl funcs
59 QUERY->ugen_ctrl( QUERY, netout_ctrl_addr, netout_cget_addr, "string", "addr" ); //! target address
60 QUERY->ugen_ctrl( QUERY, netout_ctrl_port, netout_cget_port, "int", "port" ); //! target port
61 QUERY->ugen_ctrl( QUERY, netout_ctrl_size, netout_cget_size, "int", "size" ); //! packet size
62 QUERY->ugen_ctrl( QUERY, netout_ctrl_name, netout_cget_name, "string", "name" ); //! name?
64 // add netin
65 //! UDP-based network audio receiver
66 QUERY->ugen_add( QUERY, "netin", NULL );
67 // set funcs
68 QUERY->ugen_func( QUERY, netin_ctor, netin_dtor, netin_tick, NULL );
69 // ctrl funcs
70 QUERY->ugen_ctrl( QUERY, netin_ctrl_port, netin_cget_port, "int", "port" ); //! set port to receive
71 QUERY->ugen_ctrl( QUERY, netin_ctrl_name, netin_cget_name, "string", "name" ); //! name?
73 return TRUE;
79 //-----------------------------------------------------------------------------
80 // name: struct GigaMsg
81 // desc: ...
82 //-----------------------------------------------------------------------------
83 struct GigaMsg
85 unsigned int type;
86 unsigned int len;
87 unsigned int seq_num;
89 unsigned char * payload;
91 // constructor
92 GigaMsg() {
93 type = len = seq_num = 0;
94 payload = NULL;
97 // init
98 void init( unsigned int _type, unsigned int _len )
100 type = _type;
101 len = _len;
102 payload = new unsigned char[len];
105 // destructor
106 ~GigaMsg( )
108 if( payload )
110 delete [] payload;
111 payload = NULL;
114 type = 0;
115 len = 0;
116 seq_num = 0;
123 //-----------------------------------------------------------------------------
124 // name: class GigaSend
125 // desc: ...
126 //-----------------------------------------------------------------------------
127 class GigaSend
129 public:
130 GigaSend( );
131 ~GigaSend( );
133 t_CKBOOL connect( const char * hostname, int port );
134 t_CKBOOL disconnect( );
135 t_CKBOOL send( const t_CKBYTE * buffer );
136 t_CKBOOL set_bufsize( t_CKUINT buffer_size );
137 t_CKUINT get_bufsize( );
138 t_CKBOOL good( );
140 t_CKBOOL tick_out( SAMPLE sample );
141 t_CKBOOL tick_out( SAMPLE l, SAMPLE r );
142 t_CKBOOL tick_out( SAMPLE * samples, t_CKDWORD n );
144 void set_redundancy( t_CKUINT n );
145 t_CKUINT get_redundancy( );
147 // data
148 string m_hostname;
149 int m_port;
150 string m_name;
152 protected:
153 ck_socket m_sock;
154 t_CKUINT m_red;
155 t_CKUINT m_buffer_size;
156 GigaMsg m_msg;
157 t_CKUINT m_len;
158 t_CKBYTE m_buffer[0x8000];
160 SAMPLE m_writebuf[0x8000];
161 SAMPLE * m_ptr_w;
162 SAMPLE * m_ptr_end;
168 //-----------------------------------------------------------------------------
169 // name: class GigaRecv
170 // desc: ...
171 //-----------------------------------------------------------------------------
172 class GigaRecv
174 public:
175 GigaRecv( );
176 ~GigaRecv( );
178 t_CKBOOL listen( int port );
179 t_CKBOOL disconnect( );
180 t_CKBOOL recv( t_CKBYTE * buffer );
181 t_CKBOOL expire();
182 t_CKBOOL set_bufsize( t_CKUINT size );
183 t_CKUINT get_bufsize( );
184 t_CKBOOL good( );
186 t_CKBOOL tick_in( SAMPLE * sample );
187 t_CKBOOL tick_in( SAMPLE * l, SAMPLE * r );
188 t_CKBOOL tick_in( SAMPLE * samples, t_CKDWORD n );
190 // data
191 int m_port;
192 string m_name;
194 protected:
195 ck_socket m_sock;
196 t_CKUINT m_buffer_size;
197 GigaMsg m_msg;
198 t_CKUINT m_len;
199 t_CKBYTE m_buffer[0x8000];
201 SAMPLE m_readbuf[0x8000];
202 SAMPLE * m_ptr_r;
203 SAMPLE * m_ptr_end;
209 //-----------------------------------------------------------------------------
210 // name: GigaSend()
211 // desc: ...
212 //-----------------------------------------------------------------------------
213 GigaSend::GigaSend( )
215 m_sock = NULL;
216 m_red = 1;
217 m_buffer_size = 0;
218 m_hostname = "127.0.0.1";
219 m_port = 8890;
220 m_msg.seq_num = 0;
221 m_ptr_w = m_writebuf;
222 m_ptr_end = NULL;
224 t_CKBOOL GigaSend::good( ) { return m_sock != NULL; }
229 //-----------------------------------------------------------------------------
230 // name: ~GigaSend()
231 // desc: ...
232 //-----------------------------------------------------------------------------
233 GigaSend::~GigaSend( )
235 this->disconnect();
241 //-----------------------------------------------------------------------------
242 // name: connect()
243 // desc: ...
244 //-----------------------------------------------------------------------------
245 t_CKBOOL GigaSend::connect( const char * hostname, int port )
247 if( m_sock )
248 return FALSE;
250 m_sock = ck_udp_create( );
251 if( !ck_connect( m_sock, hostname, port ) )
253 cerr << "[chuck](via netout): error: cannot connect to '" << hostname << ":"
254 << port << "'" << endl;
255 return FALSE;
258 m_hostname = hostname;
259 m_port = port;
261 return TRUE;
267 //-----------------------------------------------------------------------------
268 // name: set_bufsize()
269 // desc: ...
270 //-----------------------------------------------------------------------------
271 t_CKBOOL GigaSend::set_bufsize( t_CKUINT bufsize )
273 m_buffer_size = bufsize * sizeof(SAMPLE);
274 m_len = sizeof(GigaMsg) + m_buffer_size - sizeof( m_msg.payload );
275 m_msg.type = 0;
276 m_msg.len = bufsize;
277 m_ptr_w = m_writebuf;
278 m_ptr_end = m_writebuf + bufsize;
280 return TRUE;
282 t_CKUINT GigaSend::get_bufsize() { return m_buffer_size; }
287 //-----------------------------------------------------------------------------
288 // name: disconnect()
289 // desc: ...
290 //-----------------------------------------------------------------------------
291 t_CKBOOL GigaSend::disconnect( )
293 if( !m_sock )
294 return FALSE;
296 ck_close( m_sock );
297 m_sock = NULL;
299 return TRUE;
305 //-----------------------------------------------------------------------------
306 // name: set_redundancy()
307 // desc: ...
308 //-----------------------------------------------------------------------------
309 void GigaSend::set_redundancy( t_CKUINT n )
311 m_red = n;
317 //-----------------------------------------------------------------------------
318 // name: get_redundancy()
319 // desc: ...
320 //-----------------------------------------------------------------------------
321 t_CKUINT GigaSend::get_redundancy( )
323 return m_red;
329 //-----------------------------------------------------------------------------
330 // name: send()
331 // desc: ...
332 //-----------------------------------------------------------------------------
333 t_CKBOOL GigaSend::send( const t_CKBYTE * buffer )
335 m_msg.seq_num++;
337 memcpy( m_buffer, &m_msg, sizeof( unsigned int ) * 3 );
338 memcpy( m_buffer + sizeof( unsigned int ) * 3, buffer, m_buffer_size );
340 for( int i = 0; i < m_red; i++ )
341 ck_send( m_sock, (const char * )m_buffer, m_len );
343 return TRUE;
349 //-----------------------------------------------------------------------------
350 // name: tick_out()
351 // desc: ...
352 //-----------------------------------------------------------------------------
353 t_CKBOOL GigaSend::tick_out( SAMPLE sample )
355 // send
356 if( m_ptr_w >= m_ptr_end )
358 this->send( (t_CKBYTE *)m_writebuf );
359 m_ptr_w = m_writebuf;
362 *m_ptr_w++ = sample;
364 return TRUE;
370 //-----------------------------------------------------------------------------
371 // name: GigaRecv()
372 // desc: ...
373 //-----------------------------------------------------------------------------
374 GigaRecv::GigaRecv( )
376 m_sock = NULL;
377 m_buffer_size = 0;
378 m_msg.seq_num = 1;
379 m_port = 8890;
380 m_ptr_r = NULL;
381 m_ptr_end = NULL;
383 t_CKBOOL GigaRecv::good( ) { return m_sock != NULL; }
388 //-----------------------------------------------------------------------------
389 // name: ~GigaRecv()
390 // desc: ...
391 //-----------------------------------------------------------------------------
392 GigaRecv::~GigaRecv( )
394 this->disconnect( );
400 //-----------------------------------------------------------------------------
401 // name: listen()
402 // desc: ...
403 //-----------------------------------------------------------------------------
404 t_CKBOOL GigaRecv::listen( int port )
406 if( m_sock )
407 return FALSE;
409 m_sock = ck_udp_create();
411 // bind
412 if( !ck_bind( m_sock, port ) )
414 cerr << "[chuck](via netin): error: cannot bind to port '" << port << "'" << endl;
415 return FALSE;
418 m_port = port;
419 m_msg.seq_num = 1;
421 return TRUE;
427 //-----------------------------------------------------------------------------
428 // name: disconnect()
429 // desc: ...
430 //-----------------------------------------------------------------------------
431 t_CKBOOL GigaRecv::disconnect( )
433 if( !m_sock )
434 return FALSE;
436 ck_close( m_sock );
437 m_sock = NULL;
439 return TRUE;
445 //-----------------------------------------------------------------------------
446 // name: set_bufsize()
447 // desc: ...
448 //-----------------------------------------------------------------------------
449 t_CKBOOL GigaRecv::set_bufsize( t_CKUINT bufsize )
451 m_buffer_size = bufsize;
452 m_len = sizeof(GigaMsg) + bufsize - sizeof( m_msg.payload );
453 m_msg.type = 0;
454 m_msg.len = m_len;
456 return TRUE;
458 t_CKUINT GigaRecv::get_bufsize() { return m_buffer_size; }
463 //-----------------------------------------------------------------------------
464 // name: recv()
465 // desc: ...
466 //-----------------------------------------------------------------------------
467 t_CKBOOL GigaRecv::recv( t_CKBYTE * buffer )
469 GigaMsg * msg = (GigaMsg *)m_buffer;
471 if( !m_sock )
472 return FALSE;
474 do{ ck_recv( m_sock, (char *)m_buffer, 0x8000 ); }
475 while( msg->seq_num < m_msg.seq_num );
477 if( msg->seq_num > (m_msg.seq_num + 1) )
478 cerr << "[chuck](via netin): dropped packet, expect: " << m_msg.seq_num + 1
479 << " got: " << msg->seq_num << endl;
481 m_msg.seq_num = msg->seq_num;
482 m_msg.len = msg->len;
483 m_ptr_end = m_readbuf + msg->len;
485 memcpy( buffer, m_buffer + sizeof( unsigned int ) * 3, m_msg.len * sizeof(SAMPLE) );
487 return TRUE;
493 //-----------------------------------------------------------------------------
494 // name: expire()
495 // desc: ...
496 //-----------------------------------------------------------------------------
497 t_CKBOOL GigaRecv::expire()
499 m_msg.seq_num++;
500 return true;
506 //-----------------------------------------------------------------------------
507 // name: tick_in()
508 // desc: ...
509 //-----------------------------------------------------------------------------
510 t_CKBOOL GigaRecv::tick_in( SAMPLE * sample )
512 if( m_ptr_r >= m_ptr_end )
514 this->recv( (t_CKBYTE *)m_readbuf );
515 m_ptr_r = m_readbuf;
518 *sample = *m_ptr_r++;
520 return TRUE;
526 //-----------------------------------------------------------------------------
527 // name: netout
528 // desc: ...
529 //-----------------------------------------------------------------------------
530 UGEN_CTOR netout_ctor( t_CKTIME now )
532 GigaSend * out = new GigaSend;
533 out->set_bufsize( 512 );
535 return out;
538 UGEN_DTOR netout_dtor( t_CKTIME now, void * data )
540 GigaSend * out = (GigaSend *)data;
541 delete out;
544 UGEN_TICK netout_tick( t_CKTIME now, void * data, SAMPLE in, SAMPLE * out )
546 GigaSend * x = (GigaSend *)data;
547 *out = 0.0f;
548 return x->tick_out( in );
551 UGEN_CTRL netout_ctrl_addr( t_CKTIME now, void * data, void * value )
553 GigaSend * x = (GigaSend *)data;
554 char * str = GET_NEXT_STRING(value);
556 // check if the same and already good
557 if( x->good() && !strcmp( x->m_hostname.c_str(), str ) )
558 return;
560 // connect
561 x->disconnect();
562 x->connect( str, x->m_port );
565 UGEN_CGET netout_cget_addr( t_CKTIME now, void * data, void * out )
567 GigaSend * x = (GigaSend *)data;
568 SET_NEXT_STRING( out, (char *)x->m_hostname.c_str() );
571 UGEN_CTRL netout_ctrl_port( t_CKTIME now, void * data, void * value )
573 GigaSend * x = (GigaSend *)data;
574 int port = GET_NEXT_INT(value);
576 // check if the same and already connected
577 if( x->good() && port == x->m_port )
578 return;
580 // connect
581 x->disconnect();
582 x->connect( x->m_hostname.c_str(), port );
585 UGEN_CGET netout_cget_port( t_CKTIME now, void * data, void * out )
587 GigaSend * x = (GigaSend *)data;
588 SET_NEXT_INT( out, x->m_port );
591 UGEN_CTRL netout_ctrl_size( t_CKTIME now, void * data, void * value )
593 GigaSend * x = (GigaSend *)data;
594 int size = GET_NEXT_INT(value);
596 // sanity check
597 if( size < 1 || size > 0x8000 )
599 cerr << "[chuck](via netout): invalid buffer size '"
600 << size << "' (must be between 1 and 0x8000)" << endl;
601 return;
604 x->set_bufsize( (t_CKDWORD)size );
607 UGEN_CGET netout_cget_size( t_CKTIME now, void * data, void * out )
609 GigaSend * x = (GigaSend *)data;
610 SET_NEXT_INT( out, x->get_bufsize() );
613 UGEN_CTRL netout_ctrl_name( t_CKTIME now, void * data, void * value )
615 GigaSend * x = (GigaSend *)data;
616 char * str = GET_NEXT_STRING(value);
617 x->m_name = str;
620 UGEN_CGET netout_cget_name( t_CKTIME now, void * data, void * out )
622 GigaSend * x = (GigaSend *)data;
623 SET_NEXT_STRING( out, (char *)x->m_name.c_str() );
629 //-----------------------------------------------------------------------------
630 // name: netin
631 // desc: ...
632 //-----------------------------------------------------------------------------
633 UGEN_CTOR netin_ctor( t_CKTIME now )
635 GigaRecv * x = new GigaRecv;
636 x->listen( x->m_port );
638 return x;
641 UGEN_DTOR netin_dtor( t_CKTIME now, void * data )
643 GigaRecv * x = (GigaRecv *)data;
644 delete x;
647 UGEN_TICK netin_tick( t_CKTIME now, void * data, SAMPLE in, SAMPLE * out )
649 GigaRecv * x = (GigaRecv *)data;
650 return x->tick_in( out );
653 UGEN_CTRL netin_ctrl_port( t_CKTIME now, void * data, void * value )
655 GigaRecv * x = (GigaRecv *)data;
656 int port = GET_NEXT_INT(value);
658 // check if same and already connected
659 if( x->good() && x->m_port == port )
660 return;
662 // connect
663 x->disconnect( );
664 x->listen( port );
667 UGEN_CGET netin_cget_port( t_CKTIME now, void * data, void * out )
669 GigaRecv * x = (GigaRecv *)data;
670 SET_NEXT_INT( out, x->m_port );
673 UGEN_CTRL netin_ctrl_name( t_CKTIME now, void * data, void * value )
675 GigaRecv * x = (GigaRecv *)data;
676 char * str = GET_NEXT_STRING(value);
677 x->m_name = str;
680 UGEN_CGET netin_cget_name( t_CKTIME now, void * data, void * out )
682 GigaRecv * x = (GigaRecv *)data;
683 SET_NEXT_STRING( out, (char *)x->m_name.c_str() );