restructuring of files 6 - install script will not function at this point

git-svn-id: svn://192.168.202.10@22 3d104415-ff17-0410-8863-d5cf3c621b8a
This commit is contained in:
mattf
2006-07-07 23:25:55 +00:00
parent 543ebab11b
commit bd9f137fa4
874 changed files with 271801 additions and 0 deletions
+146
View File
@@ -0,0 +1,146 @@
#!/usr/bin/perl
### AST_VICI_conf.pl
###
### Copyright (C) 2006 Matt Florell <vicidial@gmail.com> LICENSE: GPLv2
###
### Customized Variables
$SIP_user = 'SIP/cc100'; # your phone id
$server_ip = '10.10.10.15'; # Asterisk server IP
$DB_server = '10.10.10.15'; # MySQL server IP
$DB_database = 'asterisk'; # MySQL database name
$DB_user = 'idcheck'; # MySQL user
$DB_pass = '1234'; # MySQL pass
$DB_port = '3306'; # MySQL connection port
### Constants
$record_channel='';
$filename='';
$recording_id='';
$US = '_';
$MT[0] = '';
return 1;
# this subroutine is to be used with the callerID function to customize the
# variables that are passed in the URL string and the way that they are passed,
# these are the variables you have to work with:
# $callerID_areacode
# $callerID_prefix
# $callerID_last4
# $callerID_Time
# $callerID_Channel
# $callerID_uniqueID
# $callerID_phone_ext
# $callerID_server_ip
# $callerID_extension
# $callerID_inbound_number
# $callerID_comment_a
# $callerID_comment_b
# $callerID_comment_c
# $callerID_comment_d
# $callerID_comment_e
sub create_callerID_local_query_string
{
$local_web_callerID_QUERY_STRING ='';
$local_web_callerID_QUERY_STRING.="?callerID_areacode=$callerID_areacode";
$local_web_callerID_QUERY_STRING.="&callerID_prefix=$callerID_prefix";
$local_web_callerID_QUERY_STRING.="&callerID_last4=$callerID_last4";
$local_web_callerID_QUERY_STRING.="&callerID_Time=$callerID_Time";
$local_web_callerID_QUERY_STRING.="&callerID_Channel=$callerID_Channel";
$local_web_callerID_QUERY_STRING.="&callerID_uniqueID=$callerID_uniqueID";
$local_web_callerID_QUERY_STRING.="&callerID_phone_ext=$callerID_phone_ext";
$local_web_callerID_QUERY_STRING.="&callerID_server_ip=$callerID_server_ip";
$local_web_callerID_QUERY_STRING.="&callerID_extension=$callerID_extension";
$local_web_callerID_QUERY_STRING.="&callerID_inbound_number=$callerID_inbound_number";
$local_web_callerID_QUERY_STRING.="&callerID_comment_a=$callerID_comment_a";
$local_web_callerID_QUERY_STRING.="&callerID_comment_b=$callerID_comment_b";
$local_web_callerID_QUERY_STRING.="&callerID_comment_c=$callerID_comment_c";
$local_web_callerID_QUERY_STRING.="&callerID_comment_d=$callerID_comment_d";
$local_web_callerID_QUERY_STRING.="&callerID_comment_e=$callerID_comment_e";
}
# $lead_id
# $vendor_id
# $list_id
# $phone_code
# $phone_number
# $title
# $first_name
# $middle_initial
# $last_name
# $address1
# $address2
# $address3
# $city
# $state
# $province
# $postal_code
# $country_code
# $gender
# $date_of_birth
# $alt_phone
# $email
# $security
# $comments
# $user
# $pass
# $fronter
# $closer
# $campaign
# $group
# $SQLdate
# $epoch
# $uniqueid
# $customer_zap_channel
# $server_ip
# $SIPexten
sub create_VICIDIAL_query_string
{
$VICIDIAL_web_QUERY_STRING ='';
$VICIDIAL_web_QUERY_STRING.="?lead_id=$lead_id";
$VICIDIAL_web_QUERY_STRING.="&vendor_id=$vendor_id";
$VICIDIAL_web_QUERY_STRING.="&list_id=$list_id";
$VICIDIAL_web_QUERY_STRING.="&phone_code=$phone_code";
$VICIDIAL_web_QUERY_STRING.="&phone_number=$phone_number";
$VICIDIAL_web_QUERY_STRING.="&title=$title";
$VICIDIAL_web_QUERY_STRING.="&first_name=$first_name";
$VICIDIAL_web_QUERY_STRING.="&middle_initial=$middle_initial";
$VICIDIAL_web_QUERY_STRING.="&last_name=$last_name";
$VICIDIAL_web_QUERY_STRING.="&address1=$address1";
$VICIDIAL_web_QUERY_STRING.="&address2=$address2";
$VICIDIAL_web_QUERY_STRING.="&address3=$address3";
$VICIDIAL_web_QUERY_STRING.="&city=$city";
$VICIDIAL_web_QUERY_STRING.="&state=$state";
$VICIDIAL_web_QUERY_STRING.="&province=$province";
$VICIDIAL_web_QUERY_STRING.="&postal_code=$postal_code";
$VICIDIAL_web_QUERY_STRING.="&country_code=$country_code";
$VICIDIAL_web_QUERY_STRING.="&gender=$gender";
$VICIDIAL_web_QUERY_STRING.="&date_of_birth=$date_of_birth";
$VICIDIAL_web_QUERY_STRING.="&alt_phone=$alt_phone";
$VICIDIAL_web_QUERY_STRING.="&email=$email";
$VICIDIAL_web_QUERY_STRING.="&security=$security";
$VICIDIAL_web_QUERY_STRING.="&comments=$comments";
$VICIDIAL_web_QUERY_STRING.="&user=$user";
$VICIDIAL_web_QUERY_STRING.="&pass=$userpass";
$VICIDIAL_web_QUERY_STRING.="&fronter=$fronter";
$VICIDIAL_web_QUERY_STRING.="&closer=$user";
$VICIDIAL_web_QUERY_STRING.="&campaign=$campaign";
$VICIDIAL_web_QUERY_STRING.="&group=$group";
$VICIDIAL_web_QUERY_STRING.="&channel_group=$channel_group";
$VICIDIAL_web_QUERY_STRING.="&SQLdate=$SQLdate";
$VICIDIAL_web_QUERY_STRING.="&epoch=$secX";
$VICIDIAL_web_QUERY_STRING.="&uniqueid=$uniqueid";
$VICIDIAL_web_QUERY_STRING.="&customer_zap_channel=$customer_zap_channel";
$VICIDIAL_web_QUERY_STRING.="&server_ip=$server_ip";
$VICIDIAL_web_QUERY_STRING.="&SIPexten=$SIPexten";
$VICIDIAL_web_QUERY_STRING.="&session_id=$session_id";
$VICIDIAL_web_QUERY_STRING.="&phone=$phone_number";
$VICIDIAL_web_QUERY_STRING.="&parked_by=$lead_id";
$VICIDIAL_web_QUERY_STRING =~ s/ /+/gi;
$VICIDIAL_web_QUERY_STRING =~ s/\`|\~|\:|\;|\#|\'|\"|\{|\}|\(|\)|\*|\^|\%|\$|\!|\%|\r|\t|\n//gi;
}
+14
View File
@@ -0,0 +1,14 @@
ACT|0200|0399
NT|0800|0999
NSW|1000|2599
ACT|2600|2618
NSW|2619|2899
ACT|2900|2920
NSW|2921|2999
VIC|3000|3999
QLD|4000|4999
SA|5000|5999
WA|6000|6999
TAS|7000|7999
VIC|8000|8999
QLD|9000|9999
+20
View File
@@ -0,0 +1,20 @@
package Asterisk;
require 5.004;
$VERSION = '0.08';
sub version { $VERSION; }
sub new {
my ($class, %args) = @_;
my $self = {};
$self->{configfile} = undef;
$self->{config} = {};
bless $self, ref $class || $class;
return $self;
}
sub DESTROY { }
1;
+685
View File
@@ -0,0 +1,685 @@
package Asterisk::AGI;
require 5.004;
use Asterisk;
@ISA = ( 'Asterisk' );
=head1 NAME
Asterisk::AGI - Simple Asterisk Gateway Interface Class
=head1 SYNOPSIS
use Asterisk::AGI;
$AGI = new Asterisk::AGI;
# pull AGI variables into %input
%input = $AGI->ReadParse();
# say the number 1984
$AGI->say_number(1984);
=head1 DESCRIPTION
This module should make it easier to write scripts that interact with the
asterisk open source pbx via AGI (asterisk gateway interface)
=head1 AGI COMMANDS
=cut
sub new {
my ($class, %args) = @_;
my $self = {};
$self->{'callback'} = undef;
$self->{'status'} = undef;
$self->{'lastresponse'} = undef;
bless $self, ref $class || $class;
return $self;
}
sub ReadParse {
my ($self, $fh) = @_;
my %input = ();
$fh = \*STDIN if (!$fh);
while (<$fh>) {
chomp;
last unless length($_);
if (/^agi_(\w+)\:\s+(.*)$/) {
$input{$1} = $2;
}
}
if (defined($DEBUG)&&($DEBUG>0)) {
print STDERR "AGI Environment Dump:\n";
foreach $i (sort keys %input) {
print STDERR " -- $i = $input{$i}\n";
}
}
return %input;
}
sub setcallback {
my ($self, $function) = @_;
if (defined($function) && ref($function) eq 'CODE') {
$self->{'callback'} = $function;
}
}
sub callback {
my ($self, $result) = @_;
if (defined($self->{'callback'}) && ref($self->{'callback'}) eq 'CODE') {
&{$self->{'callback'}}($result);
}
}
sub execute {
my ($self, $command) = @_;
$self->_execcommand($command);
my $res = $self->_readresponse();
return $self->_checkresult($res);
}
sub _execcommand {
my ($self, $command, $fh) = @_;
$fh = \*STDOUT if (!$fh);
select ((select ($fh), $| = 1)[0]);
return -1 if (!defined($command));
return print $fh "$command\n";
}
sub _readresponse {
my ($self, $fh) = @_;
my $response = undef;
$fh = \*STDIN if (!$fh);
$response = <$fh> || return '200 result=-1 (noresponse)';
chomp($response);
return $response;
}
sub _checkresult {
my ($self, $response) = @_;
return undef if (!defined($response));
my $result = undef;
$self->_lastresponse($response);
if ($response =~ /^200/) {
if ($response =~ /result=(-?[\d*#]+)/) {
$result = $1;
}
} elsif ($response =~ /\(noresponse\)/) {
$self->_status('noresponse');
} else {
print STDERR "Unexpected result '$response'\n" if (defined($DEBUG) && $DEBUG);
}
print STDERR "_checkresult($response) = $result\n" if (defined($DEBUG) && $DEBUG>3);
return $result;
}
sub _status {
my ($self, $status) = @_;
if (defined($status)) {
$self->{'status'} = $status;
} else {
return $self->{'status'};
}
}
sub _lastresponse {
my ($self, $response) = @_;
if (defined($response)) {
$self->{'lastresponse'} = $response;
} else {
return $self->{'lastresponse'};
}
}
=over 4
=item $AGI->stream_file($filename, $digits)
Executes AGI Command "STREAM FILE $filename $digits"
This command instructs Asterisk to play the given sound file and listen for the given dtmf digits. The
fileextension must not be used in the filename because Asterisk will find the most appropriate file
type.
Example: $AGI->stream_file('demo-echotest', '0123');
Returns: -1 on error or hangup,
0 if playback completes without a digit being pressed,
or the ASCII numerical value of the digit if a digit was pressed
=cut
sub stream_file {
my ($self, $filename, $digits) = @_;
my $ret = 0;
$digits = '""' if (!defined($digits));
return -1 if (!defined($filename));
$ret = $self->execute("STREAM FILE $filename $digits");
$self->callback($ret) if ($ret == -1);
return $ret;
}
=item $AGI->send_text($text)
Executes AGI Command "SEND TEXT "$text"
Sends the given text on a channel. Most channels do not support the transmission of text.
Example: $AGI->send_text('You've got mail!');
Returns: -1 on error or hangup,
0 if the text was sent or if the channel does not support text transmission.
=cut
sub send_text {
my ($self, $text) = @_;
my $ret = 0;
return $ret if (!defined($text));
$ret = $self->execute("SEND TEXT \"$text\"");
$self->callback($ret) if ($ret == -1);
return $ret;
}
=item $AGI->send_image($image)
Executes AGI Command "SEND IMAGE $image
Sends the given image on a channel. Most channels do not support the transmission of images.
Example: $AGI->send_image('image.png');
Returns: -1 on error or hangup,
0 if the image was sent or if the channel does not support image transmission.
=cut
sub send_image {
my ($self, $image) = @_;
my $ret = 0;
return -1 if (!defined($image));
$ret = $self->execute("SEND IMAGE $image");
$self->callback($ret) if ($ret == -1);
return $ret;
}
=item $AGI->say_number($number, $digits)
Executes AGI Command "SAY NUMBER $number $digits"
Says the given $number, returning early if any of the $digits are received.
Example: $AGI->say_number('98765');
Returns: -1 on error or hangup,
0 if playback completes without a digit being pressed,
or the ASCII numerical value of the digit of one was pressed.
=cut
sub say_number {
my ($self, $number, $digits) = @_;
my $ret = 0;
$digits = '""' if (!defined($digits));
return -1 if (!defined($number));
$number =~ s/\D//g;
$ret = $self->execute("SAY NUMBER $number $digits");
$self->callback($ret) if ($ret == -1);
return $ret;
}
=item $AGI->say_digits($number, $digits)
Executes AGI Command "SAY DIGITS $number $digits"
Says the given digit string $number, returning early if any of the $digits are received.
Example: $AGI->say_digits('8675309');
Returns: -1 on error or hangup,
0 if playback completes without a digit being pressed,
or the ASCII numerical value of the digit of one was pressed.
=cut
sub say_digits {
my ($self, $number, $digits) = @_;
my $ret = 0;
$digits = '""' if (!defined($digits));
return -1 if (!defined($number));
$number =~ s/\D//g;
$ret = $self->execute("SAY DIGITS $number $digits");
$self->callback($ret) if ($ret == -1);
return $ret;
}
=item $AGI->answer()
Executes AGI Command "ANSWER"
Answers channel if not already in answer state
Example: $AGI->answer();
Returns: -1 on channel failure, or
0 if successful
=cut
sub answer {
my ($self) = @_;
my $ret = 0;
$ret = $self->execute('ANSWER');
$self->callback($ret) if ($ret == -1);
return $ret;
}
=item $AGI->get_data($filename, $timeout, $maxdigits)
Executes AGI Command "GET DATA $filename $timeout $maxdigits"
Streams $filename and returns when $maxdigits have been received or
when $timeout has been reached. Timeout is specified in ms
Example: $AGI->get_data('demo-welcome', 15000, 5);
=cut
sub get_data {
my ($self, $filename, $timeout, $maxdigits) = @_;
my $ret = undef;
return -1 if (!defined($filename));
$ret = $self->execute("GET DATA $filename $timeout $maxdigits");
$self->callback($ret) if ($ret == -1);
return $ret;
}
=item $AGI->set_callerid($number)
Executes AGI Command "SET CALLERID $number"
Changes the callerid of the current channel to <number>
Example: $AGI->set_callerid('9995551212');
Returns: Always returns 1
=cut
sub set_callerid {
my ($self, $number) = @_;
return if (!defined($number));
return $self->execute("SET CALLERID $number");
}
=item $AGI->set_context($context)
Executes AGI Command "SET CONTEXT $context"
Changes the context for continuation upon exiting the agi application
Example: $AGI->set_context('dialout');
Returns: Always returns 0
=cut
sub set_context {
my ($self, $context) = @_;
return -1 if (!defined($context));
return $self->execute("SET CONTEXT $context");
}
=item $AGI->set_extension($extension)
Executes AGI Command "SET EXTENSION $extension"
Changes the extension for continuation upon exiting the agi application
Example: $AGI->set_extension('7');
Returns: Always returns 0
=cut
sub set_extension {
my ($self, $extension) = @_;
return -1 if (!defined($extension));
return $self->execute("SET EXTENSION $extension");
}
=item $AGI->set_priority($priority)
Executes AGI Command "SET PRIORITY $priority"
Changes the priority for continuation upon exiting the agi application
Example: $AGI->set_priority(1);
Returns: Always returns 0
=cut
sub set_priority {
my ($self, $priority) = @_;
return -1 if (!defined($priority));
return $self->execute("SET PRIORITY $priority");
}
sub receive_char {
my ($self, $timeout) = @_;
my $ret = 0;
#wait forever if timeout is not set. is this the prefered default?
$timeout = 0 if (!defined($timeout));
$ret = $self->execute("RECEIVE CHAR $timeout");
$self->callback($ret) if ($ret == -1);
return $ret;
}
sub tdd_mode {
my ($self, $mode) = @_;
return 0 if (!defined($mode));
return $self->execute("TDD MODE $mode");
}
sub wait_for_digit {
my ($self, $timeout) = @_;
my $ret = 0;
$timeout = -1 if (!defined($timeout));
$ret = $self->execute("WAIT FOR DIGIT $timeout");
$self->callback($ret) if ($ret == -1);
return $ret;
}
sub record_file {
my ($self, $filename, $format, $digits, $timeout, $beep) = @_;
my $ret = 0;
return -1 if (!defined($filename));
$digits = '""' if (!defined($digits));
$ret = $self->execute("RECORD FILE $filename $format $digits $timeout");
$self->callback($ret) if ($ret == -1);
return $ret;
}
sub set_autohangup {
my ($self, $time) = @_;
$time = 0 if (!defined($time));
return $self->execute("SET AUTOHANGUP $time");
}
=item $AGI->hangup($channel)
Executes AGI Command "HANGUP $channel"
Hangs up the passed $channel, or the current channel if $channel is not passed.
It is left to the AGI script to exit properly, otherwise you could end up with zombies.
Example: $AGI->hangup();
Returns: Always returns 1
=cut
sub hangup {
my ($self, $channel) = @_;
if ($channel) {
return $self->execute("HANGUP $channel");
} else {
return $self->execute("HANGUP");
}
}
=item $AGI->exec($app, $options)
Executes AGI Command "EXEC $app $options"
The most powerful AGI command. Executes the given application passing the given options.
Example: $AGI->exec('Dial', 'Zap/g2/8005551212');
Returns: -2 on failure to find application, or
whatever the given application returns
=cut
sub exec {
my ($self, $app, $options) = @_;
return -1 if (!defined($app));
$options = '""' if (!defined($options));
return $self->execute("EXEC $app $options");
}
sub channel_status {
my ($self, $channel) = @_;
return $self->execute("CHANNEL STATUS $channel");
}
=item $AGI->set_variable($variable, $value)
Executes AGI Command "SET VARIABLE $variable $value"
Sets the channel variable <variablename> to <value>
Example: $AGI->set_variable('status', 'authorized');
Returns: Always returns 1
=cut
sub set_variable {
my ($self, $variable, $value) = @_;
return $self->execute("SET VARIABLE $variable $value");
}
=item $AGI->get_variable($variable)
Executes AGI Command "GET VARIABLE $variablename"
Gets the channel variable <variablename>
Example: $AGI->get_variable('status');
Returns: The value of the variable, or undef if variable does not exist
=cut
sub get_variable {
my ($self, $variable) = @_;
my $result = undef;
if ($self->execute("GET VARIABLE $variable")) {
my $tempresult = $self->_lastresponse();
if ($tempresult =~ /\((.*)\)/) {
$result = $1;
}
}
return $result;
}
=item $AGI->verbose($message, $level)
Executes AGI Command "VERBOSE $message $level"
Logs $message with verboselevel $level
Example: $AGI->verbose("System Crashed\n", 1);
Returns: Always returns 1
=cut
sub verbose {
my ($self, $message, $level) = @_;
return $self->execute("VERBOSE \"$message\" $level");
}
=item $AGI->database_get($family, $key)
Executes AGI Command "DATABASE GET $family $key"
Example: $var = $AGI->database_get('test', 'status');
Returns: The value of the variable, or undef if variable does not exist
=cut
sub database_get {
my ($self, $family, $key) = @_;
my $result = undef;
if ($self->execute("DATABASE GET $family $key")) {
my $tempresult = $self->_lastresponse();
if ($tempresult =~ /\((.*)\)/) {
$result = $1;
}
}
return $result;
}
=item $AGI->database_put($family, $key, $value)
Executes AGI Command "DATABASE PUT $family $key $value"
Set/modifes database entry <family>/<key> to <value>
Example: $AGI->database_put('test', 'status', 'authorized');
Returns: 1 on success, 0 otherwise
=cut
sub database_put {
my ($self, $family, $key, $value) = @_;
return $self->execute("DATABASE PUT $family $key $value");
}
=item $AGI->database_del($family, $key)
Executes AGI Command "DATABASE DEL $family $key"
Removes database entry <family>/<key>
Example: $AGI->database_del('test', 'status');
Returns: 1 on success, 0 otherwise
=cut
sub database_del {
my ($self, $family, $key) = @_;
return $self->execute("DATABASE DEL $family $key");
}
=item $AGI->database_deltree($family, $key)
Executes AGI Command "DATABASE DELTREE $family $key"
Deletes a family or specific keytree within a family in the Asterisk database
Example: $AGI->database_deltree('test', 'status');
Example: $AGI->database_deltree('test');
Returns: 1 on success, 0 otherwise
=cut
sub database_deltree {
my ($self, $family, $key) = @_;
return $self->execute("DATABASE DELTREE $family $key");
}
sub noop {
my ($self) = @_;
return $self->execute("NOOP");
}
sub set_music {
my ($self, $mode, $class) = @_;
return $self->execute("SET MUSIC $mode $class");
}
1;
__END__
=back
+146
View File
@@ -0,0 +1,146 @@
#!/usr/bin/perl
### AST_VICI_conf.pl
###
### Copyright (C) 2006 Matt Florell <vicidial@gmail.com> LICENSE: GPLv2
###
### Customized Variables
$SIP_user = 'SIP/cc100'; # your phone id
$server_ip = '10.10.10.15'; # Asterisk server IP
$DB_server = '10.10.10.15'; # MySQL server IP
$DB_database = 'asterisk'; # MySQL database name
$DB_user = 'idcheck'; # MySQL user
$DB_pass = '1234'; # MySQL pass
$DB_port = '3306'; # MySQL connection port
### Constants
$record_channel='';
$filename='';
$recording_id='';
$US = '_';
$MT[0] = '';
return 1;
# this subroutine is to be used with the callerID function to customize the
# variables that are passed in the URL string and the way that they are passed,
# these are the variables you have to work with:
# $callerID_areacode
# $callerID_prefix
# $callerID_last4
# $callerID_Time
# $callerID_Channel
# $callerID_uniqueID
# $callerID_phone_ext
# $callerID_server_ip
# $callerID_extension
# $callerID_inbound_number
# $callerID_comment_a
# $callerID_comment_b
# $callerID_comment_c
# $callerID_comment_d
# $callerID_comment_e
sub create_callerID_local_query_string
{
$local_web_callerID_QUERY_STRING ='';
$local_web_callerID_QUERY_STRING.="?callerID_areacode=$callerID_areacode";
$local_web_callerID_QUERY_STRING.="&callerID_prefix=$callerID_prefix";
$local_web_callerID_QUERY_STRING.="&callerID_last4=$callerID_last4";
$local_web_callerID_QUERY_STRING.="&callerID_Time=$callerID_Time";
$local_web_callerID_QUERY_STRING.="&callerID_Channel=$callerID_Channel";
$local_web_callerID_QUERY_STRING.="&callerID_uniqueID=$callerID_uniqueID";
$local_web_callerID_QUERY_STRING.="&callerID_phone_ext=$callerID_phone_ext";
$local_web_callerID_QUERY_STRING.="&callerID_server_ip=$callerID_server_ip";
$local_web_callerID_QUERY_STRING.="&callerID_extension=$callerID_extension";
$local_web_callerID_QUERY_STRING.="&callerID_inbound_number=$callerID_inbound_number";
$local_web_callerID_QUERY_STRING.="&callerID_comment_a=$callerID_comment_a";
$local_web_callerID_QUERY_STRING.="&callerID_comment_b=$callerID_comment_b";
$local_web_callerID_QUERY_STRING.="&callerID_comment_c=$callerID_comment_c";
$local_web_callerID_QUERY_STRING.="&callerID_comment_d=$callerID_comment_d";
$local_web_callerID_QUERY_STRING.="&callerID_comment_e=$callerID_comment_e";
}
# $lead_id
# $vendor_id
# $list_id
# $phone_code
# $phone_number
# $title
# $first_name
# $middle_initial
# $last_name
# $address1
# $address2
# $address3
# $city
# $state
# $province
# $postal_code
# $country_code
# $gender
# $date_of_birth
# $alt_phone
# $email
# $security
# $comments
# $user
# $pass
# $fronter
# $closer
# $campaign
# $group
# $SQLdate
# $epoch
# $uniqueid
# $customer_zap_channel
# $server_ip
# $SIPexten
sub create_VICIDIAL_query_string
{
$VICIDIAL_web_QUERY_STRING ='';
$VICIDIAL_web_QUERY_STRING.="?lead_id=$lead_id";
$VICIDIAL_web_QUERY_STRING.="&vendor_id=$vendor_id";
$VICIDIAL_web_QUERY_STRING.="&list_id=$list_id";
$VICIDIAL_web_QUERY_STRING.="&phone_code=$phone_code";
$VICIDIAL_web_QUERY_STRING.="&phone_number=$phone_number";
$VICIDIAL_web_QUERY_STRING.="&title=$title";
$VICIDIAL_web_QUERY_STRING.="&first_name=$first_name";
$VICIDIAL_web_QUERY_STRING.="&middle_initial=$middle_initial";
$VICIDIAL_web_QUERY_STRING.="&last_name=$last_name";
$VICIDIAL_web_QUERY_STRING.="&address1=$address1";
$VICIDIAL_web_QUERY_STRING.="&address2=$address2";
$VICIDIAL_web_QUERY_STRING.="&address3=$address3";
$VICIDIAL_web_QUERY_STRING.="&city=$city";
$VICIDIAL_web_QUERY_STRING.="&state=$state";
$VICIDIAL_web_QUERY_STRING.="&province=$province";
$VICIDIAL_web_QUERY_STRING.="&postal_code=$postal_code";
$VICIDIAL_web_QUERY_STRING.="&country_code=$country_code";
$VICIDIAL_web_QUERY_STRING.="&gender=$gender";
$VICIDIAL_web_QUERY_STRING.="&date_of_birth=$date_of_birth";
$VICIDIAL_web_QUERY_STRING.="&alt_phone=$alt_phone";
$VICIDIAL_web_QUERY_STRING.="&email=$email";
$VICIDIAL_web_QUERY_STRING.="&security=$security";
$VICIDIAL_web_QUERY_STRING.="&comments=$comments";
$VICIDIAL_web_QUERY_STRING.="&user=$user";
$VICIDIAL_web_QUERY_STRING.="&pass=$userpass";
$VICIDIAL_web_QUERY_STRING.="&fronter=$fronter";
$VICIDIAL_web_QUERY_STRING.="&closer=$user";
$VICIDIAL_web_QUERY_STRING.="&campaign=$campaign";
$VICIDIAL_web_QUERY_STRING.="&group=$group";
$VICIDIAL_web_QUERY_STRING.="&channel_group=$channel_group";
$VICIDIAL_web_QUERY_STRING.="&SQLdate=$SQLdate";
$VICIDIAL_web_QUERY_STRING.="&epoch=$secX";
$VICIDIAL_web_QUERY_STRING.="&uniqueid=$uniqueid";
$VICIDIAL_web_QUERY_STRING.="&customer_zap_channel=$customer_zap_channel";
$VICIDIAL_web_QUERY_STRING.="&server_ip=$server_ip";
$VICIDIAL_web_QUERY_STRING.="&SIPexten=$SIPexten";
$VICIDIAL_web_QUERY_STRING.="&session_id=$session_id";
$VICIDIAL_web_QUERY_STRING.="&phone=$phone_number";
$VICIDIAL_web_QUERY_STRING.="&parked_by=$lead_id";
$VICIDIAL_web_QUERY_STRING =~ s/ /+/gi;
$VICIDIAL_web_QUERY_STRING =~ s/\`|\~|\:|\;|\#|\'|\"|\{|\}|\(|\)|\*|\^|\%|\$|\!|\%|\r|\t|\n//gi;
}
+412
View File
@@ -0,0 +1,412 @@
package Asterisk::Manager;
require 5.004;
use Asterisk;
use IO::Socket;
use Digest::MD5;
#use strict;
#use warnings;
=head1 NAME
Asterisk::Manager - Asterisk Manager Interface
=head1 SYNOPSIS
use Asterisk::Manager;
my $astman = new Asterisk::Manager;
$astman->user('username');
$astman->secret('test');
$astman->host('localhost');
$astman->connect || die "Could not connect to " . $astman->host . "!\n";
$astman->disconnect;
=head1 DESCRIPTION
This module provides a simple interface to the asterisk manager interface.
=cut
my $EOL = "\r\n";
my $BLANK = $EOL x 2;
my $VERSION = '0.01';
sub version { $VERSION; }
sub new {
my ($class, %args) = @_;
my $self = {};
$self->{_CONNFD} = undef;
$self->{_PROTOVERS} = undef;
$self->{_ERRORSTR} = undef;
$self->{_HOST} = 'localhost';
$self->{_PORT} = 5038;
$self->{_USER} = undef;
$self->{_SECRET} = undef;
$self->{_EVENTCB} = {};
$self->{_DEBUG} = 0;
$self->{_CONNECTED} = 0;
bless $self, ref $class || $class;
return $self;
}
sub DESTROY { }
sub user {
my ($self, $user) = @_;
if ($user) {
$self->{_USER} = $user;
}
return $self->{_USER};
}
sub secret {
my ($self, $secret) = @_;
if ($secret) {
$self->{_SECRET} = $secret;
}
return $self->{_SECRET};
}
sub host {
my ($self, $host) = @_;
if ($host) {
$self->{_HOST} = $host;
}
return $self->{_HOST};
}
sub port {
my ($self, $port) = @_;
if ($port) {
$self->{_PORT} = $port;
}
return $self->{_PORT};
}
sub connected {
my ($self, $connected) = @_;
if (defined($connected)) {
$self->{_CONNECTED} = $connected;
}
return $self->{_CONNECTED};
}
sub error {
my ($self, $error) = @_;
if ($error) {
$self->{_ERRORSTR} = $error;
}
return $self->{_ERRORSTR};
}
sub debug {
my ($self, $debug) = @_;
if ($debug) {
$self->{_DEBUG} = $debug;
}
return $self->{_DEBUG};
}
sub connfd {
my ($self, $connfd) = @_;
if ($connfd) {
$self->{_CONNFD} = $connfd;
}
return $self->{_CONNFD};
}
sub read_response {
my ($self, $connfd) = @_;
my @response;
if (!$connfd) {
$connfd = $self->connfd;
}
while (my $line = <$connfd>) {
last if ($line eq $EOL);
if (wantarray) {
$line =~ s/$EOL//g;
push(@response, $line) if $line;
} else {
$response[0] .= $line;
}
}
return wantarray ? @response : $response[0];
}
sub connect {
my ($self) = @_;
my $host = $self->host;
my $port = $self->port;
my $user = $self->user;
my $secret = $self->secret;
my %resp;
my $conn = new IO::Socket::INET( Proto => 'tcp',
PeerAddr => $host,
PeerPort => $port
);
if (!$conn) {
$self->error("Connection refused ($host:$port)\n");
return undef;
}
$conn->autoflush(1);
my $input = <$conn>;
$input =~ s/$EOL//g;
my ($manager, $version) = split('/', $input);
if ($manager !~ /Asterisk Call Manager/) {
return $self->error("Unknown Protocol\n");
}
$self->{_PROTOVERS} = $version;
$self->connfd($conn);
# check if the remote host supports MD5 Challenge authentication
my %authresp = $self->sendcommand( Action => 'Challenge',
AuthType => 'MD5'
);
if (($authresp{Response} eq 'Success')) {
# do md5 login
my $md5 = new Digest::MD5;
$md5->add($authresp{Challenge});
$md5->add($secret);
my $digest = $md5->hexdigest;
%resp = $self->sendcommand( Action => 'Login',
AuthType => 'MD5',
Username => $user,
Key => $digest
);
} else {
# do plain text login
%resp = $self->sendcommand( Action => 'Login',
Username => $user,
Secret => $secret
);
}
if ( ($resp{Response} ne 'Success') && ($resp{Message} ne 'Authentication accepted') ) {
$self->error("Authentication failed for user $user\n");
return undef;
}
$self->connected(1);
return $conn;
}
sub astman_h2s {
my ($self, %thash) = @_;
my $tstring = '';
foreach my $key (keys %thash) {
$tstring .= $key . ': ' . $thash{$key} . ${EOL};
}
return $tstring;
}
sub astman_s2h {
my ($self, $tstring) = @_;
my %thash;
foreach my $line (split(/$EOL/, $tstring)) {
if ($line =~ /(\w*):\s*(\w*)/) {
$thash{$1} = $2;
}
}
return %thash;
}
#$want is how you want the data returned
#$want = 0 (default) returns the results in a hash
#$want = 1 returns the results in a large string
#$want = 2 returns the results in an array
sub sendcommand {
my ($self, %command, $want) = @_;
if (!defined($want)) {
$want = 0;
}
my $conn = $self->connfd || return;
my $cstring = $self->astman_h2s(%command);
$conn->send("$cstring$EOL");
if ($want == 1) {
my $response = $self->read_response($conn);
return $response;
}
my @resp = $self->read_response($conn);
if ($want == 2) {
return @resp;
} else {
return map { split(': ', $_) } @resp;
}
}
sub setcallback {
my ($self, $event, $function) = @_;
if (defined($function) && ref($function) eq 'CODE') {
$self->{_EVENTCB}{$event} = $function;
}
}
sub eventcallback {
my ($self, %resp) = @_;
my $callback;
my $event = $resp{Event};
return if (!$event);
if (defined($self->{_EVENTCB}{$event})) {
$callback = $self->{_EVENTCB}{$event};
} elsif (defined($self->{_EVENTCB}{DEFAULT})) {
$callback = $self->{_EVENTCB}{DEFAULT};
} else {
return;
}
return &{$callback}(%resp);
}
sub eventloop {
my ($self) = @_;
while (1) {
$self->handleevent;
}
}
sub handleevent {
my ($self) = @_;
my %resp = map { split(': ', $_); } $self->read_response;
$self->eventcallback(%resp);
return %resp;
}
sub action {
my ($self, $command, $wanthash) = @_;
return if (!$command);
my $conn = $self->connfd || return;
print $conn "Action: $command" . $BLANK;
my @resp = $self->read_response($conn);
if ($wanthash) {
return map { split(': ', $_) } @resp;
} elsif (wantarray) {
return @resp;
} else {
return $resp[0];
}
}
sub command {
my ($self, $command) = @_;
return if (!$command);
return $self->sendcommand('Action' => 'Command',
'Command' => $command, 1 );
}
sub monitor {
my ($self, $channel, $file) = @_;
return if (!$channel);
return $self->sendcommand('Action' => 'Monitor',
'Channel' => $channel,
'File' => $file, 1 );
}
sub changemonitor {
my ($self, $channel, $file) = @_;
return if (!$channel);
return $self->sendcommand('Action' => 'ChangeMonitor',
'Channel' => $channel,
'File' => $file, 1 );
}
sub stopmonitor {
my ($self, $channel, $file) = @_;
return if (!$channel);
return $self->sendcommand('Action' => 'StopMonitor',
'Channel' => $channel,
'File' => $file, 1 );
}
sub disconnect {
my ($self) = @_;
my $conn = $self->connfd;
my %resp = $self->sendcommand('Action' => 'Logoff');
if ($resp{Response} eq 'Goodbye') {
$self->{_CONNFD} = undef;
$self->connected(0);
return 1;
}
return 0;
}
1;
+110
View File
@@ -0,0 +1,110 @@
package Asterisk::Outgoing;
=head1 NAME
Asterisk::Outgoing - Create outgoing call queue file
=head1 SYNOPSIS
use Asterisk::Outgoing;
my $out = new Asterisk::Outgoing;
$out->setvariable('Channel', 'Zap/1/');
$out->setvariable('MaxRetries', 0);
$out->setvariable('RetryTime', 60);
$out->setvariable('WaitTime', 60);
$out->setvariable('Application', 'Playback');
$out->setvariable('Data', 'beep');
$out->create_outgoing;
=cut
require 5.004;
use Fcntl ':flock';
use Asterisk;
@ISA = ('Asterisk');
$VERSION = '0.01';
sub new {
my ($class, %args) = @_;
my $self = {};
$self->{OUTDIR} = '/var/spool/asterisk/outgoing';
$self->{OUTTIME} = undef;
$self->{OUTVARS} = {};
$self->{ALLOWEDVARS} = [ 'channel', 'maxretries', 'retrytime', 'waittime', 'context', 'extension', 'priority', 'application', 'data', 'callerid' ];
bless $self, ref $class || $class;
return $self;
}
sub outdir {
my ($self, $dir) = @_;
if (defined($dir)) {
$self->{OUTDIR} = $dir;
}
return $self->{OUTDIR};
}
sub outtime {
my ($self, $time) = @_;
if (defined($time)) {
$self->{OUTTIME} = $time;
} elsif (!defined($self->{OUTTIME})) {
$self->{OUTTIME} = time();
}
return $self->{OUTTIME};
}
sub checkvariable {
my ($self, $var) = @_;
my $ret = 0;
foreach $allowed (@{$self->{ALLOWEDVARS}}) {
if ($allowed =~ /$var/i) {
$ret = 1;
}
}
return $ret;
}
sub setvariable {
my ($self, $var, $value) = @_;
if ($self->checkvariable($var)) {
$self->{OUTVARS}{$var} = $value;
}
}
sub create_outgoing {
my ($self) = @_;
my $time = $self->outtime();
my $outdir = $self->outdir();
my $filename = $outdir . '/' . $time . '.outgoing';
open(OUTFILE, ">$filename") || return 0;
flock(OUTFILE, LOCK_EX);
utime($time, $time, $filename);
foreach my $var (keys %{$self->{OUTVARS}}) {
print OUTFILE "$var: " . $self->{OUTVARS}{$var} . "\n";
}
flock(OUTFILE, LOCK_UN);
close(OUTFILE);
utime($time, $time, $filename);
return 1;
}
1;
+61
View File
@@ -0,0 +1,61 @@
package Asterisk::QCall;
require 5.004;
use Fcntl ':flock';
use Asterisk;
$VERSION = '0.01';
sub version { $VERSION; }
sub new {
my ($class, %args) = @_;
my $self = {};
$self->{QUEUEDIR} = '/var/spool/asterisk/qcall';
$self->{QUEUETIME} = undef;
bless $self, ref $class || $class;
return $self;
}
sub DESTROY { }
sub queuedir {
my ($self, $dir) = @_;
if (defined($dir)) {
$self->{QUEUEDIR} = $dir;
}
return $self->{QUEUEDIR};
}
sub queuetime {
my ($self, $time) = @_;
if (defined($time)) {
$self->{QUEUETIME} = $time;
} elsif (!defined($self->{QUEUETIME})) {
$self->{QUEUETIME} = time();
}
return $self->{QUEUETIME};
}
sub create_qcall {
my ($self, $dialstring, $callerid, $extension, $maxsecs, $identifier, $response) = @_;
my $time = $self->queuetime();
my $queuedir = $self->queuedir();
my $filename = $queuedir . '/' . $time . '.queue';
open(QFILE, ">$filename") || return 0;
flock(QFILE, LOCK_EX);
print QFILE "$dialstring $callerid $extension $maxsecs $identifier $response";
flock(QFILE, LOCK_UN);
close(QFILE);
my $ret = utime($time, $time, $filename);
return 1;
}
1;
+261
View File
@@ -0,0 +1,261 @@
package Asterisk::Voicemail;
require 5.004;
=head1 NAME
Asterisk::Voicemail - Stuff to deal with asterisk voicemail
=head1 SYNOPSIS
This is not completed yet
=head1 DESCRIPTION
description
=cut
use Asterisk;
@ISA = ( 'Asterisk' );
$VERSION = '0.01';
$DEBUG = 5;
sub version { $VERSION; }
sub new {
my ($class, %args) = @_;
my $self = {};
bless $self, ref $class || $class;
# while (my ($key,$value) = each %args) { $self->set($key,$value); }
return $self;
}
sub DESTROY { }
sub spooldirectory {
my ($self, $directory) = @_;
if (defined($directory)) {
$self->{'spooldirectory'} = $directory;
} else {
$self->{'spooldirectory'} = '/var/spool/asterisk/vm' if (!defined($self->{'spooldirectory'}));
}
return $self->{'spooldirectory'};
}
sub sounddirectory {
my ($self, $directory) = @_;
if (defined($directory)) {
$self->{'sounddirectory'} = $directory;
} else {
$self->{'sounddirectory'} = '/var/lib/asterisk/sounds' if (!defined($self->{'sounddirectory'}));
}
return $self->{'sounddirectory'};
}
sub serveremail {
my ($self, $email) = @_;
$self->{'serveremail'} = $email if (defined($email));
return $self->{'serveremail'};
}
sub format {
my ($self, @formats) = @_;
if (@formats) {
$self->{'formats'} = @formats;
}
return $self->{'formats'};
}
sub vmbox {
my ($self, $vmbox, $vmpass, $vmfn, $vmemail) = @_;
if (defined($vmbox) && (defined($vmpass) || defined($vmfn) || defined($vmemail)) ) {
$self->{'vmbox'}{$vmbox}{'pass'} = $vmpass if (defined($vmpass));
$self->{'vmbox'}{$vmbox}{'fn'} = $vmfn if (defined($vmfn));
$self->{'vmbox'}{$vmbox}{'email'} = $vmemail if (defined($vmemail));
} elsif (defined($vmbox)) {
return ($self->{'vmbox'}{$vmbox}{'pass'},
$self->{'vmbox'}{$vmbox}{'fn'},
$self->{'vmbox'}{$vmbox}{'email'} );
}
}
sub getfolders {
my ($self, $vmbox) = @_;
my @folders = ();
my $spool = $self->spooldirectory();
foreach $file (<$spool/$vmbox/*>) {
if ( -d $file ) {
$file =~ s/$spool\/$vmbox\///;
push(@folders, $file);
}
}
return @folders;
}
sub configfile {
my ($self, $configfile) = @_;
if (defined($configfile)) {
$self->{'configfile'} = $configfile;
} else {
$self->{'configfile'} = '/etc/asterisk/voicemail.conf' if (!defined($self->{'configfile'}));
}
return $self->{'configfile'};
}
sub readconfig {
my ($self) = @_;
my $context = '';
my $line = '';
my $configfile = $self->configfile();
open(CF, "<$configfile") || die "Error loading $configfile: $!\n";
while ($line = <CF>) {
chop($line);
$line =~ s/;.*$//;
$line =~ s/\s*$//;
if ($line =~ /^;/) {
next;
} elsif ($line =~ /^\s*$/) {
next;
} elsif ($line =~ /^\[(\w+)\]$/) {
$context = $1;
print STDERR "Context: $context\n" if ($DEBUG>3);
} elsif ($line =~ /^format\s*[=>]+\s*(.*)/) {
my $formats = $1;
$self->format(split(/|/, $formats));
} elsif ($line =~ /^serveremail\s*[=>]+\s*(.*)/) {
$self->serveremail($1);
} elsif ($line =~ /^(\d+)\s*[=>]+\s*(.*)/) {
my $vmbox = $1;
my $vmstr = $2;
my ($vmpass, $vmfn, $vmemail) = split(/,/, $vmstr);
print STDERR "VM BOX ($vmbox)\n" if ($DEBUG>3);
$self->vmbox($vmbox, $vmpass, $vmfn, $vmstr);
} else {
print STDERR "Unknown line: $line\n" if ($DEBUG);
}
}
close(CF);
}
sub appendsoundfile {
my ($self, $source, $dest) = @_;
open(IN, "<$source") || return 0;
open(OUT, ">>$dest") || return 0;
while (<IN>) {
print OUT $_;
}
close(IN);
close(OUT);
return 1;
}
sub validmailbox {
my ($self, $vmbox) = @_;
return 1 if ($self->vmbox($vmbox));
return 0;
}
sub msgcount {
my ($self, $vmbox, $folder) = @_;
my $count = 0;
return $count if (!defined($vmbox) || !defined($folder));
my $spool = $self->spooldirectory() . '/' . $vmbox . '/' . $folder;
if (opendir(DIR, $spool)) {
my @msgs = grep(/^msg.*\.txt$/, readdir(DIR));
$count = $#msgs+1;
closedir(DIR);
}
return $count;
}
sub msgcountstr {
my ($self, $vmbox, $folder) = @_;
my $count = $self->msgcount($vmbox, $folder);
if ($count > 1) {
return "$count messages";
} elsif ($count > 0) {
return "$count message";
} else {
return "no messages";
}
}
sub createdefaultmailbox {
my ($self, $vmbox) = @_;
my $spool = $self->spooldirectory();
my $sounddir = $self->sounddirectory();
my $vmdir = "$spool/$vmbox";
if ( -d $vmdir ) {
print STDERR "Directory already exists: $vmdir\n" if ($DEBUG);
} else {
mkdir($vmdir, 0755) || return 0;
mkdir("$vmdir/INBOX", 0755) || return 0;
}
$self->appendsoundfile("$sounddir/vm-theperson.gsm", "$vmdir/unavail.gsm");
$self->appendsoundfile("$sounddir/vm-theperson.gsm", "$vmdir/busy.gsm");
$self->appendsoundfile("$sounddir/vm-extension.gsm", "$vmdir/greet.gsm");
foreach $chr (split(//, $vmbox)) {
$self->appendsoundfile("$sounddir/digits/$chr.gsm", "$vmdir/unavail.gsm");
$self->appendsoundfile("$sounddir/digits/$chr.gsm", "$vmdir/busy.gsm");
$self->appendsoundfile("$sounddir/digits/$chr.gsm", "$vmdir/greet.gsm");
}
$self->appendsoundfile("$sounddir/vm-isunavail.gsm", "$vmdir/unavail.gsm");
$self->appendsoundfile("$sounddir/vm-isonphone.gsm", "$vmdir/busy.gsm");
return 1;
}
sub messages {
my ($self, $messages, $folder) = @_;
my $path = $self->spooldirectory() . '/' . $mailbox . '/' . $folder;
if (opendir(DIR, $path)) {
my @msgs = sort grep(/^msg....\.txt$/, readdir(DIR));
closedir(DIR);
return map { s/^msg(....)\.txt$/$1/; $_ } @msgs;
}
return ();
}
1;
Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 311 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 240 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 230 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 520 B

+1015
View File
File diff suppressed because it is too large Load Diff
+266
View File
@@ -0,0 +1,266 @@
package Net::HTTP;
# $Id: HTTP.pm,v 1.43 2002/12/26 09:13:53 gisle Exp $
use strict;
use vars qw($VERSION @ISA);
$VERSION = "1.00";
eval { require IO::Socket::INET } || require IO::Socket;
require Net::HTTP::Methods;
@ISA=qw(IO::Socket::INET Net::HTTP::Methods);
sub configure {
my($self, $cnf) = @_;
$self->http_configure($cnf);
}
sub http_connect {
my($self, $cnf) = @_;
$self->SUPER::configure($cnf);
}
1;
__END__
=head1 NAME
Net::HTTP - Low-level HTTP connection (client)
=head1 SYNOPSIS
use Net::HTTP;
my $s = Net::HTTP->new(Host => "www.perl.com) || die $@;
$s->write_request(GET => "/", 'User-Agent' => "Mozilla/5.0");
my($code, $mess, %h) = $s->read_response_headers;
while (1) {
my $buf;
my $n = $s->read_entity_body($buf, 1024);
die "read failed: $!" unless defined $n;
last unless $n;
print $buf;
}
=head1 DESCRIPTION
The C<Net::HTTP> class is a low-level HTTP client. An instance of the
C<Net::HTTP> class represents a connection to an HTTP server. The
HTTP protocol is described in RFC 2616. The C<Net::HTTP> class
support C<HTTP/1.0> and C<HTTP/1.1>.
C<Net::HTTP> is a sub-class of C<IO::Socket::INET>. You can mix the
methods described below with reading and writing from the socket
directly. This is not necessary a good idea, unless you know what you
are doing.
The following methods are provided (in addition to those of
C<IO::Socket::INET>):
=over
=item $s = Net::HTTP->new( %options )
The C<Net::HTTP> constructor method takes the same options as
C<IO::Socket::INET>'s as well as these:
Host: Initial host attribute value
KeepAlive: Initial keep_alive attribute value
SendTE: Initial send_te attribute_value
HTTPVersion: Initial http_version attribute value
PeerHTTPVersion: Initial peer_http_version attribute value
MaxLineLength: Initial max_line_length attribute value
MaxHeaderLines: Initial max_header_lines attribute value
The C<Host> option is also the default for C<IO::Socket::INET>'s
C<PeerAddr>. The C<PeerPort> defaults to 80 if not provided.
The C<Listen> option provided by C<IO::Socket::INET>'s constructor
method is not allowed.
If unable to connect to the given HTTP server then the constructor
returns C<undef> and $@ contains the reason. After a successful
connect, a C<Net:HTTP> object is returned.
=item $s->host
Get/set the default value of the C<Host> header to send. The $host
should not be set to an empty string (or C<undef>).
=item $s->keep_alive
Get/set the I<keep-alive> value. If this value is TRUE then the
request will be sent with headers indicating that the server should try
to keep the connection open so that multiple requests can be sent.
The actual headers set will depend on the value of the C<http_version>
and C<peer_http_version> attributes.
=item $s->send_te
Get/set the a value indicating if the request will be sent with a "TE"
header to indicate the transfer encodings that the server can chose to
use. If the C<Compress::Zlib> module is installed then this will
annouce that this client accept both the I<deflate> and I<gzip>
encodings.
=item $s->http_version
Get/set the HTTP version number that this client should announce.
This value can only be set to "1.0" or "1.1". The default is "1.1".
=item $s->peer_http_version
Get/set the protocol version number of our peer. This value will
initially be "1.0", but will be updated by a successful
read_response_headers() method call.
=item $s->max_line_length
Get/set a limit on the length of response line and response header
lines. The default is 4096. A value of 0 means no limit.
=item $s->max_header_length
Get/set a limit on the number of headers lines that a response can
have. The default is 128. A value of 0 means no limit.
=item $s->format_request($method, $uri, %headers, [$content])
Format a request message and return it as a string. If the headers do
not include a C<Host> header, then a header is inserted with the value
of the C<host> attribute. Headers like C<Connection> and
C<Keep-Alive> might also be added depending on the status of the
C<keep_alive> attribute.
If $content is given (and it is non-empty), then a C<Content-Length>
header is automatically added unless it was already present.
=item $s->write_request($method, $uri, %headers, [$content])
Format and send a request message. Arguments are the same as for
format_request(). Returns true if successful.
=item $s->format_chunk( $data )
Returns the string to be written for the given chunk of data.
=item $s->write_chunk($data)
Will write a new chunk of request entity body data. This method
should only be used if the C<Transfer-Encoding> header with a value of
C<chunked> was sent in the request. Note, writing zero-length data is
a no-op. Use the write_chunk_eof() method to signal end of entity
body data.
Returns true if successful.
=item $s->format_chunk_eof( %trailers )
Returns the string to be written for signaling EOF when a
C<Transfer-Encoding> of C<chunked> is used.
=item $s->write_chunk_eof( %trailers )
Will write eof marker for chunked data and optional trailers. Note
that trailers should not really be used unless is was signaled
with a C<Trailer> header.
Returns true if successful.
=item ($code, $mess, %headers) = $s->read_response_headers( %opts )
Read response headers from server and return it. The $code is the 3
digit HTTP status code (see L<HTTP::Status>) and $mess is the textual
message that came with it. Headers are then returned as key/value
pairs. Since key letter casing is not normalized and the same key can
even occur multiple times, assigning these values directly to a hash
is not wise. Only the $code is returned if this method is called in
scalar context.
As a side effect this method updates the 'peer_http_version'
attribute.
Options might be passed in as key/value pairs. There are currently
only two options supported; C<laxed> and C<junk_out>.
The C<laxed> option will make read_response_headers() more forgiving
towards servers that have not learned how to speak HTTP properly. The
C<laxed> option is a boolean flag, and is enabled by passing in a TRUE
value. The C<junk_out> option can be used to capture bad header lines
when C<laxed> is enabled. The value should be an array reference.
Bad header lines will be pushed onto the array.
The C<laxed> option must be specified in order to communicate with
pre-HTTP/1.0 servers that don't describe the response outcome or the
data they send back with a header block. For these servers
peer_http_version is set to "0.9" and this method returns (200,
"Assumed OK").
The method will raise an exception (die) if the server does not speak
proper HTTP or if the C<max_line_length> or C<max_header_length>
limits are reached. If the C<laxed> option is turned on and
C<max_line_length> and C<max_header_length> checks are turned off,
then no exception will be raised and this method will always
return a response code.
=item $n = $s->read_entity_body($buf, $size);
Reads chunks of the entity body content. Basically the same interface
as for read() and sysread(), but the buffer offset argument is not
supported yet. This method should only be called after a successful
read_response_headers() call.
The return value will be C<undef> on read errors, 0 on EOF, -1 if no data
could be returned this time, otherwise the number of bytes assgined
to $buf. The $buf set to "" when the return value is -1.
This method will raise exceptions (die) if the server does not speak
proper HTTP. This can only happen when reading chunked data.
=item %headers = $s->get_trailers
After read_entity_body() has returned 0 to indicate end of the entity
body, you might call this method to pick up any trailers.
=item $s->_rbuf
Get/set the read buffer content. The read_response_headers() and
read_entity_body() methods use an internal buffer which they will look
for data before they actually sysread more from the socket itself. If
they read too much, the remaining data will be left in this buffer.
=item $s->_rbuf_length
Returns the number of bytes in the read buffer. This should always be
the same as:
length($s->_rbuf)
but might be more efficient.
=back
=head1 SUBCLASSING
The read_response_headers() and read_entity_body() will invoke the
sysread() method when they need more data. Subclasses might want to
override this method to contol how reading takes place.
The object itself is a glob. Subclasses should avoid using hash key
names prefixed with C<http_> and C<io_>.
=head1 SEE ALSO
L<LWP>, L<IO::Socket::INET>, L<Net::HTTP::NB>
=head1 COPYRIGHT
Copyright 2001-2003 Gisle Aas.
This library is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.
=cut
+520
View File
@@ -0,0 +1,520 @@
package Net::HTTP::Methods;
# $Id: Methods.pm,v 1.12 2002/12/26 09:13:55 gisle Exp $
require 5.005; # 4-arg substr
use strict;
use vars qw($VERSION);
$VERSION = "1.00";
my $CRLF = "\015\012"; # "\r\n" is not portable
sub new {
my($class, %cnf) = @_;
require Symbol;
my $self = bless Symbol::gensym(), $class;
return $self->http_configure(\%cnf);
}
sub http_configure {
my($self, $cnf) = @_;
die "Listen option not allowed" if $cnf->{Listen};
my $host = delete $cnf->{Host};
my $peer = $cnf->{PeerAddr} || $cnf->{PeerHost};
if ($host) {
$cnf->{PeerAddr} = $host unless $peer;
}
else {
$host = $peer;
$host =~ s/:.*//;
}
$cnf->{PeerPort} = $self->http_default_port unless $cnf->{PeerPort};
$cnf->{Proto} = 'tcp';
my $keep_alive = delete $cnf->{KeepAlive};
my $http_version = delete $cnf->{HTTPVersion};
$http_version = "1.1" unless defined $http_version;
my $peer_http_version = delete $cnf->{PeerHTTPVersion};
$peer_http_version = "1.0" unless defined $peer_http_version;
my $send_te = delete $cnf->{SendTE};
my $max_line_length = delete $cnf->{MaxLineLength};
$max_line_length = 4*1024 unless defined $max_line_length;
my $max_header_lines = delete $cnf->{MaxHeaderLines};
$max_header_lines = 128 unless defined $max_header_lines;
return undef unless $self->http_connect($cnf);
unless ($host =~ /:/) {
my $p = $self->peerport;
$host .= ":$p";
}
$self->host($host);
$self->keep_alive($keep_alive);
$self->send_te($send_te);
$self->http_version($http_version);
$self->peer_http_version($peer_http_version);
$self->max_line_length($max_line_length);
$self->max_header_lines($max_header_lines);
${*$self}{'http_buf'} = "";
return $self;
}
sub http_default_port {
80;
}
# set up property accessors
for my $method (qw(host keep_alive send_te max_line_length max_header_lines peer_http_version)) {
my $prop_name = "http_" . $method;
no strict 'refs';
*$method = sub {
my $self = shift;
my $old = ${*$self}{$prop_name};
${*$self}{$prop_name} = shift if @_;
return $old;
};
}
# we want this one to be a bit smarter
sub http_version {
my $self = shift;
my $old = ${*$self}{'http_version'};
if (@_) {
my $v = shift;
$v = "1.0" if $v eq "1"; # float
unless ($v eq "1.0" or $v eq "1.1") {
require Carp;
Carp::croak("Unsupported HTTP version '$v'");
}
${*$self}{'http_version'} = $v;
}
$old;
}
sub format_request {
my $self = shift;
my $method = shift;
my $uri = shift;
my $content = (@_ % 2) ? pop : "";
for ($method, $uri) {
require Carp;
Carp::croak("Bad method or uri") if /\s/ || !length;
}
push(@{${*$self}{'http_request_method'}}, $method);
my $ver = ${*$self}{'http_version'};
my $peer_ver = ${*$self}{'http_peer_http_version'} || "1.0";
my @h;
my @connection;
my %given = (host => 0, "content-length" => 0, "te" => 0);
while (@_) {
my($k, $v) = splice(@_, 0, 2);
my $lc_k = lc($k);
if ($lc_k eq "connection") {
push(@connection, split(/\s*,\s*/, $v));
next;
}
if (exists $given{$lc_k}) {
$given{$lc_k}++;
}
push(@h, "$k: $v");
}
if (length($content) && !$given{'content-length'}) {
push(@h, "Content-Length: " . length($content));
}
my @h2;
if ($given{te}) {
push(@connection, "TE") unless grep lc($_) eq "te", @connection;
}
elsif ($self->send_te && zlib_ok()) {
# gzip is less wanted since the Compress::Zlib interface for
# it does not really allow chunked decoding to take place easily.
push(@h2, "TE: deflate,gzip;q=0.3");
push(@connection, "TE");
}
unless (grep lc($_) eq "close", @connection) {
if ($self->keep_alive) {
if ($peer_ver eq "1.0") {
# from looking at Netscape's headers
push(@h2, "Keep-Alive: 300");
unshift(@connection, "Keep-Alive");
}
}
else {
push(@connection, "close") if $ver ge "1.1";
}
}
push(@h2, "Connection: " . join(", ", @connection)) if @connection;
push(@h2, "Host: ${*$self}{'http_host'}") unless $given{host};
return join($CRLF, "$method $uri HTTP/$ver", @h2, @h, "", $content);
}
sub write_request {
my $self = shift;
$self->print($self->format_request(@_));
}
sub format_chunk {
my $self = shift;
return $_[0] unless defined($_[0]) && length($_[0]);
return sprintf("%x", length($_[0])) . $CRLF . $_[0] . $CRLF;
}
sub write_chunk {
my $self = shift;
return 1 unless defined($_[0]) && length($_[0]);
$self->print(sprintf("%x", length($_[0])) . $CRLF . $_[0] . $CRLF);
}
sub format_chunk_eof {
my $self = shift;
my @h;
while (@_) {
push(@h, sprintf "%s: %s$CRLF", splice(@_, 0, 2));
}
return join("", "0$CRLF", @h, $CRLF);
}
sub write_chunk_eof {
my $self = shift;
$self->print($self->format_chunk_eof(@_));
}
sub my_read {
die if @_ > 3;
my $self = shift;
my $len = $_[1];
for (${*$self}{'http_buf'}) {
if (length) {
$_[0] = substr($_, 0, $len, "");
return length($_[0]);
}
else {
return $self->sysread($_[0], $len);
}
}
}
sub my_readline {
my $self = shift;
for (${*$self}{'http_buf'}) {
my $max_line_length = ${*$self}{'http_max_line_length'};
my $pos;
while (1) {
# find line ending
$pos = index($_, "\012");
last if $pos >= 0;
die "Line too long (limit is $max_line_length)"
if $max_line_length && length($_) > $max_line_length;
# need to read more data to find a line ending
my $n = $self->sysread($_, 1024, length);
if (!$n) {
return undef unless length;
return substr($_, 0, length, "");
}
}
die "Line too long ($pos; limit is $max_line_length)"
if $max_line_length && $pos > $max_line_length;
my $line = substr($_, 0, $pos+1, "");
$line =~ s/(\015?\012)\z// || die "Assert";
return wantarray ? ($line, $1) : $line;
}
}
sub _rbuf {
my $self = shift;
if (@_) {
for (${*$self}{'http_buf'}) {
my $old;
$old = $_ if defined wantarray;
$_ = shift;
return $old;
}
}
else {
return ${*$self}{'http_buf'};
}
}
sub _rbuf_length {
my $self = shift;
return length ${*$self}{'http_buf'};
}
sub _read_header_lines {
my $self = shift;
my $junk_out = shift;
my @headers;
my $line_count = 0;
my $max_header_lines = ${*$self}{'http_max_header_lines'};
while (my $line = my_readline($self)) {
if ($line =~ /^(\S+)\s*:\s*(.*)/s) {
push(@headers, $1, $2);
}
elsif (@headers && $line =~ s/^\s+//) {
$headers[-1] .= " " . $line;
}
elsif ($junk_out) {
push(@$junk_out, $line);
}
else {
die "Bad header: '$line'\n";
}
if ($max_header_lines) {
$line_count++;
if ($line_count >= $max_header_lines) {
die "Too many header lines (limit is $max_header_lines)";
}
}
}
return @headers;
}
sub read_response_headers {
my($self, %opt) = @_;
my $laxed = $opt{laxed};
my($status, $eol) = my_readline($self);
unless (defined $status) {
die "EOF instead of response status line" unless $laxed;
# assume HTTP/0.9
${*$self}{'http_peer_http_version'} = "0.9";
${*$self}{'http_status'} = "200";
return 200 unless wantarray;
return (200, "EOF");
}
my($peer_ver, $code, $message) = split(/\s+/, $status, 3);
if (!$peer_ver || $peer_ver !~ s,^HTTP/,, || $code !~ /^[1-5]\d\d$/) {
die "Bad response status line: '$status'" unless $laxed;
# assume HTTP/0.9
${*$self}{'http_peer_http_version'} = "0.9";
${*$self}{'http_status'} = "200";
substr(${*$self}{'http_buf'}, 0, 0) = $status . $eol;
return 200 unless wantarray;
return (200, "Assumed OK");
};
${*$self}{'http_peer_http_version'} = $peer_ver;
${*$self}{'http_status'} = $code;
my $junk_out;
if ($laxed) {
$junk_out = $opt{junk_out} || [];
}
my @headers = $self->_read_header_lines($junk_out);
# pick out headers that read_entity_body might need
my @te;
my $content_length;
for (my $i = 0; $i < @headers; $i += 2) {
my $h = lc($headers[$i]);
if ($h eq 'transfer-encoding') {
push(@te, $headers[$i+1]);
}
elsif ($h eq 'content-length') {
$content_length = $headers[$i+1];
}
}
${*$self}{'http_te'} = join(",", @te);
${*$self}{'http_content_length'} = $content_length;
${*$self}{'http_first_body'}++;
delete ${*$self}{'http_trailers'};
return $code unless wantarray;
return ($code, $message, @headers);
}
sub read_entity_body {
my $self = shift;
my $buf_ref = \$_[0];
my $size = $_[1];
die "Offset not supported yet" if $_[2];
my $chunked;
my $bytes;
if (${*$self}{'http_first_body'}) {
${*$self}{'http_first_body'} = 0;
delete ${*$self}{'http_chunked'};
delete ${*$self}{'http_bytes'};
my $method = shift(@{${*$self}{'http_request_method'}});
my $status = ${*$self}{'http_status'};
if ($method eq "HEAD" || $status =~ /^(?:1|[23]04)/) {
# these responses are always empty
$bytes = 0;
}
elsif (my $te = ${*$self}{'http_te'}) {
my @te = split(/\s*,\s*/, lc($te));
die "Chunked must be last Transfer-Encoding '$te'"
unless pop(@te) eq "chunked";
for (@te) {
if ($_ eq "deflate" && zlib_ok()) {
#require Compress::Zlib;
my $i = Compress::Zlib::inflateInit();
die "Can't make inflator" unless $i;
$_ = sub { scalar($i->inflate($_[0])) }
}
elsif ($_ eq "gzip" && zlib_ok()) {
#require Compress::Zlib;
my @buf;
$_ = sub {
push(@buf, $_[0]);
return Compress::Zlib::memGunzip(join("", @buf)) if $_[1];
return "";
};
}
elsif ($_ eq "identity") {
$_ = sub { $_[0] };
}
else {
die "Can't handle transfer encoding '$te'";
}
}
@te = reverse(@te);
${*$self}{'http_te2'} = @te ? \@te : "";
$chunked = -1;
}
elsif (defined(my $content_length = ${*$self}{'http_content_length'})) {
$bytes = $content_length;
}
else {
# XXX Multi-Part types are self delimiting, but RFC 2616 says we
# only has to deal with 'multipart/byteranges'
# Read until EOF
}
}
else {
$chunked = ${*$self}{'http_chunked'};
$bytes = ${*$self}{'http_bytes'};
}
if (defined $chunked) {
# The state encoded in $chunked is:
# $chunked == 0: read CRLF after chunk, then chunk header
# $chunked == -1: read chunk header
# $chunked > 0: bytes left in current chunk to read
if ($chunked <= 0) {
my $line = my_readline($self);
if ($chunked == 0) {
die "Missing newline after chunk data: '$line'" unless $line eq "";
$line = my_readline($self);
}
my $chunk_len = $line;
$chunk_len =~ s/;.*//; # ignore potential chunk parameters
unless ($chunk_len =~ /^([\da-fA-F]+)\s*$/) {
die "Bad chunk-size in HTTP response: $line";
}
$chunked = hex($1);
if ($chunked == 0) {
${*$self}{'http_trailers'} = [$self->_read_header_lines];
$$buf_ref = "";
my $n = 0;
if (my $transforms = delete ${*$self}{'http_te2'}) {
for (@$transforms) {
$$buf_ref = &$_($$buf_ref, 1);
}
$n = length($$buf_ref);
}
# in case somebody tries to read more, make sure we continue
# to return EOF
delete ${*$self}{'http_chunked'};
${*$self}{'http_bytes'} = 0;
return $n;
}
}
my $n = $chunked;
$n = $size if $size && $size < $n;
$n = my_read($self, $$buf_ref, $n);
return undef unless defined $n;
${*$self}{'http_chunked'} = $chunked - $n;
if ($n > 0) {
if (my $transforms = ${*$self}{'http_te2'}) {
for (@$transforms) {
$$buf_ref = &$_($$buf_ref, 0);
}
$n = length($$buf_ref);
$n = -1 if $n == 0;
}
}
return $n;
}
elsif (defined $bytes) {
unless ($bytes) {
$$buf_ref = "";
return 0;
}
my $n = $bytes;
$n = $size if $size && $size < $n;
$n = my_read($self, $$buf_ref, $n);
return undef unless defined $n;
${*$self}{'http_bytes'} = $bytes - $n;
return $n;
}
else {
# read until eof
$size ||= 8*1024;
return my_read($self, $$buf_ref, $size);
}
}
sub get_trailers {
my $self = shift;
@{${*$self}{'http_trailers'} || []};
}
BEGIN {
my $zlib_ok;
sub zlib_ok {
return $zlib_ok if defined $zlib_ok;
# Try to load Compress::Zlib.
local $@;
local $SIG{__DIE__};
$zlib_ok = 0;
eval {
require Compress::Zlib;
Compress::Zlib->VERSION(1.10);
$zlib_ok++;
};
return $zlib_ok;
}
} # BEGIN
1;
+106
View File
@@ -0,0 +1,106 @@
package Net::HTTP::NB;
# $Id: NB.pm,v 1.5 2001/08/28 03:03:42 gisle Exp $
use strict;
use vars qw($VERSION @ISA);
$VERSION = "0.02";
require Net::HTTP;
@ISA=qw(Net::HTTP);
sub sysread {
my $self = $_[0];
if (${*$self}{'httpnb_read_count'}++) {
${*$self}{'http_buf'} = ${*$self}{'httpnb_save'};
die "Multi-read\n";
}
my $buf;
my $offset = $_[3] || 0;
my $n = sysread($self, $_[1], $_[2], $offset);
${*$self}{'httpnb_save'} .= substr($_[1], $offset);
return $n;
}
sub read_response_headers {
my $self = shift;
${*$self}{'httpnb_read_count'} = 0;
${*$self}{'httpnb_save'} = ${*$self}{'http_buf'};
my @h = eval { $self->SUPER::read_response_headers(@_) };
if ($@) {
return if $@ eq "Multi-read\n";
die;
}
return @h;
}
sub read_entity_body {
my $self = shift;
${*$self}{'httpnb_read_count'} = 0;
${*$self}{'httpnb_save'} = ${*$self}{'http_buf'};
# XXX I'm not so sure this does the correct thing in case of
# transfer-encoding tranforms
my $n = eval { $self->SUPER::read_entity_body(@_); };
if ($@) {
$_[0] = "";
return -1;
}
return $n;
}
1;
__END__
=head1 NAME
Net::HTTP::NB - Non-blocking HTTP client
=head1 SYNOPSIS
use Net::HTTP::NB;
my $s = Net::HTTP::NB->new(Host => "www.perl.com) || die $@;
$s->write_request(GET => "/");
use IO::Select;
my $sel = IO::Select->new($s);
READ_HEADER: {
die "Header timeout" unless $sel->can_read(10);
my($code, $mess, %h) = $s->read_response_headers;
redo READ_HEADER unless $code;
}
while (1) {
die "Body timeout" unless $sel->can_read(10);
my $buf;
my $n = $s->read_entity_body($buf, 1024);
last unless $n;
print $buf;
}
=head1 DESCRIPTION
Same interface as C<Net::HTTP> but it will never try multiple reads
when the read_response_headers() or read_entity_body() methods are
invoked. This make it possible to multiplex multiple Net::HTTP::NB
using select without risk blocking.
If read_response_headers() did not see enough data to complete the
headers an empty list is returned.
If read_entity_body() did not see new entity data in its read
the value -1 is returned.
=head1 SEE ALSO
L<Net::HTTP>
=head1 COPYRIGHT
Copyright 2001 Gisle Aas.
This library is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.
=cut
+55
View File
@@ -0,0 +1,55 @@
package Net::HTTPS;
# $Id: HTTPS.pm,v 1.3 2002/12/23 18:16:29 gisle Exp $
use strict;
use vars qw($VERSION $SSL_SOCKET_CLASS @ISA);
$VERSION = "1.00";
# Figure out which SSL implementation to use
if ($IO::Socket::SSL::VERSION) {
$SSL_SOCKET_CLASS = "IO::Socket::SSL"; # it was already loaded
}
else {
eval { require Net::SSL; }; # from Crypt-SSLeay
if ($@) {
my $old_errsv = $@;
eval {
require IO::Socket::SSL;
};
if ($@) {
$old_errsv =~ s/\s\(\@INC contains:.*\)/)/g;
die $old_errsv . $@;
}
$SSL_SOCKET_CLASS = "IO::Socket::SSL";
}
else {
$SSL_SOCKET_CLASS = "Net::SSL";
}
}
require Net::HTTP::Methods;
@ISA=($SSL_SOCKET_CLASS, 'Net::HTTP::Methods');
sub configure {
my($self, $cnf) = @_;
$self->http_configure($cnf);
}
sub http_connect {
my($self, $cnf) = @_;
$self->SUPER::configure($cnf);
}
sub http_default_port {
443;
}
# The underlying SSLeay classes fails to work if the socket is
# placed in non-blocking mode. This override of the blocking
# method makes sure it stays the way it was created.
sub blocking { } # noop
1;
+1015
View File
File diff suppressed because it is too large Load Diff
+255
View File
@@ -0,0 +1,255 @@
package Net::SSH;
use strict;
use vars qw($VERSION @ISA @EXPORT_OK $ssh $equalspace $DEBUG @ssh_options);
use Exporter;
use IO::File;
use IPC::Open2;
use IPC::Open3;
@ISA = qw(Exporter);
@EXPORT_OK = qw( ssh issh ssh_cmd sshopen2 sshopen3 );
$VERSION = '0.07';
$DEBUG = 0;
$ssh = "ssh";
=head1 NAME
Net::SSH - Perl extension for secure shell
=head1 SYNOPSIS
use Net::SSH qw(ssh issh sshopen2 sshopen3);
ssh('user@hostname', $command);
issh('user@hostname', $command);
ssh_cmd('user@hostname', $command);
ssh_cmd( {
user => 'user',
host => 'host.name',
command => 'command',
args => [ '-arg1', '-arg2' ],
stdin_string => "string\n",
} );
sshopen2('user@hostname', $reader, $writer, $command);
sshopen3('user@hostname', $writer, $reader, $error, $command);
=head1 DESCRIPTION
Simple wrappers around ssh commands.
For an all-perl implementation that does not require the system B<ssh> command,
see L<Net::SSH::Perl> instead.
=head1 SUBROUTINES
=over 4
=item ssh [USER@]HOST, COMMAND [, ARGS ... ]
Calls ssh in batch mode.
=cut
sub ssh {
my($host, @command) = @_;
@ssh_options = &_ssh_options unless @ssh_options;
my @cmd = ($ssh, @ssh_options, $host, @command);
warn "[Net::SSH::ssh] executing ". join(' ', @cmd). "\n"
if $DEBUG;
system(@cmd);
}
=item issh [USER@]HOST, COMMAND [, ARGS ... ]
Prints the ssh command to be executed, waits for the user to confirm, and
(optionally) executes the command.
=cut
sub issh {
my($host, @command) = @_;
my @cmd = ($ssh, $host, @command);
print join(' ', @cmd), "\n";
if ( &_yesno ) {
system(@cmd);
}
}
=item ssh_cmd [USER@]HOST, COMMAND [, ARGS ... ]
=item ssh_cmd OPTIONS_HASHREF
Calls ssh in batch mode. Throws a fatal error if data occurs on the command's
STDERR. Returns any data from the command's STDOUT.
If using the hashref-style of passing arguments, possible keys are:
user (optional)
host (requried)
command (required)
args (optional, arrayref)
stdin_string (optional) - written to the command's STDIN
=cut
sub ssh_cmd {
my($host, $stdin_string, @command);
if ( ref($_[0]) ) {
my $opt = shift;
$host = $opt->{host};
$host = $opt->{user}. '@'. $host if exists $opt->{user};
@command = ( $opt->{command} );
push @command, @{ $opt->{args} } if exists $opt->{args};
$stdin_string = $opt->{stdin_string};
} else {
($host, @command) = @_;
undef $stdin_string;
}
my $reader = IO::File->new();
my $writer = IO::File->new();
my $error = IO::File->new();
sshopen3( $host, $writer, $reader, $error, @command ) or die $!;
print $writer $stdin_string if defined $stdin_string;
close $writer;
local $/ = undef;
my $output_stream = <$reader>;
my $error_stream = <$error>;
if ( length $error_stream ) {
die "[Net:SSH::ssh_cmd] STDERR $error_stream";
}
return $output_stream;
}
=item sshopen2 [USER@]HOST, READER, WRITER, COMMAND [, ARGS ... ]
Connects the supplied filehandles to the ssh process (in batch mode).
=cut
sub sshopen2 {
my($host, $reader, $writer, @command) = @_;
@ssh_options = &_ssh_options unless @ssh_options;
open2($reader, $writer, $ssh, @ssh_options, $host, @command);
}
=item sshopen3 HOST, WRITER, READER, ERROR, COMMAND [, ARGS ... ]
Connects the supplied filehandles to the ssh process (in batch mode).
=cut
sub sshopen3 {
my($host, $writer, $reader, $error, @command) = @_;
@ssh_options = &_ssh_options unless @ssh_options;
open3($writer, $reader, $error, $ssh, @ssh_options, $host, @command);
}
sub _yesno {
print "Proceed [y/N]:";
my $x = scalar(<STDIN>);
$x =~ /^y/i;
}
sub _ssh_options {
my $reader = IO::File->new();
my $writer = IO::File->new();
my $error = IO::File->new();
open3($writer, $reader, $error, $ssh, '-V');
my $ssh_version = <$error>;
chomp($ssh_version);
if ( $ssh_version =~ /.*OpenSSH[-|_](\w+)\./ && $1 == 1 ) {
$equalspace = " ";
} else {
$equalspace = "=";
}
my @options = ( '-o', 'BatchMode'.$equalspace.'yes' );
if ( $ssh_version =~ /.*OpenSSH[-|_](\w+)\./ && $1 > 1 ) {
unshift @options, '-T';
}
@options;
}
=back
=head1 EXAMPLE
use Net::SSH qw(sshopen2);
use strict;
my $user = "username";
my $host = "hostname";
my $cmd = "command";
sshopen2("$user\@$host", *READER, *WRITER, "$cmd") || die "ssh: $!";
while (<READER>) {
chomp();
print "$_\n";
}
close(READER);
close(WRITER);
=head1 FREQUENTLY ASKED QUESTIONS
Q: How do you supply a password to connect with ssh within a perl script
using the Net::SSH module?
A: You don't. Use RSA or DSA keys. See the ssh-keygen(1) manpage.
Q: My script is "leaking" ssh processes.
A: See L<perlfaq8/"How do I avoid zombies on a Unix system">, L<IPC::Open2>,
L<IPC::Open3> and L<perlfunc/waitpid>.
=head1 AUTHORS
Ivan Kohler <ivan-netssh_pod@420.am>
John Harrison <japh@in-ta.net> contributed an example for the documentation.
Martin Langhoff <martin@cwa.co.nz> contributed the ssh_cmd command, and
Jeff Finucane <jeff@cmh.net> updated it and took care of the 0.04 release.
Anthony Awtrey <tony@awtrey.com> contributed a fix for those still using
OpenSSH v1.
=head1 COPYRIGHT
Copyright (c) 2002 Ivan Kohler.
Copyright (c) 2002 Freeside Internet Services, LLC
All rights reserved.
This program is free software; you can redistribute it and/or modify it under
the same terms as Perl itself.
=head1 BUGS
Not OO.
Look at IPC::Session (also fsh)
=head1 SEE ALSO
For an all-perl implementation that does not require the system B<ssh> command,
see L<Net::SSH::Perl> instead.
ssh-keygen(1), ssh(1), L<IO::File>, L<IPC::Open2>, L<IPC::Open3>
=cut
1;
+5252
View File
File diff suppressed because it is too large Load Diff
+5252
View File
File diff suppressed because it is too large Load Diff
+359
View File
@@ -0,0 +1,359 @@
package Time::HiRes;
use strict;
use vars qw($VERSION $XS_VERSION @ISA @EXPORT @EXPORT_OK $AUTOLOAD);
require Exporter;
require DynaLoader;
@ISA = qw(Exporter DynaLoader);
@EXPORT = qw( );
@EXPORT_OK = qw (usleep sleep ualarm alarm gettimeofday time tv_interval
getitimer setitimer
ITIMER_REAL ITIMER_VIRTUAL ITIMER_PROF ITIMER_REALPROF
d_usleep d_ualarm d_gettimeofday d_getitimer d_setitimer
d_nanosleep);
$VERSION = '1.59';
$XS_VERSION = $VERSION;
$VERSION = eval $VERSION;
sub AUTOLOAD {
my $constname;
($constname = $AUTOLOAD) =~ s/.*:://;
die "&Time::HiRes::constant not defined" if $constname eq 'constant';
my ($error, $val) = constant($constname);
if ($error) { die $error; }
{
no strict 'refs';
*$AUTOLOAD = sub { $val };
}
goto &$AUTOLOAD;
}
bootstrap Time::HiRes;
# Preloaded methods go here.
sub tv_interval {
# probably could have been done in C
my ($a, $b) = @_;
$b = [gettimeofday()] unless defined($b);
(${$b}[0] - ${$a}[0]) + ((${$b}[1] - ${$a}[1]) / 1_000_000);
}
# Autoload methods go after =cut, and are processed by the autosplit program.
1;
__END__
=head1 NAME
Time::HiRes - High resolution alarm, sleep, gettimeofday, interval timers
=head1 SYNOPSIS
use Time::HiRes qw( usleep ualarm gettimeofday tv_interval );
usleep ($microseconds);
ualarm ($microseconds);
ualarm ($microseconds, $interval_microseconds);
$t0 = [gettimeofday];
($seconds, $microseconds) = gettimeofday;
$elapsed = tv_interval ( $t0, [$seconds, $microseconds]);
$elapsed = tv_interval ( $t0, [gettimeofday]);
$elapsed = tv_interval ( $t0 );
use Time::HiRes qw ( time alarm sleep );
$now_fractions = time;
sleep ($floating_seconds);
alarm ($floating_seconds);
alarm ($floating_seconds, $floating_interval);
use Time::HiRes qw( setitimer getitimer
ITIMER_REAL ITIMER_VIRTUAL ITIMER_PROF ITIMER_REALPROF );
setitimer ($which, $floating_seconds, $floating_interval );
getitimer ($which);
=head1 DESCRIPTION
The C<Time::HiRes> module implements a Perl interface to the C<usleep>,
C<ualarm>, C<gettimeofday>, and C<setitimer>/C<getitimer> system calls, in other
words, high resolution time and timers. See the L</EXAMPLES> section below
and the test scripts for usage; see your system documentation for the
description of the underlying C<nanosleep> or C<usleep>, C<ualarm>,
C<gettimeofday>, and C<setitimer>/C<getitimer> calls.
If your system lacks C<gettimeofday()> or an emulation of it you don't
get C<gettimeofday()> or the one-argument form of C<tv_interval()>. If your system lacks all of
C<nanosleep()>, C<usleep()>, and C<select()>, you don't get
C<Time::HiRes::usleep()> or C<Time::HiRes::sleep()>. If your system lacks both
C<ualarm()> and C<setitimer()> you don't get
C<Time::HiRes::ualarm()> or C<Time::HiRes::alarm()>.
If you try to import an unimplemented function in the C<use> statement
it will fail at compile time.
If your subsecond sleeping is implemented with C<nanosleep()> instead of
C<usleep()>, you can mix subsecond sleeping with signals since
C<nanosleep()> does not use signals. This, however is unportable, and you
should first check for the truth value of C<&Time::HiRes::d_nanosleep> to
see whether you have nanosleep, and then carefully read your
C<nanosleep()> C API documentation for any peculiarities. (There is no
separate interface to call C<nanosleep()>; just use C<Time::HiRes::sleep()>
or C<Time::HiRes::usleep()> with small enough values.)
Unless using C<nanosleep> for mixing sleeping with signals, give
some thought to whether Perl is the tool you should be using for work
requiring nanosecond accuracies.
The following functions can be imported from this module.
No functions are exported by default.
=over 4
=item gettimeofday ()
In array context returns a two-element array with the seconds and
microseconds since the epoch. In scalar context returns floating
seconds like C<Time::HiRes::time()> (see below).
=item usleep ( $useconds )
Sleeps for the number of microseconds specified. Returns the number
of microseconds actually slept. Can sleep for more than one second,
unlike the C<usleep> system call. See also C<Time::HiRes::sleep()> below.
=item ualarm ( $useconds [, $interval_useconds ] )
Issues a C<ualarm> call; the C<$interval_useconds> is optional and
will be zero if unspecified, resulting in C<alarm>-like behaviour.
=item tv_interval
tv_interval ( $ref_to_gettimeofday [, $ref_to_later_gettimeofday] )
Returns the floating seconds between the two times, which should have
been returned by C<gettimeofday()>. If the second argument is omitted,
then the current time is used.
=item time ()
Returns a floating seconds since the epoch. This function can be
imported, resulting in a nice drop-in replacement for the C<time>
provided with core Perl; see the L</EXAMPLES> below.
B<NOTE 1>: This higher resolution timer can return values either less
or more than the core C<time()>, depending on whether your platform
rounds the higher resolution timer values up, down, or to the nearest second
to get the core C<time()>, but naturally the difference should be never
more than half a second.
B<NOTE 2>: Since Sunday, September 9th, 2001 at 01:46:40 AM GMT, when
the C<time()> seconds since epoch rolled over to 1_000_000_000, the
default floating point format of Perl and the seconds since epoch have
conspired to produce an apparent bug: if you print the value of
C<Time::HiRes::time()> you seem to be getting only five decimals, not six
as promised (microseconds). Not to worry, the microseconds are there
(assuming your platform supports such granularity in first place).
What is going on is that the default floating point format of Perl
only outputs 15 digits. In this case that means ten digits before the
decimal separator and five after. To see the microseconds you can use
either C<printf>/C<sprintf> with C<"%.6f">, or the C<gettimeofday()> function in
list context, which will give you the seconds and microseconds as two
separate values.
=item sleep ( $floating_seconds )
Sleeps for the specified amount of seconds. Returns the number of
seconds actually slept (a floating point value). This function can be
imported, resulting in a nice drop-in replacement for the C<sleep>
provided with perl, see the L</EXAMPLES> below.
=item alarm ( $floating_seconds [, $interval_floating_seconds ] )
The C<SIGALRM> signal is sent after the specified number of seconds.
Implemented using C<ualarm()>. The C<$interval_floating_seconds> argument
is optional and will be zero if unspecified, resulting in C<alarm()>-like
behaviour. This function can be imported, resulting in a nice drop-in
replacement for the C<alarm> provided with perl, see the L</EXAMPLES> below.
B<NOTE 1>: With some operating system and Perl release combinations
C<SIGALRM> restarts C<select()>, instead of interuping it.
This means that an C<alarm()> followed by a C<select()>
may together take the sum of the times specified for the the
C<alarm()> and the C<select()>, not just the time of the C<alarm()>.
=item setitimer ( $which, $floating_seconds [, $interval_floating_seconds ] )
Start up an interval timer: after a certain time, a signal arrives,
and more signals may keep arriving at certain intervals. To disable a
timer, use C<$floating_seconds> of zero. If the C<$interval_floating_seconds>
is set to zero (or unspecified), the timer is disabled B<after> the
next delivered signal.
Use of interval timers may interfere with C<alarm()>, C<sleep()>,
and C<usleep()>. In standard-speak the "interaction is unspecified",
which means that I<anything> may happen: it may work, it may not.
In scalar context, the remaining time in the timer is returned.
In list context, both the remaining time and the interval are returned.
There are usually three or four interval timers available: the C<$which>
can be C<ITIMER_REAL>, C<ITIMER_VIRTUAL>, C<ITIMER_PROF>, or C<ITIMER_REALPROF>.
Note that which ones are available depends: true UNIX platforms usually
have the first three, but (for example) Win32 and Cygwin have only
C<ITIMER_REAL>, and only Solaris seems to have C<ITIMER_REALPROF> (which is
used to profile multithreaded programs).
C<ITIMER_REAL> results in C<alarm()>-like behavior. Time is counted in
I<real time>; that is, wallclock time. C<SIGALRM> is delivered when
the timer expires.
C<ITIMER_VIRTUAL> counts time in (process) I<virtual time>; that is, only
when the process is running. In multiprocessor/user/CPU systems this
may be more or less than real or wallclock time. (This time is also
known as the I<user time>.) C<SIGVTALRM> is delivered when the timer expires.
C<ITIMER_PROF> counts time when either the process virtual time or when
the operating system is running on behalf of the process (such as I/O).
(This time is also known as the I<system time>.) (The sum of user
time and system time is known as the I<CPU time>.) C<SIGPROF> is
delivered when the timer expires. C<SIGPROF> can interrupt system calls.
The semantics of interval timers for multithreaded programs are
system-specific, and some systems may support additional interval
timers. See your C<setitimer()> documentation.
=item getitimer ( $which )
Return the remaining time in the interval timer specified by C<$which>.
In scalar context, the remaining time is returned.
In list context, both the remaining time and the interval are returned.
The interval is always what you put in using C<setitimer()>.
=back
=head1 EXAMPLES
use Time::HiRes qw(usleep ualarm gettimeofday tv_interval);
$microseconds = 750_000;
usleep $microseconds;
# signal alarm in 2.5s & every .1s thereafter
ualarm 2_500_000, 100_000;
# get seconds and microseconds since the epoch
($s, $usec) = gettimeofday;
# measure elapsed time
# (could also do by subtracting 2 gettimeofday return values)
$t0 = [gettimeofday];
# do bunch of stuff here
$t1 = [gettimeofday];
# do more stuff here
$t0_t1 = tv_interval $t0, $t1;
$elapsed = tv_interval ($t0, [gettimeofday]);
$elapsed = tv_interval ($t0); # equivalent code
#
# replacements for time, alarm and sleep that know about
# floating seconds
#
use Time::HiRes;
$now_fractions = Time::HiRes::time;
Time::HiRes::sleep (2.5);
Time::HiRes::alarm (10.6666666);
use Time::HiRes qw ( time alarm sleep );
$now_fractions = time;
sleep (2.5);
alarm (10.6666666);
# Arm an interval timer to go off first at 10 seconds and
# after that every 2.5 seconds, in process virtual time
use Time::HiRes qw ( setitimer ITIMER_VIRTUAL time );
$SIG{VTALRM} = sub { print time, "\n" };
setitimer(ITIMER_VIRTUAL, 10, 2.5);
=head1 C API
In addition to the perl API described above, a C API is available for
extension writers. The following C functions are available in the
modglobal hash:
name C prototype
--------------- ----------------------
Time::NVtime double (*)()
Time::U2time void (*)(UV ret[2])
Both functions return equivalent information (like C<gettimeofday>)
but with different representations. The names C<NVtime> and C<U2time>
were selected mainly because they are operating system independent.
(C<gettimeofday> is Unix-centric, though some platforms like VMS have
emulations for it.)
Here is an example of using C<NVtime> from C:
double (*myNVtime)();
SV **svp = hv_fetch(PL_modglobal, "Time::NVtime", 12, 0);
if (!svp) croak("Time::HiRes is required");
if (!SvIOK(*svp)) croak("Time::NVtime isn't a function pointer");
myNVtime = INT2PTR(double(*)(), SvIV(*svp));
printf("The current time is: %f\n", (*myNVtime)());
=head1 DIAGNOSTICS
=head2 negative time not invented yet
You tried to use a negative time argument.
=head2 internal error: useconds < 0 (unsigned ... signed ...)
Something went horribly wrong-- the number of microseconds that cannot
become negative just became negative. Maybe your compiler is broken?
=head1 CAVEATS
Notice that the core C<time()> maybe rounding rather than truncating.
What this means is that the core C<time()> may be reporting the time
as one second later than C<gettimeofday()> and C<Time::HiRes::time()>.
Adjusting the system clock (either manually or by services like ntp)
may cause problems, especially for long running programs that assume
a monotonously increasing time (note that all platforms do not adjust
time as gracefully as UNIX ntp does). For example in Win32 (and derived
platforms like Cygwin and MinGW) the Time::HiRes::time() may temporarily
drift off from the system clock (and the original time()) by up to 0.5
seconds. Time::HiRes will notice this eventually and recalibrate.
=head1 AUTHORS
D. Wegscheid <wegscd@whirlpool.com>
R. Schertler <roderick@argon.org>
J. Hietaniemi <jhi@iki.fi>
G. Aas <gisle@aas.no>
=head1 COPYRIGHT AND LICENSE
Copyright (c) 1996-2002 Douglas E. Wegscheid. All rights reserved.
Copyright (c) 2002,2003,2004 Jarkko Hietaniemi. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the same terms as Perl itself.
=cut
+369
View File
@@ -0,0 +1,369 @@
package Time::HiRes;
use strict;
use vars qw($VERSION $XS_VERSION @ISA @EXPORT @EXPORT_OK $AUTOLOAD);
require Exporter;
require DynaLoader;
@ISA = qw(Exporter DynaLoader);
@EXPORT = qw( );
@EXPORT_OK = qw (usleep sleep ualarm alarm gettimeofday time tv_interval
getitimer setitimer
ITIMER_REAL ITIMER_VIRTUAL ITIMER_PROF ITIMER_REALPROF
d_usleep d_ualarm d_gettimeofday d_getitimer d_setitimer
d_nanosleep);
$VERSION = '1.65';
$XS_VERSION = $VERSION;
$VERSION = eval $VERSION;
sub AUTOLOAD {
my $constname;
($constname = $AUTOLOAD) =~ s/.*:://;
die "&Time::HiRes::constant not defined" if $constname eq 'constant';
my ($error, $val) = constant($constname);
if ($error) { die $error; }
{
no strict 'refs';
*$AUTOLOAD = sub { $val };
}
goto &$AUTOLOAD;
}
bootstrap Time::HiRes;
# Preloaded methods go here.
sub tv_interval {
# probably could have been done in C
my ($a, $b) = @_;
$b = [gettimeofday()] unless defined($b);
(${$b}[0] - ${$a}[0]) + ((${$b}[1] - ${$a}[1]) / 1_000_000);
}
# Autoload methods go after =cut, and are processed by the autosplit program.
1;
__END__
=head1 NAME
Time::HiRes - High resolution alarm, sleep, gettimeofday, interval timers
=head1 SYNOPSIS
use Time::HiRes qw( usleep ualarm gettimeofday tv_interval );
usleep ($microseconds);
ualarm ($microseconds);
ualarm ($microseconds, $interval_microseconds);
$t0 = [gettimeofday];
($seconds, $microseconds) = gettimeofday;
$elapsed = tv_interval ( $t0, [$seconds, $microseconds]);
$elapsed = tv_interval ( $t0, [gettimeofday]);
$elapsed = tv_interval ( $t0 );
use Time::HiRes qw ( time alarm sleep );
$now_fractions = time;
sleep ($floating_seconds);
alarm ($floating_seconds);
alarm ($floating_seconds, $floating_interval);
use Time::HiRes qw( setitimer getitimer
ITIMER_REAL ITIMER_VIRTUAL ITIMER_PROF ITIMER_REALPROF );
setitimer ($which, $floating_seconds, $floating_interval );
getitimer ($which);
=head1 DESCRIPTION
The C<Time::HiRes> module implements a Perl interface to the
C<usleep>, C<ualarm>, C<gettimeofday>, and C<setitimer>/C<getitimer>
system calls, in other words, high resolution time and timers. See the
L</EXAMPLES> section below and the test scripts for usage; see your
system documentation for the description of the underlying
C<nanosleep> or C<usleep>, C<ualarm>, C<gettimeofday>, and
C<setitimer>/C<getitimer> calls.
If your system lacks C<gettimeofday()> or an emulation of it you don't
get C<gettimeofday()> or the one-argument form of C<tv_interval()>.
If your system lacks all of C<nanosleep()>, C<usleep()>, and
C<select()>, you don't get C<Time::HiRes::usleep()> or
C<Time::HiRes::sleep()>. If your system lacks both C<ualarm()> and
C<setitimer()> you don't get C<Time::HiRes::ualarm()> or
C<Time::HiRes::alarm()>.
If you try to import an unimplemented function in the C<use> statement
it will fail at compile time.
If your subsecond sleeping is implemented with C<nanosleep()> instead
of C<usleep()>, you can mix subsecond sleeping with signals since
C<nanosleep()> does not use signals. This, however, is not portable,
and you should first check for the truth value of
C<&Time::HiRes::d_nanosleep> to see whether you have nanosleep, and
then carefully read your C<nanosleep()> C API documentation for any
peculiarities. (There is no separate interface to call
C<nanosleep()>; just use C<Time::HiRes::sleep()> or
C<Time::HiRes::usleep()> with small enough values.)
Unless using C<nanosleep> for mixing sleeping with signals, give
some thought to whether Perl is the tool you should be using for
work requiring nanosecond accuracies.
The following functions can be imported from this module.
No functions are exported by default.
=over 4
=item gettimeofday ()
In array context returns a two-element array with the seconds and
microseconds since the epoch. In scalar context returns floating
seconds like C<Time::HiRes::time()> (see below).
=item usleep ( $useconds )
Sleeps for the number of microseconds specified. Returns the number
of microseconds actually slept. Can sleep for more than one second,
unlike the C<usleep> system call. See also C<Time::HiRes::sleep()> below.
=item ualarm ( $useconds [, $interval_useconds ] )
Issues a C<ualarm> call; the C<$interval_useconds> is optional and
will be zero if unspecified, resulting in C<alarm>-like behaviour.
Note that the interaction between alarms and sleeps are unspecified.
=item tv_interval
tv_interval ( $ref_to_gettimeofday [, $ref_to_later_gettimeofday] )
Returns the floating seconds between the two times, which should have
been returned by C<gettimeofday()>. If the second argument is omitted,
then the current time is used.
=item time ()
Returns a floating seconds since the epoch. This function can be
imported, resulting in a nice drop-in replacement for the C<time>
provided with core Perl; see the L</EXAMPLES> below.
B<NOTE 1>: This higher resolution timer can return values either less
or more than the core C<time()>, depending on whether your platform
rounds the higher resolution timer values up, down, or to the nearest second
to get the core C<time()>, but naturally the difference should be never
more than half a second.
B<NOTE 2>: Since Sunday, September 9th, 2001 at 01:46:40 AM GMT, when
the C<time()> seconds since epoch rolled over to 1_000_000_000, the
default floating point format of Perl and the seconds since epoch have
conspired to produce an apparent bug: if you print the value of
C<Time::HiRes::time()> you seem to be getting only five decimals, not
six as promised (microseconds). Not to worry, the microseconds are
there (assuming your platform supports such granularity in the first
place). What is going on is that the default floating point format of
Perl only outputs 15 digits. In this case that means ten digits
before the decimal separator and five after. To see the microseconds
you can use either C<printf>/C<sprintf> with C<"%.6f">, or the
C<gettimeofday()> function in list context, which will give you the
seconds and microseconds as two separate values.
=item sleep ( $floating_seconds )
Sleeps for the specified amount of seconds. Returns the number of
seconds actually slept (a floating point value). This function can
be imported, resulting in a nice drop-in replacement for the C<sleep>
provided with perl, see the L</EXAMPLES> below.
Note that the interaction between alarms and sleeps are unspecified.
=item alarm ( $floating_seconds [, $interval_floating_seconds ] )
The C<SIGALRM> signal is sent after the specified number of seconds.
Implemented using C<ualarm()>. The C<$interval_floating_seconds> argument
is optional and will be zero if unspecified, resulting in C<alarm()>-like
behaviour. This function can be imported, resulting in a nice drop-in
replacement for the C<alarm> provided with perl, see the L</EXAMPLES> below.
B<NOTE 1>: With some combinations of operating systems and Perl
releases C<SIGALRM> restarts C<select()>, instead of interrupting it.
This means that an C<alarm()> followed by a C<select()> may together
take the sum of the times specified for the the C<alarm()> and the
C<select()>, not just the time of the C<alarm()>.
Note that the interaction between alarms and sleeps are unspecified.
=item setitimer ( $which, $floating_seconds [, $interval_floating_seconds ] )
Start up an interval timer: after a certain time, a signal arrives,
and more signals may keep arriving at certain intervals. To disable
an "itimer", use C<$floating_seconds> of zero. If the
C<$interval_floating_seconds> is set to zero (or unspecified), the
timer is disabled B<after> the next delivered signal.
Use of interval timers may interfere with C<alarm()>, C<sleep()>,
and C<usleep()>. In standard-speak the "interaction is unspecified",
which means that I<anything> may happen: it may work, it may not.
In scalar context, the remaining time in the timer is returned.
In list context, both the remaining time and the interval are returned.
There are usually three or four interval timers available: the
C<$which> can be C<ITIMER_REAL>, C<ITIMER_VIRTUAL>, C<ITIMER_PROF>, or
C<ITIMER_REALPROF>. Note that which ones are available depends: true
UNIX platforms usually have the first three, but (for example) Win32
and Cygwin have only C<ITIMER_REAL>, and only Solaris seems to have
C<ITIMER_REALPROF> (which is used to profile multithreaded programs).
C<ITIMER_REAL> results in C<alarm()>-like behavior. Time is counted in
I<real time>; that is, wallclock time. C<SIGALRM> is delivered when
the timer expires.
C<ITIMER_VIRTUAL> counts time in (process) I<virtual time>; that is,
only when the process is running. In multiprocessor/user/CPU systems
this may be more or less than real or wallclock time. (This time is
also known as the I<user time>.) C<SIGVTALRM> is delivered when the
timer expires.
C<ITIMER_PROF> counts time when either the process virtual time or when
the operating system is running on behalf of the process (such as I/O).
(This time is also known as the I<system time>.) (The sum of user
time and system time is known as the I<CPU time>.) C<SIGPROF> is
delivered when the timer expires. C<SIGPROF> can interrupt system calls.
The semantics of interval timers for multithreaded programs are
system-specific, and some systems may support additional interval
timers. See your C<setitimer()> documentation.
=item getitimer ( $which )
Return the remaining time in the interval timer specified by C<$which>.
In scalar context, the remaining time is returned.
In list context, both the remaining time and the interval are returned.
The interval is always what you put in using C<setitimer()>.
=back
=head1 EXAMPLES
use Time::HiRes qw(usleep ualarm gettimeofday tv_interval);
$microseconds = 750_000;
usleep $microseconds;
# signal alarm in 2.5s & every .1s thereafter
ualarm 2_500_000, 100_000;
# get seconds and microseconds since the epoch
($s, $usec) = gettimeofday;
# measure elapsed time
# (could also do by subtracting 2 gettimeofday return values)
$t0 = [gettimeofday];
# do bunch of stuff here
$t1 = [gettimeofday];
# do more stuff here
$t0_t1 = tv_interval $t0, $t1;
$elapsed = tv_interval ($t0, [gettimeofday]);
$elapsed = tv_interval ($t0); # equivalent code
#
# replacements for time, alarm and sleep that know about
# floating seconds
#
use Time::HiRes;
$now_fractions = Time::HiRes::time;
Time::HiRes::sleep (2.5);
Time::HiRes::alarm (10.6666666);
use Time::HiRes qw ( time alarm sleep );
$now_fractions = time;
sleep (2.5);
alarm (10.6666666);
# Arm an interval timer to go off first at 10 seconds and
# after that every 2.5 seconds, in process virtual time
use Time::HiRes qw ( setitimer ITIMER_VIRTUAL time );
$SIG{VTALRM} = sub { print time, "\n" };
setitimer(ITIMER_VIRTUAL, 10, 2.5);
=head1 C API
In addition to the perl API described above, a C API is available for
extension writers. The following C functions are available in the
modglobal hash:
name C prototype
--------------- ----------------------
Time::NVtime double (*)()
Time::U2time void (*)(UV ret[2])
Both functions return equivalent information (like C<gettimeofday>)
but with different representations. The names C<NVtime> and C<U2time>
were selected mainly because they are operating system independent.
(C<gettimeofday> is Unix-centric, though some platforms like VMS have
emulations for it.)
Here is an example of using C<NVtime> from C:
double (*myNVtime)();
SV **svp = hv_fetch(PL_modglobal, "Time::NVtime", 12, 0);
if (!svp) croak("Time::HiRes is required");
if (!SvIOK(*svp)) croak("Time::NVtime isn't a function pointer");
myNVtime = INT2PTR(double(*)(), SvIV(*svp));
printf("The current time is: %f\n", (*myNVtime)());
=head1 DIAGNOSTICS
=head2 negative time not invented yet
You tried to use a negative time argument.
=head2 internal error: useconds < 0 (unsigned ... signed ...)
Something went horribly wrong-- the number of microseconds that cannot
become negative just became negative. Maybe your compiler is broken?
=head1 CAVEATS
Notice that the core C<time()> maybe rounding rather than truncating.
What this means is that the core C<time()> may be reporting the time
as one second later than C<gettimeofday()> and C<Time::HiRes::time()>.
Adjusting the system clock (either manually or by services like ntp)
may cause problems, especially for long running programs that assume
a monotonously increasing time (note that all platforms do not adjust
time as gracefully as UNIX ntp does). For example in Win32 (and derived
platforms like Cygwin and MinGW) the Time::HiRes::time() may temporarily
drift off from the system clock (and the original time()) by up to 0.5
seconds. Time::HiRes will notice this eventually and recalibrate.
=head1 AUTHORS
D. Wegscheid <wegscd@whirlpool.com>
R. Schertler <roderick@argon.org>
J. Hietaniemi <jhi@iki.fi>
G. Aas <gisle@aas.no>
=head1 COPYRIGHT AND LICENSE
Copyright (c) 1996-2002 Douglas E. Wegscheid. All rights reserved.
Copyright (c) 2002,2003,2004 Jarkko Hietaniemi. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the same terms as Perl itself.
=cut
+351
View File
@@ -0,0 +1,351 @@
package Time::HiRes;
use strict;
use vars qw($VERSION $XS_VERSION @ISA @EXPORT @EXPORT_OK $AUTOLOAD);
require Exporter;
require DynaLoader;
@ISA = qw(Exporter DynaLoader);
@EXPORT = qw( );
@EXPORT_OK = qw (usleep sleep ualarm alarm gettimeofday time tv_interval
getitimer setitimer
ITIMER_REAL ITIMER_VIRTUAL ITIMER_PROF ITIMER_REALPROF
d_usleep d_ualarm d_gettimeofday d_getitimer d_setitimer
d_nanosleep);
$VERSION = '1.55';
$XS_VERSION = $VERSION;
$VERSION = eval $VERSION;
sub AUTOLOAD {
my $constname;
($constname = $AUTOLOAD) =~ s/.*:://;
die "&Time::HiRes::constant not defined" if $constname eq 'constant';
my ($error, $val) = constant($constname);
if ($error) { die $error; }
{
no strict 'refs';
*$AUTOLOAD = sub { $val };
}
goto &$AUTOLOAD;
}
bootstrap Time::HiRes;
# Preloaded methods go here.
sub tv_interval {
# probably could have been done in C
my ($a, $b) = @_;
$b = [gettimeofday()] unless defined($b);
(${$b}[0] - ${$a}[0]) + ((${$b}[1] - ${$a}[1]) / 1_000_000);
}
# Autoload methods go after =cut, and are processed by the autosplit program.
1;
__END__
=head1 NAME
Time::HiRes - High resolution alarm, sleep, gettimeofday, interval timers
=head1 SYNOPSIS
use Time::HiRes qw( usleep ualarm gettimeofday tv_interval );
usleep ($microseconds);
ualarm ($microseconds);
ualarm ($microseconds, $interval_microseconds);
$t0 = [gettimeofday];
($seconds, $microseconds) = gettimeofday;
$elapsed = tv_interval ( $t0, [$seconds, $microseconds]);
$elapsed = tv_interval ( $t0, [gettimeofday]);
$elapsed = tv_interval ( $t0 );
use Time::HiRes qw ( time alarm sleep );
$now_fractions = time;
sleep ($floating_seconds);
alarm ($floating_seconds);
alarm ($floating_seconds, $floating_interval);
use Time::HiRes qw( setitimer getitimer
ITIMER_REAL ITIMER_VIRTUAL ITIMER_PROF ITIMER_REALPROF );
setitimer ($which, $floating_seconds, $floating_interval );
getitimer ($which);
=head1 DESCRIPTION
The C<Time::HiRes> module implements a Perl interface to the C<usleep>,
C<ualarm>, C<gettimeofday>, and C<setitimer>/C<getitimer> system calls, in other
words, high resolution time and timers. See the L</EXAMPLES> section below
and the test scripts for usage; see your system documentation for the
description of the underlying C<nanosleep> or C<usleep>, C<ualarm>,
C<gettimeofday>, and C<setitimer>/C<getitimer> calls.
If your system lacks C<gettimeofday()> or an emulation of it you don't
get C<gettimeofday()> or the one-argument form of C<tv_interval()>. If your system lacks all of
C<nanosleep()>, C<usleep()>, and C<select()>, you don't get
C<Time::HiRes::usleep()> or C<Time::HiRes::sleep()>. If your system lacks both
C<ualarm()> and C<setitimer()> you don't get
C<Time::HiRes::ualarm()> or C<Time::HiRes::alarm()>.
If you try to import an unimplemented function in the C<use> statement
it will fail at compile time.
If your subsecond sleeping is implemented with C<nanosleep()> instead of
C<usleep()>, you can mix subsecond sleeping with signals since
C<nanosleep()> does not use signals. This, however is unportable, and you
should first check for the truth value of C<&Time::HiRes::d_nanosleep> to
see whether you have nanosleep, and then carefully read your
C<nanosleep()> C API documentation for any peculiarities. (There is no
separate interface to call C<nanosleep()>; just use C<Time::HiRes::sleep()>
or C<Time::HiRes::usleep()> with small enough values.)
Unless using C<nanosleep> for mixing sleeping with signals, give
some thought to whether Perl is the tool you should be using for work
requiring nanosecond accuracies.
The following functions can be imported from this module.
No functions are exported by default.
=over 4
=item gettimeofday ()
In array context returns a two-element array with the seconds and
microseconds since the epoch. In scalar context returns floating
seconds like C<Time::HiRes::time()> (see below).
=item usleep ( $useconds )
Sleeps for the number of microseconds specified. Returns the number
of microseconds actually slept. Can sleep for more than one second,
unlike the C<usleep> system call. See also C<Time::HiRes::sleep()> below.
=item ualarm ( $useconds [, $interval_useconds ] )
Issues a C<ualarm> call; the C<$interval_useconds> is optional and
will be zero if unspecified, resulting in C<alarm>-like behaviour.
=item tv_interval
tv_interval ( $ref_to_gettimeofday [, $ref_to_later_gettimeofday] )
Returns the floating seconds between the two times, which should have
been returned by C<gettimeofday()>. If the second argument is omitted,
then the current time is used.
=item time ()
Returns a floating seconds since the epoch. This function can be
imported, resulting in a nice drop-in replacement for the C<time>
provided with core Perl; see the L</EXAMPLES> below.
B<NOTE 1>: This higher resolution timer can return values either less
or more than the core C<time()>, depending on whether your platform
rounds the higher resolution timer values up, down, or to the nearest second
to get the core C<time()>, but naturally the difference should be never
more than half a second.
B<NOTE 2>: Since Sunday, September 9th, 2001 at 01:46:40 AM GMT, when
the C<time()> seconds since epoch rolled over to 1_000_000_000, the
default floating point format of Perl and the seconds since epoch have
conspired to produce an apparent bug: if you print the value of
C<Time::HiRes::time()> you seem to be getting only five decimals, not six
as promised (microseconds). Not to worry, the microseconds are there
(assuming your platform supports such granularity in first place).
What is going on is that the default floating point format of Perl
only outputs 15 digits. In this case that means ten digits before the
decimal separator and five after. To see the microseconds you can use
either C<printf>/C<sprintf> with C<"%.6f">, or the C<gettimeofday()> function in
list context, which will give you the seconds and microseconds as two
separate values.
=item sleep ( $floating_seconds )
Sleeps for the specified amount of seconds. Returns the number of
seconds actually slept (a floating point value). This function can be
imported, resulting in a nice drop-in replacement for the C<sleep>
provided with perl, see the L</EXAMPLES> below.
=item alarm ( $floating_seconds [, $interval_floating_seconds ] )
The C<SIGALRM> signal is sent after the specified number of seconds.
Implemented using C<ualarm()>. The C<$interval_floating_seconds> argument
is optional and will be zero if unspecified, resulting in C<alarm()>-like
behaviour. This function can be imported, resulting in a nice drop-in
replacement for the C<alarm> provided with perl, see the L</EXAMPLES> below.
B<NOTE 1>: With some operating system and Perl release combinations
C<SIGALRM> restarts C<select()>, instead of interuping it.
This means that an C<alarm()> followed by a C<select()>
may together take the sum of the times specified for the the
C<alarm()> and the C<select()>, not just the time of the C<alarm()>.
=item setitimer ( $which, $floating_seconds [, $interval_floating_seconds ] )
Start up an interval timer: after a certain time, a signal arrives,
and more signals may keep arriving at certain intervals. To disable a
timer, use C<$floating_seconds> of zero. If the C<$interval_floating_seconds>
is set to zero (or unspecified), the timer is disabled B<after> the
next delivered signal.
Use of interval timers may interfere with C<alarm()>, C<sleep()>,
and C<usleep()>. In standard-speak the "interaction is unspecified",
which means that I<anything> may happen: it may work, it may not.
In scalar context, the remaining time in the timer is returned.
In list context, both the remaining time and the interval are returned.
There are usually three or four interval timers available: the C<$which>
can be C<ITIMER_REAL>, C<ITIMER_VIRTUAL>, C<ITIMER_PROF>, or C<ITIMER_REALPROF>.
Note that which ones are available depends: true UNIX platforms usually
have the first three, but (for example) Win32 and Cygwin have only
C<ITIMER_REAL>, and only Solaris seems to have C<ITIMER_REALPROF> (which is
used to profile multithreaded programs).
C<ITIMER_REAL> results in C<alarm()>-like behavior. Time is counted in
I<real time>; that is, wallclock time. C<SIGALRM> is delivered when
the timer expires.
C<ITIMER_VIRTUAL> counts time in (process) I<virtual time>; that is, only
when the process is running. In multiprocessor/user/CPU systems this
may be more or less than real or wallclock time. (This time is also
known as the I<user time>.) C<SIGVTALRM> is delivered when the timer expires.
C<ITIMER_PROF> counts time when either the process virtual time or when
the operating system is running on behalf of the process (such as I/O).
(This time is also known as the I<system time>.) (The sum of user
time and system time is known as the I<CPU time>.) C<SIGPROF> is
delivered when the timer expires. C<SIGPROF> can interrupt system calls.
The semantics of interval timers for multithreaded programs are
system-specific, and some systems may support additional interval
timers. See your C<setitimer()> documentation.
=item getitimer ( $which )
Return the remaining time in the interval timer specified by C<$which>.
In scalar context, the remaining time is returned.
In list context, both the remaining time and the interval are returned.
The interval is always what you put in using C<setitimer()>.
=back
=head1 EXAMPLES
use Time::HiRes qw(usleep ualarm gettimeofday tv_interval);
$microseconds = 750_000;
usleep $microseconds;
# signal alarm in 2.5s & every .1s thereafter
ualarm 2_500_000, 100_000;
# get seconds and microseconds since the epoch
($s, $usec) = gettimeofday;
# measure elapsed time
# (could also do by subtracting 2 gettimeofday return values)
$t0 = [gettimeofday];
# do bunch of stuff here
$t1 = [gettimeofday];
# do more stuff here
$t0_t1 = tv_interval $t0, $t1;
$elapsed = tv_interval ($t0, [gettimeofday]);
$elapsed = tv_interval ($t0); # equivalent code
#
# replacements for time, alarm and sleep that know about
# floating seconds
#
use Time::HiRes;
$now_fractions = Time::HiRes::time;
Time::HiRes::sleep (2.5);
Time::HiRes::alarm (10.6666666);
use Time::HiRes qw ( time alarm sleep );
$now_fractions = time;
sleep (2.5);
alarm (10.6666666);
# Arm an interval timer to go off first at 10 seconds and
# after that every 2.5 seconds, in process virtual time
use Time::HiRes qw ( setitimer ITIMER_VIRTUAL time );
$SIG{VTALRM} = sub { print time, "\n" };
setitimer(ITIMER_VIRTUAL, 10, 2.5);
=head1 C API
In addition to the perl API described above, a C API is available for
extension writers. The following C functions are available in the
modglobal hash:
name C prototype
--------------- ----------------------
Time::NVtime double (*)()
Time::U2time void (*)(UV ret[2])
Both functions return equivalent information (like C<gettimeofday>)
but with different representations. The names C<NVtime> and C<U2time>
were selected mainly because they are operating system independent.
(C<gettimeofday> is Unix-centric, though some platforms like VMS have
emulations for it.)
Here is an example of using C<NVtime> from C:
double (*myNVtime)();
SV **svp = hv_fetch(PL_modglobal, "Time::NVtime", 12, 0);
if (!svp) croak("Time::HiRes is required");
if (!SvIOK(*svp)) croak("Time::NVtime isn't a function pointer");
myNVtime = INT2PTR(double(*)(), SvIV(*svp));
printf("The current time is: %f\n", (*myNVtime)());
=head1 DIAGNOSTICS
=head2 negative time not invented yet
You tried to use a negative time argument.
=head2 internal error: useconds < 0 (unsigned ... signed ...)
Something went horribly wrong-- the number of microseconds that cannot
become negative just became negative. Maybe your compiler is broken?
=head1 CAVEATS
Notice that the core C<time()> maybe rounding rather than truncating.
What this means is that the core C<time()> may be reporting the time as one second
later than C<gettimeofday()> and C<Time::HiRes::time()>.
=head1 AUTHORS
D. Wegscheid <wegscd@whirlpool.com>
R. Schertler <roderick@argon.org>
J. Hietaniemi <jhi@iki.fi>
G. Aas <gisle@aas.no>
=head1 COPYRIGHT AND LICENSE
Copyright (c) 1996-2002 Douglas E. Wegscheid. All rights reserved.
Copyright (c) 2002,2003,2004 Jarkko Hietaniemi. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the same terms as Perl itself.
=cut
+289
View File
@@ -0,0 +1,289 @@
package Time::Local;
require Exporter;
use Carp;
use Config;
use strict;
use integer;
use vars qw( $VERSION @ISA @EXPORT @EXPORT_OK );
$VERSION = '1.07';
@ISA = qw( Exporter );
@EXPORT = qw( timegm timelocal );
@EXPORT_OK = qw( timegm_nocheck timelocal_nocheck );
my @MonthDays = (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
# Determine breakpoint for rolling century
my $ThisYear = (localtime())[5];
my $Breakpoint = ($ThisYear + 50) % 100;
my $NextCentury = $ThisYear - $ThisYear % 100;
$NextCentury += 100 if $Breakpoint < 50;
my $Century = $NextCentury - 100;
my $SecOff = 0;
my (%Options, %Cheat);
my $MaxInt = ((1<<(8 * $Config{intsize} - 2))-1)*2 + 1;
my $MaxDay = int(($MaxInt-43200)/86400)-1;
# Determine the EPOC day for this machine
my $Epoc = 0;
if ($^O eq 'vos') {
# work around posix-977 -- VOS doesn't handle dates in
# the range 1970-1980.
$Epoc = _daygm((0, 0, 0, 1, 0, 70, 4, 0));
}
elsif ($^O eq 'MacOS') {
no integer;
$MaxDay *=2 if $^O eq 'MacOS'; # time_t unsigned ... quick hack?
# MacOS time() is seconds since 1 Jan 1904, localtime
# so we need to calculate an offset to apply later
$Epoc = 693901;
$SecOff = timelocal(localtime(0)) - timelocal(gmtime(0));
$Epoc += _daygm(gmtime(0));
}
else {
$Epoc = _daygm(gmtime(0));
}
%Cheat=(); # clear the cache as epoc has changed
sub _daygm {
$_[3] + ($Cheat{pack("ss",@_[4,5])} ||= do {
my $month = ($_[4] + 10) % 12;
my $year = $_[5] + 1900 - $month/10;
365*$year + $year/4 - $year/100 + $year/400 + ($month*306 + 5)/10 - $Epoc
});
}
sub _timegm {
my $sec = $SecOff + $_[0] + 60 * $_[1] + 3600 * $_[2];
no integer;
$sec + 86400 * &_daygm;
}
sub timegm {
my ($sec,$min,$hour,$mday,$month,$year) = @_;
if ($year >= 1000) {
$year -= 1900;
}
elsif ($year < 100 and $year >= 0) {
$year += ($year > $Breakpoint) ? $Century : $NextCentury;
}
unless ($Options{no_range_check}) {
if (abs($year) >= 0x7fff) {
$year += 1900;
croak "Cannot handle date ($sec, $min, $hour, $mday, $month, $year)";
}
croak "Month '$month' out of range 0..11" if $month > 11 or $month < 0;
my $md = $MonthDays[$month];
++$md unless $month != 1 or $year % 4 or !($year % 400);
croak "Day '$mday' out of range 1..$md" if $mday > $md or $mday < 1;
croak "Hour '$hour' out of range 0..23" if $hour > 23 or $hour < 0;
croak "Minute '$min' out of range 0..59" if $min > 59 or $min < 0;
croak "Second '$sec' out of range 0..59" if $sec > 59 or $sec < 0;
}
my $days = _daygm(undef, undef, undef, $mday, $month, $year);
unless ($Options{no_range_check} or abs($days) < $MaxDay) {
$year += 1900;
croak "Cannot handle date ($sec, $min, $hour, $mday, $month, $year)";
}
$sec += $SecOff + 60*$min + 3600*$hour;
no integer;
$sec + 86400*$days;
}
sub timegm_nocheck {
local $Options{no_range_check} = 1;
&timegm;
}
sub timelocal {
no integer;
my $ref_t = &timegm;
my $loc_t = _timegm(localtime($ref_t));
# Is there a timezone offset from GMT or are we done
my $zone_off = $ref_t - $loc_t
or return $loc_t;
# Adjust for timezone
$loc_t = $ref_t + $zone_off;
# Are we close to a DST change or are we done
my $dst_off = $ref_t - _timegm(localtime($loc_t))
or return $loc_t;
# Adjust for DST change
$loc_t += $dst_off;
# for a negative offset from GMT, and if the original date
# was a non-extent gap in a forward DST jump, we should
# now have the wrong answer - undo the DST adjust;
return $loc_t if $zone_off <= 0;
my ($s,$m,$h) = localtime($loc_t);
$loc_t -= $dst_off if $s != $_[0] || $m != $_[1] || $h != $_[2];
$loc_t;
}
sub timelocal_nocheck {
local $Options{no_range_check} = 1;
&timelocal;
}
1;
__END__
=head1 NAME
Time::Local - efficiently compute time from local and GMT time
=head1 SYNOPSIS
$time = timelocal($sec,$min,$hour,$mday,$mon,$year);
$time = timegm($sec,$min,$hour,$mday,$mon,$year);
=head1 DESCRIPTION
These routines are the inverse of built-in perl functions localtime()
and gmtime(). They accept a date as a six-element array, and return
the corresponding time(2) value in seconds since the system epoch
(Midnight, January 1, 1970 UTC on Unix, for example). This value can
be positive or negative, though POSIX only requires support for
positive values, so dates before the system's epoch may not work on
all operating systems.
It is worth drawing particular attention to the expected ranges for
the values provided. The value for the day of the month is the actual day
(ie 1..31), while the month is the number of months since January (0..11).
This is consistent with the values returned from localtime() and gmtime().
The timelocal() and timegm() functions perform range checking on the
input $sec, $min, $hour, $mday, and $mon values by default. If you'd
rather they didn't, you can explicitly import the timelocal_nocheck()
and timegm_nocheck() functions.
use Time::Local 'timelocal_nocheck';
{
# The 365th day of 1999
print scalar localtime timelocal_nocheck 0,0,0,365,0,99;
# The twenty thousandth day since 1970
print scalar localtime timelocal_nocheck 0,0,0,20000,0,70;
# And even the 10,000,000th second since 1999!
print scalar localtime timelocal_nocheck 10000000,0,0,1,0,99;
}
Your mileage may vary when trying these with minutes and hours,
and it doesn't work at all for months.
Strictly speaking, the year should also be specified in a form consistent
with localtime(), i.e. the offset from 1900.
In order to make the interpretation of the year easier for humans,
however, who are more accustomed to seeing years as two-digit or four-digit
values, the following conventions are followed:
=over 4
=item *
Years greater than 999 are interpreted as being the actual year,
rather than the offset from 1900. Thus, 1963 would indicate the year
Martin Luther King won the Nobel prize, not the year 2863.
=item *
Years in the range 100..999 are interpreted as offset from 1900,
so that 112 indicates 2012. This rule also applies to years less than zero
(but see note below regarding date range).
=item *
Years in the range 0..99 are interpreted as shorthand for years in the
rolling "current century," defined as 50 years on either side of the current
year. Thus, today, in 1999, 0 would refer to 2000, and 45 to 2045,
but 55 would refer to 1955. Twenty years from now, 55 would instead refer
to 2055. This is messy, but matches the way people currently think about
two digit dates. Whenever possible, use an absolute four digit year instead.
=back
The scheme above allows interpretation of a wide range of dates, particularly
if 4-digit years are used.
Please note, however, that the range of dates that can be actually be handled
depends on the size of an integer (time_t) on a given platform.
Currently, this is 32 bits for most systems, yielding an approximate range
from Dec 1901 to Jan 2038.
Both timelocal() and timegm() croak if given dates outside the supported
range.
=head1 IMPLEMENTATION
These routines are quite efficient and yet are always guaranteed to agree
with localtime() and gmtime(). We manage this by caching the start times
of any months we've seen before. If we know the start time of the month,
we can always calculate any time within the month. The start times
are calculated using a mathematical formula. Unlike other algorithms
that do multiple calls to gmtime().
timelocal() is implemented using the same cache. We just assume that we're
translating a GMT time, and then fudge it when we're done for the timezone
and daylight savings arguments. Note that the timezone is evaluated for
each date because countries occasionally change their official timezones.
Assuming that localtime() corrects for these changes, this routine will
also be correct.
=head1 BUGS
The whole scheme for interpreting two-digit years can be considered a bug.
The proclivity to croak() is probably a bug.
=head1 SUPPORT
Support for this module is provided via the perl5-porters@perl.org
email list. See http://lists.perl.org/ for more details.
Please submit bugs using the RT system at bugs.perl.org, the perlbug
script, or as a last resort, to the perl5-porters@perl.org list.
=head1 AUTHOR
This module is based on a Perl 4 library, timelocal.pl, that was
included with Perl 4.036, and was most likely written by Tom
Christiansen.
The current version was written by Graham Barr.
It is now being maintained separately from the Perl core by Dave
Rolsky, <autarch@urth.org>.
=cut
+90
View File
@@ -0,0 +1,90 @@
package Time::gmtime;
use strict;
use 5.006_001;
use Time::tm;
our(@ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS, $VERSION);
BEGIN {
use Exporter ();
@ISA = qw(Exporter Time::tm);
@EXPORT = qw(gmtime gmctime);
@EXPORT_OK = qw(
$tm_sec $tm_min $tm_hour $tm_mday
$tm_mon $tm_year $tm_wday $tm_yday
$tm_isdst
);
%EXPORT_TAGS = ( FIELDS => [ @EXPORT_OK, @EXPORT ] );
$VERSION = 1.02;
}
use vars @EXPORT_OK;
sub populate (@) {
return unless @_;
my $tmob = Time::tm->new();
@$tmob = (
$tm_sec, $tm_min, $tm_hour, $tm_mday,
$tm_mon, $tm_year, $tm_wday, $tm_yday,
$tm_isdst )
= @_;
return $tmob;
}
sub gmtime (;$) { populate CORE::gmtime(@_ ? shift : time)}
sub gmctime (;$) { scalar CORE::gmtime(@_ ? shift : time)}
1;
__END__
=head1 NAME
Time::gmtime - by-name interface to Perl's built-in gmtime() function
=head1 SYNOPSIS
use Time::gmtime;
$gm = gmtime();
printf "The day in Greenwich is %s\n",
(qw(Sun Mon Tue Wed Thu Fri Sat Sun))[ gm->wday() ];
use Time::gmtime w(:FIELDS;
printf "The day in Greenwich is %s\n",
(qw(Sun Mon Tue Wed Thu Fri Sat Sun))[ gm_wday() ];
$now = gmctime();
use Time::gmtime;
use File::stat;
$date_string = gmctime(stat($file)->mtime);
=head1 DESCRIPTION
This module's default exports override the core gmtime() function,
replacing it with a version that returns "Time::tm" objects.
This object has methods that return the similarly named structure field
name from the C's tm structure from F<time.h>; namely sec, min, hour,
mday, mon, year, wday, yday, and isdst.
You may also import all the structure fields directly into your namespace
as regular variables using the :FIELDS import tag. (Note that this
still overrides your core functions.) Access these fields as variables
named with a preceding C<tm_> in front their method names. Thus,
C<$tm_obj-E<gt>mday()> corresponds to $tm_mday if you import the fields.
The gmctime() function provides a way of getting at the
scalar sense of the original CORE::gmtime() function.
To access this functionality without the core overrides,
pass the C<use> an empty import list, and then access
function functions with their full qualified names.
On the other hand, the built-ins are still available
via the C<CORE::> pseudo-package.
=head1 NOTE
While this class is currently implemented using the Class::Struct
module to build a struct-like class, you shouldn't rely upon this.
=head1 AUTHOR
Tom Christiansen
+86
View File
@@ -0,0 +1,86 @@
package Time::localtime;
use strict;
use 5.006_001;
use Time::tm;
our(@ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS, $VERSION);
BEGIN {
use Exporter ();
@ISA = qw(Exporter Time::tm);
@EXPORT = qw(localtime ctime);
@EXPORT_OK = qw(
$tm_sec $tm_min $tm_hour $tm_mday
$tm_mon $tm_year $tm_wday $tm_yday
$tm_isdst
);
%EXPORT_TAGS = ( FIELDS => [ @EXPORT_OK, @EXPORT ] );
$VERSION = 1.02;
}
use vars @EXPORT_OK;
sub populate (@) {
return unless @_;
my $tmob = Time::tm->new();
@$tmob = (
$tm_sec, $tm_min, $tm_hour, $tm_mday,
$tm_mon, $tm_year, $tm_wday, $tm_yday,
$tm_isdst )
= @_;
return $tmob;
}
sub localtime (;$) { populate CORE::localtime(@_ ? shift : time)}
sub ctime (;$) { scalar CORE::localtime(@_ ? shift : time) }
1;
__END__
=head1 NAME
Time::localtime - by-name interface to Perl's built-in localtime() function
=head1 SYNOPSIS
use Time::localtime;
printf "Year is %d\n", localtime->year() + 1900;
$now = ctime();
use Time::localtime;
use File::stat;
$date_string = ctime(stat($file)->mtime);
=head1 DESCRIPTION
This module's default exports override the core localtime() function,
replacing it with a version that returns "Time::tm" objects.
This object has methods that return the similarly named structure field
name from the C's tm structure from F<time.h>; namely sec, min, hour,
mday, mon, year, wday, yday, and isdst.
You may also import all the structure fields directly into your namespace
as regular variables using the :FIELDS import tag. (Note that this still
overrides your core functions.) Access these fields as
variables named with a preceding C<tm_> in front their method names.
Thus, C<$tm_obj-E<gt>mday()> corresponds to $tm_mday if you import
the fields.
The ctime() function provides a way of getting at the
scalar sense of the original CORE::localtime() function.
To access this functionality without the core overrides,
pass the C<use> an empty import list, and then access
function functions with their full qualified names.
On the other hand, the built-ins are still available
via the C<CORE::> pseudo-package.
=head1 NOTE
While this class is currently implemented using the Class::Struct
module to build a struct-like class, you shouldn't rely upon this.
=head1 AUTHOR
Tom Christiansen
+33
View File
@@ -0,0 +1,33 @@
package Time::tm;
use strict;
our $VERSION = '1.00';
use Class::Struct qw(struct);
struct('Time::tm' => [
map { $_ => '$' } qw{ sec min hour mday mon year wday yday isdst }
]);
1;
__END__
=head1 NAME
Time::tm - internal object used by Time::gmtime and Time::localtime
=head1 SYNOPSIS
Don't use this module directly.
=head1 DESCRIPTION
This module is used internally as a base class by Time::localtime And
Time::gmtime functions. It creates a Time::tm struct object which is
addressable just like's C's tm structure from F<time.h>; namely with sec,
min, hour, mday, mon, year, wday, yday, and isdst.
This class is an internal interface only.
=head1 AUTHOR
Tom Christiansen
+51
View File
@@ -0,0 +1,51 @@
MA|01000|02799
RI|02800|02999
NH|03000|03899
ME|03900|04999
VT|05000|05999
CT|06000|06999
NJ|07000|08999
NY|10000|14999
PA|15000|19699
DE|19700|19999
DC|20000|20599
MD|20600|21999
VA|22000|24699
WV|24700|26999
NC|27000|28999
SC|29000|29999
GA|30000|31999
FL|32000|34999
AL|35000|36999
TN|37000|38599
MS|38600|39999
KY|40000|42999
OH|43000|45999
IN|46000|47999
MI|48000|49999
IA|50000|52999
WI|53000|54999
MN|55000|56999
SD|57000|57999
ND|58000|58999
MT|59000|59999
IL|60000|62999
MO|63000|65999
KS|66000|67999
NE|68000|69999
LA|70000|71599
AR|71600|72999
OK|73000|74999
TX|75000|79999
CO|80000|81999
WY|82000|83199
ID|83200|83999
UT|84000|84999
AZ|85000|86999
NM|87000|88899
NV|88900|89999
CA|90000|96699
HI|96700|96999
OR|97000|97999
WA|98000|99499
AK|99500|99999
Binary file not shown.
Binary file not shown.
+1
View File
@@ -0,0 +1 @@
Õ8z*½PScOȪP,ór)" ×␍‰¼+àEÓ<7‘Ôøj2ýîÕhØÕÑ#8誙éBØ,ƒ65ŸÂCb (ÔøRºý¡aá.4³ Áµ‘•™âáäWFR2¹Á) ±‰Õ8z.ý¿¤hÜÍK]…º%Mq]¤œ°Í·M]ƒ %tñ•Ôøyî½\ƒ á‘,Yµc:â•SÄÏd<,ióŸ£UäôÔøK:ô»B.e©Z%¢Vn*àóä¡Q´­Eã!tä+DìÔùCWETÁbíÁ´øo‡k]¡Žb­ÉŸ›”cÔøCz´ãÁÕ”ª.”ãÂ4û6±£_ÂM¬è]]¸æDóÔøbv¼]áÅ–)`]¢kéÊœ_uYª®©]ÁUU2FòÔør.½]á·Mt÷…ÃZÇlöd]£C]6¦ø]Y[Ê.jÔøR÷=_a ë­º_ ‚Ü­ÊÜâÁ1©Z…šâÁÌ]…æßÔør2ýÕ¢)6A›]â­É]¢(,Qáœ]™”\gSÕ4Âaõ‹¦&¬Q2cÊ>”¬vø\udI$P`ë®ÚÝu
Binary file not shown.
+3
View File
@@ -0,0 +1,3 @@
ÕxZ²ýP4e5cU\ #n7#¤¸ŽHVŽêc ØÍŒÉÕxC»=æâ¸Ö¹A`ø‘a肹 ¹µBÁ+3+Õx;ÿ4ÍQ‘ªÓ‡Á¨x‹¸å¡7␍TÖÞ_¡ª°’› ÕxJöüÍB<]ÁÚ%]á‡Ð¸
]ât×]"0s Õwb2ý¡"ÙhÏÏ£&ñ 0_CÚ%‚Ø,Ï#ÁdAœÕxZ·=a#^T­I¿XV¥ØÕ¡±s6©IsBt—IrŸÕx%~´¶Â— Žb!aÏ8s‡ËaÓÍ8cFå )“8ëÕxZvý¢E„XÝÌ]#y¥02•¨Ï":#ƒ8tÕxZvü"%Ñ|©ƒ_âÓ,äϢø“YŒè×ÕxJúôåA¥Ú}’·¡¼m¡Ìe·Ñ+6µj_¡Æ-gF|ÕxK>üaâ-
ì®ØwCY␍Œè—¡J,ƒFsÏÁ­Í®ZÕx<>ô_"q-³£µ )²‹ Ÿ¡*Ƭså ÷␍Ps‹Õv‘æµ_åÃc•Ûã„íÓg‹Î²rG$R 埗Yµ
Binary file not shown.
+2
View File
@@ -0,0 +1,2 @@
Υχ;ϋ=PW1W#X υ[r)ΆdΡ[K±δ%7®
Υψ$ώτ£c±#2¤κ΅+)U…΅BV4FΒ¬£Α›S΄½ΥχC{4[γHnpή¥¤κ•·”£βΨbΒΟƒ`εgΈβΥχC?=εγW␍n(*ΉΆEΝn,©ΉΒΖ{Qα–εΑαΞ6¦qΥχR·=Ή!ηΖ®\Οb#΅V‰)Ή«°Λ £ΐ…h~ ΥχR»=£ ²΄Ρ“£΅η␍\%Ά.ΜΠkε‚nΝΜ\–ΥχR»=εΑ—pzΫΟαµr’δ>ά™=£΅$u ΘμΥχR»=ΟG…Ο ΘµjΥ&Οa·ΣyΟΰΧΥχCΏ<ΟΒ·+61γaΝΧΟ£pτK¦σΉΆβιηΥχ;ΎτWCΡlR΅™ƒLΤΙJΧε$Έ=R£Αf¤‡¶Υψ%>³γ##xw…bΆ ΙLMδα“Ω}‰Οbj&‡V¤ΥψϊμΉΰΉκ:3 ¥αΤέk¶Ία+[µ? ΅ΰ®kSΥψ%vσ£A¥bY—ΨΝ•9‹‰λ7©ΰέ‘Ψε
Binary file not shown.
+2
View File
@@ -0,0 +1,2 @@
Õ8‚®ýPRáW¸é\-Ѹ£¬eŒ•lñìG'„XVÔÔùbúýî¤Õ,‹µbÓ*V èÂÔrK"“bTÕJ¤°Ôú5~³ÕaÈ‹fÅ9áZÚÉTŽÈ¥`Í•ááI”ŒZ^Õ8‚nýYäÃZ2!QÄhzã˜äk¥Ì*Š·‘ƒ›"xSÕ8‚nô“£ªâ漓‚Ƹ®‘ÃÓ*Ž‹"“‚fsŒãÔùSzó‘CdÖƒHÝΡµQTëÎÁºmqÓÂZ•£sÔùbû=iB
ª‘·V“bc« #“meTQ¢ÅJeÔùS;4‘¡Š²ŽUQ¡\ÔÆH'k‚ JéXž»á+ ˜ÊÓÕ8‚2¼U"àê #ÒçÃØ9еkÃÚ:'œQ„ "IÔø‚.ü‘S”Ìc§"7ÊоÏRërŒâ“Á%ÚœÎÄÔúD~óÕV΢Ée’¢ VãÒÁ¸Õqräã!±·EÔùK¾üáÁ¡i}9EiÁšë™UEã¡Lyª¥ê“áXz«9#Õ3âáõ—È­°ržQ¨ Y”ÍsÌq[‘HܘaM­òí2
Binary file not shown.
+1
View File
@@ -0,0 +1 @@
Õxj·=P3cWc•T qFÜš$·DV•ìD%CHÕxS<UÖkoà“Â6±RˆÙU¢t¤.5\U¾”¡Æ+Õxj·=§B¾”ÅÄd§‰`ɼTUÁ 9D§!ÂòR‰YÕwrw=Ï RQÅSÂq9aÖUÂ:²Žšè‘‚cxIÕxS?=UàÇË7!Tá¹mfžÌ‚B¤¥šåaâ²*ÕxK¾óS¡l£¶¸U¡,•jd¹U€‹MÉt¯U“íZfÕxCþ²y"£0•œÓ‘Á›YñLËUÁ#Ùœ;SÁÊr§¸Õx<¾óUÁa\=GÆåáE*U·OUádÞÅhUá>&‡T»ÕxD?4åAáœ9EŒ©Á'Ú¸½UÁÅ2r [SªyÇqÕxb·<©ÂH×maQb␍ÅZ%ãB#hS¢H;K)Õxbû=mAâ¹K&²«¡µÊÐ^WW¡›CÈjg“¡¦ú’ŠäÕxbû=§¡óUÁ5q^ƒåŠÓ©ÆÝSÂ;L­fŸÕw’.ýåÂÙPÞS¡ Ó¥ÊÜFär6zœA[´»M­
Binary file not shown.
+1
View File
@@ -0,0 +1 @@
уВD;3Pв2FЙXL╓Qе▌EFфFFyДD╛ Аж÷уВ-~╙Ц└╖(я;Em╕3з╣<\ёт╛K≈i╧da1s␍уЬ5~ЙЕyjX╝W╖Q▄╪Wбб≥┼хлД╒╓ЬV┐уЬ=?4ЕBрЦ2%XW╒j▌fRyUB·]iПМ╔б┴▒пн²уЬD=Еб'╒╣:еWB╔ax╫Г"tМ ≈)Г║╨,Nа уВS<обьжNH9W└ыF┴ХsЦ╓*╚▒еF▐Ц╥(н/уВZШ<Wд+!ИJ²о┌*╠nEфЦ╒c√6BПоаБЭvs3уВb╩=ЕаФэБ:╓mbй]Jя-ЕЙV≈┐╧┌f535aуВZШ=о║Hl╤║зоБbСO╘Е│kJZ╦WбХu.а╒уВS=WcX°ё8j≥ц≥XПлгW╓ЗZ'кcёZ√fж╨уЬ<Ъ=WB╛$jdКД┌S╛X]на▀JяZ√ЦбРo SуЬ.>УЕ║W╓╡XW│ТlK%aЕ║.у▄ТЯ╧бл╘ь╜ж4╧Й╬Ел+MЛv_dх≈к╠.┘кЯ#╣IZAьЪ⌡Y╣
Binary file not shown.
+115
View File
@@ -0,0 +1,115 @@
# $Id: Makefile,v 1.9 2005/10/27 17:53:35 stevek Exp $
#
# Makefile, based on the Asterisk Makefile, Coypright (C) 1999, Mark Spencer
#
# Copyright (C) 2002,2003 Junghanns.NET GmbH
#
# Klaus-Peter Junghanns <kapejod@ns1.jnetdns.de>
#
# This program is free software and may be modified and
# distributed under the terms of the GNU Public License.
#
.EXPORT_ALL_VARIABLES:
#
# app_conference defines which can be passed on the command-line
#
DESTDIR :=
INSTALL_MODULES_DIR := /usr/lib/asterisk/modules
INSTALL_CONFIG_DIR := /etc/asterisk
ASTERISK_INCLUDE_DIR := /usr/include/asterisk
# turn app_conference debugging on or off ( 0 == OFF, 1 == ON )
APP_CONFERENCE_DEBUG := 1
# 0 = OFF 1 = astdsp 2 = speex
SILDET := 2
#
# app_conference objects to build
#
OBJS = app_conference.o conference.o member.o frame.o cli.o
SHAREDOS = app_conference.so
#
# standard compile settings
#
PROC = $(shell uname -m)
INSTALL = install
CC = gcc
# skip asterisk includes if they are in /usr/include/asterisk
ifneq ($(shell dirname $(ASTERISK_INCLUDE_DIR)), /usr/include)
INCLUDE = -I$(ASTERISK_INCLUDE_DIR)
endif
LIBS = -ldl -lpthread -lm
DEBUG := -g
CFLAGS += -pipe -fPIC -Wall -Wmissing-prototypes -Wmissing-declarations $(DEBUG) $(INCLUDE) -D_REENTRANT -D_GNU_SOURCE
CFLAGS += $(shell if uname -m | grep -q ppc; then echo "-fsigned-char"; fi)
CFLAGS += -DCRYPTO
ifeq ($(APP_CONFERENCE_DEBUG), 1)
CFLAGS += -DAPP_CONFERENCE_DEBUG
endif
#
# additional flag values for silence detection
#
ifeq ($(SILDET), 2)
OBJS += libspeex/preprocess.o libspeex/misc.o libspeex/smallft.o
CFLAGS += -Ilibspeex -DSILDET=2
endif
ifeq ($(SILDET), 1)
CFLAGS += -DSILDET=1
endif
OSARCH=$(shell uname -s)
ifeq (${OSARCH},Darwin)
SOLINK=-dynamic -bundle -undefined suppress -force_flat_namespace
else
SOLINK=-shared -Xlinker -x
endif
#
# targets
#
all: $(SHAREDOS)
clean:
rm -f *.so *.o $(OBJS)
app_conference.so : $(OBJS)
$(CC) -shared -Xlinker -x -o $@ $(OBJS)
vad_test: vad_test.o libspeex/preprocess.o libspeex/misc.o libspeex/smallft.o
$(CC) $(PROFILE) -o $@ $^ -lm
install: all
if [ ! -d ${DESTDIR}${INSTALL_MODULES_DIR} ]; then \
$(INSTALL) -m 755 -d ${DESTDIR}${INSTALL_MODULES_DIR} ; \
fi
for x in $(SHAREDOS); do \
$(INSTALL) -m 755 $$x ${DESTDIR}$(INSTALL_MODULES_DIR) ; \
done
cp -f *.gsm /var/lib/asterisk/sounds
cp -f *.wav /var/lib/asterisk/sounds
#config: all
# if [ ! -d ${DESTDIR}${INSTALL_CONFIG_DIR} ]; then \
# $(INSTALL) -m 755 -d ${DESTDIR}${INSTALL_CONFIG_DIR} ; \
# fi
# $(INSTALL) -m 640 conf.conf ${DESTDIR}${INSTALL_CONFIG_DIR}
+2
View File
@@ -0,0 +1,2 @@
Õ8šê½PRá•=:¢^
àÜr(ÛžfMÑ[àE8‡Á‘Õ8¢®½áƒv†G—(QE!”fÝ…ã ¢­Q[…¢¬O*Ö©Ôúrû<ÓHWSœ€áw“tÖ8ÜÁµDÅÆxí"IGDèÔüLÔ:RŠÄ«ÁUX¹…¢Éj¸£]‚H䋨êÔûL~ü¹âãrœãA␍fa¡»áÖ®2·…_Á(º®9FÔù‚·<Qñ*1­­‚A$ŽHä_¡Ÿ+ŽUT»¡œ.Š5›Õ8¢n½a#6©y>Ü—ã‰áL]ëRQh_¢¹ÃÓÔø‚²³…7#uG©B.Vƒ³i]‚žM†cj…¢E2•šÅÔù[vª…A¥ÑåDy«œ”Âac]ÂÖloŒÛá‚HtR©FÔùzöô‡—ÃæHy­!ÕЦð«AqŽ8¨ã!Q‡ȤÔûc=á¡á6 áB)SdÞ­U9Æáñ"<55ÅÔûc¿=ÕÁŒÛ‰ømábÛÂSc_žÜ©äëáÂH¬UÉDÔù{7=_!1˜Ö¥•!‰S©Ô왩¸ãn:5P!kuÚëæ
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+341
View File
@@ -0,0 +1,341 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) 19yy <name of author>
This program 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.
This program 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 this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) 19yy name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.
+121
View File
@@ -0,0 +1,121 @@
# $Id: Makefile,v 1.9 2005/10/27 17:53:35 stevek Exp $
#
# Makefile, based on the Asterisk Makefile, Coypright (C) 1999, Mark Spencer
#
# Copyright (C) 2002,2003 Junghanns.NET GmbH
#
# Klaus-Peter Junghanns <kapejod@ns1.jnetdns.de>
#
# This program is free software and may be modified and
# distributed under the terms of the GNU Public License.
#
.EXPORT_ALL_VARIABLES:
#
# app_conference defines which can be passed on the command-line
#
INSTALL_PREFIX := /usr
INSTALL_MODULES_DIR := $(INSTALL_PREFIX)/lib/asterisk/modules
ASTERISK_INCLUDE_DIR := $(HOME)/local/asterisk/asterisk/include
# turn app_conference debugging on or off ( 0 == OFF, 1 == ON )
APP_CONFERENCE_DEBUG := 1
# 0 = OFF 1 = astdsp 2 = speex
SILDET := 2
#
# app_conference objects to build
#
OBJS = app_conference.o conference.o member.o frame.o cli.o
SHAREDOS = app_conference.so
#
# standard compile settings
#
PROC = $(shell uname -m)
INSTALL = install
CC = gcc
INCLUDE = -I$(ASTERISK_INCLUDE_DIR)
LIBS = -ldl -lpthread -lm
DEBUG := -g
CFLAGS = -pipe -fPIC -Wall -Wmissing-prototypes -Wmissing-declarations $(DEBUG) $(INCLUDE) -D_REENTRANT -D_GNU_SOURCE
#CFLAGS += -O2
#CFLAGS += -O3 -march=pentium3 -msse -mfpmath=sse,387 -ffast-math
# PERF: below is 10% faster than -O2 or -O3 alone.
#CFLAGS += -O3 -ffast-math -funroll-loops
# below is another 5% faster or so.
CFLAGS += -O3 -ffast-math -funroll-all-loops -fprefetch-loop-arrays -fsingle-precision-constant
# this is fun for PPC
#CFLAGS += -mcpu=7450 -faltivec -mabi=altivec -mdynamic-no-pic
# this is fun for x86
CFLAGS += -march=pentium3 -msse -mfpmath=sse,387
# adding -msse -mfpmath=sse has little effect.
#CFLAGS += -O3 -msse -mfpmath=sse
#CFLAGS += $(shell if $(CC) -march=$(PROC) -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-march=$(PROC)"; fi)
CFLAGS += $(shell if uname -m | grep -q ppc; then echo "-fsigned-char"; fi)
CFLAGS += -DCRYPTO
ifeq ($(APP_CONFERENCE_DEBUG), 1)
CFLAGS += -DAPP_CONFERENCE_DEBUG
endif
#
# additional flag values for silence detection
#
ifeq ($(SILDET), 2)
OBJS += libspeex/preprocess.o libspeex/misc.o libspeex/smallft.o
CFLAGS += -Ilibspeex -DSILDET=2
endif
ifeq ($(SILDET), 1)
CFLAGS += -DSILDET=1
endif
OSARCH=$(shell uname -s)
ifeq (${OSARCH},Darwin)
SOLINK=-dynamic -bundle -undefined suppress -force_flat_namespace
else
SOLINK=-shared -Xlinker -x
endif
#
# targets
#
all: $(SHAREDOS)
clean:
rm -f *.so *.o $(OBJS)
app_conference.so : $(OBJS)
$(CC) -pg -shared -Xlinker -x -o $@ $(OBJS)
vad_test: vad_test.o libspeex/preprocess.o libspeex/misc.o libspeex/smallft.o
$(CC) $(PROFILE) -o $@ $^ -lm
install: all
for x in $(SHAREDOS); do $(INSTALL) -m 755 $$x $(INSTALL_MODULES_DIR) ; done
cp -f *.gsm /var/lib/asterisk/sounds
cp -f *.wav /var/lib/asterisk/sounds
# /var/horizon/mojo/lib/horizoncmd restart asterisk
# make sure you restart asterisk after make install
# config: all
# cp conf.conf /etc/asterisk/
+170
View File
@@ -0,0 +1,170 @@
app_conference is a channel-independent conference application.
Design goals
It has several design goals which are different than meetme:
* It does not require a zap channel for timing.
* It is very efficient when used with channels which support DTX (silence
detection/discontinuous transmission).
* It can do VAD on channels which do not support DTX (although this
is more expensive than just mixing them, but less expensive then
encoding; therefore it might still be a win).
* It presents messages on the Monitor interface for determine which
speakers are active.
I believe that people other than myself are using this, but my environment is
pretty rigid, and cases outside of this aren't tested:
* Some callers come from the PSTN via IAX2 from a box with Zaptel cards,
via uLaw.
* Other callers come from iaxclient based softphones using speex
(was GSM) via IAX2 (with DTX).
* Some conferences have a single SIP channel which listens in GSM.
Mixing design
* Minimize encoding/decoding, minimize mixing.
* Minimize generational loss from trancoding.
* Usual cases are handled very efficiently:
o One speaker: That speaker's frame is sent directly to each
participant which uses the same codec. It is trancoded
_once_ for each additional codec type used by participants.
o Two speakers: Each speaker gets the other speaker's frames.
The two speaker's frames are decoded and mixed, and then
encoded _once_ for each codec type used by participants.
License
Naturally, app_conference is GPL. The CVS also includes parts of libspeex,
which is distributed under it's a BSD-style license.
Getting app_conference
app_conference is available from the 'iaxclient' project on sourceforge:
* CVS browse: http://iaxclient.cvs.sourceforge.net/iaxclient/app_conference/
* Project page: http://sourceforge.net/projects/iaxclient/
Compiling app_conference
* just like any other asterisk application.
* Some makefile fiddling may be necessary
Using app_conference
There is no configuration file. Conferences are created on-the-fly.
Dialplan syntax: Conference(ConferenceName|Flags|Priority[|VADSTART|VADCONTINUE])
* ConferenceName: Whatever you want to name the conference
* Flags one of more of the following:
o M: Moderator (presently same as speaker)
o S: Speaker
o L: Listener
o T: "Telephone caller" (just for stats?).
o V: Do VAD on this caller
o D: Use Denoise filter on this caller.
o d: Send manager events when DTMF is received.
o q: Do not play enter or exit sounds.
o i: use inband dtmf broadcast.
o t: use rfc dtmf signal broadcast.
* Priority: Currently ignored; was to be a "speaking priority" so a
higher priority caller could "override" others.
* VADSTART: Optional: "probability" to use to detect start of speech.
* VADCONTINUE: Optional: "probability" to use to detect continuation
of speech.
Features / CLI/Manager Commands
* conference debug <conference_name> [ on | off ]
enable debugging for a conference
* conference show stats show conference stats
* conference play sound <channel-id> <sound-file> [mute]
play a sound to a conference member, optionally muting them.
Manager Events
app_conference generates several detailed manager events so that applications
interfacing with the manager API can monitor conferences:
* ConferenceState: sent as members begin/end speaking.
Channel: The channel
State: "speaking" or "silent"
* ConferenceDTMF: sent when conference members send DTMF to the conference
Channel: The channel
Key: The DTMF key send [0-9*#]
* ConferenceSoundComplete: send when the conference has finished playing
a sound to a user
Channel: The channel
Sound: The first 255 bytes of the file requested in conference play
sound CLI/Mgr command.
Benchmarking
It would be nice to have solid benchmarks to present, but a good size
machine should be able to handle many callers when either (a) they are
using DTX, or (b) they are listen-only. It's used often with hundreds of
simultaneous callers.
Discussion
The iaxclient-devel mailing list is probably as good a place as any to discuss.
---
app_conference is brought to you by the letter q, and the number e
Matt Florell Changes for VD_app_conference tarball version. In order to use this
as seemlessly as possible for VICIDIAL it was necessary to modify the code. This
module can now be used in place of using meetme for VICIDIAL. This is
experimental, please test thoroughly before putting it in production.
CHANGES MADE FOR VICIDIAL:
- Default to member type of S instead of L
- Commented out many repetative NOTICEs and ERRORs
- Added entry and exit sounds except for Local/786 and Local/8500998 (VDsilent and DTMFapp)
- Added conf-onlyperson mesage to first conference participant
- Included enter.gsm and leave.gsm files as well as DTMF wav and gsm sounds
- Removed restart from "make install" and added audio file copying
- If no 'd' option is set and DTMF frames are detected, the DTMF audio will be played to the member
- Added 'q' flag to prevent playing of entry/exit sounds
- Added 'i' flag to enable playing of DTMF sounds inband to all members
- Added 't' flag to enable sending of RFC DTMF signals to all members
- Changed delimiter to pipe | from slash / to be more compliant with meetme standards
NOTE TO 64-BIT LINUX USERS:
If you have problems with 64-bit Linux please use the included 64_Makefile instead of the default one.
COMPILE NOTES:
Some Makefile alterations may be necessary for your system:
From Alek Barkley:
I am running FC4 with latest updates ( 2.6.16 kernel )
My CPU is AMD K6 and GCC 4.0.2.
I edited Makefile in app_conference distribution.
To enter CPU architecture in my case -march=k6
========================================================
PROC = k6
# this is fun for x86
#CFLAGS += -march=pentium3 -msse -mfpmath=sse,387
CFLAGS += -march=k6
===========================================================
VD_app_conference CHANGELOG
- Release 0.4 - First VICIDIAL-centric release
- Release 0.5 - Fixed the dtmf broadcast logic and a star/hash bug
- Added 64-bit makefile thanks to Jon Hood
- Release 0.6 - Added Makefile notes and changed some Makefile flags
+86
View File
@@ -0,0 +1,86 @@
VICIDIAL and app_conference
(1.2 tree) EXPERIMENTAL!!!
app_conference offers the plusses of being able to do conferencing
without any zaptel hardware or timers as well as doing native codec
streaming, meaning no manditory downsampling to slin like meetme.
These two features alone mean a rather significant performance boost
to companies who only use VOIP for agents and trunks as well as not
requiring the cost of zaptel hardware or the nightmare of getting
ztdummy to work on some systems.
As of right now, I have a test system fully up and running using
app_conference with VICIDIAL on Asterisk 1.2.8. I have made several
modifications to the app_conference code to make it more of a drop-in
replacement for meetme so that it does not require any changes to the
VICIDIAL codebase. I have added entry and exit sounds(slightly
different from meetme's) as well as "only one in this conference"
message in addition to changing the default member type to speaker(S).
So far I have tested with IAX and SIP channels only and everything
works just like on meetme but I have not done any capacity testing or
tested it in production yet.
If you want to use app_conference instead of meetme for VICIDIAL then follow these instructions:
cd /usr/src/asterisk
wget http://www.eflo.net/files/VD_app_conference_0.6.zip
unzip VD_app_conference_0.6.zip
cd app_conference
make clean
make
make install
In your extensions.conf file you would replace these lines:
exten => 8600051,1,Meetme,8600051
exten => 8600052,1,Meetme,8600052
...continue through 8600100...
exten => 78600051,1,Meetme,8600051|q
exten => 78600052,1,Meetme,8600052|q
...continue through 78600100...
exten => 68600051,1,Meetme,8600051|mq
exten => 68600052,1,Meetme,8600052|mq
...continue through 68600100...
with these lines:
exten => 8600051,1,Conference(8600051)
exten => 8600052,1,Conference(8600052)
...continue through 8600100...
exten => 78600051,1,Conference(8600051|q)
exten => 78600052,1,Conference(8600052|q)
...continue through 78600100...
exten => 68600051,1,Conference(8600051|Lq)
exten => 68600052,1,Conference(8600052|Lq)
...continue through 68600100...
NOTES:
Here are the possible feature flags for this version of app_conference:
o M: Moderator (presently same as speaker) [default]
o S: Speaker
o L: Listener
o T: "Telephone caller" (just for stats?).
o V: Do VAD on this caller
o D: Use Denoise filter on this caller.
o d: Send manager events when DTMF is received.
o q: Do not play enter or exit sounds.
o i: use inband dtmf broadcast.
o t: use rfc dtmf signal broadcast.
COMPILE NOTES:
Some Makefile alterations may be necessary for your system:
From Alek Barkley:
I am running FC4 with latest updates ( 2.6.16 kernel )
My CPU is AMD K6 and GCC 4.0.2.
I edited Makefile in app_conference distribution.
To enter CPU architecture in my case -march=k6
========================================================
PROC = k6
# this is fun for x86
#CFLAGS += -march=pentium3 -msse -mfpmath=sse,387
CFLAGS += -march=k6
===========================================================
+146
View File
@@ -0,0 +1,146 @@
// $Id: app_conference.c,v 1.22 2005/10/26 21:02:07 stevek Exp $
/*
* app_conference
*
* A channel independent conference application for Asterisk
*
* Copyright (C) 2002, 2003 Junghanns.NET GmbH
* Copyright (C) 2003, 2004 HorizonLive.com, Inc.
*
* Klaus-Peter Junghanns <kapejod@ns1.jnetdns.de>
*
* This program may be modified and distributed under the
* terms of the GNU Public License.
*
*/
#include "app_conference.h"
#include "common.h"
/*
a conference has n + 1 threads, where n is the number of
members and 1 is a conference thread which sends audio
back to the members.
each member thread reads frames from the channel and
add's them to the member's frame queue.
the conference thread reads frames from each speaking members
queue, mixes them, and then re-queues them for the member thread
to send back to the user.
*/
//
// app_conference text descriptions
//
static char *tdesc = "Channel Independent Conference Application" ;
static char *app = "Conference" ;
static char *synopsis = "Channel Independent Conference" ;
static char *descrip = " Conference(): returns 0\n"
"if the user exits with the '#' key, or -1 if the user hangs up.\n" ;
//
// functions defined in asterisk/module.h
//
STANDARD_LOCAL_USER ;
LOCAL_USER_DECL;
int unload_module( void )
{
ast_log( LOG_NOTICE, "unloading app_conference module\n" ) ;
STANDARD_HANGUP_LOCALUSERS ; // defined in asterisk/module.h
// register conference cli functions
unregister_conference_cli() ;
return ast_unregister_application( app ) ;
}
int load_module( void )
{
ast_log( LOG_NOTICE, "loading app_conference module [ $Revision: 1.22 $ ]\n" ) ;
// intialize conference
init_conference() ;
// register conference cli functions
register_conference_cli() ;
return ast_register_application( app, app_conference_main, synopsis, descrip ) ;
}
char *description( void )
{
return tdesc ;
}
int usecount( void )
{
int res;
STANDARD_USECOUNT( res ) ; // defined in asterisk/module.h
return res;
}
char *key()
{
return ASTERISK_GPL_KEY ;
}
//
// main app_conference function
//
int app_conference_main( struct ast_channel* chan, void* data )
{
int res = 0 ;
struct localuser *u ;
// defined in asterisk/module.h
LOCAL_USER_ADD( u ) ;
// call member thread function
res = member_exec( chan, data ) ;
// defined in asterisk/module.h
LOCAL_USER_REMOVE( u ) ;
return res ;
}
//
// utility functions
//
// now returns milliseconds
long usecdiff( struct timeval* timeA, struct timeval* timeB )
{
long a_secs = timeA->tv_sec - timeB->tv_sec ;
long b_secs = (long)( timeA->tv_usec / 1000 ) - (long)( timeB->tv_usec / 1000 ) ;
long u_secs = ( a_secs * 1000 ) + b_secs ;
return u_secs ;
}
// increment a timeval by ms milliseconds
void add_milliseconds( struct timeval* tv, long ms )
{
// add the microseconds to the microseconds field
tv->tv_usec += ( ms * 1000 ) ;
// calculate the number of seconds to increment
long s = ( tv->tv_usec / 1000000 ) ;
// adjust the microsends field
if ( s > 0 ) tv->tv_usec -= ( s * 1000000 ) ;
// increment the seconds field
tv->tv_sec += s ;
return ;
}
+200
View File
@@ -0,0 +1,200 @@
// $Id: app_conference.h,v 1.11 2005/12/16 22:31:58 stevek Exp $
/*
* app_conference
*
* A channel independent conference application for Asterisk
*
* Copyright (C) 2002, 2003 Junghanns.NET GmbH
* Copyright (C) 2003, 2004 HorizonLive.com, Inc.
*
* Klaus-Peter Junghanns <kapejod@ns1.jnetdns.de>
*
* This program may be modified and distributed under the
* terms of the GNU Public License.
*
*/
#ifndef _ASTERISK_CONF_H
#define _ASTERISK_CONF_H
#include <stdio.h>
/* asterisk includes */
#include <asterisk/pbx.h>
#include <asterisk/module.h>
#include <asterisk/logger.h>
#include <asterisk/lock.h>
#include <asterisk/frame.h>
#include <asterisk/manager.h>
#include <asterisk/dsp.h>
#include <asterisk/translate.h>
#include <asterisk/channel.h>
#include <asterisk/file.h>
#include <asterisk/cli.h>
/* standard includes */
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <math.h>
#include <pthread.h>
#if (SILDET == 2)
#include "libspeex/speex_preprocess.h"
#endif
//
// app_conference defines
//
// debug logging level
// LOG_NOTICE for debugging, LOG_DEBUG for production
#ifdef APP_CONFERENCE_DEBUG
#define AST_CONF_DEBUG LOG_NOTICE
#else
#define AST_CONF_DEBUG LOG_DEBUG
#endif
//
// feature defines
//
// number of times the last non-silent frame should be
// repeated after silence starts
//#define AST_CONF_CACHE_LAST_FRAME 1
//
// debug defines
//
#define DEBUG_USE_TIMELOG
#define DEBUG_FRAME_TIMESTAMPS
// #define DEBUG_OUTPUT_PCM
//
// !!! THESE CONSTANTS SHOULD BE CLEANED UP AND CLARIFIED !!!
//
//
// sample information for AST_FORMAT_SLINEAR format
//
#define AST_CONF_SAMPLE_RATE 8000
#define AST_CONF_SAMPLE_SIZE 16
#define AST_CONF_FRAME_INTERVAL 20
//
// so, since we cycle approximately every 20ms,
// we can compute the following values:
//
// 160 samples per 20 ms frame -or-
// ( 8000 samples-per-second * ( 20 ms / 1000 ms-per-second ) ) = 160 samples
//
// 320 bytes ( 2560 bits ) of data 20 ms frame -or-
// ( 160 samples * 16 bits-per-sample / 8 bits-per-byte ) = 320 bytes
//
// 160 samples 16-bit signed linear
#define AST_CONF_BLOCK_SAMPLES 160
// 2 bytes per sample ( i.e. 16-bit )
#define AST_CONF_BYTES_PER_SAMPLE 2
// 320 bytes for each 160 sample frame of 16-bit audio
#define AST_CONF_FRAME_DATA_SIZE 320
// 1000 ms-per-second / 20 ms-per-frame = 50 frames-per-second
#define AST_CONF_FRAMES_PER_SECOND ( 1000 / AST_CONF_FRAME_INTERVAL )
//
// buffer and queue values
//
// account for friendly offset when allocating buffer for frame
#define AST_CONF_BUFFER_SIZE ( AST_CONF_FRAME_DATA_SIZE + AST_FRIENDLY_OFFSET )
// maximum number of frames queued per member
#define AST_CONF_MAX_QUEUE 100
// minimum number of frames queued per member
#define AST_CONF_MIN_QUEUE 0
// number of queued frames before we start dropping
#define AST_CONF_QUEUE_DROP_THRESHOLD 4
// number of milliseconds between frame drops
#define AST_CONF_QUEUE_DROP_TIME_LIMIT 750
//
// timer and sleep values
//
// milliseconds we're willing to wait for a channel
// event before we check for outgoing frames
#define AST_CONF_WAITFOR_LATENCY 40
// milliseconds to sleep before trying to process frames
#define AST_CONF_CONFERENCE_SLEEP 40
// milliseconds to wait between state notification updates
#define AST_CONF_NOTIFICATION_SLEEP 500
//
// warning threshold values
//
// number of frames behind before warning
#define AST_CONF_OUTGOING_FRAMES_WARN 50
// number of milliseconds off AST_CONF_FRAME_INTERVAL before warning
#define AST_CONF_INTERVAL_WARNING 1000
//
// silence detection values
//
// toggle silence detection
#define ENABLE_SILENCE_DETECTION 1
// silence threshold
#define AST_CONF_SILENCE_THRESHOLD 128
// speech tail (delay before dropping silent frames, in ms.
// #define AST_CONF_SPEECH_TAIL 180
// number of frames to ignore speex_preprocess() after speech detected
#define AST_CONF_SKIP_SPEEX_PREPROCESS 20
// our speex probability values
#define AST_CONF_PROB_START 0.05
#define AST_CONF_PROB_CONTINUE 0.02
//
// format translation values
//
// AST_FORMAT_MAX_AUDIO is 1 << 15, so we support 0..15
#define AC_SUPPORTED_FORMATS 16
#define AC_SLINEAR_INDEX 6
//
// app_conference functions
//
// main module function
int app_conference_main( struct ast_channel* chan, void* data ) ;
// utility functions
long usecdiff( struct timeval* timeA, struct timeval* timeB ) ;
void add_milliseconds( struct timeval* tv, long ms ) ;
#endif
+332
View File
@@ -0,0 +1,332 @@
// $Id: cli.c,v 1.6 2005/12/21 21:34:50 stevek Exp $
/*
* app_conference
*
* A channel independent conference application for Asterisk
*
* Copyright (C) 2002, 2003 Junghanns.NET GmbH
* Copyright (C) 2003, 2004 HorizonLive.com, Inc.
*
* Klaus-Peter Junghanns <kapejod@ns1.jnetdns.de>
*
* This program may be modified and distributed under the
* terms of the GNU Public License.
*
*/
#include "cli.h"
//
// debug functions
//
static char conference_debug_usage[] =
"usage: conference debug <conference_name> [ on | off ]\n"
" enable debugging for a conference\n"
;
static struct ast_cli_entry cli_debug = {
{ "conference", "debug", NULL },
conference_debug,
"enable debugging for a conference",
conference_debug_usage
} ;
int conference_debug( int fd, int argc, char *argv[] )
{
if ( argc < 3 )
return RESULT_SHOWUSAGE ;
// get the conference name
const char* name = argv[2] ;
// get the new state
int state = 0 ;
if ( argc == 3 )
{
// no state specified, so toggle it
state = -1 ;
}
else
{
if ( strncasecmp( name, "YES", 4 ) == 0 )
state = 1 ;
else if ( strncasecmp( name, "NO", 3 ) == 0 )
state = 0 ;
else
return RESULT_SHOWUSAGE ;
}
int new_state = set_conference_debugging( name, state ) ;
if ( new_state == 1 )
{
ast_cli( fd, "enabled conference debugging, name => %s, new_state => %d\n",
name, new_state ) ;
}
else if ( new_state == 0 )
{
ast_cli( fd, "disabled conference debugging, name => %s, new_state => %d\n",
name, new_state ) ;
}
else
{
// error setting state
ast_cli( fd, "\nunable to set debugging state, name => %s\n\n", name ) ;
}
return RESULT_SUCCESS ;
}
//
// stats functions
//
static char conference_show_stats_usage[] =
"usage: conference show stats\n"
" display stats for active conferences.\n"
;
static struct ast_cli_entry cli_show_stats = {
{ "conference", "show", "stats", NULL },
conference_show_stats,
"show conference stats",
conference_show_stats_usage
} ;
int conference_show_stats( int fd, int argc, char *argv[] )
{
if ( argc < 3 )
return RESULT_SHOWUSAGE ;
// get count of active conferences
int count = get_conference_count() ;
ast_cli( fd, "\n\nCONFERENCE STATS, ACTIVE( %d )\n\n", count ) ;
// if zero, go no further
if ( count <= 0 )
return RESULT_SUCCESS ;
//
// get the conference stats
//
// array of stats structs
ast_conference_stats stats[ count ] ;
// get stats structs
count = get_conference_stats( stats, count ) ;
// make sure we were able to fetch some
if ( count <= 0 )
{
ast_cli( fd, "!!! error fetching conference stats, available => %d !!!\n", count ) ;
return RESULT_SUCCESS ;
}
//
// output the conference stats
//
// output header
ast_cli( fd, "%-20.20s %-40.40s %-40.40s\n", "Name", "Connection Type", "Member Type" ) ;
ast_cli( fd, "%-20.20s %-40.40s %-40.40s\n", "----", "---------------", "-----------" ) ;
ast_conference_stats* s = NULL ;
char ct[64] ;
char mt[64] ;
int i;
for ( i = 0 ; i < count ; ++i )
{
s = &(stats[i]) ;
// format connection type
snprintf( ct, 40, "phone( %d ), iax( %d ), sip( %d )",
s->phone, s->iaxclient, s->sip ) ;
// format memeber type
snprintf( mt, 40, "moderators( %d ), listeners( %d )",
s->moderators, s->listeners ) ;
// output this conferences stats
ast_cli( fd, "%-20.20s %-40.40s %-40.40s\n", (char*)( &(s->name) ), ct, mt ) ;
}
ast_cli( fd, "\n" ) ;
//
// drill down to specific stats
//
if ( argc == 4 )
{
// show stats for a particular conference
conference_show_stats_name( fd, argv[3] ) ;
}
return RESULT_SUCCESS ;
}
int conference_show_stats_name( int fd, const char* name )
{
// not implemented yet
return RESULT_SUCCESS ;
}
//
// play sound
//
static char conference_play_sound_usage[] =
"usage: conference play sound <channel-id> <sound-file> [mute]\n"
" play sound <sound-file> to conference member <channel-id>.\n"
" mute the channel if 'mute' is present.\n"
;
static struct ast_cli_entry cli_play_sound = {
{ "conference", "play", "sound", NULL },
conference_play_sound,
"play a sound to a conference member",
conference_play_sound_usage
} ;
int conference_play_sound( int fd, int argc, char *argv[] )
{
char *channel, *file;
int mute = 0;
struct ast_conf_member *member;
struct ast_conf_soundq *newsound;
struct ast_conf_soundq **q;
if ( argc < 5 )
return RESULT_SHOWUSAGE ;
channel = argv[3];
file = argv[4];
if(argc > 5 && !strcmp(argv[5], "mute"))
mute = 1;
member = find_member(channel, 1);
if(!member) {
ast_cli(fd, "Member %s not found\n", channel);
return RESULT_FAILURE;
}
newsound = calloc(1,sizeof(struct ast_conf_soundq));
newsound->stream = ast_openstream(member->chan, file, NULL);
if(!newsound->stream) {
ast_cli(fd, "Sound %s not found\n", file);
free(newsound);
ast_mutex_unlock(&member->lock);
return RESULT_FAILURE;
}
member->chan->stream = NULL;
newsound->muted = mute;
ast_copy_string(newsound->name, file, sizeof(newsound->name));
// append sound to the end of the list.
for(q=&member->soundq; *q; q = &((*q)->next)) ;;
*q = newsound;
ast_mutex_unlock(&member->lock);
ast_cli( fd, "Playing sound %s to member %s %s\n",
file, channel, mute ? "with mute" : "");
return RESULT_SUCCESS ;
}
//
// stop sounds
//
static char conference_stop_sounds_usage[] =
"usage: conference stop sounds <channel-id>\n"
" stop sounds for conference member <channel-id>.\n"
;
static struct ast_cli_entry cli_stop_sounds = {
{ "conference", "stop", "sounds", NULL },
conference_stop_sounds,
"stop sounds for a conference member",
conference_stop_sounds_usage
} ;
int conference_stop_sounds( int fd, int argc, char *argv[] )
{
char *channel;
struct ast_conf_member *member;
struct ast_conf_soundq *sound;
struct ast_conf_soundq *next;
if ( argc < 4 )
return RESULT_SHOWUSAGE ;
channel = argv[3];
member = find_member(channel, 1);
if(!member) {
ast_cli(fd, "Member %s not found\n", channel);
return RESULT_FAILURE;
}
// clear all sounds
sound = member->soundq;
member->soundq = NULL;
while(sound) {
next = sound->next;
ast_closestream(sound->stream);
free(sound);
sound = next;
}
// reset write format, since we're done playing the sound
if ( ast_set_write_format( member->chan, member->write_format ) < 0 )
{
ast_log( LOG_ERROR, "unable to set write format to %d\n",
member->write_format ) ;
}
ast_mutex_unlock(&member->lock);
ast_cli( fd, "Stopped sounds to member %s\n", channel);
return RESULT_SUCCESS ;
}
//
// cli initialization function
//
void register_conference_cli( void )
{
ast_cli_register( &cli_debug ) ;
ast_cli_register( &cli_show_stats ) ;
ast_cli_register( &cli_play_sound ) ;
ast_cli_register( &cli_stop_sounds ) ;
}
void unregister_conference_cli( void )
{
ast_cli_unregister( &cli_debug ) ;
ast_cli_unregister( &cli_show_stats ) ;
ast_cli_unregister( &cli_play_sound ) ;
ast_cli_unregister( &cli_stop_sounds ) ;
}
+47
View File
@@ -0,0 +1,47 @@
// $Id: cli.h,v 1.3 2005/10/26 21:02:07 stevek Exp $
/*
* app_conference
*
* A channel independent conference application for Asterisk
*
* Copyright (C) 2002, 2003 Junghanns.NET GmbH
* Copyright (C) 2003, 2004 HorizonLive.com, Inc.
*
* Klaus-Peter Junghanns <kapejod@ns1.jnetdns.de>
*
* This program may be modified and distributed under the
* terms of the GNU Public License.
*
*/
#ifndef _APP_CONF_CLI_H
#define _APP_CONF_CLI_H
//
// includes
//
#include "app_conference.h"
#include "common.h"
//
// function declarations
//
int conference_show_stats( int fd, int argc, char *argv[] ) ;
int conference_show_stats_name( int fd, const char* name ) ;
int conference_debug( int fd, int argc, char *argv[] ) ;
int conference_no_debug( int fd, int argc, char *argv[] ) ;
int conference_play_sound( int fd, int argc, char *argv[] ) ;
int conference_stop_sounds( int fd, int argc, char *argv[] ) ;
void register_conference_cli( void ) ;
void unregister_conference_cli( void ) ;
#endif
+50
View File
@@ -0,0 +1,50 @@
// $Id: common.h,v 1.3 2005/10/26 21:02:07 stevek Exp $
/*
* app_conference
*
* A channel independent conference application for Asterisk
*
* Copyright (C) 2002, 2003 Junghanns.NET GmbH
* Copyright (C) 2003, 2004 HorizonLive.com, Inc.
*
* Klaus-Peter Junghanns <kapejod@ns1.jnetdns.de>
*
* This program may be modified and distributed under the
* terms of the GNU Public License.
*
*/
#ifndef _APP_CONF_COMMON_H
#define _APP_CONF_COMMON_H
// typedef includes
#include "conf_frame.h"
// function includesee
#include "conference.h"
#include "member.h"
#include "frame.h"
#include "cli.h"
/* Utility functions */
/* LOG the time taken to execute a function (like lock acquisition */
#if 1
#define TIMELOG(func,min,message) \
do { \
struct timeval t1, t2; \
int diff; \
gettimeofday(&t1,NULL); \
func; \
gettimeofday(&t2,NULL); \
if((diff = usecdiff(&t2, &t1)) > min) \
ast_log( AST_CONF_DEBUG, "TimeLog: %s: %d ms\n", message, diff); \
} while (0)
#else
#define TIMELOG(func,min,message) func
#endif
#endif
+61
View File
@@ -0,0 +1,61 @@
// $Id: conf_frame.h,v 1.3 2005/10/26 21:02:07 stevek Exp $
/*
* app_conference
*
* A channel independent conference application for Asterisk
*
* Copyright (C) 2002, 2003 Junghanns.NET GmbH
* Copyright (C) 2003, 2004 HorizonLive.com, Inc.
*
* Klaus-Peter Junghanns <kapejod@ns1.jnetdns.de>
*
* This program may be modified and distributed under the
* terms of the GNU Public License.
*
*/
#ifndef _APP_CONF_STRUCTS_H
#define _APP_CONF_STRUCTS_H
//
// includes
//
#include "app_conference.h"
#include "common.h"
//
// struct declarations
//
typedef struct conf_frame
{
// frame audio data
struct ast_frame* fr ;
// array of converted versions for listeners
struct ast_frame* converted[ AC_SUPPORTED_FORMATS ] ;
// pointer to the frame's owner
struct ast_conf_member* member ; // who sent this frame
// frame meta data
// struct timeval timestamp ;
// unsigned long cycleid ;
// int priority ;
// linked-list pointers
struct conf_frame* next ;
struct conf_frame* prev ;
// should this frame be preserved
short static_frame ;
// pointer to mixing buffer
char* mixed_buffer ;
} conf_frame ;
#endif
File diff suppressed because it is too large Load Diff
+121
View File
@@ -0,0 +1,121 @@
// $Id: conference.h,v 1.6 2005/10/26 21:02:07 stevek Exp $
/*
* app_conference
*
* A channel independent conference application for Asterisk
*
* Copyright (C) 2002, 2003 Junghanns.NET GmbH
* Copyright (C) 2003, 2004 HorizonLive.com, Inc.
*
* Klaus-Peter Junghanns <kapejod@ns1.jnetdns.de>
*
* This program may be modified and distributed under the
* terms of the GNU Public License.
*
*/
#ifndef _APP_CONF_CONFERENCE_H
#define _APP_CONF_CONFERENCE_H
//
// includes
//
#include "app_conference.h"
#include "common.h"
//
// struct declarations
//
typedef struct ast_conference_stats
{
// conference name ( copied for ease of use )
char name[128] ;
// type of connection
unsigned short phone ;
unsigned short iaxclient ;
unsigned short sip ;
// type of users
unsigned short moderators ;
unsigned short listeners ;
// accounting data
unsigned long frames_in ;
unsigned long frames_out ;
unsigned long frames_mixed ;
struct timeval time_entered ;
} ast_conference_stats ;
struct ast_conference
{
// conference name
char name[128] ;
// single-linked list of members in conference
struct ast_conf_member* memberlist ;
int membercount ;
// conference thread id
pthread_t conference_thread ;
// conference data mutex
ast_mutex_t lock ;
// pointer to next conference in single-linked list
struct ast_conference* next ;
// pointer to translation paths
struct ast_trans_pvt* from_slinear_paths[ AC_SUPPORTED_FORMATS ] ;
// conference stats
ast_conference_stats stats ;
// keep track of current delivery time
struct timeval delivery_time ;
// 1 => on, 0 => off
short debug_flag ;
} ;
//
// function declarations
//
struct ast_conference* start_conference( struct ast_conf_member* member ) ;
void conference_exec( struct ast_conference* conf ) ;
struct ast_conference* find_conf( const char* name ) ;
struct ast_conference* create_conf( char* name, struct ast_conf_member* member ) ;
void remove_conf( struct ast_conference* conf ) ;
// find a particular member, locking if requested.
struct ast_conf_member *find_member ( char *chan, int lock) ;
int queue_frame_for_listener( struct ast_conference* conf, struct ast_conf_member* member, conf_frame* frame ) ;
int queue_frame_for_speaker( struct ast_conference* conf, struct ast_conf_member* member, conf_frame* frame ) ;
int queue_silent_frame( struct ast_conference* conf, struct ast_conf_member* member ) ;
void add_member( struct ast_conf_member* member, struct ast_conference* conf ) ;
int remove_member( struct ast_conf_member* member, struct ast_conference* conf ) ;
int count_member( struct ast_conf_member* member, struct ast_conference* conf, short add_member ) ;
// called by app_confernce.c:load_module()
void init_conference( void ) ;
int get_conference_count( void ) ;
int get_conference_stats( ast_conference_stats* stats, int requested ) ;
int get_conference_stats_by_name( ast_conference_stats* stats, const char* name ) ;
int set_conference_debugging( const char* name, int state ) ;
#endif
Binary file not shown.
+614
View File
@@ -0,0 +1,614 @@
// $Id: frame.c,v 1.7 2005/10/27 17:53:35 stevek Exp $
/*
* app_conference
*
* A channel independent conference application for Asterisk
*
* Copyright (C) 2002, 2003 Junghanns.NET GmbH
* Copyright (C) 2003, 2004 HorizonLive.com, Inc.
*
* Klaus-Peter Junghanns <kapejod@ns1.jnetdns.de>
*
* This program may be modified and distributed under the
* terms of the GNU Public License.
*
*/
#include "frame.h"
conf_frame* mix_frames( conf_frame* frames_in, int speaker_count, int listener_count )
{
if ( frames_in == NULL )
return NULL ;
conf_frame* frames_out = NULL ;
if ( speaker_count > 1 )
{
if ( speaker_count == 2 && listener_count == 0 )
{
// optimize here also?
frames_out = mix_multiple_speakers( frames_in, speaker_count, listener_count ) ;
}
else
{
// mix spoken frames for sending
// ( note: this call also releases us from free'ing spoken_frames )
frames_out = mix_multiple_speakers( frames_in, speaker_count, listener_count ) ;
}
}
else if ( speaker_count == 1 )
{
// pass-through frames
frames_out = mix_single_speaker( frames_in ) ;
}
else
{
// no frames to send, leave frames_out null
}
return frames_out ;
}
conf_frame* mix_single_speaker( conf_frame* frames_in )
{
#ifdef APP_CONFERENCE_DEBUG
// ast_log( AST_CONF_DEBUG, "returning single spoken frame\n" ) ;
//
// check input
//
if ( frames_in == NULL )
{
ast_log( AST_CONF_DEBUG, "unable to mix single spoken frame with null frame\n" ) ;
return NULL ;
}
if ( frames_in->fr == NULL )
{
ast_log( AST_CONF_DEBUG, "unable to mix single spoken frame with null data\n" ) ;
return NULL ;
}
if ( frames_in->member == NULL )
{
ast_log( AST_CONF_DEBUG, "unable to mix single spoken frame with null member\n" ) ;
return NULL ;
}
#endif // APP_CONFERENCE_DEBUG
//
// 'mix' the frame
//
// copy orignal frame to converted array so listeners don't need to re-encode it
frames_in->converted[ frames_in->member->read_format_index ] = ast_frdup( frames_in->fr ) ;
// convert frame to slinear, if we have a path
frames_in->fr = convert_frame_to_slinear(
frames_in->member->to_slinear,
frames_in->fr
) ;
// set the frame's member to null ( i.e. all listeners )
frames_in->member = NULL ;
return frames_in ;
}
// {
//
// a little optimization for testing only:
// when two speakers ( of the same type ) and no listeners
// are in a conference, we just swamp the frame's member pointers
//
/*
if (
listeners == 0
&& speakers == 2
&& cf_spokenFrames->member->read_format == cf_spokenFrames->next->member->write_format
&& cf_spokenFrames->member->write_format == cf_spokenFrames->next->member->read_format
)
{
struct ast_conf_member* m = NULL ;
m = cf_spokenFrames->member ;
cf_spokenFrames->member = cf_spokenFrames->next->member ;
cf_spokenFrames->next->member = m ;
return cf_spokenFrames ;
}
*/
// }
void set_conf_frame_delivery( conf_frame* frame, struct timeval time )
{
for ( ; frame != NULL ; frame = frame->next )
{
if ( frame->fr != NULL )
{
// copy passed timeval to frame's delivery timeval
frame->fr->delivery = time ;
}
}
return ;
}
conf_frame* mix_multiple_speakers(
conf_frame* frames_in,
int speakers,
int listeners
)
{
#ifdef APP_CONFERENCE_DEBUG
//
// check input
//
// no frames to mix
if ( ( frames_in == NULL ) || ( frames_in->fr == NULL ) )
{
ast_log( AST_CONF_DEBUG, "passed spoken frame list was NULL\n" ) ;
return NULL ;
}
// if less than two speakers, then no frames to mix
if ( speakers < 2 )
{
ast_log( AST_CONF_DEBUG, "mix_multiple_speakers() called with less than two speakers\n" ) ;
return NULL ;
}
#endif // APP_CONFERENCE_DEBUG
//
// at this point we know that there is more than one frame,
// and that the frames need to be converted to pcm to be mixed
//
// now, if there are only two frames and two members,
// we can swap them. ( but we'll get to that later. )
//
//
// loop through the spoken frames, making a list of spoken members,
// and converting gsm frames to slinear frames so we can mix them.
//
// pointer to the spoken frames list
conf_frame* cf_spoken = frames_in ;
// pointer to the new list of mixed frames
conf_frame* cf_sendFrames = NULL ;
while ( cf_spoken != NULL )
{
//
// while we're looping through the spoken frames, we'll
// convert the frame to a format suitable for mixing
//
// if the frame fails to convert, drop it and treat
// the speaking member like a listener by not adding
// them to the cf_sendFrames list
//
if ( cf_spoken->member == NULL )
{
ast_log( LOG_WARNING, "unable to determine frame member\n" ) ;
}
else
{
// ast_log( AST_CONF_DEBUG, "converting frame to slinear, channel => %s\n", cf_spoken->member->channel_name ) ;
cf_spoken->fr = convert_frame_to_slinear(
cf_spoken->member->to_slinear,
cf_spoken->fr
) ;
if ( cf_spoken->fr == NULL )
{
ast_log( LOG_WARNING, "unable to convert frame to slinear\n" ) ;
}
else
{
// create new conf frame with last frame as 'next'
cf_sendFrames = create_conf_frame( cf_spoken->member, cf_sendFrames, NULL ) ;
}
}
// point to the next spoken frame
cf_spoken = cf_spoken->next ;
}
// if necessary, add a frame with a null member pointer.
// this frame will hold the audio mixed for all listeners
if ( listeners > 0 )
{
cf_sendFrames = create_conf_frame( NULL, cf_sendFrames, NULL ) ;
}
//
// mix the audio
//
// convenience pointer that skips over the friendly offset
char* cp_listenerData ;
// pointer to the send frames list
conf_frame* cf_send = NULL ;
for ( cf_send = cf_sendFrames ; cf_send != NULL ; cf_send = cf_send->next )
{
// allocate a mix buffer which fill large enough memory to
// hold a frame, and reset it's memory so we don't get noise
char* cp_listenerBuffer = malloc( AST_CONF_BUFFER_SIZE ) ;
memset( cp_listenerBuffer, 0x0, AST_CONF_BUFFER_SIZE ) ;
// point past the friendly offset right to the data
cp_listenerData = cp_listenerBuffer + AST_FRIENDLY_OFFSET ;
// reset the spoken list pointer
cf_spoken = frames_in ;
// really mix the audio
for ( ; cf_spoken != NULL ; cf_spoken = cf_spoken->next )
{
//
// if the members are equal, and they
// are not null, do not mix them.
//
if (
( cf_send->member == cf_spoken->member )
&& ( cf_send->member != NULL )
)
{
// don't mix this frame
}
else if ( cf_spoken->fr == NULL )
{
ast_log( LOG_WARNING, "unable to mix conf_frame with null ast_frame\n" ) ;
}
else
{
// mix the new frame in with the existing buffer
mix_slinear_frames( cp_listenerData, (char*)( cf_spoken->fr->data ), cf_spoken->fr->samples ) ;
}
}
// copy a pointer to the frame data to the conf_frame
cf_send->mixed_buffer = cp_listenerData ;
}
//
// copy the mixed buffer to a new frame
//
// reset the send list pointer
cf_send = cf_sendFrames ;
while ( cf_send != NULL )
{
cf_send->fr = create_slinear_frame( cf_send->mixed_buffer ) ;
cf_send = cf_send->next ;
}
//
// clean up the spoken frames we were passed
// ( caller will only be responsible for free'ing returns frames )
//
// reset the spoken list pointer
cf_spoken = frames_in ;
while ( cf_spoken != NULL )
{
// delete the frame
cf_spoken = delete_conf_frame( cf_spoken ) ;
}
// return the list of frames for sending
return cf_sendFrames ;
}
struct ast_frame* convert_frame_to_slinear( struct ast_trans_pvt* trans, struct ast_frame* fr )
{
// check for null frame
if ( fr == NULL )
{
ast_log( LOG_ERROR, "unable to translate null frame to slinear\n" ) ;
return NULL ;
}
// we don't need to duplicate this frame since
// the normal translation would free it anyway, so
// we'll just pretend we free'd and malloc'd a new one.
if ( fr->subclass == AST_FORMAT_SLINEAR )
return fr ;
// check for null translator ( after we've checked that we need to translate )
if ( trans == NULL )
{
// ast_log( LOG_ERROR, "unable to translate frame with null translation path\n" ) ;
return fr ;
}
// return the converted frame
return convert_frame( trans, fr ) ;
}
struct ast_frame* convert_frame_from_slinear( struct ast_trans_pvt* trans, struct ast_frame* fr )
{
// check for null translator ( after we've checked that we need to translate )
if ( trans == NULL )
{
// ast_log( LOG_ERROR, "unable to translate frame with null translation path\n" ) ;
return fr ;
}
// check for null frame
if ( fr == NULL )
{
ast_log( LOG_ERROR, "unable to translate null slinear frame\n" ) ;
return NULL ;
}
// if the frame is not slinear, return an error
if ( fr->subclass != AST_FORMAT_SLINEAR )
{
ast_log( LOG_ERROR, "unable to translate non-slinear frame\n" ) ;
return NULL ;
}
// return the converted frame
return convert_frame( trans, fr ) ;
}
struct ast_frame* convert_frame( struct ast_trans_pvt* trans, struct ast_frame* fr )
{
if ( trans == NULL )
{
ast_log( LOG_WARNING, "unable to convert frame with null translator\n" ) ;
return NULL ;
}
if ( fr == NULL )
{
ast_log( LOG_WARNING, "unable to convert null frame\n" ) ;
return NULL ;
}
// convert the frame
struct ast_frame* translated_frame = ast_translate( trans, fr, 1 ) ;
// check for errors
if ( translated_frame == NULL )
{
ast_log( LOG_ERROR, "unable to translate frame\n" ) ;
return NULL ;
}
// return the translated frame
return translated_frame ;
}
conf_frame* delete_conf_frame( conf_frame* cf )
{
// check for null frames
if ( cf == NULL )
{
ast_log( AST_CONF_DEBUG, "unable to delete null conf frame\n" ) ;
return NULL ;
}
// check for frame marked as static
if ( cf->static_frame == 1 )
return NULL ;
if ( cf->fr != NULL )
{
ast_frfree( cf->fr ) ;
cf->fr = NULL ;
}
// make sure converted frames are set to null
int c;
for ( c = 0 ; c < AC_SUPPORTED_FORMATS ; ++c )
{
if ( cf->converted[ c ] != NULL )
{
ast_frfree( cf->converted[ c ] ) ;
cf->converted[ c ] = NULL ;
}
}
// get a pointer to the next frame
// in the list so we can return it
conf_frame* nf = cf->next ;
free( cf ) ;
cf = NULL ;
return nf ;
}
conf_frame* create_conf_frame( struct ast_conf_member* member, conf_frame* next, const struct ast_frame* fr )
{
// pointer to list of mixed frames
conf_frame* cf = malloc( sizeof( struct conf_frame ) ) ;
if ( cf == NULL )
{
ast_log( LOG_ERROR, "unable to allocate memory for conf frame\n" ) ;
return NULL ;
}
//
// init with some defaults
//
// make sure converted frames are set to null
// for ( int c = 0 ; c < AC_SUPPORTED_FORMATS ; ++c )
// {
// cf->converted[ c ] = NULL ;
// }
memset( (struct ast_frame*)( cf->converted ), 0x0, ( sizeof( struct ast_frame* ) * AC_SUPPORTED_FORMATS ) ) ;
cf->member = member ;
// cf->priority = 0 ;
cf->prev = NULL ;
cf->next = next ;
cf->static_frame = 0 ;
// establish relationship to 'next'
if ( next != NULL ) next->prev = cf ;
// this holds the ast_frame pointer
cf->fr = ( fr == NULL ) ? NULL : ast_frdup( ( struct ast_frame* )( fr ) ) ;
// this holds the temporu mix buffer
cf->mixed_buffer = NULL ;
return cf ;
}
conf_frame* copy_conf_frame( conf_frame* src )
{
//
// check inputs
//
if ( src == NULL )
{
ast_log( AST_CONF_DEBUG, "unable to copy null conf frame\n" ) ;
return NULL ;
}
//
// copy the frame
//
struct conf_frame *cfr = NULL ;
// create a new conf frame
cfr = create_conf_frame( src->member, NULL, src->fr ) ;
if ( cfr == NULL )
{
ast_log( AST_CONF_DEBUG, "unable to create new conf frame for copy\n" ) ;
return NULL ;
}
return cfr ;
}
//
// slinear frame functions
//
struct ast_frame* create_slinear_frame( char* data )
{
struct ast_frame* f ;
f = calloc( 1, sizeof( struct ast_frame ) ) ;
if ( f == NULL )
{
ast_log( LOG_ERROR, "unable to allocate memory for slinear frame\n" ) ;
return NULL ;
}
f->frametype = AST_FRAME_VOICE ;
f->subclass = AST_FORMAT_SLINEAR ;
f->samples = AST_CONF_BLOCK_SAMPLES ;
f->offset = AST_FRIENDLY_OFFSET ;
f->mallocd = AST_MALLOCD_HDR | AST_MALLOCD_DATA ;
f->datalen = AST_CONF_FRAME_DATA_SIZE ;
f->data = data ;
f->src = NULL ;
return f ;
}
void mix_slinear_frames( char *dst, const char *src, int samples )
{
if ( dst == NULL ) return ;
if ( src == NULL ) return ;
int i, val ;
for ( i = 0 ; i < samples ; ++i )
{
val = ( (short*)dst )[i] + ( (short*)src )[i] ;
if ( val > 0x7fff )
{
( (short*)dst )[i] = 0x7fff - 1 ;
continue ;
}
else if ( val < -0x7fff )
{
( (short*)dst )[i] = -0x7fff + 1 ;
continue ;
}
else
{
( (short*)dst )[i] = val ;
continue ;
}
}
return ;
}
//
// silent frame functions
//
conf_frame* get_silent_frame( void )
{
static conf_frame* static_silent_frame = NULL ;
// we'll let this leak until the application terminates
if ( static_silent_frame == NULL )
{
// ast_log( AST_CONF_DEBUG, "creating cached silent frame\n" ) ;
struct ast_frame* fr = get_silent_slinear_frame() ;
static_silent_frame = create_conf_frame( NULL, NULL, fr ) ;
if ( static_silent_frame == NULL )
{
ast_log( LOG_WARNING, "unable to create cached silent frame\n" ) ;
return NULL ;
}
// init the 'converted' slinear silent frame
static_silent_frame->converted[ AC_SLINEAR_INDEX ] = get_silent_slinear_frame() ;
// mark frame as static so it's not deleted
static_silent_frame->static_frame = 1 ;
}
return static_silent_frame ;
}
struct ast_frame* get_silent_slinear_frame( void )
{
static struct ast_frame* f = NULL ;
// we'll let this leak until the application terminates
if ( f == NULL )
{
char* data = malloc( AST_CONF_BUFFER_SIZE ) ;
memset( data, 0x0, AST_CONF_BUFFER_SIZE ) ;
f = create_slinear_frame( data ) ;
}
return ast_frdup( f ) ;
}
+60
View File
@@ -0,0 +1,60 @@
// $Id: frame.h,v 1.6 2005/10/26 21:02:07 stevek Exp $
/*
* app_conference
*
* A channel independent conference application for Asterisk
*
* Copyright (C) 2002, 2003 Junghanns.NET GmbH
* Copyright (C) 2003, 2004 HorizonLive.com, Inc.
*
* Klaus-Peter Junghanns <kapejod@ns1.jnetdns.de>
*
* This program may be modified and distributed under the
* terms of the GNU Public License.
*
*/
#ifndef _APP_CONF_FRAME_H
#define _APP_CONF_FRAME_H
//
// includes
//
#include "app_conference.h"
#include "common.h"
//
// function declarations
//
// mixing
conf_frame* mix_frames( conf_frame* frames_in, int speaker_count, int listener_count ) ;
conf_frame* mix_multiple_speakers( conf_frame* frames_in, int speakers, int listeners ) ;
conf_frame* mix_single_speaker( conf_frame* frames_in ) ;
// frame creation and deletion
conf_frame* create_conf_frame( struct ast_conf_member* member, conf_frame* next, const struct ast_frame* fr ) ;
conf_frame* delete_conf_frame( conf_frame* cf ) ;
conf_frame* copy_conf_frame( conf_frame* src ) ;
// convert frame functions
struct ast_frame* convert_frame_to_slinear( struct ast_trans_pvt* trans, struct ast_frame* fr ) ;
struct ast_frame* convert_frame_from_slinear( struct ast_trans_pvt* trans, struct ast_frame* fr ) ;
struct ast_frame* convert_frame( struct ast_trans_pvt* trans, struct ast_frame* fr ) ;
// slinear frame functions
struct ast_frame* create_slinear_frame( char* data ) ;
void mix_slinear_frames( char* dst, const char* src, int samples ) ;
// silent frame functions
conf_frame* get_silent_frame( void ) ;
struct ast_frame* get_silent_slinear_frame( void ) ;
// set delivery timestamp for frames
void set_conf_frame_delivery( conf_frame* frame, struct timeval time ) ;
#endif
+2
View File
@@ -0,0 +1,2 @@
Õø\}PcÈ£P tÛ†§¬D#E)¤™î#àÑi(*ÕøEÿ3yÂBãF:W£Ì×2›¢ÓÔWâåÔ¢6èÕøTþéyÁªu–ÃÆW¢I+‘sdWÁ󣩿øy¢®su»Õ÷k¿2yƒ©©áËc„tä9,,WÂÌk|UTWãu#.1Õøcÿ}yQÒÅã(î é¬d£Úº\2Åï!•␍‚£QÕø\?;wÁÃaÔòñW‚nfy¢.7©FW‚•š©ó)Õ÷{?<y踥¾:y‚ŒkmņWÃYk‹™¢,sņոk¿3WávÛ§'“WA«k5ËÍAó0”u*ï!¼eS␍ÕøM¾êy¡«ªcÍyâJ㫉ŠwqÇk
°wÂ9uáÓÕø\3y¡C†§£Ò»"XyÖ™¡wr:ªïA¬Ýk‹MÕøT¾©™ÁᜑVxï¡ä꙾,WâHr\ʧw¢6é°ó]Õ¸>úYW!àíµQë nµSíB*ÜqU—U¡ºy˜×Õö²³>ÓÇX¦ŸWQŽDâ¿íÇÊ!ï÷ûýö
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,7 @@
/misc.c/1.1/Thu Mar 25 15:10:17 2004//
/misc.h/1.1/Thu Mar 25 15:10:17 2004//
/preprocess.c/1.4/Fri Mar 25 20:26:26 2005//
/smallft.c/1.3/Fri Mar 25 20:26:26 2005//
/smallft.h/1.2/Wed Jul 7 13:39:42 2004//
/speex_preprocess.h/1.1/Thu Mar 25 15:10:17 2004//
D
@@ -0,0 +1 @@
app_conference/libspeex
+1
View File
@@ -0,0 +1 @@
:pserver:anonymous@iaxclient.cvs.sourceforge.net:/cvsroot/iaxclient
+145
View File
@@ -0,0 +1,145 @@
/* Copyright (C) 2002 Jean-Marc Valin
File: mics.c
Various utility routines for Speex
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
- Neither the name of the Xiph.org Foundation nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "misc.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#ifndef RELEASE
void print_vec(float *vec, int len, char *name)
{
int i;
printf ("%s ", name);
for (i=0;i<len;i++)
printf (" %f", vec[i]);
printf ("\n");
}
#endif
unsigned int be_int(unsigned int i)
{
unsigned int ret=i;
#ifndef WORDS_BIGENDIAN
ret = i>>24;
ret += (i>>8)&0x0000ff00;
ret += (i<<8)&0x00ff0000;
ret += (i<<24);
#endif
return ret;
}
unsigned int le_int(unsigned int i)
{
unsigned int ret=i;
#ifdef WORDS_BIGENDIAN
ret = i>>24;
ret += (i>>8)&0x0000ff00;
ret += (i<<8)&0x00ff0000;
ret += (i<<24);
#endif
return ret;
}
unsigned short be_short(unsigned short s)
{
unsigned short ret=s;
#ifndef WORDS_BIGENDIAN
ret = s>>8;
ret += s<<8;
#endif
return ret;
}
unsigned short le_short(unsigned short s)
{
unsigned short ret=s;
#ifdef WORDS_BIGENDIAN
ret = s>>8;
ret += s<<8;
#endif
return ret;
}
void *speex_alloc (int size)
{
return calloc(size,1);
}
void *speex_realloc (void *ptr, int size)
{
return realloc(ptr, size);
}
void speex_free (void *ptr)
{
free(ptr);
}
void *speex_move (void *dest, void *src, int n)
{
return memmove(dest,src,n);
}
void speex_error(char *str)
{
fprintf (stderr, "Fatal error: %s\n", str);
exit(1);
}
void speex_warning(char *str)
{
fprintf (stderr, "warning: %s\n", str);
}
void speex_warning_int(char *str, int val)
{
fprintf (stderr, "warning: %s %d\n", str, val);
}
void speex_rand_vec(float std, spx_sig_t *data, int len)
{
int i;
for (i=0;i<len;i++)
data[i]+=SIG_SCALING*3*std*((((float)rand())/RAND_MAX)-.5);
}
float speex_rand(float std)
{
return 3*std*((((float)rand())/RAND_MAX)-.5);
}
void _speex_putc(int ch, void *file)
{
FILE *f = (FILE *)file;
fputc(ch, f);
}
+147
View File
@@ -0,0 +1,147 @@
/* Copyright (C) 2002 Jean-Marc Valin */
/**
@file misc.h
@brief Various compatibility routines for Speex
*/
/*
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
- Neither the name of the Xiph.org Foundation nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef MISC_H
#define MISC_H
#ifndef VERSION
#define VERSION "speex-1.1"
#endif
#ifdef FIXED_POINT
typedef signed short spx_word16_t;
typedef signed int spx_word32_t;
typedef spx_word32_t spx_mem_t;
typedef spx_word16_t spx_coef_t;
typedef spx_word16_t spx_lsp_t;
typedef spx_word32_t spx_sig_t;
#define LPC_SCALING 8192.
#define SIG_SCALING 16384
#define LSP_SCALING 8192.
#define LPC_SHIFT 13
#define SIG_SHIFT 14
#define PSHR(a,shift) (((a)+(1<<((shift)-1))) >> (shift))
#define SHR(a,shift) ((a) >> (shift))
#define SHL(a,shift) ((a) << (shift))
/* result fits in 16 bits */
#define MULT16_16_16(a,b) (((short)(a))*(b))
#define MULT16_16(a,b) (((signed int)(a))*(b))
#define MULT16_32_Q13(a,b) (((a)*((b)>>13)) + ((a)*((signed int)((b)&0x00001fff))>>13))
#define MULT16_32_Q14(a,b) (((a)*((b)>>14)) + ((a)*((signed int)((b)&0x00003fff))>>14))
#define MULT16_32_Q15(a,b) (((a)*((b)>>15)) + ((a)*((signed int)((b)&0x00007fff))>>15))
#define MULT16_16_Q13(a,b) (((signed int)(a))*(b)>>13)
#define MULT16_16_Q14(a,b) (((signed int)(a))*(b)>>14)
#define MULT16_16_Q15(a,b) (((signed int)(a))*(b)>>15)
#define MULT16_16_P14(a,b) ((8192+((signed int)(a))*(b))>>14)
#define DIV32_16(a,b) (((signed int)(a))/(b))
#else
typedef float spx_mem_t;
typedef float spx_coef_t;
typedef float spx_lsp_t;
typedef float spx_sig_t;
typedef float spx_word16_t;
typedef float spx_word32_t;
#define LPC_SCALING 1.
#define SIG_SCALING 1.
#define LSP_SCALING 1.
#define LPC_SHIFT 0
#define SIG_SHIFT 0
#define PSHR(a,shift) (a)
#define SHR(a,shift) (a)
#define SHL(a,shift) (a)
#define MULT16_16_16(a,b) ((a)*(b))
#define MULT16_16(a,b) ((a)*(b))
#define MULT16_32_Q13(a,b) ((a)*(b))
#define MULT16_32_Q14(a,b) ((a)*(b))
#define MULT16_32_Q15(a,b) ((a)*(b))
#define MULT16_16_Q13(a,b) ((a)*(b))
#define MULT16_16_Q14(a,b) ((a)*(b))
#define MULT16_16_Q15(a,b) ((a)*(b))
#endif
#ifndef RELEASE
void print_vec(float *vec, int len, char *name);
#endif
unsigned int be_int(unsigned int i);
unsigned int le_int(unsigned int i);
unsigned short be_short(unsigned short s);
unsigned short le_short(unsigned short s);
/** Speex wrapper for calloc. To do your own dynamic allocation, all you need to do is replace this function, speex_realloc and speex_free */
void *speex_alloc (int size);
/** Speex wrapper for realloc. To do your own dynamic allocation, all you need to do is replace this function, speex_alloc and speex_free */
void *speex_realloc (void *ptr, int size);
/** Speex wrapper for calloc. To do your own dynamic allocation, all you need to do is replace this function, speex_realloc and speex_alloc */
void speex_free (void *ptr);
/** Speex wrapper for mem_move */
void *speex_move (void *dest, void *src, int n);
void speex_error(char *str);
void speex_warning(char *str);
void speex_warning_int(char *str, int val);
void speex_rand_vec(float std, spx_sig_t *data, int len);
float speex_rand(float std);
void _speex_putc(int ch, void *file);
#endif
File diff suppressed because it is too large Load Diff
Binary file not shown.
File diff suppressed because it is too large Load Diff
+42
View File
@@ -0,0 +1,42 @@
/********************************************************************
* *
* THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2001 *
* by the XIPHOPHORUS Company http://www.xiph.org/ *
* *
********************************************************************
function: fft transform
last mod: $Id: smallft.h,v 1.2 2004/07/07 13:39:42 stevek Exp $
********************************************************************/
#ifndef _V_SMFT_H_
#define _V_SMFT_H_
/*#include "vorbis/codec.h"*/
#ifdef __cplusplus
extern "C" {
#endif
struct drft_lookup{
int n;
float *trigcache;
int *splitcache;
};
extern void drft_forward(struct drft_lookup *l,float *data);
extern void drft_backward(struct drft_lookup *l,float *data);
extern void drft_init(struct drft_lookup *l,int n);
extern void drft_clear(struct drft_lookup *l);
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,139 @@
/* Copyright (C) 2003 Epic Games
Written by Jean-Marc Valin
File: speex_preprocess.h
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef __cplusplus
extern "C" {
#endif
struct drft_lookup;
typedef struct SpeexPreprocessState {
int frame_size; /**< Number of samples processed each time */
int ps_size; /**< Number of points in the power spectrum */
int sampling_rate; /**< Sampling rate of the input/output */
/* parameters */
int denoise_enabled;
int agc_enabled;
float agc_level;
int vad_enabled;
// probabilities to check speech_prob against
float speech_prob_start ;
float speech_prob_continue ;
float *frame; /**< Processing frame (2*ps_size) */
float *ps; /**< Current power spectrum */
float *gain2; /**< Adjusted gains */
float *window; /**< Analysis/Synthesis window */
float *noise; /**< Noise estimate */
float *old_ps; /**< Power spectrum for last frame */
float *gain; /**< Ephraim Malah gain */
float *prior; /**< A-priori SNR */
float *post; /**< A-posteriori SNR */
float *S; /**< Smoothed power spectrum */
float *Smin; /**< See Cohen paper */
float *Stmp; /**< See Cohen paper */
float *update_prob; /**< Propability of speech presence for noise update */
float *zeta; /**< Smoothed a priori SNR */
float Zpeak;
float Zlast;
float *loudness_weight; /**< Perceptual loudness curve */
float *echo_noise;
float *noise_bands;
float *noise_bands2;
int noise_bandsN;
float *speech_bands;
float *speech_bands2;
int speech_bandsN;
float *inbuf; /**< Input buffer (overlapped analysis) */
float *outbuf; /**< Output buffer (for overlap and add) */
float speech_prob;
int last_speech;
float loudness; /**< loudness estimate */
float loudness2; /**< loudness estimate */
int nb_adapt; /**< Number of frames used for adaptation so far */
int nb_loudness_adapt; /**< Number of frames used for loudness adaptation so far */
int consec_noise; /**< Number of consecutive noise frames */
int nb_preprocess; /**< Number of frames processed so far */
struct drft_lookup *fft_lookup; /**< Lookup table for the FFT */
} SpeexPreprocessState;
/** Creates a new preprocessing state */
SpeexPreprocessState *speex_preprocess_state_init(int frame_size, int sampling_rate);
/** Destroys a denoising state */
void speex_preprocess_state_destroy(SpeexPreprocessState *st);
/** Preprocess a frame */
int speex_preprocess(SpeexPreprocessState *st, short *x, float *noise);
/** Preprocess a frame */
void speex_preprocess_estimate_update(SpeexPreprocessState *st, short *x, float *noise);
/** Used like the ioctl function to control the preprocessor parameters */
int speex_preprocess_ctl(SpeexPreprocessState *st, int request, void *ptr);
#define SPEEX_PROB_START 0.35
#define SPEEX_PROB_CONTINUE 0.1
#define SPEEX_PREPROCESS_SET_DENOISE 0
#define SPEEX_PREPROCESS_GET_DENOISE 1
#define SPEEX_PREPROCESS_SET_AGC 2
#define SPEEX_PREPROCESS_GET_AGC 3
#define SPEEX_PREPROCESS_SET_VAD 4
#define SPEEX_PREPROCESS_GET_VAD 5
#define SPEEX_PREPROCESS_SET_AGC_LEVEL 6
#define SPEEX_PREPROCESS_GET_AGC_LEVEL 7
#define SPEEX_PREPROCESS_SET_PROB_START 8
#define SPEEX_PREPROCESS_GET_PROB_START 9
#define SPEEX_PREPROCESS_SET_PROB_CONTINUE 10
#define SPEEX_PREPROCESS_GET_PROB_CONTINUE 11
#ifdef __cplusplus
}
#endif
File diff suppressed because it is too large Load Diff
+212
View File
@@ -0,0 +1,212 @@
// $Id: member.h,v 1.7 2005/11/02 22:42:42 stevek Exp $
/*
* app_conference
*
* A channel independent conference application for Asterisk
*
* Copyright (C) 2002, 2003 Junghanns.NET GmbH
* Copyright (C) 2003-2005 HorizonLive.com, Inc.
*
* Klaus-Peter Junghanns <kapejod@ns1.jnetdns.de>
* Steve Kann <stevek@stevek.com>
*
* This program may be modified and distributed under the
* terms of the GNU Public License.
*
*/
#ifndef _APP_CONF_MEMBER_H
#define _APP_CONF_MEMBER_H
//
// includes
//
#include "app_conference.h"
#include "common.h"
#include "asterisk/app.h"
//
// struct declarations
//
struct ast_conf_soundq
{
char name[256];
struct ast_filestream *stream; // the stream
int muted; // should incoming audio be muted while we play?
struct ast_conf_soundq *next;
};
struct ast_conf_member
{
ast_mutex_t lock ; // member data mutex
struct ast_channel* chan ; // member's channel
char* channel_name ; // member's channel name
// values passed to create_member () via *data
int priority ; // highest priority gets the channel
char* flags ; // raw member-type flags
char type ; // L = ListenOnly, M = Moderator, S = Standard (Listen/Talk)
char* id ; // member id
// determine by flags and channel name
char connection_type ; // T = telephone, X = iaxclient, S = sip
// vad voice probability thresholds
float vad_prob_start ;
float vad_prob_continue ;
// ready flag
short ready_for_outgoing ;
// input frame queue
conf_frame* inFrames ;
conf_frame* inFramesTail ;
unsigned int inFramesCount ;
// input/output smoother
struct ast_smoother *inSmoother;
struct ast_packer *outPacker;
int smooth_size_in;
int smooth_size_out;
int smooth_multiple;
// frames needed by conference_exec
unsigned int inFramesNeeded ;
// used when caching last frame
conf_frame* inFramesLast ;
unsigned int inFramesRepeatLast ;
unsigned short okayToCacheLast ;
// output frame queue
conf_frame* outFrames ;
conf_frame* outFramesTail ;
unsigned int outFramesCount ;
// time we last dropped a frame
struct timeval last_in_dropped ;
struct timeval last_out_dropped ;
// ( not currently used )
// int samplesperframe ;
// used for determining need to mix frames
// and for management interface notification
short speaking_state_prev ;
short speaking_state_notify ;
short speaking_state ;
// pointer to next member in single-linked list
struct ast_conf_member* next ;
// accounting values
unsigned long frames_in ;
unsigned long frames_in_dropped ;
unsigned long frames_out ;
unsigned long frames_out_dropped ;
// for counting sequentially dropped frames
unsigned int sequential_drops ;
unsigned long since_dropped ;
// start time
struct timeval time_entered ;
struct timeval lastsent_timeval ;
// flag indicating we should remove this member
short remove_flag ;
#if ( SILDET == 2 )
// pointer to speex preprocessor dsp
SpeexPreprocessState *dsp ;
// number of frames to ignore speex_preprocess()
int ignore_speex_count;
#else
// placeholder when preprocessing is not enabled
void* dsp ;
#endif
// audio format this member is using
int write_format ;
int read_format ;
int write_format_index ;
int read_format_index ;
// member frame translators
struct ast_trans_pvt* to_slinear ;
struct ast_trans_pvt* from_slinear ;
// For playing sounds
struct ast_conf_soundq *soundq;
#ifdef DEBUG_OUTPUT_PCM
FILE *incoming_fh;
#endif
int send_dtmf:1;
int quiet_entry_exit:1;
int inband_dtmf:1;
int rfc_dtmf:1;
} ;
struct conf_member
{
struct ast_conf_member* realmember ;
struct conf_member* next ;
} ;
//
// function declarations
//
int member_exec( struct ast_channel* chan, void* data ) ;
int basic_play_sound ( char *channel, char *file ) ;
struct ast_conf_member* create_member( struct ast_channel* chan, const char* data ) ;
struct ast_conf_member* delete_member( struct ast_conf_member* member ) ;
// incoming queue
int queue_incoming_frame( struct ast_conf_member* member, struct ast_frame* fr ) ;
conf_frame* get_incoming_frame( struct ast_conf_member* member ) ;
// outgoing queue
int queue_outgoing_frame( struct ast_conf_member* member, const struct ast_frame* fr, struct timeval delivery ) ;
int __queue_outgoing_frame( struct ast_conf_member* member, const struct ast_frame* fr, struct timeval delivery ) ;
conf_frame* get_outgoing_frame( struct ast_conf_member* member ) ;
void send_state_change_notifications( struct ast_conf_member* member ) ;
//
// meta-info accessors functions
//
short memberIsPhoneClient( struct ast_conf_member* member ) ;
short memberIsIaxClient( struct ast_conf_member* member ) ;
short memberIsSIPClient( struct ast_conf_member* member ) ;
short memberIsModerator( struct ast_conf_member* member ) ;
short memberIsListener( struct ast_conf_member* member ) ;
//
// packer functions
//
struct ast_packer;
extern struct ast_packer *ast_packer_new(int bytes);
extern void ast_packer_set_flags(struct ast_packer *packer, int flags);
extern int ast_packer_get_flags(struct ast_packer *packer);
extern void ast_packer_free(struct ast_packer *s);
extern void ast_packer_reset(struct ast_packer *s, int bytes);
extern int ast_packer_feed(struct ast_packer *s, const struct ast_frame *f);
extern struct ast_frame *ast_packer_read(struct ast_packer *s);
#endif
+2
View File
@@ -0,0 +1,2 @@
Õ:“nôPSaÌtÖªj*PÕR6ÛžD ␍IÁ‰àDCtbëÕ<kºêáCÈk<¸Ö»Â¬£ª5†¹#BâtdêíB¸1xVÕÔûk¶©…# Ì‹'ŒÝbgMKŒ©yâÃÅiµ)ï¢èåO ¤Ôû{6ªw!·Sã§(ï¢ñœ‰È«»¢VÕ6Ž\yB8×7Õ<cú©­Á›K£êñ¾©Ž©ˆÃFÖ¬£»‚V¸±È£ÔûkviïB³[Q\C6êxfæßB¾,6)‡»"˜ã°ñZÕ;{:ª½Âäè­h¤½Â—5ÓÃw£QœtÖ²»¡ÌmÉÔü\:¢íâž,R)ía×VN©ÝaES¦¬=ïÁÑÆVI#Ôûkv©»Á·†Oi‚aÅÑ”y¡Ñ[özïÁJ•VÝÕ<szª½‚„Ž4¢½¢V±Y,ׇ+£¥S«#7"â·"Ôücú¡ï¡6åIw!¶Ý׫A(s5Y␍íTâ\Ê;Ôûs6ª»ª×8ÖÜïÂÈyu8ÞwÁŽÜÊCÅ«â:ªã·•Õ4ë©õ{ÃH±<i†¿Ç
ÜnCŒWí8âª:˜!]®×yì
Binary file not shown.