/usr/share/perl5/Protocol/OSC.pod is in libprotocol-osc-perl 0.08-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 | =encoding utf8
=head1 NAME
Protocol::OSC - Open Sound Control v1.1 implementation
=head1 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
=head1 DESCRIPTION
This module implements (de)coding and processing of OSC packets according the specification. It's pure Perl implementation, yet faster
than L<Net::LibLO> and L<Net::OpenSoundControl> (~2x). Also it provides connection agnostic interface and
path matching and type tagging according L<OSC v1 specification|http://opensoundcontrol.org/spec-1_0> ( and L<v1.1|http://opensoundcontrol.org/spec-1_1> )
=head1 CONSTRUCTOR
=head2 new( ?actions => {}, ?scheduler => sub {...} )
Creates Protocol::Instance with optional L</actions> argument which is hashref of pairs: I<< path => coderef >> and optional default scheduler for L</process> method - see below.
=head1 METHODS
=head2 message($path, $typetag, ?@args)
Encodes message to packet. Typetag supports these OSC-types: I<ifstdbht>. Everything else (like I<TFNI>) will not affect packing of B<@args>.
Alias: B<msg>
=head2 bundle(undef || $unix_time, [@message_or_bundle], ...)
Encodes bundle to packet. Pack several OSC messages/bundles to a bundle.
=head2 parse($data)
Parses OSC packet data. Returns OSC message/bundle.
OSC-message is a blessed arrayref B<[$path, $type, @args]> with corresponding methods B<path>, B<type>, B<args>.
OSC-bundle is a blessed arrayref B<[$time, @packets]> with corresponding methods B<time>, B<packets>
=head2 process($data, ?$scheduler_cb)
Parses OSC packet/data and process messages in it. It will call matched actions through B<$scheduler_cb> which is
just C<< sub { $_[0]->(splice @_,1) } >> by default(or specified in constructor).
Arguments to scheduler are B<$action_coderef, $time, $action_path, $osc_msg, ?@osc_bundles>.
=head2 actions
Returns hashref of actions: B<< path => coderef >> pairs. One could modify this hashref or use methods below.
=head2 set_cb($path, $cb)
Set coderef B<$cb> to B<actions>
=head2 del_cb($path)
Remove coderef at B<$path> from B<actions> at B<$path>
=head2 match($osc_path_pattern)
Returns mathched actions in form of list of arrayrefs B<[$path, $coderef]>
=head2 time2tag($unix_time)
Converts (fractional) unix epoch time to NTP timestamp, which is list of B<($seconds_since_1900_01_01, $int32_fraction_parts_of_second)>.
If B<$unix_time> is undef then (0,1) is returned which means immediate execution by OSC specs.
=head2 tag2time($ntp_time, $fraction_of_sec)
Reverse of previous.
=head2 to_stream($data)
Packs raw OSC data for (tcp) streaming.
=head2 from_stream($buf)
Returns list of raw OSC data packets in B<$buf> from stream buffer and residue of B<$buf>.
If $buf is incomplete - returns only B<$buf>.
=head1 EXAMPLES
=head2 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));
=head2 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;
}
}
=head2 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));
=head2 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]);
=head2 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% --
=head2 NB
No validation checks performed
=head1 SUPPORT
=over
=item * GitHub
L<http://github.com/vividsnow/Protocol-OSC>
=item * Search MetaCPAN
L<https://metacpan.org/module/Protocol::OSC>
=back
=head1 AUTHOR
Yegor Korablev <egor@cpan.org>
=head1 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.
=head1 TODO
more docs, examples and tests.. as usual )
=head1 SEE ALSO
L<Net::LibLO>, L<Net::OpenSoundControl>, L<AnyEvent::Handle::UDP>
=cut
|