Provided by: libprotocol-osc-perl_0.09-1_all
NAME
Protocol::OSC - Open Sound Control v1.1 implementation
SYNOPSIS
my $osc = Protocol::OSC->new; my $data = $osc->message(qw(/echo isf 3 ping 3.14)); # pack my $packet = $osc->parse($data); # parse $osc->actions->{$path} = $code_ref; # add callback $packet->process($data, $scheduler_coderef); # parse and execute callbacks
DESCRIPTION
This module implements (de)coding and processing of OSC packets according the specification. It's pure Perl implementation, yet faster than Net::LibLO and Net::OpenSoundControl (~2x). Also it provides connection agnostic interface and path matching and type tagging according OSC v1 specification <http://opensoundcontrol.org/spec-1_0> ( and v1.1 <http://opensoundcontrol.org/spec-1_1> )
CONSTRUCTOR
new( ?actions => {}, ?scheduler => sub {...} ) Creates Protocol::Instance with optional "actions" argument which is hashref of pairs: path => coderef and optional default scheduler for "process" method - see below.
METHODS
message($path, $typetag, ?@args) Encodes message to packet. Typetag supports these OSC-types: ifstdbht. Everything else (like TFNI) will not affect packing of @args. Alias: msg bundle(undef || $unix_time, [@message_or_bundle], ...) Encodes bundle to packet. Pack several OSC messages/bundles to a bundle. parse($data) Parses OSC packet data. Returns OSC message/bundle. OSC-message is a blessed arrayref [$path, $type, @args] with corresponding methods path, type, args. OSC-bundle is a blessed arrayref [$time, @packets] with corresponding methods time, packets process($data, ?$scheduler_cb) Parses OSC packet/data and process messages in it. It will call matched actions through $scheduler_cb which is just "sub { $_[0]->(splice @_,1) }" by default(or specified in constructor). Arguments to scheduler are $action_coderef, $time, $action_path, $osc_msg, ?@osc_bundles. actions Returns hashref of actions: path => coderef pairs. One could modify this hashref or use methods below. set_cb($path, $cb) Set coderef $cb to actions del_cb($path) Remove coderef at $path from actions at $path match($osc_path_pattern) Returns mathched actions in form of list of arrayrefs [$path, $coderef] time2tag($unix_time) Converts (fractional) unix epoch time to NTP timestamp, which is list of ($seconds_since_1900_01_01, $int32_fraction_parts_of_second). If $unix_time is undef then (0,1) is returned which means immediate execution by OSC specs. tag2time($ntp_time, $fraction_of_sec) Reverse of previous. to_stream($data) Packs raw OSC data for (tcp) streaming. from_stream($buf) Returns list of raw OSC data packets in $buf from stream buffer and residue of $buf. If $buf is incomplete - returns only $buf.
EXAMPLES
Sending make packet my $data = $osc->message(my @specs = qw(/echo isf 3 ping 3.14)); # or use Time::HiRes 'time'; my $data $osc->bundle(time, [@specs], [@specs2], ...); via UDP my $udp = IO::Socket::INET->new( PeerAddr => 'localhost', PeerPort => $port, Proto => 'udp', Type => SOCK_DGRAM) || die $!; $udp->send($data); via TCP my $tcp = IO::Socket::INET->new( PeerAddr => 'localhost', PeerPort => $port, Proto => 'tcp', Type => SOCK_STREAM) || die $!; $tcp->syswrite($osc->to_stream($data)); Receiving UDP my $in = IO::Socket::INET->new( qw(LocalAddr localhost LocalPort), $port, qw(Proto udp Type), SOCK_DGRAM ) || die $!; $in->recv(my $packet, $in->sockopt(SO_RCVBUF)); my $p = $osc->parse($packet); TCP my $in = IO::Socket::INET->new( qw(LocalAddr localhost LocalPort), $port, qw(Proto tcp Type), SOCK_STREAM, qw(Listen 1 Reuse 1) ) || die $!; while (my $sock = $in->accept) { my $tail; while ($sock->sysread(my $buf, $in->sockopt(SO_RCVBUF))) { my @packets = $p->from_stream(length($tail) ? $tail.$buf : $buf); $tail = pop @packets; $osc->parse($_) for @packets; } } Dispatching $osc->set_cb('/echo', sub { my ($at_time, $path, $msg, @maybe_bundles) = @_; say $at_time if $at_time; # time of parent bundle if message comes from bundle(s) say $path; # matched path say $msg->path; # path pattern of OSC message say $msg->type; # typetag say @{$msg->args}; # message arguments map { # all bundles from which $msg comes (from inner to outer) say $_->time; # time of bundle say $_->packets; # array of messages/bundle in bundle } @maybe_bundles; }); ... $osc->process($osc->parse($data)); Ping-Pong using AnyEvent::Handle::UDP use AnyEvent::Handle::UDP; my $udp_handle = AnyEvent::Handle::UDP->new( bind => [0, $port], on_recv => sub { my ($data, $handle, $client_addr) = @_; my $msg = $osc->parse($data); say $msg->path; $handle->push_send($osc->message(qw(/pong i), ($msg->args)[0]), $client_addr) if $msg->path eq '/ping'; } ); $udp_handle->push_send($osc->message(qw(/ping i 3)), [0, $port]); Benchmarks encode cmpthese -1, { 'Net::LibLO::Message' => sub { Net::LibLO::Message->new(qw(isf 3 laaaa 3.0)) }, 'Protocol::OSC' => sub { $protocol->message(qw(/echo isf 3 laaaa 3.0)) }, 'Net::OpenSoundControl' => sub { Net::OpenSoundControl::encode([qw(/echo i 3 s laaaa f 3.0)]) } }; ... Rate Net::LibLO::Message Net::OpenSoundControl Protocol::OSC Net::LibLO::Message 20479/s -- -7% -51% Net::OpenSoundControl 21920/s 7% -- -48% Protocol::OSC 41754/s 104% 90% -- decode cmpthese -1, { 'Protocol::OSC' => sub { $protocol->parse($data) }, 'Net::OpenSoundControl' => sub { Net::OpenSoundControl::decode($data) } }; Rate Net::OpenSoundControl Protocol::OSC Net::OpenSoundControl 1630/s -- -65% Protocol::OSC 4654/s 186% -- NB No validation checks performed
SUPPORT
• GitHub <http://github.com/vividsnow/Protocol-OSC> • Search MetaCPAN <https://metacpan.org/module/Protocol::OSC>
AUTHOR
Yegor Korablev <egor@cpan.org>
LICENSE
This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.
TODO
more docs, examples and tests.. as usual )
SEE ALSO
Net::LibLO, Net::OpenSoundControl, AnyEvent::Handle::UDP