mirror of
https://github.com/asterisk/asterisk.git
synced 2025-11-19 08:11:21 +00:00
Add option for recording conference (bug #3393), thanks moc!
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@4876 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
@@ -70,6 +70,9 @@ static char *descrip =
|
|||||||
" 'e' -- select an empty conference\n"
|
" 'e' -- select an empty conference\n"
|
||||||
" 'E' -- select an empty pinless conference\n"
|
" 'E' -- select an empty pinless conference\n"
|
||||||
" 'v' -- video mode\n"
|
" 'v' -- video mode\n"
|
||||||
|
" 'r' -- Record conference (records as ${MEETME_RECORDINGFILE}\n"
|
||||||
|
" using format ${MEETME_RECORDINGFORMAT}). Default filename is\n"
|
||||||
|
" meetme-conf-rec-${CONFNO}-${UNIQUEID} and the default format is wav.\n"
|
||||||
" 'q' -- quiet mode (don't play enter/leave sounds)\n"
|
" 'q' -- quiet mode (don't play enter/leave sounds)\n"
|
||||||
" 'M' -- enable music on hold when the conference has a single caller\n"
|
" 'M' -- enable music on hold when the conference has a single caller\n"
|
||||||
" 'x' -- close the conference when last marked user exits\n"
|
" 'x' -- close the conference when last marked user exits\n"
|
||||||
@@ -114,8 +117,13 @@ static struct ast_conference {
|
|||||||
struct ast_conf_user *firstuser; /* Pointer to the first user struct */
|
struct ast_conf_user *firstuser; /* Pointer to the first user struct */
|
||||||
struct ast_conf_user *lastuser; /* Pointer to the last user struct */
|
struct ast_conf_user *lastuser; /* Pointer to the last user struct */
|
||||||
time_t start; /* Start time (s) */
|
time_t start; /* Start time (s) */
|
||||||
|
int recording; /* recording status */
|
||||||
int isdynamic; /* Created on the fly? */
|
int isdynamic; /* Created on the fly? */
|
||||||
int locked; /* Is the conference locked? */
|
int locked; /* Is the conference locked? */
|
||||||
|
pthread_t recordthread; /* thread for recording */
|
||||||
|
pthread_attr_t attr; /* thread attribute */
|
||||||
|
char *recordingfilename; /* Filename to record the Conference into */
|
||||||
|
char *recordingformat; /* Format to record the Conference in */
|
||||||
char pin[AST_MAX_EXTENSION]; /* If protected by a PIN */
|
char pin[AST_MAX_EXTENSION]; /* If protected by a PIN */
|
||||||
struct ast_conference *next;
|
struct ast_conference *next;
|
||||||
} *confs;
|
} *confs;
|
||||||
@@ -140,12 +148,18 @@ AST_MUTEX_DEFINE_STATIC(conflock);
|
|||||||
|
|
||||||
static int admin_exec(struct ast_channel *chan, void *data);
|
static int admin_exec(struct ast_channel *chan, void *data);
|
||||||
|
|
||||||
|
static void *recordthread(void *args);
|
||||||
|
|
||||||
#include "enter.h"
|
#include "enter.h"
|
||||||
#include "leave.h"
|
#include "leave.h"
|
||||||
|
|
||||||
#define ENTER 0
|
#define ENTER 0
|
||||||
#define LEAVE 1
|
#define LEAVE 1
|
||||||
|
|
||||||
|
#define MEETME_RECORD_OFF 0
|
||||||
|
#define MEETME_RECORD_ACTIVE 1
|
||||||
|
#define MEETME_RECORD_TERMINATE 2
|
||||||
|
|
||||||
#define CONF_SIZE 320
|
#define CONF_SIZE 320
|
||||||
|
|
||||||
#define CONFFLAG_ADMIN (1 << 1) /* If set the user has admin access on the conference */
|
#define CONFFLAG_ADMIN (1 << 1) /* If set the user has admin access on the conference */
|
||||||
@@ -162,6 +176,7 @@ static int admin_exec(struct ast_channel *chan, void *data);
|
|||||||
#define CONFFLAG_EXIT_CONTEXT (1 << 12) /* If set, the MeetMe will exit to the specified context */
|
#define CONFFLAG_EXIT_CONTEXT (1 << 12) /* If set, the MeetMe will exit to the specified context */
|
||||||
#define CONFFLAG_MARKEDUSER (1 << 13) /* If set, the user will be marked */
|
#define CONFFLAG_MARKEDUSER (1 << 13) /* If set, the user will be marked */
|
||||||
#define CONFFLAG_INTROUSER (1 << 14) /* If set, user will be ask record name on entry of conference */
|
#define CONFFLAG_INTROUSER (1 << 14) /* If set, user will be ask record name on entry of conference */
|
||||||
|
#define CONFFLAG_RECORDCONF (1<< 15) /* If set, the MeetMe will be recorded */
|
||||||
|
|
||||||
static int careful_write(int fd, unsigned char *data, int len)
|
static int careful_write(int fd, unsigned char *data, int len)
|
||||||
{
|
{
|
||||||
@@ -244,7 +259,7 @@ static struct ast_conference *build_conf(char *confno, char *pin, int make, int
|
|||||||
/* Setup a new zap conference */
|
/* Setup a new zap conference */
|
||||||
ztc.chan = 0;
|
ztc.chan = 0;
|
||||||
ztc.confno = -1;
|
ztc.confno = -1;
|
||||||
ztc.confmode = ZT_CONF_CONFANN;
|
ztc.confmode = ZT_CONF_CONFANN | ZT_CONF_CONFANNMON;
|
||||||
if (ioctl(cnf->fd, ZT_SETCONF, &ztc)) {
|
if (ioctl(cnf->fd, ZT_SETCONF, &ztc)) {
|
||||||
ast_log(LOG_WARNING, "Error setting conference\n");
|
ast_log(LOG_WARNING, "Error setting conference\n");
|
||||||
if (cnf->chan)
|
if (cnf->chan)
|
||||||
@@ -528,6 +543,7 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, int c
|
|||||||
char *agifiledefault = "conf-background.agi";
|
char *agifiledefault = "conf-background.agi";
|
||||||
char meetmesecs[30] = "";
|
char meetmesecs[30] = "";
|
||||||
char exitcontext[AST_MAX_EXTENSION] = "";
|
char exitcontext[AST_MAX_EXTENSION] = "";
|
||||||
|
char recordingtmp[AST_MAX_EXTENSION] = "";
|
||||||
int dtmf;
|
int dtmf;
|
||||||
|
|
||||||
ZT_BUFFERINFO bi;
|
ZT_BUFFERINFO bi;
|
||||||
@@ -540,6 +556,23 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, int c
|
|||||||
}
|
}
|
||||||
memset(user, 0, sizeof(struct ast_conf_user));
|
memset(user, 0, sizeof(struct ast_conf_user));
|
||||||
|
|
||||||
|
if (confflags & CONFFLAG_RECORDCONF && conf->recording !=MEETME_RECORD_ACTIVE) {
|
||||||
|
conf->recordingfilename = pbx_builtin_getvar_helper(chan,"MEETME_RECORDINGFILE");
|
||||||
|
if (!conf->recordingfilename) {
|
||||||
|
snprintf(recordingtmp,sizeof(recordingtmp),"meetme-conf-rec-%s-%s",conf->confno,chan->uniqueid);
|
||||||
|
conf->recordingfilename = ast_strdupa(recordingtmp);
|
||||||
|
}
|
||||||
|
conf->recordingformat = pbx_builtin_getvar_helper(chan, "MEETME_RECORDINGFORMAT");
|
||||||
|
if (!conf->recordingformat) {
|
||||||
|
snprintf(recordingtmp,sizeof(recordingtmp), "wav");
|
||||||
|
conf->recordingformat = ast_strdupa(recordingtmp);
|
||||||
|
}
|
||||||
|
pthread_attr_init(&conf->attr);
|
||||||
|
pthread_attr_setdetachstate(&conf->attr, PTHREAD_CREATE_DETACHED);
|
||||||
|
ast_verbose(VERBOSE_PREFIX_4 "Starting recording of MeetMe Conference %s into file %s.%s.\n", conf->confno, conf->recordingfilename, conf->recordingformat);
|
||||||
|
ast_pthread_create(&conf->recordthread, &conf->attr, recordthread, conf);
|
||||||
|
}
|
||||||
|
|
||||||
user->user_no = 0; /* User number 0 means starting up user! (dead - not in the list!) */
|
user->user_no = 0; /* User number 0 means starting up user! (dead - not in the list!) */
|
||||||
|
|
||||||
time(&user->jointime);
|
time(&user->jointime);
|
||||||
@@ -1070,6 +1103,16 @@ outrun:
|
|||||||
}
|
}
|
||||||
if (!cur)
|
if (!cur)
|
||||||
ast_log(LOG_WARNING, "Conference not found\n");
|
ast_log(LOG_WARNING, "Conference not found\n");
|
||||||
|
if (conf->recording == MEETME_RECORD_ACTIVE) {
|
||||||
|
conf->recording = MEETME_RECORD_TERMINATE;
|
||||||
|
ast_mutex_unlock(&conflock);
|
||||||
|
while (1) {
|
||||||
|
ast_mutex_lock(&conflock);
|
||||||
|
if (conf->recording == MEETME_RECORD_OFF)
|
||||||
|
break;
|
||||||
|
ast_mutex_unlock(&conflock);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (conf->chan)
|
if (conf->chan)
|
||||||
ast_hangup(conf->chan);
|
ast_hangup(conf->chan);
|
||||||
else
|
else
|
||||||
@@ -1287,6 +1330,8 @@ static int conf_exec(struct ast_channel *chan, void *data)
|
|||||||
confflags |= CONFFLAG_AGI;
|
confflags |= CONFFLAG_AGI;
|
||||||
if (strchr(inflags, 'w'))
|
if (strchr(inflags, 'w'))
|
||||||
confflags |= CONFFLAG_WAITMARKED;
|
confflags |= CONFFLAG_WAITMARKED;
|
||||||
|
if (strchr(inflags, 'r'))
|
||||||
|
confflags |= CONFFLAG_RECORDCONF;
|
||||||
if (strchr(inflags, 'd'))
|
if (strchr(inflags, 'd'))
|
||||||
dynamic = 1;
|
dynamic = 1;
|
||||||
if (strchr(inflags, 'D')) {
|
if (strchr(inflags, 'D')) {
|
||||||
@@ -1613,6 +1658,45 @@ static int admin_exec(struct ast_channel *chan, void *data) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void *recordthread(void *args)
|
||||||
|
{
|
||||||
|
struct ast_conference *cnf;
|
||||||
|
struct ast_frame *f=NULL;
|
||||||
|
int flags;
|
||||||
|
struct ast_filestream *s;
|
||||||
|
int res=0;
|
||||||
|
|
||||||
|
cnf = (struct ast_conference *)args;
|
||||||
|
ast_stopstream(cnf->chan);
|
||||||
|
flags = O_CREAT|O_TRUNC|O_WRONLY;
|
||||||
|
s = ast_writefile(cnf->recordingfilename, cnf->recordingformat, NULL, flags, 0, 0644);
|
||||||
|
|
||||||
|
if (s) {
|
||||||
|
cnf->recording = MEETME_RECORD_ACTIVE;
|
||||||
|
while (ast_waitfor(cnf->chan, -1) > -1) {
|
||||||
|
f = ast_read(cnf->chan);
|
||||||
|
if (!f) {
|
||||||
|
res = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (f->frametype == AST_FRAME_VOICE) {
|
||||||
|
res = ast_writestream(s, f);
|
||||||
|
if (res)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ast_frfree(f);
|
||||||
|
if (cnf->recording == MEETME_RECORD_TERMINATE) {
|
||||||
|
ast_mutex_lock(&conflock);
|
||||||
|
ast_mutex_unlock(&conflock);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cnf->recording = MEETME_RECORD_OFF;
|
||||||
|
ast_closestream(s);
|
||||||
|
}
|
||||||
|
pthread_exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
int unload_module(void)
|
int unload_module(void)
|
||||||
{
|
{
|
||||||
STANDARD_HANGUP_LOCALUSERS;
|
STANDARD_HANGUP_LOCALUSERS;
|
||||||
|
|||||||
Reference in New Issue
Block a user