Compare commits

...

3 Commits

Author SHA1 Message Date
Joe Garlick
cf2b2c7f83 chan_websocket.c: Add DTMF messages
Added DTMF messages to the chan_websocket feature.

When a user presses DTMF during a call over chan_websocket it will send a message like:
"DTMF_END digit:1"

Resolves: https://github.com/asterisk/asterisk-feature-requests/issues/70
2025-09-08 14:33:57 +00:00
Igor Goncharovsky
f4e88b56e0 app_queue.c: Add new global 'log_unpause_on_reason_change'
In many asterisk-based systems, the pause reason is used to separate
pauses by type,and logically, changing the reason defines two intervals
that should be accounted for separately. The introduction of a new
option allows me to separate the intervals of operator inactivity in
the log by the event of unpausing.

UserNote: Add new global option 'log_unpause_on_reason_change' that
is default disabled. When enabled cause addition of UNPAUSE event on
every re-PAUSE with reason changed.
2025-09-08 14:28:45 +00:00
Igor Goncharovsky
e6ade6ddbd app_waitforsilence.c: Use milliseconds to calculate timeout time
The functions WaitForNoise() and WaitForSilence() use the time()
functions to calculate elapsed time, which causes the timer to fire on
a whole second boundary, and the actual function execution time to fire
the timer may be 1 second less than expected. This fix replaces time()
with ast_tvnow().

Fixes: #1401
2025-09-08 14:27:24 +00:00
4 changed files with 50 additions and 4 deletions

View File

@@ -1801,6 +1801,9 @@ static int force_longest_waiting_caller;
/*! \brief queues.conf [general] option */
static int log_caller_id_name;
/*! \brief queues.conf [general] option */
static int log_unpause_on_reason_change;
/*! \brief name of the ringinuse field in the realtime database */
static char *realtime_ringinuse_field;
@@ -8068,6 +8071,11 @@ static void set_queue_member_pause(struct call_queue *q, struct member *mem, con
if (mem->paused == paused) {
ast_debug(1, "%spausing already-%spaused queue member %s:%s\n",
(paused ? "" : "un"), (paused ? "" : "un"), q->name, mem->interface);
if (log_unpause_on_reason_change && paused) {
if (!ast_strings_equal(mem->reason_paused, reason)) {
ast_queue_log(q->name, "NONE", mem->membername, "UNPAUSE", "%s", "Auto-Unpause");
}
}
}
if (mem->realtime && !ast_strlen_zero(mem->rt_uniqueid)) {
@@ -9900,6 +9908,7 @@ static void queue_reset_global_params(void)
negative_penalty_invalid = 0;
log_membername_as_agent = 0;
force_longest_waiting_caller = 0;
log_unpause_on_reason_change = 0;
}
/*! Set the global queue parameters as defined in the "general" section of queues.conf */
@@ -9928,6 +9937,9 @@ static void queue_set_global_params(struct ast_config *cfg)
if ((general_val = ast_variable_retrieve(cfg, "general", "force_longest_waiting_caller"))) {
force_longest_waiting_caller = ast_true(general_val);
}
if ((general_val = ast_variable_retrieve(cfg, "general", "log_unpause_on_reason_change"))) {
log_unpause_on_reason_change = ast_true(general_val);
}
/* Apply log-caller-id-name in the same place as other global settings */
if ((general_val = ast_variable_retrieve(cfg, "general", "log-caller-id-name"))) {
log_caller_id_name = ast_true(general_val);

View File

@@ -158,7 +158,7 @@ static const struct wait_type wait_for_noise = {
.func = ast_dsp_noise,
};
static int do_waiting(struct ast_channel *chan, int timereqd, time_t waitstart, int timeout, const struct wait_type *wait_for)
static int do_waiting(struct ast_channel *chan, int timereqd, struct timeval waitstart, int timeout, const struct wait_type *wait_for)
{
RAII_VAR(struct ast_format *, rfmt, NULL, ao2_cleanup);
int res;
@@ -216,7 +216,7 @@ static int do_waiting(struct ast_channel *chan, int timereqd, time_t waitstart,
break;
}
if (timeout && difftime(time(NULL), waitstart) >= timeout) {
if (timeout && ast_tvdiff_ms(ast_tvnow(), waitstart) >= timeout * 1000) {
pbx_builtin_setvar_helper(chan, "WAITSTATUS", "TIMEOUT");
ast_debug(1, "WAITSTATUS was set to TIMEOUT\n");
res = 0;
@@ -238,7 +238,7 @@ static int waitfor_exec(struct ast_channel *chan, const char *data, const struct
int timereqd = 1000;
int timeout = 0;
int iterations = 1, i;
time_t waitstart;
struct timeval waitstart;
char *parse;
struct ast_silence_generator *silgen = NULL;
@@ -284,7 +284,7 @@ static int waitfor_exec(struct ast_channel *chan, const char *data, const struct
silgen = ast_channel_start_silence_generator(chan);
}
time(&waitstart);
waitstart = ast_tvnow();
for (i = 0; i < iterations && res == 1; i++) {
res = do_waiting(chan, timereqd, waitstart, timeout, wait_for);
}

View File

@@ -156,6 +156,7 @@ struct websocket_pvt {
#define QUEUE_DRAINED "QUEUE_DRAINED"
#define DRIVER_STATUS "STATUS"
#define MEDIA_BUFFERING_COMPLETED "MEDIA_BUFFERING_COMPLETED"
#define DTMF_END "DTMF_END"
#define QUEUE_LENGTH_MAX 1000
#define QUEUE_LENGTH_XOFF_LEVEL 900
@@ -168,6 +169,7 @@ static int webchan_call(struct ast_channel *ast, const char *dest, int timeout);
static struct ast_frame *webchan_read(struct ast_channel *ast);
static int webchan_write(struct ast_channel *ast, struct ast_frame *f);
static int webchan_hangup(struct ast_channel *ast);
static int webchan_send_dtmf_text(struct ast_channel *ast, char digit, unsigned int duration);
static struct ast_channel_tech websocket_tech = {
.type = "WebSocket",
@@ -177,6 +179,7 @@ static struct ast_channel_tech websocket_tech = {
.read = webchan_read,
.write = webchan_write,
.hangup = webchan_hangup,
.send_digit_end = webchan_send_dtmf_text,
};
static void set_channel_format(struct websocket_pvt * instance,
@@ -1410,6 +1413,32 @@ static int webchan_hangup(struct ast_channel *ast)
return 0;
}
static int webchan_send_dtmf_text(struct ast_channel *ast, char digit, unsigned int duration)
{
struct websocket_pvt *instance = ast_channel_tech_pvt(ast);
char *command;
int res = 0;
if (!instance) {
return -1;
}
res = ast_asprintf(&command, "%s digit:%c", DTMF_END, digit);
if (res <= 0 || !command) {
ast_log(LOG_ERROR, "%s: Failed to create DTMF_END\n", ast_channel_name(instance->channel));
return 0;
}
res = ast_websocket_write_string(instance->websocket, command);
if (res != 0) {
ast_log(LOG_ERROR, "%s: Failed to send DTMF_END\n", ast_channel_name(instance->channel));
ast_free(command);
return 0;
}
ast_debug(3, "%s: Sent %s\n", ast_channel_name(instance->channel), command);
ast_free(command);
return 0;
}
/*!
* \internal
*

View File

@@ -82,6 +82,11 @@ monitor-type = MixMonitor
;
;force_longest_waiting_caller = no
;
; Add unpause event to queue log in case of pause send twice with different reason code.
;
;log_unpause_on_reason_change = no
;
;
;[markq]
;
; A sample call queue