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
23 -----------------------------------------------------------------------------*/
25 //-----------------------------------------------------------------------------
29 // author: Ge Wang (gewang@cs.princeton.edu)
30 // Perry R. Cook (prc@cs.princeton.edu)
32 //-----------------------------------------------------------------------------
34 #include "util_network.h"
41 //-----------------------------------------------------------------------------
44 //-----------------------------------------------------------------------------
45 DLL_QUERY
net_query( Chuck_DL_Query
* QUERY
)
48 //! \sectionMain network
54 //! UDP-based network audio transmitter
55 QUERY
->ugen_add( QUERY
, "netout", NULL
);
57 QUERY
->ugen_func( QUERY
, netout_ctor
, netout_dtor
, netout_tick
, NULL
);
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?
65 //! UDP-based network audio receiver
66 QUERY
->ugen_add( QUERY
, "netin", NULL
);
68 QUERY
->ugen_func( QUERY
, netin_ctor
, netin_dtor
, netin_tick
, NULL
);
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?
79 //-----------------------------------------------------------------------------
80 // name: struct GigaMsg
82 //-----------------------------------------------------------------------------
89 unsigned char * payload
;
93 type
= len
= seq_num
= 0;
98 void init( unsigned int _type
, unsigned int _len
)
102 payload
= new unsigned char[len
];
123 //-----------------------------------------------------------------------------
124 // name: class GigaSend
126 //-----------------------------------------------------------------------------
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( );
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( );
155 t_CKUINT m_buffer_size
;
158 t_CKBYTE m_buffer
[0x8000];
160 SAMPLE m_writebuf
[0x8000];
168 //-----------------------------------------------------------------------------
169 // name: class GigaRecv
171 //-----------------------------------------------------------------------------
178 t_CKBOOL
listen( int port
);
179 t_CKBOOL
disconnect( );
180 t_CKBOOL
recv( t_CKBYTE
* buffer
);
182 t_CKBOOL
set_bufsize( t_CKUINT size
);
183 t_CKUINT
get_bufsize( );
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
);
196 t_CKUINT m_buffer_size
;
199 t_CKBYTE m_buffer
[0x8000];
201 SAMPLE m_readbuf
[0x8000];
209 //-----------------------------------------------------------------------------
212 //-----------------------------------------------------------------------------
213 GigaSend::GigaSend( )
218 m_hostname
= "127.0.0.1";
221 m_ptr_w
= m_writebuf
;
224 t_CKBOOL
GigaSend::good( ) { return m_sock
!= NULL
; }
229 //-----------------------------------------------------------------------------
232 //-----------------------------------------------------------------------------
233 GigaSend::~GigaSend( )
241 //-----------------------------------------------------------------------------
244 //-----------------------------------------------------------------------------
245 t_CKBOOL
GigaSend::connect( const char * hostname
, int port
)
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
;
258 m_hostname
= hostname
;
267 //-----------------------------------------------------------------------------
268 // name: set_bufsize()
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
);
277 m_ptr_w
= m_writebuf
;
278 m_ptr_end
= m_writebuf
+ bufsize
;
282 t_CKUINT
GigaSend::get_bufsize() { return m_buffer_size
; }
287 //-----------------------------------------------------------------------------
288 // name: disconnect()
290 //-----------------------------------------------------------------------------
291 t_CKBOOL
GigaSend::disconnect( )
305 //-----------------------------------------------------------------------------
306 // name: set_redundancy()
308 //-----------------------------------------------------------------------------
309 void GigaSend::set_redundancy( t_CKUINT n
)
317 //-----------------------------------------------------------------------------
318 // name: get_redundancy()
320 //-----------------------------------------------------------------------------
321 t_CKUINT
GigaSend::get_redundancy( )
329 //-----------------------------------------------------------------------------
332 //-----------------------------------------------------------------------------
333 t_CKBOOL
GigaSend::send( const t_CKBYTE
* buffer
)
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
);
349 //-----------------------------------------------------------------------------
352 //-----------------------------------------------------------------------------
353 t_CKBOOL
GigaSend::tick_out( SAMPLE sample
)
356 if( m_ptr_w
>= m_ptr_end
)
358 this->send( (t_CKBYTE
*)m_writebuf
);
359 m_ptr_w
= m_writebuf
;
370 //-----------------------------------------------------------------------------
373 //-----------------------------------------------------------------------------
374 GigaRecv::GigaRecv( )
383 t_CKBOOL
GigaRecv::good( ) { return m_sock
!= NULL
; }
388 //-----------------------------------------------------------------------------
391 //-----------------------------------------------------------------------------
392 GigaRecv::~GigaRecv( )
400 //-----------------------------------------------------------------------------
403 //-----------------------------------------------------------------------------
404 t_CKBOOL
GigaRecv::listen( int port
)
409 m_sock
= ck_udp_create();
412 if( !ck_bind( m_sock
, port
) )
414 cerr
<< "[chuck](via netin): error: cannot bind to port '" << port
<< "'" << endl
;
427 //-----------------------------------------------------------------------------
428 // name: disconnect()
430 //-----------------------------------------------------------------------------
431 t_CKBOOL
GigaRecv::disconnect( )
445 //-----------------------------------------------------------------------------
446 // name: set_bufsize()
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
);
458 t_CKUINT
GigaRecv::get_bufsize() { return m_buffer_size
; }
463 //-----------------------------------------------------------------------------
466 //-----------------------------------------------------------------------------
467 t_CKBOOL
GigaRecv::recv( t_CKBYTE
* buffer
)
469 GigaMsg
* msg
= (GigaMsg
*)m_buffer
;
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
) );
493 //-----------------------------------------------------------------------------
496 //-----------------------------------------------------------------------------
497 t_CKBOOL
GigaRecv::expire()
506 //-----------------------------------------------------------------------------
509 //-----------------------------------------------------------------------------
510 t_CKBOOL
GigaRecv::tick_in( SAMPLE
* sample
)
512 if( m_ptr_r
>= m_ptr_end
)
514 this->recv( (t_CKBYTE
*)m_readbuf
);
518 *sample
= *m_ptr_r
++;
526 //-----------------------------------------------------------------------------
529 //-----------------------------------------------------------------------------
530 UGEN_CTOR
netout_ctor( t_CKTIME now
)
532 GigaSend
* out
= new GigaSend
;
533 out
->set_bufsize( 512 );
538 UGEN_DTOR
netout_dtor( t_CKTIME now
, void * data
)
540 GigaSend
* out
= (GigaSend
*)data
;
544 UGEN_TICK
netout_tick( t_CKTIME now
, void * data
, SAMPLE in
, SAMPLE
* out
)
546 GigaSend
* x
= (GigaSend
*)data
;
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
) )
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
)
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
);
597 if( size
< 1 || size
> 0x8000 )
599 cerr
<< "[chuck](via netout): invalid buffer size '"
600 << size
<< "' (must be between 1 and 0x8000)" << endl
;
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
);
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 //-----------------------------------------------------------------------------
632 //-----------------------------------------------------------------------------
633 UGEN_CTOR
netin_ctor( t_CKTIME now
)
635 GigaRecv
* x
= new GigaRecv
;
636 x
->listen( x
->m_port
);
641 UGEN_DTOR
netin_dtor( t_CKTIME now
, void * data
)
643 GigaRecv
* x
= (GigaRecv
*)data
;
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
)
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
);
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() );