# $Id: RPTP.pm,v 1.2 1999/03/12 18:51:45 boyns Exp $ -*-perl-*-
#
# Copyright (C) 1993-98 Mark R. Boyns <boyns@doit.org>
#
# This file is part of rplay.
#
# rplay is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# rplay is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with rplay; see the file COPYING. If not, write to the
# Free Software Foundation, Inc.,
# 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
#
require "rplay.ph";
require 5.000;
package RPTP;
require "shellwords.pl";
use FileHandle;
use Socket;
use strict;
## Create a new RPlay object.
sub new
{
my $self = {};
bless $self;
$self->{debug} = 0;
$self->{server} = ();
$self->{callbacks} = ();
$self->{socket} = undef;
$self;
}
sub debug
{
my $self = shift;
$self->{debug} = @_[0];
}
## Connect to a rplay server.
sub connect
{
my $self = shift;
my ($that_host, $that_port) = @_;
my ($pat, $name, $aliases, $proto, $port, $udp);
my (@bytes, $addrtype, $length, $old);
my ($that, $that_addr);
my ($this, $this_addr, $this_host);
my $sockaddr = 'S n a4 x8';
($name, $aliases, $proto) = getprotobyname ('tcp');
my $tcp = $proto;
#($name, $aliases, $port, $proto) = getservbyname ('rplay', 'udp');
$that_port = &main::RPTP_PORT;
chop ($this_host = `hostname`);
($name, $aliases, $addrtype, $length, $this_addr) =
gethostbyname ($this_host);
die "$this_host: unknown host\n" unless $name;
($name, $aliases, $addrtype, $length, $that_addr) =
gethostbyname ($that_host);
die "$that_host: unknown host\n" unless $name;
$this = pack ($sockaddr, AF_INET, 0, $this_addr);
$that = pack ($sockaddr, AF_INET, $that_port, $that_addr);
$self->{socket} = new FileHandle;
socket ($self->{socket}, AF_INET, SOCK_STREAM, $udp) || die "socket: $!";
connect ($self->{socket}, $that) || die "connect: $!";
$old = select ($self->{socket});
$| = 1;
select ($old);
my %hash = $self->readline();
foreach (keys %hash)
{
$self->{"server_$_"} = $hash{$_};
}
}
## Close the rplay server connection.
sub disconnect
{
my $self = shift;
close ($self->{socket});
}
sub server_info
{
my $self = shift;
$self->{"server_".@_[0]};
}
##
sub readline
{
my $self = shift;
my %hash;
my $sock = $self->{socket};
chomp(my $line = <$sock>);
print "readline: $line\n" if $self->{debug};
my $type = substr($line, 0, 1);
$hash{'_type'} = $type;
$line = substr($line, 1);
foreach (shellwords($line))
{
my ($name, $value) = split('=');
$hash{$name} = $value;
}
%hash;
}
##
sub writeline
{
my $self = shift;
my $sock = $self->{socket};
print "writeline: ", join(" ", @_), "\n" if $self->{debug};
print $sock join(" ", @_), "\n";
}
## Convert different types arguments to a list of hash references.
sub parse
{
my $self = shift;
my ($r, @refs);
$r = ref ($_[0]);
if ($r eq "HASH")
{
@refs = @_;
}
elsif ($r eq "ARRAY")
{
foreach (@_)
{
my (%attr, $i, @list);
@list = @$_;
for ($i = 0; $i < $#list; $i+=2)
{
$attr{$list[$i]} = $list[$i+1];
}
push (@refs, \%attr);
}
}
else
{
my (%attr, $i);
for ($i = 0; $i < $#_; $i+=2)
{
$attr{$_[$i]} = $_[$i+1];
}
push (@refs, \%attr);
}
return @refs;
}
## Create the appropriate RPLAY packet and send it to the server.
sub doit
{
my $self = shift;
my $command = shift;
my @refs = $self->parse (@_);
my (%attrs, $line);
#die "Not connected - use connect() first." unless $connected;
$line = "$command";
foreach (@refs)
{
%attrs = %$_;
foreach (keys %attrs)
{
$line .= " $_=\"$attrs{$_}\"";
}
}
die "Missing id or sound." unless $attrs{sound} or $attrs{id};
$self->writeline($line);
}
## Play sounds.
sub play
{
my $self = shift;
$self->doit ("play", @_);
}
## Pause sounds.
sub pause
{
my $self = shift;
$self->doit ("pause", @_);
}
## Continue sounds.
sub continue
{
my $self = shift;
$self->doit ("continue", @_);
}
## Stop sounds.
sub stop
{
my $self = shift;
$self->doit ("stop", @_);
}
## Done sounds.
sub done
{
my $self = shift;
$self->doit ("done", @_);
}
# "continue"
# "done"
# "error"
# "flow"
# "level"
# "modify"
# "ok"
# "pause"
# "play"
# "position"
# "skip"
# "stop"
# "timeout"
# "volume"
sub notify
{
my $self = shift;
my($type, $func) = @_;
$self->{callbacks}{$type} = $func;
}
my %proto =
(
"+" => "ok",
"-" => "error",
"!" => "timeout",
"@" => "event"
);
sub mainloop
{
my $self = shift;
my $single = shift;
if (!$self->{initialized})
{
my $emask;
foreach (keys %{$self->{callbacks}})
{
next if /(ok|error|timeout|event)/;
$emask .= "$_|";
}
chop $emask;
$self->writeline("set notify=$emask");
$self->{initialized} = 1;
}
for (;;)
{
my %hash = $self->readline();
my $type = $proto{$hash{_type}};
next if ($hash{command} eq "set");
my $func;
if (exists($self->{callbacks}{all}))
{
$func = $self->{callbacks}{all};
}
elsif (exists($self->{callbacks}{$type}))
{
$func = $self->{callbacks}{$type};
}
else
{
$func = $self->{callbacks}{$hash{$type}};
}
&$func(%hash) if $func;
last if $single;
}
}
1;