aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormartinp <martinp@f38db490-d61c-443f-a65b-d21fe96a405b>2004-02-03 16:57:00 +0000
committermartinp <martinp@f38db490-d61c-443f-a65b-d21fe96a405b>2004-02-03 16:57:00 +0000
commitf38bc8131c9eda8d0b0eabaafbaa53f4247989c4 (patch)
tree737412e9d633692be843c8429cc62df22fc5cfd7
parent30674920f6b94533e355a87eaf823cf14bcba9ef (diff)
Add recording agent's calls patch. Basically the call starts recording when the agent picks up and the file is stamped with the agent's id and the timestamp. Also optionally a URL link to that file may be inserted in the userfield of the CDR record. By default the recorded file will be mixed if soxmix is available.
git-svn-id: http://svn.digium.com/svn/asterisk/trunk@2121 f38db490-d61c-443f-a65b-d21fe96a405b
-rwxr-xr-xchannels/chan_agent.c79
-rwxr-xr-xconfigs/agents.conf.sample23
-rwxr-xr-xformats/format_gsm.c15
-rwxr-xr-xformats/format_wav_gsm.c15
-rwxr-xr-xinclude/asterisk/monitor.h4
-rwxr-xr-xres/res_monitor.c51
-rwxr-xr-xres/res_parking.c12
7 files changed, 186 insertions, 13 deletions
diff --git a/channels/chan_agent.c b/channels/chan_agent.c
index 593de03cf..90734a61b 100755
--- a/channels/chan_agent.c
+++ b/channels/chan_agent.c
@@ -72,6 +72,7 @@ static char *descrip2 =
static char moh[80] = "default";
#define AST_MAX_AGENT 80 /* Agent ID or Password max length */
+#define AST_MAX_BUF 256
static int capability = -1;
@@ -86,6 +87,13 @@ static ast_mutex_t usecnt_lock = AST_MUTEX_INITIALIZER;
/* Protect the interface list (of sip_pvt's) */
static ast_mutex_t agentlock = AST_MUTEX_INITIALIZER;
+int recordagentcalls = 0;
+char recordformat[AST_MAX_BUF];
+char recordformatext[AST_MAX_BUF];
+int createlink = 0;
+char urlprefix[AST_MAX_BUF];
+char savecallsin[AST_MAX_BUF];
+
static struct agent_pvt {
ast_mutex_t lock; /* Channel private lock */
int dead; /* Poised for destruction? */
@@ -164,7 +172,7 @@ static void agent_unlink(struct agent_pvt *agent)
static struct agent_pvt *add_agent(char *agent, int pending)
{
- char tmp[256];
+ char tmp[AST_MAX_BUF];
char *password=NULL, *name=NULL;
struct agent_pvt *p, *prev;
@@ -244,6 +252,33 @@ static int agent_answer(struct ast_channel *ast)
return -1;
}
+static int agent_start_monitoring(struct ast_channel *ast, int needlock)
+{
+ struct agent_pvt *p = ast->pvt->pvt;
+ char tmp[AST_MAX_BUF],tmp2[AST_MAX_BUF], *pointer;
+ char filename[AST_MAX_BUF];
+ int res = -1;
+ if (!p)
+ return -1;
+ if (!ast->monitor) {
+ snprintf(filename, sizeof(filename), "agent-%s-%s",p->agent, ast->uniqueid);
+ snprintf(tmp, sizeof(tmp), "%s%s",savecallsin ? savecallsin : "", filename);
+ if ((pointer = strchr(tmp, '.')))
+ *pointer = '-';
+ ast_monitor_start(ast, recordformat, tmp, needlock);
+ ast_monitor_setjoinfiles(ast, 1);
+ snprintf(tmp2, sizeof(tmp2), "%s%s.%s", urlprefix ? urlprefix : "", filename, recordformatext);
+#if 0
+ ast_verbose("name is %s, link is %s\n",tmp, tmp2);
+#endif
+ if (!ast->cdr)
+ ast->cdr = ast_cdr_alloc();
+ ast_cdr_setuserfield(ast, tmp2);
+ res = 0;
+ } else
+ ast_log(LOG_ERROR, "Recording already started on that call.\n");
+ return res;
+}
static struct ast_frame *agent_read(struct ast_channel *ast)
{
struct agent_pvt *p = ast->pvt->pvt;
@@ -302,6 +337,8 @@ static struct ast_frame *agent_read(struct ast_channel *ast)
}
CLEANUP(ast,p);
ast_mutex_unlock(&p->lock);
+ if (f == &answer_frame)
+ agent_start_monitoring(ast,0);
return f;
}
@@ -430,6 +467,7 @@ static int agent_call(struct ast_channel *ast, char *dest, int timeout)
ast_setstate(ast, AST_STATE_RINGING);
else {
ast_setstate(ast, AST_STATE_UP);
+ agent_start_monitoring(ast,0);
p->acknowledged = 1;
}
res = 0;
@@ -703,6 +741,14 @@ static int read_agent_config(void)
p = p->next;
}
strcpy(moh, "default");
+ /* set the default recording values */
+ recordagentcalls = 0;
+ createlink = 0;
+ strcpy(recordformat, "wav");
+ strcpy(recordformatext, "wav");
+ strcpy(urlprefix, "");
+ strcpy(savecallsin, "");
+
v = ast_variable_browse(cfg, "agents");
while(v) {
/* Create the interface list */
@@ -727,6 +773,27 @@ static int read_agent_config(void)
wrapuptime = 0;
} else if (!strcasecmp(v->name, "musiconhold")) {
strncpy(moh, v->value, sizeof(moh) - 1);
+ } else if (!strcasecmp(v->name, "recordagentcalls")) {
+ recordagentcalls = ast_true(v->value);
+ } else if (!strcasecmp(v->name, "createlink")) {
+ createlink = ast_true(v->value);
+ } else if (!strcasecmp(v->name, "recordformat")) {
+ strncpy(recordformat, v->value, sizeof(recordformat) - 1);
+ if (!strcasecmp(v->value, "wav49"))
+ strcpy(recordformatext, "WAV");
+ else
+ strncpy(recordformatext, v->value, sizeof(recordformat) - 1);
+ } else if (!strcasecmp(v->name, "urlprefix")) {
+ strncpy(urlprefix, v->value, sizeof(urlprefix) - 2);
+ if (urlprefix[strlen(urlprefix) - 1] != '/')
+ strcat(urlprefix, "/");
+ } else if (!strcasecmp(v->name, "savecallsin")) {
+ if (v->value[0] == '/')
+ strncpy(savecallsin, v->value, sizeof(savecallsin) - 2);
+ else
+ snprintf(savecallsin, sizeof(savecallsin) - 2, "/%s", v->value);
+ if (savecallsin[strlen(savecallsin) - 1] != '/')
+ strcat(savecallsin, "/");
}
v = v->next;
}
@@ -965,10 +1032,10 @@ static int powerof(unsigned int v)
static int agents_show(int fd, int argc, char **argv)
{
struct agent_pvt *p;
- char username[256];
- char location[256];
- char talkingto[256];
- char moh[256];
+ char username[AST_MAX_BUF];
+ char location[AST_MAX_BUF];
+ char talkingto[AST_MAX_BUF];
+ char moh[AST_MAX_BUF];
if (argc != 2)
return RESULT_SHOWUSAGE;
@@ -1107,7 +1174,7 @@ static int __login_exec(struct ast_channel *chan, void *data, int callbackmode)
!strcmp(p->password, pass) && !p->pending) {
if (!p->chan) {
if (callbackmode) {
- char tmpchan[256] = "";
+ char tmpchan[AST_MAX_BUF] = "";
int pos = 0;
/* Retrieve login chan */
for (;;) {
diff --git a/configs/agents.conf.sample b/configs/agents.conf.sample
index 015a202ea..a015ac130 100755
--- a/configs/agents.conf.sample
+++ b/configs/agents.conf.sample
@@ -33,6 +33,29 @@
;group=1,2
;group=
;
+; --------------------------------------------------
+; This section is devoted to recording agent's calls
+; The keywords are global to the chan_agent channel driver
+;
+; Enable recording calls addressed to agents. It's turned off by default.
+;recordagentcalls=yes
+;
+; The format to be used to record the calls: wav, gsm, wav49.
+; By default its "wav".
+;recordformat=gsm
+;
+; Insert into CDR userfield a name of the the created recording
+; By default it's turned off.
+;createlink=yes
+;
+; The text to be added to the name of the recording. Allows forming a url link.
+;urlprefix=http://localhost/calls/
+;
+; The optional directory to save the conversations in. The default is
+; /var/spool/asterisk/monitor
+;savecallsin=/var/calls
+; --------------------------------------------------
+;
; This section contains the agent definitions, in the form:
;
; agent => agentid,agentpassword,name
diff --git a/formats/format_gsm.c b/formats/format_gsm.c
index 88ca9fde7..4ac2b5a5d 100755
--- a/formats/format_gsm.c
+++ b/formats/format_gsm.c
@@ -33,11 +33,18 @@
#endif
#include "msgsm.h"
-
/* Some Ideas for this code came from makegsme.c by Jeffrey Chilton */
/* Portions of the conversion code are by guido@sienanet.it */
+/* silent gsm frame */
+/* begin binary data: */
+char gsm_silence[] = /* 33 */
+{0xD8,0x20,0xA2,0xE1,0x5A,0x50,0x00,0x49,0x24,0x92,0x49,0x24,0x50,0x00,0x49
+,0x24,0x92,0x49,0x24,0x50,0x00,0x49,0x24,0x92,0x49,0x24,0x50,0x00,0x49,0x24
+,0x92,0x49,0x24};
+/* end binary data. size = 33 bytes */
+
struct ast_filestream {
void *reserved[AST_RESERVED_POINTERS];
/* Believe it or not, we must decode/recode to account for the
@@ -193,6 +200,12 @@ static int gsm_seek(struct ast_filestream *fs, long sample_offset, int whence)
if (whence != SEEK_FORCECUR) {
offset = (offset > max)?max:offset;
offset = (offset < min)?min:offset;
+ } else if (offset > max) {
+ int i;
+ lseek(fs->fd, 0, SEEK_END);
+ for (i=0; i< (offset - max) / 33; i++) {
+ write(fs->fd, gsm_silence, 33);
+ }
}
return lseek(fs->fd, offset, SEEK_SET);
}
diff --git a/formats/format_wav_gsm.c b/formats/format_wav_gsm.c
index 009c576bb..5b502ff32 100755
--- a/formats/format_wav_gsm.c
+++ b/formats/format_wav_gsm.c
@@ -37,6 +37,15 @@
/* Portions of the conversion code are by guido@sienanet.it */
+/* begin binary data: */
+char msgsm_silence[] = /* 65 */
+{0x48,0x17,0xD6,0x84,0x02,0x80,0x24,0x49,0x92,0x24,0x89,0x02,0x80,0x24,0x49
+,0x92,0x24,0x89,0x02,0x80,0x24,0x49,0x92,0x24,0x89,0x02,0x80,0x24,0x49,0x92
+,0x24,0x09,0x82,0x74,0x61,0x4D,0x28,0x00,0x48,0x92,0x24,0x49,0x92,0x28,0x00
+,0x48,0x92,0x24,0x49,0x92,0x28,0x00,0x48,0x92,0x24,0x49,0x92,0x28,0x00,0x48
+,0x92,0x24,0x49,0x92,0x00};
+/* end binary data. size = 65 bytes */
+
struct ast_filestream {
void *reserved[AST_RESERVED_POINTERS];
/* Believe it or not, we must decode/recode to account for the
@@ -487,6 +496,12 @@ static int wav_seek(struct ast_filestream *fs, long sample_offset, int whence)
if (whence != SEEK_FORCECUR) {
offset = (offset < min)?min:offset;
offset = (offset > max)?max:offset;
+ } else if (offset > max) {
+ int i;
+ lseek(fs->fd, 0, SEEK_END);
+ for (i=0; i< (offset - max) / 65; i++) {
+ write(fs->fd, msgsm_silence, 65);
+ }
}
fs->secondhalf = 0;
return lseek(fs->fd, offset, SEEK_SET);
diff --git a/include/asterisk/monitor.h b/include/asterisk/monitor.h
index 206b3b557..b62499d1f 100755
--- a/include/asterisk/monitor.h
+++ b/include/asterisk/monitor.h
@@ -15,7 +15,9 @@ struct ast_channel_monitor
char read_filename[ FILENAME_MAX ];
char write_filename[ FILENAME_MAX ];
char filename_base[ FILENAME_MAX ];
+ int filename_changed;
char *format;
+ int joinfiles;
int (*stop)( struct ast_channel *chan, int need_lock);
};
@@ -30,4 +32,6 @@ int ast_monitor_stop( struct ast_channel *chan, int need_lock);
int ast_monitor_change_fname( struct ast_channel *chan,
const char *fname_base, int need_lock );
+void ast_monitor_setjoinfiles(struct ast_channel *chan, int turnon);
+
#endif /* _MONITOR_H */
diff --git a/res/res_monitor.c b/res/res_monitor.c
index 7cf22e812..676cb3258 100755
--- a/res/res_monitor.c
+++ b/res/res_monitor.c
@@ -4,6 +4,7 @@
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
+#include <libgen.h> //dirname()
#include <asterisk/lock.h>
#include <asterisk/channel.h>
@@ -48,6 +49,7 @@ int ast_monitor_start( struct ast_channel *chan, const char *format_spec,
const char *fname_base, int need_lock )
{
int res = 0;
+ char tmp[256];
if( need_lock ) {
if (ast_mutex_lock(&chan->lock)) {
@@ -73,11 +75,19 @@ int ast_monitor_start( struct ast_channel *chan, const char *format_spec,
/* Determine file names */
if( fname_base && strlen( fname_base ) ) {
+ int directory = strchr(fname_base, '/') ? 1 : 0;
+ /* try creating the directory just in case it doesn't exist */
+ if (directory) {
+ char *name = strdup(fname_base);
+ snprintf(tmp, sizeof(tmp), "mkdir -p %s",dirname(name));
+ free(name);
+ system(tmp);
+ }
snprintf( monitor->read_filename, FILENAME_MAX, "%s/%s-in",
- AST_MONITOR_DIR, fname_base );
+ directory ? "" : AST_MONITOR_DIR, fname_base );
snprintf( monitor->write_filename, FILENAME_MAX, "%s/%s-out",
- AST_MONITOR_DIR, fname_base );
- *monitor->filename_base = 0;
+ directory ? "" : AST_MONITOR_DIR, fname_base );
+ strncpy(monitor->filename_base, fname_base, sizeof(monitor->filename_base) - 1);
} else {
ast_mutex_lock( &monitorlock );
snprintf( monitor->read_filename, FILENAME_MAX, "%s/audio-in-%ld",
@@ -93,6 +103,7 @@ int ast_monitor_start( struct ast_channel *chan, const char *format_spec,
}
snprintf( monitor->filename_base, FILENAME_MAX, "%s/%s",
AST_MONITOR_DIR, channel_name );
+ monitor->filename_changed = 1;
free( channel_name );
}
@@ -164,7 +175,7 @@ int ast_monitor_stop( struct ast_channel *chan, int need_lock )
ast_closestream( chan->monitor->write_stream );
}
- if(chan->monitor->filename_base&&strlen(chan->monitor->filename_base)) {
+ if(chan->monitor->filename_changed&&strlen(chan->monitor->filename_base)) {
if( ast_fileexists(chan->monitor->read_filename,NULL,NULL) > 0 ) {
snprintf( filename, FILENAME_MAX, "%s-in",
chan->monitor->filename_base );
@@ -191,7 +202,19 @@ int ast_monitor_stop( struct ast_channel *chan, int need_lock )
chan->monitor->write_filename );
}
}
-
+ if (chan->monitor->joinfiles && strlen(chan->monitor->filename_base)) {
+ char tmp[255];
+ char *format = !strcasecmp(chan->monitor->format,"wav49") ? "WAV" : chan->monitor->format;
+ char *name = chan->monitor->filename_base;
+ int directory = strchr(name, '/') ? 1 : 0;
+ char *dir = directory ? "" : AST_MONITOR_DIR;
+ snprintf(tmp, sizeof(tmp), "nice -n 19 soxmix %s/%s-in.%s %s/%s-out.%s %s/%s.%s && rm -rf %s/%s-* &", dir, name, format, dir, name, format, dir, name, format, dir, name);
+#if 0
+ ast_verbose("executing %s\n",tmp);
+#endif
+ if (system(tmp) == -1)
+ ast_log(LOG_WARNING, "You might not have the soxmix installed and available in the path, please check.\n");
+ }
free( chan->monitor->format );
free( chan->monitor );
chan->monitor = NULL;
@@ -207,6 +230,7 @@ int ast_monitor_stop( struct ast_channel *chan, int need_lock )
int ast_monitor_change_fname( struct ast_channel *chan,
const char *fname_base, int need_lock )
{
+ char tmp[256];
if( (!fname_base) || (!strlen(fname_base)) ) {
ast_log( LOG_WARNING,
"Cannot change monitor filename of channel %s to null",
@@ -222,8 +246,17 @@ int ast_monitor_change_fname( struct ast_channel *chan,
}
if( chan->monitor ) {
+ int directory = strchr(fname_base, '/') ? 1 : 0;
+ /* try creating the directory just in case it doesn't exist */
+ if (directory) {
+ char *name = strdup(fname_base);
+ snprintf(tmp, sizeof(tmp), "mkdir -p %s",dirname(name));
+ free(name);
+ system(tmp);
+ }
+
snprintf( chan->monitor->filename_base, FILENAME_MAX, "%s/%s",
- AST_MONITOR_DIR, fname_base );
+ directory ? "" : AST_MONITOR_DIR, fname_base );
} else {
ast_log( LOG_WARNING,
"Cannot change monitor filename of channel %s to %s, monitoring not started",
@@ -379,6 +412,12 @@ static int change_monitor_action(struct mansession *s, struct message *m)
return 0;
}
+void ast_monitor_setjoinfiles(struct ast_channel *chan, int turnon)
+{
+ if (chan->monitor)
+ chan->monitor->joinfiles = turnon;
+}
+
int load_module(void)
{
ast_register_application( "Monitor", start_monitor_exec, monitor_synopsis, monitor_descrip );
diff --git a/res/res_parking.c b/res/res_parking.c
index 0d0a714c9..5c8049822 100755
--- a/res/res_parking.c
+++ b/res/res_parking.c
@@ -234,6 +234,18 @@ int ast_bridge_call(struct ast_channel *chan, struct ast_channel *peer, int allo
return -1;
peer->appl = "Bridged Call";
peer->data = chan->name;
+ /* copy the userfield from the B-leg to A-leg if applicable */
+ if (chan->cdr && peer->cdr && strlen(peer->cdr->userfield)) {
+ char tmp[256];
+ if (strlen(chan->cdr->userfield)) {
+ snprintf(tmp, sizeof(tmp), "%s;%s",chan->cdr->userfield, peer->cdr->userfield);
+ ast_cdr_appenduserfield(chan, tmp);
+ } else
+ ast_cdr_setuserfield(chan, peer->cdr->userfield);
+ /* free the peer's cdr without ast_cdr_free complaining */
+ free(peer->cdr);
+ peer->cdr = NULL;
+ }
for (;;) {
res = ast_channel_bridge(chan, peer, (allowdisconnect||allowredirect_out ? AST_BRIDGE_DTMF_CHANNEL_0 : 0) + (allowredirect_in ? AST_BRIDGE_DTMF_CHANNEL_1 : 0), &f, &who);
if (res < 0) {