Stereo Call Recording commit
git-svn-id: svn://192.168.202.10@3941 3d104415-ff17-0410-8863-d5cf3c621b8a
This commit is contained in:
@@ -20,7 +20,7 @@
|
||||
# Based on perl scripts in ViciDial from Matt Florell and post:
|
||||
# http://www.vicidial.org/VICIDIALforum/viewtopic.php?p=22506&sid=ca5347cffa6f6382f56ce3db9fb3d068#22506
|
||||
#
|
||||
# Copyright (C) 2024 I. Taushanov, Matt Florell <vicidial@gmail.com> LICENSE: AGPLv2
|
||||
# Copyright (C) 2025 I. Taushanov, Matt Florell <vicidial@gmail.com> LICENSE: AGPLv2
|
||||
#
|
||||
# CHANGES
|
||||
# 90615-1701 - First version
|
||||
@@ -73,6 +73,7 @@
|
||||
# 231126-2227 - Added vicidial_hci_log archiving
|
||||
# 240916-2159 - Added --extended-log-only
|
||||
# 240924-2041 - Added --vicidial-log-only
|
||||
# 250914-1537 - Added archiving of recording_log_stereo and recording_log_parallel tables
|
||||
#
|
||||
|
||||
$CALC_TEST=0;
|
||||
@@ -4037,6 +4038,104 @@ if (!$T)
|
||||
$sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr;
|
||||
$sthA->execute or die "executing: $stmtA ", $dbhA->errstr;
|
||||
}
|
||||
|
||||
##### recording_log_stereo
|
||||
$stmtA = "SELECT count(*) from recording_log_stereo;";
|
||||
$sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr;
|
||||
$sthA->execute or die "executing: $stmtA ", $dbhA->errstr;
|
||||
$sthArows=$sthA->rows;
|
||||
if ($sthArows > 0)
|
||||
{
|
||||
@aryA = $sthA->fetchrow_array;
|
||||
$recording_log_stereo_count = $aryA[0];
|
||||
}
|
||||
$sthA->finish();
|
||||
|
||||
$stmtA = "SELECT count(*) from recording_log_stereo_archive;";
|
||||
$sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr;
|
||||
$sthA->execute or die "executing: $stmtA ", $dbhA->errstr;
|
||||
$sthArows=$sthA->rows;
|
||||
if ($sthArows > 0)
|
||||
{
|
||||
@aryA = $sthA->fetchrow_array;
|
||||
$recording_log_stereo_archive_count = $aryA[0];
|
||||
}
|
||||
$sthA->finish();
|
||||
|
||||
if (!$Q) {print "\nProcessing recording_log_stereo table... ($recording_log_stereo_count|$recording_log_stereo_archive_count)\n";}
|
||||
$stmtA = "INSERT IGNORE INTO recording_log_stereo_archive SELECT * from recording_log_stereo;";
|
||||
$sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr;
|
||||
$sthA->execute or die "executing: $stmtA ", $dbhA->errstr;
|
||||
|
||||
$sthArows = $sthA->rows;
|
||||
if (!$Q) {print "$sthArows rows inserted into recording_log_stereo_archive table \n";}
|
||||
|
||||
$rv = $sthA->err();
|
||||
if (!$rv)
|
||||
{
|
||||
$stmtA = "DELETE FROM recording_log_stereo WHERE start_time < '$RECdel_time';";
|
||||
$sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr;
|
||||
$sthA->execute or die "executing: $stmtA ", $dbhA->errstr;
|
||||
$sthArows = $sthA->rows;
|
||||
if (!$Q) {print "$sthArows rows deleted from recording_log_stereo table \n";}
|
||||
|
||||
$stmtA = "optimize table recording_log_stereo;";
|
||||
$sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr;
|
||||
$sthA->execute or die "executing: $stmtA ", $dbhA->errstr;
|
||||
|
||||
$stmtA = "optimize table recording_log_stereo_archive;";
|
||||
$sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr;
|
||||
$sthA->execute or die "executing: $stmtA ", $dbhA->errstr;
|
||||
}
|
||||
|
||||
##### recording_log_parallel
|
||||
$stmtA = "SELECT count(*) from recording_log_parallel;";
|
||||
$sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr;
|
||||
$sthA->execute or die "executing: $stmtA ", $dbhA->errstr;
|
||||
$sthArows=$sthA->rows;
|
||||
if ($sthArows > 0)
|
||||
{
|
||||
@aryA = $sthA->fetchrow_array;
|
||||
$recording_log_parallel_count = $aryA[0];
|
||||
}
|
||||
$sthA->finish();
|
||||
|
||||
$stmtA = "SELECT count(*) from recording_log_parallel_archive;";
|
||||
$sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr;
|
||||
$sthA->execute or die "executing: $stmtA ", $dbhA->errstr;
|
||||
$sthArows=$sthA->rows;
|
||||
if ($sthArows > 0)
|
||||
{
|
||||
@aryA = $sthA->fetchrow_array;
|
||||
$recording_log_parallel_archive_count = $aryA[0];
|
||||
}
|
||||
$sthA->finish();
|
||||
|
||||
if (!$Q) {print "\nProcessing recording_log_parallel table... ($recording_log_parallel_count|$recording_log_parallel_archive_count)\n";}
|
||||
$stmtA = "INSERT IGNORE INTO recording_log_parallel_archive SELECT * from recording_log_parallel;";
|
||||
$sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr;
|
||||
$sthA->execute or die "executing: $stmtA ", $dbhA->errstr;
|
||||
|
||||
$sthArows = $sthA->rows;
|
||||
if (!$Q) {print "$sthArows rows inserted into recording_log_parallel_archive table \n";}
|
||||
|
||||
$rv = $sthA->err();
|
||||
if (!$rv)
|
||||
{
|
||||
$stmtA = "DELETE FROM recording_log_parallel WHERE start_time < '$RECdel_time';";
|
||||
$sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr;
|
||||
$sthA->execute or die "executing: $stmtA ", $dbhA->errstr;
|
||||
$sthArows = $sthA->rows;
|
||||
if (!$Q) {print "$sthArows rows deleted from recording_log_parallel table \n";}
|
||||
|
||||
$stmtA = "optimize table recording_log_parallel;";
|
||||
$sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr;
|
||||
$sthA->execute or die "executing: $stmtA ", $dbhA->errstr;
|
||||
|
||||
$stmtA = "optimize table recording_log_parallel_archive;";
|
||||
$sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr;
|
||||
$sthA->execute or die "executing: $stmtA ", $dbhA->errstr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -173,9 +173,10 @@
|
||||
# 240401-1810 - Added purging of vicidial_pending_ar records older than 7 days
|
||||
# 240420-2209 - Added Conference Updater option
|
||||
# 250103-0932 - Added ConfBridge code and enhanced_agent_monitoring system setting code
|
||||
# 250914-1601 - Added pruning of recording_live table entries over 7 days old, deletion of parallel recording source files 3+ days
|
||||
#
|
||||
|
||||
$build = '250103-0932';
|
||||
$build = '250914-1601';
|
||||
|
||||
$DB=0; # Debug flag
|
||||
$teodDB=0; # flag to log Timeclock End of Day processes to log file
|
||||
@@ -444,6 +445,8 @@ foreach(@conf)
|
||||
{$PATHlogs = $line; $PATHlogs =~ s/.*=//gi;}
|
||||
if ( ($line =~ /^PATHsounds/) && ($CLIsounds < 1) )
|
||||
{$PATHsounds = $line; $PATHsounds =~ s/.*=//gi;}
|
||||
if ( ($line =~ /^PATHmonitor/) && ($CLImonitor < 1) )
|
||||
{$PATHmonitor = $line; $PATHmonitor =~ s/.*=//gi;}
|
||||
if ( ($line =~ /^VARactive_keepalives/) && ($CLIactive_keepalives < 1) )
|
||||
{$VARactive_keepalives = $line; $VARactive_keepalives =~ s/.*=//gi;}
|
||||
if ( ($line =~ /^VARserver_ip/) && ($CLIserver_ip < 1) )
|
||||
@@ -496,7 +499,7 @@ $dbhA = DBI->connect("DBI:mysql:$VARDB_database:$VARDB_server:$VARDB_port", "$VA
|
||||
|
||||
|
||||
##### Get the settings from system_settings #####
|
||||
$stmtA = "SELECT sounds_central_control_active,active_voicemail_server,custom_dialplan_entry,default_codecs,generate_cross_server_exten,voicemail_timezones,default_voicemail_timezone,call_menu_qualify_enabled,allow_voicemail_greeting,reload_timestamp,meetme_enter_login_filename,meetme_enter_leave3way_filename,allow_chats,enable_auto_reports,enable_drop_lists,expired_lists_inactive,sip_event_logging,call_quota_lead_ranking,inbound_answer_config,log_latency_gaps,demographic_quotas,weekday_resets,highest_lead_id,hopper_hold_inserts FROM system_settings;";
|
||||
$stmtA = "SELECT sounds_central_control_active,active_voicemail_server,custom_dialplan_entry,default_codecs,generate_cross_server_exten,voicemail_timezones,default_voicemail_timezone,call_menu_qualify_enabled,allow_voicemail_greeting,reload_timestamp,meetme_enter_login_filename,meetme_enter_leave3way_filename,allow_chats,enable_auto_reports,enable_drop_lists,expired_lists_inactive,sip_event_logging,call_quota_lead_ranking,inbound_answer_config,log_latency_gaps,demographic_quotas,weekday_resets,highest_lead_id,hopper_hold_inserts,stereo_recording,stereo_parallel_recording FROM system_settings;";
|
||||
# print "$stmtA\n";
|
||||
$sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr;
|
||||
$sthA->execute or die "executing: $stmtA ", $dbhA->errstr;
|
||||
@@ -528,6 +531,8 @@ if ($sthArows > 0)
|
||||
$SSweekday_resets = $aryA[21];
|
||||
$SShighest_lead_id = $aryA[22];
|
||||
$SShopper_hold_inserts = $aryA[23];
|
||||
$SSstereo_recording = $aryA[24];
|
||||
$SSstereo_parallel_recording = $aryA[25];
|
||||
}
|
||||
$sthA->finish();
|
||||
if ($DBXXX > 0) {print "SYSTEM SETTINGS: $sounds_central_control_active|$active_voicemail_server|$SScustom_dialplan_entry|$SSdefault_codecs\n";}
|
||||
@@ -1216,6 +1221,36 @@ if ($timeclock_end_of_day_NOW > 0)
|
||||
}
|
||||
if ($teodDB) {$event_string = "Empty $vicidial_conf_table entries cleared: $conf_cleared"; &teod_logger;}
|
||||
|
||||
### If stereo parallel recording is enabled on this system, delete parallel source files over 3 days old every night
|
||||
if ( ($SSstereo_recording > 0) && ($SSstereo_parallel_recording > 0) )
|
||||
{
|
||||
### find 'find' to gather the list of files to delete
|
||||
$findbin = '';
|
||||
if ( -e ('/usr/bin/find')) {$findbin = '/usr/bin/find';}
|
||||
else
|
||||
{
|
||||
if ( -e ('/bin/find')) {$findbin = '/bin/find';}
|
||||
else
|
||||
{
|
||||
if ( -e ('/usr/sbin/find')) {$findbin = '/usr/sbin/find';}
|
||||
else
|
||||
{
|
||||
if ($DB) {print "Can't find -find- binary! No file deletions will be possible...\n";}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$PATHmonitorTRASH = $PATHmonitor.'TRASH';
|
||||
$now_epoch = int(time());
|
||||
# command to trigger old stereo parallel source file deletion:
|
||||
$parallel_delete_command = "$findbin $PATHmonitorTRASH -maxdepth 2 -type f -mtime +3 | xargs rm -f ";
|
||||
if (!$Q) {print "Triggering old Parallel source recording file deletion... |$parallel_delete_command| \n";}
|
||||
`/usr/bin/screen -d -m -S PD$reset_test $parallel_delete_command `;
|
||||
$end_epoch = int(time());
|
||||
$run_length = ($end_epoch - $now_epoch);
|
||||
if (!$Q) {print " Parallel source recording file deletion complete ($run_length sec) \n";}
|
||||
if ($teodDB) {$event_string = "Old Parallel source recording file deletion complete ($run_length sec): $parallel_delete_command"; &teod_logger;}
|
||||
}
|
||||
|
||||
### Only run the following on one server in the cluster, the one set as the active voicemail server ###
|
||||
if ( ($active_voicemail_server =~ /$server_ip/) && ((length($active_voicemail_server)) eq (length($server_ip))) )
|
||||
@@ -2308,6 +2343,21 @@ if ($timeclock_end_of_day_NOW > 0)
|
||||
##### END vicidial_lead_24hour_calls end of day process removing records older than 1 day #####
|
||||
|
||||
|
||||
##### BEGIN recording_live_log end of day process removing records older than 7 days #####
|
||||
$stmtA = "DELETE FROM recording_live_log WHERE start_time < \"$SDSQLdate\";";
|
||||
$sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr;
|
||||
$sthA->execute or die "executing: $stmtA ", $dbhA->errstr;
|
||||
$sthArows = $sthA->rows;
|
||||
$event_string = "$sthArows rows deleted from recording_live_log table";
|
||||
if (!$Q) {print "$event_string \n";}
|
||||
if ($teodDB) {&teod_logger;}
|
||||
|
||||
$stmtA = "optimize table recording_live_log;";
|
||||
$sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr;
|
||||
$sthA->execute or die "executing: $stmtA ", $dbhA->errstr;
|
||||
##### END recording_live_log end of day process removing records older than 7 days #####
|
||||
|
||||
|
||||
##### START latency log summary log inserts
|
||||
|
||||
##### gather vicidial_agent_latency_log #####
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
# ### recording mixing/compressing/ftping scripts
|
||||
##0,3,6,9,12,15,18,21,24,27,30,33,36,39,42,45,48,51,54,57 * * * * /usr/share/astguiclient/AST_CRON_audio_1_move_mix.pl
|
||||
# 0,3,6,9,12,15,18,21,24,27,30,33,36,39,42,45,48,51,54,57 * * * * /usr/share/astguiclient/AST_CRON_audio_1_move_VDonly.pl
|
||||
# 1,4,7,10,13,16,19,22,25,28,31,34,37,40,43,46,49,52,55,58 * * * * /usr/share/astguiclient/AST_CRON_audio_2_compress.pl --GSM
|
||||
# 2,5,8,11,14,17,20,23,26,29,32,35,38,41,44,47,50,53,56,59 * * * * /usr/share/astguiclient/AST_CRON_audio_3_ftp.pl --GSM
|
||||
# 1,4,7,10,13,16,19,22,25,28,31,34,37,40,43,46,49,52,55,58 * * * * /usr/share/astguiclient/AST_CRON_audio_2_compress.pl --MP3
|
||||
# 2,5,8,11,14,17,20,23,26,29,32,35,38,41,44,47,50,53,56,59 * * * * /usr/share/astguiclient/AST_CRON_audio_3_ftp.pl --MP3
|
||||
#
|
||||
# make sure that the following directories exist:
|
||||
# /var/spool/asterisk/monitor # default Asterisk recording directory
|
||||
@@ -36,6 +36,7 @@
|
||||
# 190311-0105 - Added code to check for agent-muted recordings
|
||||
# 231019-2202 - Changed sleep time between directory scans from 5 to 15 seconds
|
||||
# 250430-0850 - Added --POST options for skipping over recordings for leads with active calls, and using logs for statuss
|
||||
# 250909-0845 - Added trigger for stereo recording script, if enabled and raw audio files present
|
||||
#
|
||||
|
||||
$HTTPS=0;
|
||||
@@ -227,14 +228,16 @@ $dbhA = DBI->connect("DBI:mysql:$VARDB_database:$VARDB_server:$VARDB_port", "$VA
|
||||
|
||||
##### Get the settings from system_settings #####
|
||||
$SSmute_recordings=0;
|
||||
$stmtA = "SELECT mute_recordings FROM system_settings;";
|
||||
$stmtA = "SELECT mute_recordings,stereo_recording,stereo_parallel_recording FROM system_settings;";
|
||||
$sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr;
|
||||
$sthA->execute or die "executing: $stmtA ", $dbhA->errstr;
|
||||
$sthArows=$sthA->rows;
|
||||
if ($sthArows > 0)
|
||||
{
|
||||
@aryA = $sthA->fetchrow_array;
|
||||
$SSmute_recordings = $aryA[0];
|
||||
$SSmute_recordings = $aryA[0];
|
||||
$SSstereo_recording = $aryA[1];
|
||||
$SSstereo_parallel_recording = $aryA[2];
|
||||
}
|
||||
$sthA->finish();
|
||||
|
||||
@@ -268,6 +271,22 @@ else
|
||||
}
|
||||
}
|
||||
|
||||
# time variable definitions
|
||||
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
|
||||
$year = ($year + 1900);
|
||||
$mon++;
|
||||
$wtoday = $wday;
|
||||
if ($mon < 10) {$mon = "0$mon";}
|
||||
if ($mday < 10) {$mday = "0$mday";}
|
||||
if ($hour < 10) {$hour = "0$hour";}
|
||||
if ($min < 10) {$min = "0$min";}
|
||||
if ($sec < 10) {$sec = "0$sec";}
|
||||
$now_date = "$year-$mon-$mday $hour:$min:$sec";
|
||||
$dateint = "$year$mon$mday$hour$min$sec";
|
||||
$today_start = "$year-$mon-$mday 00:00:00";
|
||||
$today_date = "$year-$mon-$mday";
|
||||
$hm = "$hour$min";
|
||||
|
||||
### directory where in/out recordings are saved to by Asterisk
|
||||
$dir1 = "$PATHmonitor";
|
||||
$dir2 = "$PATHDONEmonitor";
|
||||
@@ -660,6 +679,10 @@ foreach(@FILES)
|
||||
if($DBX){print STDERR "\n|$stmtA|\n";}
|
||||
$affected_rows = $dbhA->do($stmtA); # or die "Couldn't execute query:|$stmtA|\n";
|
||||
|
||||
$stmtA = "UPDATE recording_live set end_time=NOW(),recording_status='FINISHED FILE-MERGE' where recording_id='$recording_id' and recording_status='STARTED';";
|
||||
if($DBX){print STDERR "\n|$stmtA|\n";}
|
||||
$affected_rows = $dbhA->do($stmtA); # or die "Couldn't execute query:|$stmtA|\n";
|
||||
|
||||
### sleep for twenty hundredths of a second to not flood the server with disk activity
|
||||
usleep(1*200*1000);
|
||||
|
||||
@@ -687,6 +710,63 @@ if($DBX)
|
||||
print "Run time: $run_length seconds \n";
|
||||
}
|
||||
|
||||
if ($SSstereo_recording > 0)
|
||||
{
|
||||
$PATHmonitorS = $PATHmonitor.'S';
|
||||
$PATHmonitorP = $PATHmonitor.'P';
|
||||
|
||||
if($DBX)
|
||||
{print "Checking for Stereo Call Recordings in $PATHmonitorS \n";}
|
||||
|
||||
opendir(sFILE, "$PATHmonitorS/");
|
||||
@sFILES = readdir(sFILE);
|
||||
|
||||
### Loop through files first to gather filesizes
|
||||
$trigger_stereo=0;
|
||||
$i=0;
|
||||
foreach(@sFILES)
|
||||
{
|
||||
if ( (length($sFILES[$i]) > 4) && (!-d "$dir1/$sFILES[$i]") && ($sFILES[$i] =~ /\.wav$/i) )
|
||||
{
|
||||
$trigger_stereo++;
|
||||
if ($DBX) {print "Stereo file found! $sFILES[$i] \n";}
|
||||
last;
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
|
||||
if ( ($SSstereo_parallel_recording > 0) && ($trigger_stereo < 1) )
|
||||
{
|
||||
if($DBX)
|
||||
{print "Checking for Stereo Parallel Call Recordings in $PATHmonitorP \n";}
|
||||
|
||||
opendir(pFILE, "$PATHmonitorP/");
|
||||
@pFILES = readdir(pFILE);
|
||||
|
||||
### Loop through files first to gather filesizes
|
||||
$trigger_stereo=0;
|
||||
$i=0;
|
||||
foreach(@pFILES)
|
||||
{
|
||||
if ( (length($pFILES[$i]) > 4) && (!-d "$dir1/$pFILES[$i]") && ($pFILES[$i] =~ /\.wav$/i) )
|
||||
{
|
||||
$trigger_stereo++;
|
||||
if ($DBX) {print "Stereo Parallel file found! $pFILES[$i] \n";}
|
||||
last;
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
|
||||
if ($trigger_stereo > 0)
|
||||
{
|
||||
# command to trigger stereo call file processing, preserving flags from this script:
|
||||
$stereo_command = "$PATHhome/AST_CRON_audio_1_stereo.pl $args ";
|
||||
if ($DBX) {print "Triggering Stereo call file processing... |$stereo_command| \n";}
|
||||
`/usr/bin/screen -d -m -S SP$hm $stereo_command `;
|
||||
}
|
||||
}
|
||||
|
||||
if ($DB) {print "DONE... EXITING\n\n";}
|
||||
|
||||
$sthA->finish();
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
# ### recording mixing/compressing/ftping scripts
|
||||
# 0,3,6,9,12,15,18,21,24,27,30,33,36,39,42,45,48,51,54,57 * * * * /usr/share/astguiclient/AST_CRON_audio_1_move_mix.pl --MIX
|
||||
##0,3,6,9,12,15,18,21,24,27,30,33,36,39,42,45,48,51,54,57 * * * * /usr/share/astguiclient/AST_CRON_audio_1_move_VDonly.pl
|
||||
# 1,4,7,10,13,16,19,22,25,28,31,34,37,40,43,46,49,52,55,58 * * * * /usr/share/astguiclient/AST_CRON_audio_2_compress.pl --GSM
|
||||
# 2,5,8,11,14,17,20,23,26,29,32,35,38,41,44,47,50,53,56,59 * * * * /usr/share/astguiclient/AST_CRON_audio_3_ftp.pl --GSM
|
||||
# 1,4,7,10,13,16,19,22,25,28,31,34,37,40,43,46,49,52,55,58 * * * * /usr/share/astguiclient/AST_CRON_audio_2_compress.pl --MP3
|
||||
# 2,5,8,11,14,17,20,23,26,29,32,35,38,41,44,47,50,53,56,59 * * * * /usr/share/astguiclient/AST_CRON_audio_3_ftp.pl --MP3
|
||||
#
|
||||
# make sure that the following directories exist:
|
||||
# /var/spool/asterisk/monitor # default Asterisk recording directory
|
||||
|
||||
@@ -0,0 +1,970 @@
|
||||
#!/usr/bin/perl
|
||||
#
|
||||
# AST_CRON_audio_1_stereo.pl
|
||||
#
|
||||
# This is a STEP-1 program in the audio archival process
|
||||
#
|
||||
# IMPORTANT!!! ONLY TO BE USED WHEN STEREO VICIDIAL CALL RECORDINGS ARE ON THE SYSTEM!
|
||||
#
|
||||
# runs every 3 minutes if there are stereo call recording files to process.
|
||||
# Processes audio and moves to other directories for further processing.
|
||||
#
|
||||
# Do NOT put this script in the crontab! It is launched as needed by the
|
||||
# "AST_CRON_audio_1_move_VDonly.pl" script, which should be run every 3 minutes
|
||||
#
|
||||
# make sure that the following directories exist:
|
||||
# /var/spool/asterisk/monitorS # default Asterisk stereo recording directory
|
||||
# /var/spool/asterisk/monitorP # default Asterisk stereo parallel recording directory
|
||||
# /var/spool/asterisk/monitorTRASH # where the used parallel files are put
|
||||
# /var/spool/asterisk/monitorDONE # where the mixed -all files are put
|
||||
# /var/spool/asterisk/monitor/ORIG # where the original -in and -out files are put
|
||||
#
|
||||
# This program assumes that recordings are saved by Asterisk as .wav
|
||||
#
|
||||
# Copyright (C) 2025 Matt Florell <vicidial@gmail.com> LICENSE: AGPLv2
|
||||
#
|
||||
#
|
||||
# 250909-0955 - First Build
|
||||
#
|
||||
|
||||
$HTTPS=0;
|
||||
$status_post_logs=0;
|
||||
$delay_post_live=0;
|
||||
$ignore_parallel=0;
|
||||
$now_epoch = int(time());
|
||||
|
||||
### begin parsing run-time options ###
|
||||
if (length($ARGV[0])>1)
|
||||
{
|
||||
$i=0;
|
||||
while ($#ARGV >= $i)
|
||||
{
|
||||
$args = "$args $ARGV[$i]";
|
||||
$i++;
|
||||
}
|
||||
|
||||
if ($args =~ /--help/i)
|
||||
{
|
||||
print "allowed run time options:\n";
|
||||
print " [--help] = this screen\n";
|
||||
print " [--quiet] = suppress output, if possible\n";
|
||||
print " [--debug] = debug\n";
|
||||
print " [--debugX] = super debug\n";
|
||||
print " [--test] = test\n";
|
||||
print " [--ignore-parallel] = do not process parallel stereo recordings\n";
|
||||
print " [--HTTPS] = use https instead of http in local location\n";
|
||||
print " [--POST] = post call variable filename replacement, MUST define STATUS and CAMP below\n";
|
||||
print " [--STATUS-POST=X] = only run post call variable filename replacement on specific status calls\n";
|
||||
print " If multiple statuses, use --- delimiting, i.e.: SALE---PRESALE\n";
|
||||
print " For status wildcards, use * flag, i.e.: S* to match SALE and SQUAL\n";
|
||||
print " For all statuses, use ----ALL----\n";
|
||||
print " \n";
|
||||
print " [--CAMP-POST=X] = only run post call variable filename replacement on specific campaigns or ingroups\n";
|
||||
print " If multiple campaigns or ingroups, use --- delimiting, i.e.: TESTCAMP---TEST_IN2\n";
|
||||
print " For all calls, use ----ALL----\n";
|
||||
print " [--CLEAR-POST-NO-MATCH] = clear POST filename variables if no match is found\n";
|
||||
print " [--STATUS-POST-LOGS] = use the call logs for POST filename status variable, if found\n";
|
||||
print " [--DELAY-POST-LIVE-CALLS] = delay processing of recordings using POST filename variables if any live calls/agents for lead\n";
|
||||
print "\n";
|
||||
exit;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($args =~ /--quiet/)
|
||||
{
|
||||
$q=1;
|
||||
}
|
||||
if ($args =~ /--debug/i)
|
||||
{
|
||||
$DB=1;
|
||||
print "\n----- DEBUG -----\n\n";
|
||||
}
|
||||
if ($args =~ /--debugX/i)
|
||||
{
|
||||
$DBX=1;
|
||||
print "\n----- SUPER DEBUG -----\n\n";
|
||||
}
|
||||
if ($args =~ /--test/)
|
||||
{
|
||||
$T=1; $TEST=1;
|
||||
if ($q < 1) {print "\n-----TESTING -----\n\n";}
|
||||
}
|
||||
if ($args =~ /--ignore-parallel/)
|
||||
{
|
||||
$ignore_parallel=1;
|
||||
if ($q < 1) {print "\n----- IGNORING PARALLEL CALL RECORDINGS -----\n\n";}
|
||||
}
|
||||
if ($args =~ /--HTTPS/i)
|
||||
{
|
||||
$HTTPS=1;
|
||||
if ($DB) {print "HTTPS location option enabled\n";}
|
||||
}
|
||||
if ($args =~ /--POST/i)
|
||||
{
|
||||
$POST=1;
|
||||
if ($DB) {print "POST post call variable filename replacement\n";}
|
||||
|
||||
if ($args =~ /--STATUS-POST=/i)
|
||||
{
|
||||
@data_in = split(/--STATUS-POST=/,$args);
|
||||
$status_post = $data_in[1];
|
||||
$status_post =~ s/ .*//gi;
|
||||
if ($q < 1) {print "\n----- STATUS POST SET: $status_post -----\n\n";}
|
||||
}
|
||||
else
|
||||
{
|
||||
$POST=0;
|
||||
if ($q < 1) {print "\n----- POST disabled, no status set -----\n\n";}
|
||||
}
|
||||
|
||||
if ($args =~ /--CAMP-POST=/i)
|
||||
{
|
||||
@data_in = split(/--CAMP-POST=/,$args);
|
||||
$camp_post = $data_in[1];
|
||||
$camp_post =~ s/ .*//gi;
|
||||
if ($q < 1) {print "\n----- CAMP POST SET: $camp_post -----\n\n";}
|
||||
}
|
||||
else
|
||||
{
|
||||
$POST=0;
|
||||
if ($q < 1) {print "\n----- POST disabled, no campaigns set -----\n\n";}
|
||||
}
|
||||
if ($args =~ /--STATUS-POST-LOGS/i)
|
||||
{
|
||||
$status_post_logs=1;
|
||||
if ($q < 1) {print "\n----- STATUS POST LOGS SET: $status_post_logs -----\n\n";}
|
||||
}
|
||||
if ($args =~ /--DELAY-POST-LIVE-CALLS/i)
|
||||
{
|
||||
$delay_post_live=1;
|
||||
if ($q < 1) {print "\n----- DELAY POST LIVE SET: $delay_post_live -----\n\n";}
|
||||
}
|
||||
}
|
||||
if ($args =~ /--CLEAR-POST-NO-MATCH/i)
|
||||
{
|
||||
$CLEAR_POST=1;
|
||||
if ($DB) {print "--- CLEAR-POST-NO-MATCH ENABLED ---\n";}
|
||||
}
|
||||
}
|
||||
|
||||
if ( ($POST > 0) && ( (length($camp_post) < 1) || (length($status_post) < 1) ) )
|
||||
{
|
||||
$POST=0;
|
||||
if ($q < 1) {print "\n----- POST disabled, status or campaign invalid: |$camp_post|$status_post| -----\n\n";}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
#print "no command line options set\n";
|
||||
}
|
||||
|
||||
|
||||
# default path to astguiclient configuration file:
|
||||
$PATHconf = '/etc/astguiclient.conf';
|
||||
|
||||
open(conf, "$PATHconf") || die "can't open $PATHconf: $!\n";
|
||||
@conf = <conf>;
|
||||
close(conf);
|
||||
$i=0;
|
||||
foreach(@conf)
|
||||
{
|
||||
$line = $conf[$i];
|
||||
$line =~ s/ |>|\n|\r|\t|\#.*|;.*//gi;
|
||||
if ( ($line =~ /^PATHhome/) && ($CLIhome < 1) )
|
||||
{$PATHhome = $line; $PATHhome =~ s/.*=//gi;}
|
||||
if ( ($line =~ /^PATHlogs/) && ($CLIlogs < 1) )
|
||||
{$PATHlogs = $line; $PATHlogs =~ s/.*=//gi;}
|
||||
if ( ($line =~ /^PATHagi/) && ($CLIagi < 1) )
|
||||
{$PATHagi = $line; $PATHagi =~ s/.*=//gi;}
|
||||
if ( ($line =~ /^PATHweb/) && ($CLIweb < 1) )
|
||||
{$PATHweb = $line; $PATHweb =~ s/.*=//gi;}
|
||||
if ( ($line =~ /^PATHsounds/) && ($CLIsounds < 1) )
|
||||
{$PATHsounds = $line; $PATHsounds =~ s/.*=//gi;}
|
||||
if ( ($line =~ /^PATHmonitor/) && ($CLImonitor < 1) )
|
||||
{$PATHmonitor = $line; $PATHmonitor =~ s/.*=//gi;}
|
||||
if ( ($line =~ /^PATHDONEmonitor/) && ($CLIDONEmonitor < 1) )
|
||||
{$PATHDONEmonitor = $line; $PATHDONEmonitor =~ s/.*=//gi;}
|
||||
if ( ($line =~ /^VARserver_ip/) && ($CLIserver_ip < 1) )
|
||||
{$VARserver_ip = $line; $VARserver_ip =~ s/.*=//gi;}
|
||||
if ( ($line =~ /^VARDB_server/) && ($CLIDB_server < 1) )
|
||||
{$VARDB_server = $line; $VARDB_server =~ s/.*=//gi;}
|
||||
if ( ($line =~ /^VARDB_database/) && ($CLIDB_database < 1) )
|
||||
{$VARDB_database = $line; $VARDB_database =~ s/.*=//gi;}
|
||||
if ( ($line =~ /^VARDB_user/) && ($CLIDB_user < 1) )
|
||||
{$VARDB_user = $line; $VARDB_user =~ s/.*=//gi;}
|
||||
if ( ($line =~ /^VARDB_pass/) && ($CLIDB_pass < 1) )
|
||||
{$VARDB_pass = $line; $VARDB_pass =~ s/.*=//gi;}
|
||||
if ( ($line =~ /^VARDB_port/) && ($CLIDB_port < 1) )
|
||||
{$VARDB_port = $line; $VARDB_port =~ s/.*=//gi;}
|
||||
if ( ($line =~ /^VARFTP_host/) && ($CLIFTP_host < 1) )
|
||||
{$VARFTP_host = $line; $VARFTP_host =~ s/.*=//gi;}
|
||||
if ( ($line =~ /^VARFTP_user/) && ($CLIFTP_user < 1) )
|
||||
{$VARFTP_user = $line; $VARFTP_user =~ s/.*=//gi;}
|
||||
if ( ($line =~ /^VARFTP_pass/) && ($CLIFTP_pass < 1) )
|
||||
{$VARFTP_pass = $line; $VARFTP_pass =~ s/.*=//gi;}
|
||||
if ( ($line =~ /^VARFTP_port/) && ($CLIFTP_port < 1) )
|
||||
{$VARFTP_port = $line; $VARFTP_port =~ s/.*=//gi;}
|
||||
if ( ($line =~ /^VARFTP_dir/) && ($CLIFTP_dir < 1) )
|
||||
{$VARFTP_dir = $line; $VARFTP_dir =~ s/.*=//gi;}
|
||||
if ( ($line =~ /^VARHTTP_path/) && ($CLIHTTP_path < 1) )
|
||||
{$VARHTTP_path = $line; $VARHTTP_path =~ s/.*=//gi;}
|
||||
$i++;
|
||||
}
|
||||
|
||||
# Customized Variables
|
||||
$server_ip = $VARserver_ip; # Asterisk server IP
|
||||
if (!$VARDB_port) {$VARDB_port='3306';}
|
||||
|
||||
use Time::HiRes ('gettimeofday','usleep','sleep'); # necessary to have perl sleep command of less than one second
|
||||
use DBI;
|
||||
|
||||
$dbhA = DBI->connect("DBI:mysql:$VARDB_database:$VARDB_server:$VARDB_port", "$VARDB_user", "$VARDB_pass")
|
||||
or die "Couldn't connect to database: " . DBI->errstr;
|
||||
|
||||
##### Get the settings from system_settings #####
|
||||
$SSmute_recordings=0;
|
||||
$stmtA = "SELECT mute_recordings,stereo_recording,stereo_parallel_recording FROM system_settings;";
|
||||
$sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr;
|
||||
$sthA->execute or die "executing: $stmtA ", $dbhA->errstr;
|
||||
$sthArows=$sthA->rows;
|
||||
if ($sthArows > 0)
|
||||
{
|
||||
@aryA = $sthA->fetchrow_array;
|
||||
$SSmute_recordings = $aryA[0];
|
||||
$SSstereo_recording = $aryA[1];
|
||||
$SSstereo_parallel_recording = $aryA[2];
|
||||
}
|
||||
$sthA->finish();
|
||||
|
||||
##### Get the settings from servers #####
|
||||
$vicidial_recording_limit=0;
|
||||
$stmtA = "SELECT vicidial_recording_limit FROM servers where server_ip='$server_ip';";
|
||||
$sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr;
|
||||
$sthA->execute or die "executing: $stmtA ", $dbhA->errstr;
|
||||
$sthArows=$sthA->rows;
|
||||
if ($sthArows > 0)
|
||||
{
|
||||
@aryA = $sthA->fetchrow_array;
|
||||
$vicidial_recording_limit = $aryA[0];
|
||||
$start_epoch_test = ($now_epoch - ( ($vicidial_recording_limit * 2) * 60) );
|
||||
}
|
||||
$sthA->finish();
|
||||
|
||||
# calculate server recording limit time, plus 60 minutes
|
||||
($Rsec,$Rmin,$Rhour,$Rmday,$Rmon,$Ryear,$Rwday,$Ryday,$Risdst) = localtime(time() - (($vicidial_recording_limit + 60) * 60));
|
||||
$Ryear = ($Ryear + 1900);
|
||||
$Ryy = $Ryear; $Ryy =~ s/^..//gi;
|
||||
$Rmon++;
|
||||
if ($Rmon < 10) {$Rmon = "0$Rmon";}
|
||||
if ($Rmday < 10) {$Rmday = "0$Rmday";}
|
||||
if ($Rhour < 10) {$Rhour = "0$Rhour";}
|
||||
if ($Rmin < 10) {$Rmin = "0$Rmin";}
|
||||
if ($Rsec < 10) {$Rsec = "0$Rsec";}
|
||||
$SQLdate_REC_limit="$Ryear-$Rmon-$Rmday $Rhour:$Rmin:$Rsec";
|
||||
|
||||
### find soxmix or sox to do the mixing
|
||||
$soxbin = '';
|
||||
if ( -e ('/usr/bin/sox')) {$soxbin = '/usr/bin/sox';}
|
||||
else
|
||||
{
|
||||
if ( -e ('/usr/local/bin/sox')) {$soxbin = '/usr/local/bin/sox';}
|
||||
else
|
||||
{
|
||||
print "Can't find sox binary! Exiting...\n";
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
### find soxi to gather the length info if needed
|
||||
$soxibin = '';
|
||||
if ( -e ('/usr/bin/soxi')) {$soxibin = '/usr/bin/soxi';}
|
||||
else
|
||||
{
|
||||
if ( -e ('/usr/local/bin/soxi')) {$soxibin = '/usr/local/bin/soxi';}
|
||||
else
|
||||
{
|
||||
if ( -e ('/usr/sbin/soxi')) {$soxibin = '/usr/sbin/soxi';}
|
||||
else
|
||||
{
|
||||
if ($DB) {print "Can't find soxi binary! No length calculations will be available...\n";}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($SSstereo_recording < 1)
|
||||
{
|
||||
if ($DB) {print "Stereo Call Recording is disabled on this system, exiting... |$SSstereo_recording| \n";}
|
||||
exit;
|
||||
}
|
||||
|
||||
### directory where in/out recordings are saved to by Asterisk
|
||||
$dir1 = $PATHmonitor.'S';
|
||||
$dir2 = "$PATHDONEmonitor";
|
||||
$PATHmonitorP = $PATHmonitor.'P';
|
||||
$PATHmonitorTRASH = $PATHmonitor.'TRASH';
|
||||
|
||||
|
||||
|
||||
####################################################
|
||||
##### BEGIN parallel call recording processing #####
|
||||
####################################################
|
||||
if ( ($ignore_parallel < 1) && ($SSstereo_parallel_recording > 0) )
|
||||
{
|
||||
if (!-e "$PATHmonitorTRASH/one-sec-silence.wav")
|
||||
{
|
||||
# generate 1 second silence file, to be used to create stereo files with only one side having audio
|
||||
`$soxbin -n -c 1 -r 8k -b 16 "$PATHmonitorTRASH/one-sec-silence.wav" synth 1 sine 0`;
|
||||
if($DBX){print "Created one-sec-silence.wav audio file. \n";}
|
||||
}
|
||||
|
||||
opendir(pFILE, "$PATHmonitorP/");
|
||||
@pFILES = readdir(pFILE);
|
||||
|
||||
### Loop through files first to gather filesizes
|
||||
$parallel_files_ct=0;
|
||||
$i=0;
|
||||
foreach(@pFILES)
|
||||
{
|
||||
$pFILEsize1[$i] = 0;
|
||||
if ( (length($pFILES[$i]) > 4) && (!-d "$PATHmonitorP/$pFILES[$i]") )
|
||||
{
|
||||
$parallel_files_ct++;
|
||||
$pFILEsize1[$i] = (-s "$PATHmonitorP/$pFILES[$i]");
|
||||
if ($DBX) {print "$parallel_files_ct $pFILES[$i] $pFILEsize1[$i]\n";}
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
|
||||
if ($parallel_files_ct < 1)
|
||||
{
|
||||
if ($DBX) {print "No parallel files found to process: $parallel_files_ct \n";}
|
||||
}
|
||||
else
|
||||
{
|
||||
sleep(15);
|
||||
|
||||
### Loop through files a second time to gather filesizes again 5 seconds later
|
||||
$i=0;
|
||||
$active_recordings=0;
|
||||
$delay_ct=0;
|
||||
$processed_ct=0;
|
||||
$stereo_rec_made=0;
|
||||
foreach(@pFILES)
|
||||
{
|
||||
$lead_id=0;
|
||||
$vicidial_id='';
|
||||
$pFILEsize2[$i] = 0;
|
||||
|
||||
if ( (length($pFILES[$i]) > 4) && (!-d "$PATHmonitorP/$pFILES[$i]") )
|
||||
{
|
||||
$pFILEsize2[$i] = (-s "$PATHmonitorP/$pFILES[$i]");
|
||||
if ($DBX) {print "$pFILES[$i] $pFILEsize2[$i]\n\n";}
|
||||
|
||||
if ( ($pFILES[$i] !~ /out\.wav|out\.gsm|lost\+found/i) && ($pFILEsize1[$i] eq $pFILEsize2[$i]) && (length($pFILES[$i]) > 4))
|
||||
{
|
||||
$process_recording=0;
|
||||
$INfile = $pFILES[$i];
|
||||
$OUTfile = $pFILES[$i];
|
||||
$OUTfile =~ s/-in\.wav/-out.wav/gi;
|
||||
$OUTfile =~ s/-in\.gsm/-out.gsm/gi;
|
||||
$ALLfile = $pFILES[$i];
|
||||
$ALLfile =~ s/-in\.wav/-all.wav/gi;
|
||||
$ALLfile =~ s/-in\.gsm/-all.gsm/gi;
|
||||
$SQLpFILE = $pFILES[$i];
|
||||
$SQLpFILE =~ s/-in\.wav|-in\.gsm//gi;
|
||||
$filenameSQL='';
|
||||
|
||||
$length_in_sec=0;
|
||||
$rec_ended=0;
|
||||
$start_epoch=0;
|
||||
$stmtA = "SELECT parallel_recording_id,channel,length_in_sec,lead_id,vicidial_id,start_time,end_time,user,UNIX_TIMESTAMP(start_time),recording_status from recording_log_parallel where filename='$SQLpFILE' and server_ip='$server_ip' and start_time >= \"$SQLdate_REC_limit\" order by parallel_recording_id desc LIMIT 1;";
|
||||
if($DBX){print STDERR "\n|$stmtA|\n";}
|
||||
$sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr;
|
||||
$sthA->execute or die "executing: $stmtA ", $dbhA->errstr;
|
||||
$sthArows=$sthA->rows;
|
||||
if ($sthArows > 0)
|
||||
{
|
||||
@aryA = $sthA->fetchrow_array;
|
||||
$parallel_recording_id = $aryA[0];
|
||||
$channel = $aryA[1];
|
||||
$length_in_sec = $aryA[2];
|
||||
$lead_id = $aryA[3];
|
||||
$vicidial_id = $aryA[4];
|
||||
$start_time = $aryA[5];
|
||||
$end_time = $aryA[6];
|
||||
$user = $aryA[7];
|
||||
$start_epoch = $aryA[8];
|
||||
$recording_status = $aryA[9];
|
||||
if (length($end_time) > 15) {$rec_ended=1;}
|
||||
$process_recording=1;
|
||||
}
|
||||
$sthA->finish();
|
||||
|
||||
# get the length of the file from soxi
|
||||
@soxi_output = `$soxibin -D $PATHmonitorP/$pFILES[$i]`;
|
||||
$soxi_sec = $soxi_output[0];
|
||||
$soxi_sec =~ s/\..*|\n|\r| //gi;
|
||||
|
||||
### process the recording files
|
||||
if ($process_recording > 0)
|
||||
{
|
||||
$stereo_rec_ids='Stereo Rec IDs:';
|
||||
if ($DB) {print "|$parallel_recording_id|$length_in_sec($soxi_sec)|$INfile| \n";}
|
||||
|
||||
# Look for stereo recordings using this parallel_recording_id
|
||||
$stmtA = "SELECT filename,lead_id,recording_id,options,start_time,end_time,UNIX_TIMESTAMP(start_time),UNIX_TIMESTAMP(end_time) FROM recording_log_stereo where start_time >= \"$SQLdate_REC_limit\" and parallel_recording_id='$parallel_recording_id' and server_ip='$server_ip' order by recording_id limit 10;";
|
||||
$sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr;
|
||||
$sthA->execute or die "executing: $stmtA ", $dbhA->errstr;
|
||||
$sthArowsRECS=$sthA->rows;
|
||||
if ($DBX) {print "DEBUG: $sthArowsRECS|$stmtA|\n";}
|
||||
$prc=0;
|
||||
while ($sthArowsRECS > $prc)
|
||||
{
|
||||
@aryA = $sthA->fetchrow_array;
|
||||
$PR_filenameIN[$prc] = $aryA[0]."-in.wav";
|
||||
$PR_filenameOUT[$prc] = $aryA[0]."-out.wav";
|
||||
$PR_lead_id[$prc] = $aryA[1];
|
||||
$PR_recording_id[$prc] = $aryA[2];
|
||||
$PR_options[$prc] = $aryA[3];
|
||||
$PR_start_time[$prc] = $aryA[4];
|
||||
$PR_end_time[$prc] = $aryA[5];
|
||||
$PR_start_epoch[$prc] = $aryA[6];
|
||||
$PR_end_epoch[$prc] = $aryA[7];
|
||||
if ( ($PR_end_epoch[$prc] =~ /^NULL$/i) || ($PR_end_epoch[$prc] < 1000) || (length($PR_end_epoch[$prc]) < 4) )
|
||||
{$PR_end_epoch[$prc] = ($start_epoch + $soxi_sec);}
|
||||
$prc++;
|
||||
}
|
||||
$sthA->finish();
|
||||
|
||||
$prc=0;
|
||||
while ($sthArowsRECS > $prc)
|
||||
{
|
||||
$stereo_file_processed=0;
|
||||
if ($PR_options[$prc] =~ /AGENT-CONTROLLED/)
|
||||
{
|
||||
$temp_start_test = ($PR_start_epoch[$prc] - $start_epoch);
|
||||
$temp_ac_length = ($PR_end_epoch[$prc] - $PR_start_epoch[$prc]);
|
||||
$temp_length_test = ($soxi_sec - $temp_ac_length);
|
||||
|
||||
# if agent-controlled file is shorter than, or starts after parallel file, use sox to create shorter file matching start/stop
|
||||
if ( ($temp_start_test > 2) || ($temp_length_test > 4) )
|
||||
{
|
||||
if ($PR_options[$prc] =~ /CUSTOMER_ONLY/)
|
||||
{
|
||||
# stereo recording is shorter than parallel recording, copy Left(-in/silence) and trim Right channels to stereo mixing directory
|
||||
$mix_commandA = "cp -f $PATHmonitorTRASH/one-sec-silence.wav $dir1/$PR_filenameIN[$prc]";
|
||||
$mix_commandB = "$soxbin \"$PATHmonitorP/$OUTfile\" \"$dir1/$PR_filenameOUT[$prc]\" trim $temp_start_test $temp_ac_length";
|
||||
$stereo_file_processed++;
|
||||
}
|
||||
if ($PR_options[$prc] =~ /CUSTOMER_MUTE/)
|
||||
{
|
||||
# stereo recording is shorter than parallel recording, trim Left and copy Right(-out/silence) channels to stereo mixing directory
|
||||
$mix_commandA = "$soxbin \"$PATHmonitorP/$INfile\" \"$dir1/$PR_filenameIN[$prc]\" trim $temp_start_test $temp_ac_length";
|
||||
$mix_commandB = "cp -f $PATHmonitorTRASH/one-sec-silence.wav $dir1/$PR_filenameOUT[$prc]";
|
||||
$stereo_file_processed++;
|
||||
}
|
||||
if ( ($stereo_file_processed < 1) || ($PR_options[$prc] =~ /BOTH_CHANNELS/) )
|
||||
{
|
||||
# stereo recording is shorter than parallel recording, merge Left and Right channels into a single Stereo WAV audio file
|
||||
$mix_commandA = "$soxbin \"$PATHmonitorP/$INfile\" \"$dir1/$PR_filenameIN[$prc]\" trim $temp_start_test $temp_ac_length";
|
||||
$mix_commandB = "$soxbin \"$PATHmonitorP/$OUTfile\" \"$dir1/$PR_filenameOUT[$prc]\" trim $temp_start_test $temp_ac_length";
|
||||
$stereo_file_processed++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($PR_options[$prc] =~ /CUSTOMER_ONLY/)
|
||||
{
|
||||
# stereo recording is same length as parallel recording, copy Left(-in/silence) and Right channels to stereo mixing directory
|
||||
$mix_commandA = "cp -f $PATHmonitorTRASH/one-sec-silence.wav $dir1/$PR_filenameIN[$prc]";
|
||||
$mix_commandB = "cp -f $PATHmonitorP/$OUTfile $dir1/$PR_filenameOUT[$prc]";
|
||||
$stereo_file_processed++;
|
||||
}
|
||||
if ($PR_options[$prc] =~ /CUSTOMER_MUTE/)
|
||||
{
|
||||
# stereo recording is same length as parallel recording, copy Left and Right(-out/silence) channels to stereo mixing directory
|
||||
$mix_commandA = "cp -f $PATHmonitorP/$INfile $dir1/$PR_filenameIN[$prc]";
|
||||
$mix_commandB = "cp -f $PATHmonitorTRASH/one-sec-silence.wav $dir1/$PR_filenameOUT[$prc]";
|
||||
$stereo_file_processed++;
|
||||
}
|
||||
if ( ($stereo_file_processed < 1) || ($PR_options[$prc] =~ /BOTH_CHANNELS/) )
|
||||
{
|
||||
# stereo recording is same length as parallel recording, copy Left and Right channels to stereo mixing directory
|
||||
$mix_commandA = "cp -f $PATHmonitorP/$INfile $dir1/$PR_filenameIN[$prc]";
|
||||
$mix_commandB = "cp -f $PATHmonitorP/$OUTfile $dir1/$PR_filenameOUT[$prc]";
|
||||
$stereo_file_processed++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( ($PR_options[$prc] =~ /CUSTOMER-ONLY/) && ($stereo_file_processed < 1) )
|
||||
{
|
||||
# stereo recording is same length as parallel recording, copy Left(-in/silence) and Right channels to stereo mixing directory
|
||||
$mix_commandA = "cp -f $PATHmonitorTRASH/one-sec-silence.wav $dir1/$PR_filenameIN[$prc]";
|
||||
$mix_commandB = "cp -f $PATHmonitorP/$OUTfile $dir1/$PR_filenameOUT[$prc]";
|
||||
$stereo_file_processed++;
|
||||
}
|
||||
if ( ($PR_options[$prc] =~ /CUSTOMER-MUTED/) && ($stereo_file_processed < 1) )
|
||||
{
|
||||
# stereo recording is same length as parallel recording, copy Left and Right(-out/silence) channels to stereo mixing directory
|
||||
$mix_commandA = "cp -f $PATHmonitorP/$INfile $dir1/$PR_filenameIN[$prc]";
|
||||
$mix_commandB = "cp -f $PATHmonitorTRASH/one-sec-silence.wav $dir1/$PR_filenameOUT[$prc]";
|
||||
$stereo_file_processed++;
|
||||
}
|
||||
if ( ($PR_options[$prc] =~ /FULL-RECORDING/) && ($stereo_file_processed < 1) )
|
||||
{
|
||||
# stereo recording is same length as parallel recording, copy Left and Right channels to stereo mixing directory
|
||||
$mix_commandA = "cp -f $PATHmonitorP/$INfile $dir1/$PR_filenameIN[$prc]";
|
||||
$mix_commandB = "cp -f $PATHmonitorP/$OUTfile $dir1/$PR_filenameOUT[$prc]";
|
||||
$stereo_file_processed++;
|
||||
}
|
||||
|
||||
if ($stereo_file_processed > 0)
|
||||
{
|
||||
`$mix_commandA`;
|
||||
`$mix_commandB`;
|
||||
$stereo_rec_made++;
|
||||
$stereo_rec_ids .= " $PR_recording_id[$prc]";
|
||||
if($DBX){print "Copy commands run: |$stereo_rec_made|$prc|$mix_commandA|$mix_commandB|\n";}
|
||||
}
|
||||
else
|
||||
{
|
||||
if($DBX){print "ERROR, file cannot be processed: |$prc|$parallel_recording_id|$PR_recording_id[$prc]|$PR_filename[$prc]|\n";}
|
||||
}
|
||||
|
||||
$prc++;
|
||||
}
|
||||
|
||||
if (!$T)
|
||||
{
|
||||
`mv -f "$PATHmonitorP/$INfile" "$PATHmonitorTRASH/$INfile"`;
|
||||
`mv -f "$PATHmonitorP/$OUTfile" "$PATHmonitorTRASH/$OUTfile"`;
|
||||
}
|
||||
|
||||
$lengthSQL='';
|
||||
if ( ( ($length_in_sec < 1) || ($length_in_sec =~ /^NULL$/i) || (length($length_in_sec)<1) ) && (length($soxibin) > 3) )
|
||||
{
|
||||
$lengthSQL = ",length_in_sec='$soxi_sec'";
|
||||
}
|
||||
|
||||
$stmtA = "UPDATE recording_log_parallel set recording_status='PROCESSED', processing_log=CONCAT(processing_log,' $stereo_rec_ids') $lengthSQL where parallel_recording_id='$parallel_recording_id';";
|
||||
if($DBX){print STDERR "\n|$stmtA|\n";}
|
||||
$affected_rows = $dbhA->do($stmtA); # or die "Couldn't execute query:|$stmtA|\n";
|
||||
|
||||
### sleep for twenty hundredths of a second to not flood the server with disk activity
|
||||
usleep(1*200*1000);
|
||||
|
||||
$processed_ct++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{$active_recordings++;}
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
|
||||
if($DBX)
|
||||
{
|
||||
$end_epoch = int(time());
|
||||
$run_length = ($end_epoch - $now_epoch);
|
||||
|
||||
print "\nPARALLEL RECORDING Debug output:\n";
|
||||
print "Total parallel files: $i \n";
|
||||
print " Active recordings: $active_recordings \n";
|
||||
print " Processed files: $processed_ct \n";
|
||||
print " Stereo files made: $stereo_rec_made \n";
|
||||
print "\n";
|
||||
print "Run time: $run_length seconds \n";
|
||||
}
|
||||
}
|
||||
}
|
||||
##################################################
|
||||
##### END parallel call recording processing #####
|
||||
##################################################
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
##################################################
|
||||
##### BEGIN stereo call recording processing #####
|
||||
##################################################
|
||||
|
||||
opendir(FILE, "$dir1/");
|
||||
@FILES = readdir(FILE);
|
||||
|
||||
|
||||
### Loop through files first to gather filesizes
|
||||
$i=0;
|
||||
foreach(@FILES)
|
||||
{
|
||||
$FILEsize1[$i] = 0;
|
||||
if ( (length($FILES[$i]) > 4) && (!-d "$dir1/$FILES[$i]") )
|
||||
{
|
||||
$FILEsize1[$i] = (-s "$dir1/$FILES[$i]");
|
||||
if ($DBX) {print "$FILES[$i] $FILEsize1[$i]\n";}
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
|
||||
sleep(15);
|
||||
|
||||
|
||||
### Loop through files a second time to gather filesizes again 5 seconds later
|
||||
$i=0;
|
||||
$active_recordings=0;
|
||||
$delay_ct=0;
|
||||
$processed_ct=0;
|
||||
$post_status_change_ct=0;
|
||||
foreach(@FILES)
|
||||
{
|
||||
$lead_id=0;
|
||||
$vicidial_id='';
|
||||
$FILEsize2[$i] = 0;
|
||||
|
||||
if ( (length($FILES[$i]) > 4) && (!-d "$dir1/$FILES[$i]") )
|
||||
{
|
||||
$FILEsize2[$i] = (-s "$dir1/$FILES[$i]");
|
||||
if ($DBX) {print "$FILES[$i] $FILEsize2[$i]\n\n";}
|
||||
|
||||
if ( ($FILES[$i] !~ /out\.wav|out\.gsm|lost\+found/i) && ($FILEsize1[$i] eq $FILEsize2[$i]) && (length($FILES[$i]) > 4))
|
||||
{
|
||||
$INfile = $FILES[$i];
|
||||
$OUTfile = $FILES[$i];
|
||||
$OUTfile =~ s/-in\.wav/-out.wav/gi;
|
||||
$OUTfile =~ s/-in\.gsm/-out.gsm/gi;
|
||||
$ALLfile = $FILES[$i];
|
||||
$ALLfile =~ s/-in\.wav/-all.wav/gi;
|
||||
$ALLfile =~ s/-in\.gsm/-all.gsm/gi;
|
||||
$SQLFILE = $FILES[$i];
|
||||
$SQLFILE =~ s/-in\.wav|-in\.gsm//gi;
|
||||
$filenameSQL='';
|
||||
|
||||
$length_in_sec=0;
|
||||
$rec_ended=0;
|
||||
$start_epoch=0;
|
||||
$stmtA = "SELECT recording_id,length_in_sec,lead_id,vicidial_id,start_time,end_time,user,UNIX_TIMESTAMP(start_time) from recording_log where filename='$SQLFILE' order by recording_id desc LIMIT 1;";
|
||||
if($DBX){print STDERR "\n|$stmtA|\n";}
|
||||
$sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr;
|
||||
$sthA->execute or die "executing: $stmtA ", $dbhA->errstr;
|
||||
$sthArows=$sthA->rows;
|
||||
if ($sthArows > 0)
|
||||
{
|
||||
@aryA = $sthA->fetchrow_array;
|
||||
$recording_id = $aryA[0];
|
||||
$length_in_sec = $aryA[1];
|
||||
$lead_id = $aryA[2];
|
||||
$vicidial_id = $aryA[3];
|
||||
$start_time = $aryA[4];
|
||||
$end_time = $aryA[5];
|
||||
$user = $aryA[6];
|
||||
$start_epoch = $aryA[7];
|
||||
if (length($end_time) > 15) {$rec_ended=1;}
|
||||
}
|
||||
$sthA->finish();
|
||||
|
||||
$process_recording=1;
|
||||
### this is where code for agent-muted recordings went, if found then delay processing(not available for stereo call recordings)
|
||||
|
||||
### check for POST variables, and delay setting
|
||||
if ( ($delay_post_live > 0) && ($POST > 0) && ($ALLfile =~ /POSTVLC|POSTSP|POSTADDR3|POSTSTATUS/) )
|
||||
{
|
||||
if ($lead_id > 0)
|
||||
{
|
||||
$VLA_count=0;
|
||||
$VAC_count=0;
|
||||
if ( ($start_epoch > 0) && ($start_epoch < $start_epoch_test) )
|
||||
{
|
||||
if ($DBX > 0) {print "DEBUG6: delay processing past server limit, process now: ($start_epoch|$start_epoch_test) |$SQLFILE|ended: $rec_ended|\n";}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($DBX > 0) {print "DEBUG7: delay processing not past server limit yet: ($start_epoch|$start_epoch_test) |$SQLFILE|ended: $rec_ended|\n";}
|
||||
|
||||
### check if any live agents are connected to this lead_id right now
|
||||
$stmtA = "SELECT count(*) from vicidial_live_agents where lead_id='$lead_id';";
|
||||
if($DBX){print STDERR "\n|$stmtA|\n";}
|
||||
$sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr;
|
||||
$sthA->execute or die "executing: $stmtA ", $dbhA->errstr;
|
||||
$sthArows=$sthA->rows;
|
||||
if ($sthArows > 0)
|
||||
{
|
||||
@aryA = $sthA->fetchrow_array;
|
||||
$VLA_count = $aryA[0];
|
||||
}
|
||||
$sthA->finish();
|
||||
|
||||
### check if any live calls are tied to this lead_id right now
|
||||
$stmtA = "SELECT count(*) from vicidial_auto_calls where lead_id='$lead_id';";
|
||||
if($DBX){print STDERR "\n|$stmtA|\n";}
|
||||
$sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr;
|
||||
$sthA->execute or die "executing: $stmtA ", $dbhA->errstr;
|
||||
$sthArows=$sthA->rows;
|
||||
if ($sthArows > 0)
|
||||
{
|
||||
@aryA = $sthA->fetchrow_array;
|
||||
$VAC_count = $aryA[0];
|
||||
}
|
||||
$sthA->finish();
|
||||
}
|
||||
|
||||
if ( ($VLA_count > 0) || ($VAC_count > 0) )
|
||||
{
|
||||
if ($DBX > 0) {print "DEBUG4: delay processing active, do not process: ($VLA_count|$VAC_count) |$SQLFILE|ended: $rec_ended|\n";}
|
||||
$process_recording=0;
|
||||
$delay_ct++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($DBX > 0) {print "DEBUG5: delay processing - no calls or agents found, OK to process: ($VLA_count|$VAC_count) |$SQLFILE|ended: $rec_ended|\n";}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
### process the recording files
|
||||
if ($process_recording > 0)
|
||||
{
|
||||
if ($DB) {print "|$recording_id|$length_in_sec|$INfile| |$ALLfile|\n";}
|
||||
|
||||
# merge Left and Right channels into a single Stereo WAV audio file
|
||||
`$soxbin -M "$dir1/$INfile" "$dir1/$OUTfile" "$dir2/$ALLfile"`;
|
||||
|
||||
if (!$T)
|
||||
{
|
||||
`mv -f "$dir1/$INfile" "$dir2/ORIG/$INfile"`;
|
||||
`mv -f "$dir1/$OUTfile" "$dir2/ORIG/$OUTfile"`;
|
||||
}
|
||||
|
||||
$lengthSQL='';
|
||||
if ( ( ($length_in_sec < 1) || ($length_in_sec =~ /^NULL$/i) || (length($length_in_sec)<1) ) && (length($soxibin) > 3) )
|
||||
{
|
||||
@soxi_output = `$soxibin -D $dir2/$ALLfile`;
|
||||
$soxi_sec = $soxi_output[0];
|
||||
$soxi_sec =~ s/\..*|\n|\r| //gi;
|
||||
$soxi_min = ($soxi_sec / 60);
|
||||
$soxi_min = sprintf("%.2f", $soxi_min);
|
||||
$lengthSQL = ",length_in_sec='$soxi_sec',length_in_min='$soxi_min'";
|
||||
}
|
||||
|
||||
##### BEGIN post call variable replacement #####
|
||||
if ($POST > 0)
|
||||
{
|
||||
if ($ALLfile =~ /POSTVLC|POSTSP|POSTADDR3|POSTSTATUS/)
|
||||
{
|
||||
$origALLfile = $ALLfile;
|
||||
$origSQLFILE = $SQLFILE;
|
||||
$vendor_lead_code=''; $security_phrase=''; $address3=''; $status='';
|
||||
$status_ALL=0;
|
||||
$camp_ALL=0;
|
||||
$camp_status_selected=0;
|
||||
|
||||
if ($status_post =~ /----ALL----/)
|
||||
{
|
||||
$status_ALL++;
|
||||
if($DBX){print "All Statuses: |$status_post|$status_ALL|\n";}
|
||||
}
|
||||
|
||||
if ($camp_post =~ /----ALL----/)
|
||||
{
|
||||
$camp_ALL++;
|
||||
if($DBX){print "All Campaigs and Ingroups: |$camp_post|$camp_ALL|\n";}
|
||||
}
|
||||
|
||||
if ( ($camp_ALL < 1) || ($status_ALL < 1) )
|
||||
{
|
||||
$camp_postSQL='';
|
||||
if ($camp_ALL < 1)
|
||||
{
|
||||
$camp_postSQL = $camp_post;
|
||||
$camp_postSQL =~ s/---/','/gi;
|
||||
$camp_postSQL = "and campaign_id IN('$camp_postSQL')";
|
||||
}
|
||||
if ($vicidial_id =~ /\./)
|
||||
{
|
||||
$log_lookupSQL = "SELECT status from vicidial_log where uniqueid='$vicidial_id' and lead_id='$lead_id' $camp_postSQL;";
|
||||
}
|
||||
else
|
||||
{
|
||||
$log_lookupSQL = "SELECT status from vicidial_closer_log where closecallid='$vicidial_id' and lead_id='$lead_id' $camp_postSQL;";
|
||||
}
|
||||
if($DBX){print STDERR "\n|$log_lookupSQL|\n";}
|
||||
$sthA = $dbhA->prepare($log_lookupSQL) or die "preparing: ",$dbhA->errstr;
|
||||
$sthA->execute or die "executing: $log_lookupSQL ", $dbhA->errstr;
|
||||
$sthArows=$sthA->rows;
|
||||
if ($sthArows > 0)
|
||||
{
|
||||
@aryA = $sthA->fetchrow_array;
|
||||
$lead_status = $aryA[0];
|
||||
if ($status_ALL > 0)
|
||||
{$camp_status_selected++;}
|
||||
else
|
||||
{
|
||||
@status_vars = split(/---/,$status_post);
|
||||
$fc=0;
|
||||
foreach(@status_vars)
|
||||
{
|
||||
$status_temp = $status_vars[$fc];
|
||||
if ($status_vars[$fc] =~ /\*/)
|
||||
{
|
||||
$status_temp =~ s/\*/.*/gi;
|
||||
if ( ($lead_status =~ /^$status_temp/) && ($status_vars[$fc] =~ /\*$/) )
|
||||
{$camp_status_selected++;}
|
||||
if ( ($lead_status =~ /$status_temp$/) && ($status_vars[$fc] =~ /^\*/) )
|
||||
{$camp_status_selected++;}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($lead_status =~ /^$status_temp$/)
|
||||
{$camp_status_selected++;}
|
||||
}
|
||||
if ($DBX) {print " POST processing DEBUG: $fc|$status_temp|$lead_status|$lead_id|$vicidial_id|$ALLfile|\n";}
|
||||
$fc++;
|
||||
}
|
||||
}
|
||||
if ($DB) {print " POST processing SELECT: |$camp_status_selected|$sthArows|$camp_postSQL|$camp_ALL|$status_post|$status_ALL|$ALLfile|\n";}
|
||||
}
|
||||
else
|
||||
{if ($DB) {print " POST processing ERROR: lead not found: |$lead_id|$ALLfile|\n";} }
|
||||
$sthA->finish();
|
||||
}
|
||||
|
||||
if ( ( ($camp_ALL > 0) && ($status_ALL > 0) ) || ($camp_status_selected > 0) )
|
||||
{
|
||||
$stmtA = "SELECT vendor_lead_code,security_phrase,address3,status from vicidial_list where lead_id='$lead_id' LIMIT 1;";
|
||||
if($DBX){print STDERR "\n|$stmtA|\n";}
|
||||
$sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr;
|
||||
$sthA->execute or die "executing: $stmtA ", $dbhA->errstr;
|
||||
$sthArows=$sthA->rows;
|
||||
if ($sthArows > 0)
|
||||
{
|
||||
@aryA = $sthA->fetchrow_array;
|
||||
$vendor_lead_code = $aryA[0];
|
||||
$security_phrase = $aryA[1];
|
||||
$address3 = $aryA[2];
|
||||
$status = $aryA[3];
|
||||
|
||||
$vendor_lead_code =~ s/[^a-zA-Z0-9_-]//gi;
|
||||
$security_phrase =~ s/[^a-zA-Z0-9_-]//gi;
|
||||
$address3 =~ s/[^a-zA-Z0-9_-]//gi;
|
||||
$status =~ s/[^a-zA-Z0-9_-]//gi;
|
||||
}
|
||||
else
|
||||
{if ($DB) {print " POST processing ERROR: lead not found: |$lead_id|$ALLfile|\n";} }
|
||||
$sthA->finish();
|
||||
|
||||
if ( ($status_post_logs > 0) && ($ALLfile =~ /POSTSTATUS/) )
|
||||
{
|
||||
$log_status = $status;
|
||||
if ($vicidial_id =~ /\./)
|
||||
{
|
||||
$log_lookupSQL = "SELECT status from vicidial_log where uniqueid='$vicidial_id' and lead_id='$lead_id' and user='$user' order by call_date desc limit 1;";
|
||||
}
|
||||
else
|
||||
{
|
||||
$log_lookupSQL = "SELECT status from vicidial_closer_log where closecallid='$vicidial_id' and lead_id='$lead_id' and user='$user' order by call_date desc limit 1;";
|
||||
}
|
||||
if($DBX){print STDERR "\n|$log_lookupSQL|\n";}
|
||||
$sthA = $dbhA->prepare($log_lookupSQL) or die "preparing: ",$dbhA->errstr;
|
||||
$sthA->execute or die "executing: $log_lookupSQL ", $dbhA->errstr;
|
||||
$sthArows=$sthA->rows;
|
||||
if ($sthArows > 0)
|
||||
{
|
||||
@aryA = $sthA->fetchrow_array;
|
||||
$log_status = $aryA[0];
|
||||
}
|
||||
|
||||
if ($log_status ne $status)
|
||||
{$post_status_change_ct++;}
|
||||
if ($DB) {print " POST processing Log status override: lead: |$status| log: |$log_status| $post_status_change_ct \n";}
|
||||
$status = $log_status;
|
||||
}
|
||||
$ALLfile =~ s/POSTVLC/$vendor_lead_code/gi;
|
||||
$ALLfile =~ s/POSTSP/$security_phrase/gi;
|
||||
$ALLfile =~ s/POSTADDR3/$address3/gi;
|
||||
$ALLfile =~ s/POSTSTATUS/$status/gi;
|
||||
$SQLFILE =~ s/POSTVLC/$vendor_lead_code/gi;
|
||||
$SQLFILE =~ s/POSTSP/$security_phrase/gi;
|
||||
$SQLFILE =~ s/POSTADDR3/$address3/gi;
|
||||
$SQLFILE =~ s/POSTSTATUS/$status/gi;
|
||||
$filenameSQL = ",filename='$SQLFILE'";
|
||||
|
||||
`mv -f "$dir2/$origALLfile" "$dir2/$ALLfile"`;
|
||||
|
||||
if ($DB) {print " POST processing COMPLETE: old: |$origALLfile| new: |$ALLfile|\n";}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($DB) {print " POST processing SKIPPED: |$camp_ALL|$status_ALL|$camp_status_selected|$lead_id|$vicidial_id|$ALLfile|\n";}
|
||||
|
||||
if ($CLEAR_POST > 0)
|
||||
{
|
||||
$ALLfile =~ s/POSTVLC//gi;
|
||||
$ALLfile =~ s/POSTSP//gi;
|
||||
$ALLfile =~ s/POSTADDR3//gi;
|
||||
$ALLfile =~ s/POSTSTATUS//gi;
|
||||
$SQLFILE =~ s/POSTVLC//gi;
|
||||
$SQLFILE =~ s/POSTSP//gi;
|
||||
$SQLFILE =~ s/POSTADDR3//gi;
|
||||
$SQLFILE =~ s/POSTSTATUS//gi;
|
||||
$filenameSQL = ",filename='$SQLFILE'";
|
||||
|
||||
`mv -f "$dir2/$origALLfile" "$dir2/$ALLfile"`;
|
||||
|
||||
if ($DB) {print " CLEAR POST COMPLETE: old: |$origALLfile| new: |$ALLfile|\n";}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{if ($DB) {print " POST processing ERROR: No variables found: |$ALLfile|\n";} }
|
||||
}
|
||||
##### END post call variable replacement #####
|
||||
|
||||
$HTTP='http';
|
||||
if ($HTTPS > 0) {$HTTP='https';}
|
||||
$stmtA = "UPDATE recording_log set location='$HTTP://$server_ip/RECORDINGS/$ALLfile' $filenameSQL $lengthSQL where recording_id='$recording_id';";
|
||||
if($DBX){print STDERR "\n|$stmtA|\n";}
|
||||
$affected_rows = $dbhA->do($stmtA); # or die "Couldn't execute query:|$stmtA|\n";
|
||||
|
||||
$stmtA = "UPDATE recording_live set end_time=NOW(),recording_status='FINISHED FILE-MERGE' where recording_id='$recording_id' and recording_status='STARTED';";
|
||||
if($DBX){print STDERR "\n|$stmtA|\n";}
|
||||
$affected_rows = $dbhA->do($stmtA); # or die "Couldn't execute query:|$stmtA|\n";
|
||||
|
||||
### sleep for twenty hundredths of a second to not flood the server with disk activity
|
||||
usleep(1*200*1000);
|
||||
|
||||
$processed_ct++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{$active_recordings++;}
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
|
||||
if($DBX)
|
||||
{
|
||||
$end_epoch = int(time());
|
||||
$run_length = ($end_epoch - $now_epoch);
|
||||
|
||||
print "\nDebug output:\n";
|
||||
print "Total files: $i \n";
|
||||
print " Active recordings: $active_recordings \n";
|
||||
print " Delayed processing: $delay_ct \n";
|
||||
print " Processed files: $processed_ct \n";
|
||||
print " POST log status diff: $post_status_change_ct \n";
|
||||
print "\n";
|
||||
print "Run time: $run_length seconds \n";
|
||||
}
|
||||
|
||||
################################################
|
||||
##### END stereo call recording processing #####
|
||||
################################################
|
||||
|
||||
|
||||
if ($DB) {print "DONE... EXITING\n\n";}
|
||||
|
||||
$sthA->finish();
|
||||
$dbhA->disconnect();
|
||||
|
||||
|
||||
exit;
|
||||
@@ -12,8 +12,8 @@
|
||||
# ### recording mixing/compressing/ftping scripts
|
||||
##0,3,6,9,12,15,18,21,24,27,30,33,36,39,42,45,48,51,54,57 * * * * /usr/share/astguiclient/AST_CRON_audio_1_move_mix.pl
|
||||
# 0,3,6,9,12,15,18,21,24,27,30,33,36,39,42,45,48,51,54,57 * * * * /usr/share/astguiclient/AST_CRON_audio_1_move_VDonly.pl
|
||||
# 1,4,7,10,13,16,19,22,25,28,31,34,37,40,43,46,49,52,55,58 * * * * /usr/share/astguiclient/AST_CRON_audio_2_compress.pl --GSM
|
||||
# 2,5,8,11,14,17,20,23,26,29,32,35,38,41,44,47,50,53,56,59 * * * * /usr/share/astguiclient/AST_CRON_audio_3_ftp.pl --GSM
|
||||
# 1,4,7,10,13,16,19,22,25,28,31,34,37,40,43,46,49,52,55,58 * * * * /usr/share/astguiclient/AST_CRON_audio_2_compress.pl --MP3
|
||||
# 2,5,8,11,14,17,20,23,26,29,32,35,38,41,44,47,50,53,56,59 * * * * /usr/share/astguiclient/AST_CRON_audio_3_ftp.pl --MP3
|
||||
#
|
||||
# FLAGS FOR COMPRESSION CODECS
|
||||
# --GSM = GSM 6.10 codec
|
||||
@@ -28,7 +28,7 @@
|
||||
#
|
||||
# This program assumes that recordings are saved by Asterisk as .wav
|
||||
#
|
||||
# Copyright (C) 2024 Matt Florell <vicidial@gmail.com> LICENSE: AGPLv2
|
||||
# Copyright (C) 2025 Matt Florell <vicidial@gmail.com> LICENSE: AGPLv2
|
||||
#
|
||||
#
|
||||
# 80302-1958 - First Build
|
||||
@@ -40,6 +40,7 @@
|
||||
# 170212-0732 - Added --file-sorting option to put files into dated directories (THIS WILL NOT ALLOW FTP ARCHIVING)
|
||||
# 230201-0007 - Allowed for handling of stereo gateway recordings
|
||||
# 240213-1146 - Added --GATEWAY option
|
||||
# 250909-1030 - Added code to detect stereo audio files for MP3 stereo processing
|
||||
#
|
||||
|
||||
$GSM=0; $MP3=0; $OGG=0; $GSW=0;
|
||||
@@ -251,6 +252,22 @@ if ( ($GSM > 0) || ($OGG > 0) || ($GSW > 0) )
|
||||
}
|
||||
}
|
||||
|
||||
### find soxi to gather the length/channels info if needed
|
||||
$soxibin = '';
|
||||
if ( -e ('/usr/bin/soxi')) {$soxibin = '/usr/bin/soxi';}
|
||||
else
|
||||
{
|
||||
if ( -e ('/usr/local/bin/soxi')) {$soxibin = '/usr/local/bin/soxi';}
|
||||
else
|
||||
{
|
||||
if ( -e ('/usr/sbin/soxi')) {$soxibin = '/usr/sbin/soxi';}
|
||||
else
|
||||
{
|
||||
if ($DB) {print "Can't find soxi binary! No length calculations will be available...\n";}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($MP3 > 0)
|
||||
{
|
||||
### find lame mp3 encoder binary to do the compression
|
||||
@@ -381,9 +398,18 @@ foreach(@FILES)
|
||||
$MP3file =~ s/-all\.wav/-all.mp3/gi;
|
||||
$MP3file =~ s/\.wav|\.gsm/.mp3/gi;
|
||||
|
||||
$soxi_channels=1;
|
||||
if (length($soxibin) > 3)
|
||||
{
|
||||
@soxi_output = `$soxibin -c $dir2/$ALLfile`;
|
||||
$soxi_channels = $soxi_output[0];
|
||||
$soxi_channels =~ s/\D//gi;
|
||||
$soxi_channels = ($soxi_channels + 0);
|
||||
}
|
||||
|
||||
if ($DB) {print "|$recording_id|$ALLfile|$dir2/$location$MP3file| |$SQLfile|\n";}
|
||||
|
||||
if ($GATEWAY > 0)
|
||||
if ( ($GATEWAY > 0) || ($soxi_channels > 1) )
|
||||
{
|
||||
`$lamebin -b 16 -m s --silent "$dir2/$ALLfile" "$dir2/$location$MP3file"`;
|
||||
}
|
||||
|
||||
+115
-3
@@ -9,7 +9,7 @@
|
||||
# !!!!!!!! IMPORTANT !!!!!!!!!!!!!!!!!!
|
||||
# THIS SCRIPT SHOULD ONLY BE RUN ON ONE SERVER ON YOUR CLUSTER
|
||||
#
|
||||
# Copyright (C) 2024 Matt Florell <vicidial@gmail.com> LICENSE: AGPLv2
|
||||
# Copyright (C) 2025 Matt Florell <vicidial@gmail.com> LICENSE: AGPLv2
|
||||
#
|
||||
# CHANGES
|
||||
# 60717-1214 - changed to DBI by Marin Blu
|
||||
@@ -36,6 +36,7 @@
|
||||
# 231228-1901 - Added optimizing of vicidial_3way_press_multi records
|
||||
# 240219-0811 - Added optimizing of server_live_... tables
|
||||
# 240709-1300 - Added Validate XFER vicidial_auto_calls: "--check-xfers" flag
|
||||
# 250914-1537 - Added archiving of recording_live table
|
||||
#
|
||||
|
||||
$session_flush=0;
|
||||
@@ -44,6 +45,7 @@ $reset_stuck_leads=0;
|
||||
$stuck_lists='';
|
||||
$stuck_listsSQL='';
|
||||
$check_xfers=0;
|
||||
$vicidial_recording_limit=60;
|
||||
|
||||
### begin parsing run-time options ###
|
||||
if (length($ARGV[0])>1)
|
||||
@@ -293,19 +295,32 @@ $dbhA = DBI->connect("DBI:mysql:$VARDB_database:$VARDB_server:$VARDB_port", "$VA
|
||||
or die "Couldn't connect to database: " . DBI->errstr;
|
||||
|
||||
### Grab Server values from the database
|
||||
$stmtA = "SELECT vd_server_logs FROM servers where server_ip = '$VARserver_ip';";
|
||||
$stmtA = "SELECT vd_server_logs,vicidial_recording_limit FROM servers where server_ip = '$VARserver_ip';";
|
||||
$sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr;
|
||||
$sthA->execute or die "executing: $stmtA ", $dbhA->errstr;
|
||||
$sthArows=$sthA->rows;
|
||||
if ($sthArows > 0)
|
||||
{
|
||||
@aryA = $sthA->fetchrow_array;
|
||||
$DBvd_server_logs = $aryA[0];
|
||||
$DBvd_server_logs = $aryA[0];
|
||||
$vicidial_recording_limit = $aryA[1];
|
||||
if ($DBvd_server_logs =~ /Y/) {$SYSLOG = '1';}
|
||||
else {$SYSLOG = '0';}
|
||||
}
|
||||
$sthA->finish();
|
||||
|
||||
($Rsec,$Rmin,$Rhour,$Rmday,$Rmon,$Ryear,$Rwday,$Ryday,$Risdst) = localtime(time() - ($vicidial_recording_limit * 60));
|
||||
$Ryear = ($Ryear + 1900);
|
||||
$Ryy = $Ryear; $Ryy =~ s/^..//gi;
|
||||
$Rmon++;
|
||||
if ($Rmon < 10) {$Rmon = "0$Rmon";}
|
||||
if ($Rmday < 10) {$Rmday = "0$Rmday";}
|
||||
if ($Rhour < 10) {$Rhour = "0$Rhour";}
|
||||
if ($Rmin < 10) {$Rmin = "0$Rmin";}
|
||||
if ($Rsec < 10) {$Rsec = "0$Rsec";}
|
||||
$SQLdate_REC_limit="$Ryear-$Rmon-$Rmday $Rhour:$Rmin:$Rsec";
|
||||
|
||||
|
||||
### Grab system_settings values from the database
|
||||
$stmtA = "SELECT sip_event_logging,enable_auto_reports FROM system_settings limit 1;";
|
||||
$sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr;
|
||||
@@ -1002,6 +1017,103 @@ if ($check_xfers > 0)
|
||||
}
|
||||
|
||||
|
||||
### BEGIN archive recording_live that are FINISHED ###
|
||||
$rl_count=0;
|
||||
$stmtA = "SELECT count(*) FROM recording_live;";
|
||||
$sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr;
|
||||
$sthA->execute or die "executing: $stmtA ", $dbhA->errstr;
|
||||
$sthArowsACTIVE=$sthA->rows;
|
||||
if ($DBX) {print "DEBUG: $sthArowsACTIVE|$stmtA|\n";}
|
||||
if ($sthArowsACTIVE > 0)
|
||||
{
|
||||
@aryA = $sthA->fetchrow_array;
|
||||
$rl_count = $aryA[0];
|
||||
}
|
||||
$sthA->finish();
|
||||
|
||||
if ($rl_count > 0)
|
||||
{
|
||||
$stmtA = "INSERT IGNORE INTO recording_live_log SELECT * FROM recording_live where end_time <= \"$SQLdate_NOW\" and end_time IS NOT NULL and recording_status LIKE \"FINISHED%\";";
|
||||
$sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr;
|
||||
$sthA->execute or die "executing: $stmtA ", $dbhA->errstr;
|
||||
$sthArows = $sthA->rows;
|
||||
if (!$Q) {print "$sthArows rows inserted into recording_live_log table\n";}
|
||||
|
||||
if ($sthArows > 0)
|
||||
{
|
||||
$stmtA = "DELETE FROM recording_live where end_time <= \"$SQLdate_NOW\" and end_time IS NOT NULL and recording_status LIKE \"FINISHED%\";";
|
||||
$sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr;
|
||||
$sthA->execute or die "executing: $stmtA ", $dbhA->errstr;
|
||||
$sthArows = $sthA->rows;
|
||||
if (!$Q) {print "$sthArows rows deleted from recording_live table\n";}
|
||||
}
|
||||
|
||||
### Gather older STARTED recording_live records from the database to confirm they are still active
|
||||
$stmtA = "SELECT user,lead_id,recording_id FROM recording_live where start_time <= \"$SQLdate_REC_limit\" and recording_status='STARTED';";
|
||||
$sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr;
|
||||
$sthA->execute or die "executing: $stmtA ", $dbhA->errstr;
|
||||
$sthArowsRECS=$sthA->rows;
|
||||
if ($DBX) {print "DEBUG: $sthArowsRECS|$stmtA|\n";}
|
||||
$orc=0;
|
||||
while ($sthArowsRECS > $orc)
|
||||
{
|
||||
@aryA = $sthA->fetchrow_array;
|
||||
$OR_user[$orc] = $aryA[0];
|
||||
$OR_lead_id[$orc] = $aryA[1];
|
||||
$OR_recording_id[$orc] = $aryA[2];
|
||||
$orc++;
|
||||
}
|
||||
$sthA->finish();
|
||||
|
||||
$orc=0;
|
||||
while ($sthArowsRECS > $orc)
|
||||
{
|
||||
$al_count=0;
|
||||
$stmtA = "SELECT count(*) FROM vicidial_live_agents where user='$OR_user[$orc]' and lead_id='$OR_lead_id[$orc]';";
|
||||
$sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr;
|
||||
$sthA->execute or die "executing: $stmtA ", $dbhA->errstr;
|
||||
$sthArowsAGNT=$sthA->rows;
|
||||
if ($DBX) {print "DEBUG: $sthArowsAGNT|$stmtA|\n";}
|
||||
if ($sthArowsAGNT > 0)
|
||||
{
|
||||
@aryA = $sthA->fetchrow_array;
|
||||
$al_count = $aryA[0];
|
||||
}
|
||||
$sthA->finish();
|
||||
|
||||
if ($al_count < 1)
|
||||
{
|
||||
$stmtA = "UPDATE recording_live SET recording_status='FINISHED CHECK' where recording_id='$OR_recording_id[$orc]';";
|
||||
$sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr;
|
||||
$sthA->execute or die "executing: $stmtA ", $dbhA->errstr;
|
||||
$sthArows = $sthA->rows;
|
||||
if ($DBX) {print "$sthArows rows set to finished in recording_live table: |$OR_recording_id[$orc]|$OR_user[$orc]|$OR_lead_id[$orc]|\n";}
|
||||
|
||||
$stmtA = "INSERT IGNORE INTO recording_live_log SELECT * FROM recording_live where recording_id='$OR_recording_id[$orc]';";
|
||||
$sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr;
|
||||
$sthA->execute or die "executing: $stmtA ", $dbhA->errstr;
|
||||
$sthArows = $sthA->rows;
|
||||
if (!$Q) {print "$sthArows rows inserted into recording_live_log table: |$OR_recording_id[$orc]|$OR_user[$orc]|$OR_lead_id[$orc]|\n";}
|
||||
|
||||
$stmtA = "DELETE FROM recording_live where recording_id='$OR_recording_id[$orc]';";
|
||||
$sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr;
|
||||
$sthA->execute or die "executing: $stmtA ", $dbhA->errstr;
|
||||
$sthArows = $sthA->rows;
|
||||
if (!$Q) {print "$sthArows rows delete from recording_live_log table: |$OR_recording_id[$orc]|$OR_user[$orc]|$OR_lead_id[$orc]|\n";}
|
||||
}
|
||||
$orc++;
|
||||
}
|
||||
|
||||
# optimize recording_live table
|
||||
$stmtA = "optimize table recording_live;";
|
||||
$sthA = $dbhA->prepare($stmtA) or die "preparing: ",$dbhA->errstr;
|
||||
$sthA->execute or die "executing: $stmtA ", $dbhA->errstr;
|
||||
|
||||
$sthA->finish();
|
||||
}
|
||||
### END archive recording_live that are FINISHED ###
|
||||
|
||||
|
||||
$dbhA->disconnect();
|
||||
|
||||
exit;
|
||||
|
||||
Reference in New Issue
Block a user