mirror of
https://github.com/asterisk/asterisk.git
synced 2025-09-06 04:30:28 +00:00
(closes issue #12982)
Reported by: bcnit Tested by: murf I discovered that also, in the previous bug fixes and changes, the cdr.conf 'unanswered' option is not being obeyed, so I fixed this. And, yes, there are two 'answer' times involved in this scenario, and I would agree with you, that the first answer time is the time that should appear in the CDR. (the second 'answer' time is the time that the bridge was begun). I made the necessary adjustments, recording the first answer time into the peer cdr, and then using that to override the bridge cdr's value. To get the 'unanswered' CDRs to appear, I purposely output them, using the dial cmd to mark them as DIALED (with a new flag), and outputting them if they bear that flag, and you are in the right mode. I also corrected one small mention of the Zap device to equally consider the dahdi device. I heavily tested 10-sec-wait macros in dial, and without the macro call; I tested hangups while the macro was running vs. letting the macro complete and the bridge form. Looks OK. Removed all the instrumentation and debug. git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/1.4@135799 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
@@ -578,6 +578,10 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, struct dial_l
|
|||||||
if (option_verbose > 2)
|
if (option_verbose > 2)
|
||||||
ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", c->name, in->name);
|
ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", c->name, in->name);
|
||||||
peer = c;
|
peer = c;
|
||||||
|
if (peer->cdr) {
|
||||||
|
peer->cdr->answer = ast_tvnow();
|
||||||
|
peer->cdr->disposition = AST_CDR_ANSWERED;
|
||||||
|
}
|
||||||
ast_copy_flags(peerflags, o,
|
ast_copy_flags(peerflags, o,
|
||||||
OPT_CALLEE_TRANSFER | OPT_CALLER_TRANSFER |
|
OPT_CALLEE_TRANSFER | OPT_CALLER_TRANSFER |
|
||||||
OPT_CALLEE_HANGUP | OPT_CALLER_HANGUP |
|
OPT_CALLEE_HANGUP | OPT_CALLER_HANGUP |
|
||||||
@@ -1761,8 +1765,9 @@ static int dial_exec_full(struct ast_channel *chan, void *data, struct ast_flags
|
|||||||
res = -1;
|
res = -1;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (opermode && (!strncmp(chan->name,"Zap",3)) &&
|
if (opermode &&
|
||||||
(!strncmp(peer->name,"Zap",3)))
|
(((!strncasecmp(chan->name,"Zap",3)) && (!strncasecmp(peer->name,"Zap",3))) ||
|
||||||
|
((!strncasecmp(chan->name,"Dahdi",5)) && (!strncasecmp(peer->name,"Dahdi",5)))))
|
||||||
{
|
{
|
||||||
struct oprmode oprmode;
|
struct oprmode oprmode;
|
||||||
|
|
||||||
|
@@ -36,6 +36,7 @@
|
|||||||
#define AST_CDR_FLAG_ENABLE (1 << 7)
|
#define AST_CDR_FLAG_ENABLE (1 << 7)
|
||||||
#define AST_CDR_FLAG_ANSLOCKED (1 << 8)
|
#define AST_CDR_FLAG_ANSLOCKED (1 << 8)
|
||||||
#define AST_CDR_FLAG_DONT_TOUCH (1 << 9)
|
#define AST_CDR_FLAG_DONT_TOUCH (1 << 9)
|
||||||
|
#define AST_CDR_FLAG_DIALED (1 << 10)
|
||||||
|
|
||||||
/*! Disposition */
|
/*! Disposition */
|
||||||
#define AST_CDR_NULL 0
|
#define AST_CDR_NULL 0
|
||||||
@@ -103,6 +104,7 @@ struct ast_cdr {
|
|||||||
struct ast_cdr *next;
|
struct ast_cdr *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
int ast_cdr_isset_unanswered(void);
|
||||||
void ast_cdr_getvar(struct ast_cdr *cdr, const char *name, char **ret, char *workspace, int workspacelen, int recur, int raw);
|
void ast_cdr_getvar(struct ast_cdr *cdr, const char *name, char **ret, char *workspace, int workspacelen, int recur, int raw);
|
||||||
int ast_cdr_setvar(struct ast_cdr *cdr, const char *name, const char *value, int recur);
|
int ast_cdr_setvar(struct ast_cdr *cdr, const char *name, const char *value, int recur);
|
||||||
int ast_cdr_serialize_variables(struct ast_cdr *cdr, char *buf, size_t size, char delim, char sep, int recur);
|
int ast_cdr_serialize_variables(struct ast_cdr *cdr, char *buf, size_t size, char delim, char sep, int recur);
|
||||||
|
@@ -162,6 +162,11 @@ void ast_cdr_unregister(const char *name)
|
|||||||
AST_LIST_UNLOCK(&be_list);
|
AST_LIST_UNLOCK(&be_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ast_cdr_isset_unanswered(void)
|
||||||
|
{
|
||||||
|
return unanswered;
|
||||||
|
}
|
||||||
|
|
||||||
/*! Duplicate a CDR record
|
/*! Duplicate a CDR record
|
||||||
\returns Pointer to new CDR record
|
\returns Pointer to new CDR record
|
||||||
*/
|
*/
|
||||||
|
@@ -1514,7 +1514,10 @@ int ast_hangup(struct ast_channel *chan)
|
|||||||
ast_cause2str(chan->hangupcause)
|
ast_cause2str(chan->hangupcause)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (chan->cdr && !ast_test_flag(chan->cdr, AST_CDR_FLAG_BRIDGED) && !ast_test_flag(chan->cdr, AST_CDR_FLAG_POST_DISABLED) && chan->cdr->disposition != AST_CDR_NULL) {
|
if (chan->cdr && !ast_test_flag(chan->cdr, AST_CDR_FLAG_BRIDGED) &&
|
||||||
|
!ast_test_flag(chan->cdr, AST_CDR_FLAG_POST_DISABLED) &&
|
||||||
|
(chan->cdr->disposition != AST_CDR_NULL || ast_test_flag(chan->cdr, AST_CDR_FLAG_DIALED))) {
|
||||||
|
|
||||||
ast_cdr_end(chan->cdr);
|
ast_cdr_end(chan->cdr);
|
||||||
ast_cdr_detach(chan->cdr);
|
ast_cdr_detach(chan->cdr);
|
||||||
}
|
}
|
||||||
@@ -3052,6 +3055,8 @@ int ast_call(struct ast_channel *chan, char *addr, int timeout)
|
|||||||
/* Stop if we're a zombie or need a soft hangup */
|
/* Stop if we're a zombie or need a soft hangup */
|
||||||
ast_channel_lock(chan);
|
ast_channel_lock(chan);
|
||||||
if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan)) {
|
if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan)) {
|
||||||
|
if (chan->cdr)
|
||||||
|
ast_set_flag(chan->cdr, AST_CDR_FLAG_DIALED);
|
||||||
if (chan->tech->call)
|
if (chan->tech->call)
|
||||||
res = chan->tech->call(chan, addr, timeout);
|
res = chan->tech->call(chan, addr, timeout);
|
||||||
ast_set_flag(chan, AST_FLAG_OUTGOING);
|
ast_set_flag(chan, AST_FLAG_OUTGOING);
|
||||||
|
@@ -1475,8 +1475,19 @@ int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast
|
|||||||
ast_cdr_start(bridge_cdr);
|
ast_cdr_start(bridge_cdr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ast_cdr_answer(bridge_cdr);
|
/* peer->cdr->answer will be set when a macro runs on the peer;
|
||||||
ast_cdr_answer(chan->cdr); /* for the sake of cli status checks */
|
in that case, the bridge answer will be delayed while the
|
||||||
|
macro plays on the peer channel. The peer answered the call
|
||||||
|
before the macro started playing. To the phone system,
|
||||||
|
this is billable time for the call, even tho the caller
|
||||||
|
hears nothing but ringing while the macro does its thing. */
|
||||||
|
if (peer->cdr && !ast_tvzero(peer->cdr->answer)) {
|
||||||
|
bridge_cdr->answer = peer->cdr->answer;
|
||||||
|
chan->cdr->answer = peer->cdr->answer;
|
||||||
|
} else {
|
||||||
|
ast_cdr_answer(bridge_cdr);
|
||||||
|
ast_cdr_answer(chan->cdr); /* for the sake of cli status checks */
|
||||||
|
}
|
||||||
ast_set_flag(chan->cdr, AST_CDR_FLAG_BRIDGED);
|
ast_set_flag(chan->cdr, AST_CDR_FLAG_BRIDGED);
|
||||||
if (peer->cdr) {
|
if (peer->cdr) {
|
||||||
ast_set_flag(peer->cdr, AST_CDR_FLAG_BRIDGED);
|
ast_set_flag(peer->cdr, AST_CDR_FLAG_BRIDGED);
|
||||||
@@ -1550,7 +1561,7 @@ int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast
|
|||||||
if (res < 0) {
|
if (res < 0) {
|
||||||
if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_test_flag(peer, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan) && !ast_check_hangup(peer))
|
if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_test_flag(peer, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan) && !ast_check_hangup(peer))
|
||||||
ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name);
|
ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name);
|
||||||
return -1;
|
goto before_you_go;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!f || (f->frametype == AST_FRAME_CONTROL &&
|
if (!f || (f->frametype == AST_FRAME_CONTROL &&
|
||||||
@@ -1647,6 +1658,7 @@ int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast
|
|||||||
ast_frfree(f);
|
ast_frfree(f);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
before_you_go:
|
||||||
/* obey the NoCDR() wishes. */
|
/* obey the NoCDR() wishes. */
|
||||||
if (!chan->cdr || (chan->cdr && !ast_test_flag(chan->cdr, AST_CDR_FLAG_POST_DISABLED))) {
|
if (!chan->cdr || (chan->cdr && !ast_test_flag(chan->cdr, AST_CDR_FLAG_POST_DISABLED))) {
|
||||||
|
|
||||||
@@ -1659,12 +1671,22 @@ int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast
|
|||||||
ast_cdr_specialized_reset(chan->cdr,0);
|
ast_cdr_specialized_reset(chan->cdr,0);
|
||||||
}
|
}
|
||||||
if (peer->cdr) {
|
if (peer->cdr) {
|
||||||
if (orig_peer_cdr && peer->cdr != orig_peer_cdr) {
|
/* before resetting the peer cdr, throw a copy of it to the
|
||||||
/* this can only happen if there was a transfer, methinks */
|
backend, just in case the cdr.conf file is calling for
|
||||||
ast_cdr_specialized_reset(orig_peer_cdr,0);
|
unanswered CDR's. */
|
||||||
} else {
|
|
||||||
ast_cdr_specialized_reset(peer->cdr,0);
|
/* When peer->cdr isn't the same addr as orig_peer_cdr,
|
||||||
|
this can only happen if there was a transfer, methinks;
|
||||||
|
at any rate, only pay attention to the original*/
|
||||||
|
if (ast_cdr_isset_unanswered()) {
|
||||||
|
struct ast_cdr *dupd = ast_cdr_dup(orig_peer_cdr);
|
||||||
|
if (dupd) {
|
||||||
|
if (ast_tvzero(dupd->end) && ast_cdr_isset_unanswered())
|
||||||
|
ast_cdr_end(dupd);
|
||||||
|
ast_cdr_detach(dupd);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
ast_cdr_specialized_reset(orig_peer_cdr,0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
|
Reference in New Issue
Block a user