mirror of
https://github.com/asterisk/asterisk.git
synced 2025-08-21 05:03:51 +00:00
Compare commits
5 Commits
95d65bbe30
...
4a1a8987c2
Author | SHA1 | Date | |
---|---|---|---|
|
4a1a8987c2 | ||
|
71b538e79f | ||
|
8bfa3be27f | ||
|
8837723f7d | ||
|
94afcffce9 |
@@ -132,6 +132,9 @@
|
||||
<argument name="mailbox" />
|
||||
<argument name="context" />
|
||||
</option>
|
||||
<option name="N">
|
||||
<para>Do not answer the channel automatically.</para>
|
||||
</option>
|
||||
<option name="o">
|
||||
<para>Only listen to audio coming from this channel.</para>
|
||||
</option>
|
||||
@@ -289,6 +292,9 @@
|
||||
<argument name="mailbox" />
|
||||
<argument name="context" />
|
||||
</option>
|
||||
<option name="N">
|
||||
<para>Do not answer the channel automatically.</para>
|
||||
</option>
|
||||
<option name="o">
|
||||
<para>Only listen to audio coming from this channel.</para>
|
||||
</option>
|
||||
@@ -408,6 +414,7 @@ enum {
|
||||
OPTION_UNIQUEID = (1 << 19), /* The chanprefix is a channel uniqueid or fully specified channel name. */
|
||||
OPTION_LONG_QUEUE = (1 << 20), /* Allow usage of a long queue to store audio frames. */
|
||||
OPTION_INTERLEAVED = (1 << 21), /* Interleave the Read and Write frames in the output frame. */
|
||||
OPTION_NOANSWER = (1 << 22), /* Do not automatically answer the channel */
|
||||
};
|
||||
|
||||
enum {
|
||||
@@ -432,6 +439,7 @@ AST_APP_OPTIONS(spy_opts, {
|
||||
AST_APP_OPTION_ARG('g', OPTION_GROUP, OPT_ARG_GROUP),
|
||||
AST_APP_OPTION('l', OPTION_LONG_QUEUE),
|
||||
AST_APP_OPTION_ARG('n', OPTION_NAME, OPT_ARG_NAME),
|
||||
AST_APP_OPTION('N', OPTION_NOANSWER),
|
||||
AST_APP_OPTION('o', OPTION_READONLY),
|
||||
AST_APP_OPTION('q', OPTION_QUIET),
|
||||
AST_APP_OPTION_ARG('r', OPTION_RECORD, OPT_ARG_RECORD),
|
||||
@@ -999,8 +1007,9 @@ static int common_exec(struct ast_channel *chan, struct ast_flags *flags,
|
||||
ast_channel_unlock(chan);
|
||||
}
|
||||
|
||||
if (ast_channel_state(chan) != AST_STATE_UP)
|
||||
if (!ast_test_flag(flags, OPTION_NOANSWER) && ast_channel_state(chan) != AST_STATE_UP) {
|
||||
ast_answer(chan);
|
||||
}
|
||||
|
||||
ast_channel_set_flag(chan, AST_FLAG_SPYING);
|
||||
|
||||
|
@@ -3168,6 +3168,10 @@ static struct ast_frame *__analog_handle_event(struct analog_pvt *p, struct ast_
|
||||
ast_debug(2, "Letting this call hang up normally, since it's not the only call\n");
|
||||
} else if (!p->owner || !p->subs[ANALOG_SUB_REAL].owner || ast_channel_state(ast) != AST_STATE_UP) {
|
||||
ast_debug(2, "Called Subscriber Held does not apply: channel state is %d\n", ast_channel_state(ast));
|
||||
} else if (p->owner && p->subs[ANALOG_SUB_REAL].owner && ast_strlen_zero(ast_channel_appl(p->subs[ANALOG_SUB_REAL].owner))) {
|
||||
/* If the channel application is empty, it is likely a masquerade has occured, in which case don't hold any calls.
|
||||
* This conditional matches only executions that would have reached the strcmp below. */
|
||||
ast_debug(1, "Skipping Called Subscriber Held; channel has no application\n");
|
||||
} else if (!p->owner || !p->subs[ANALOG_SUB_REAL].owner || strcmp(ast_channel_appl(p->subs[ANALOG_SUB_REAL].owner), "AppDial")) {
|
||||
/* Called Subscriber held only applies to incoming calls, not outgoing calls.
|
||||
* We can't use p->outgoing because that is always true, for both incoming and outgoing calls, so it's not accurate.
|
||||
|
@@ -568,6 +568,16 @@ int stasis_app_control_ring(struct stasis_app_control *control);
|
||||
*/
|
||||
int stasis_app_control_ring_stop(struct stasis_app_control *control);
|
||||
|
||||
/*!
|
||||
* \brief Indicate progress to the channel associated with this control.
|
||||
*
|
||||
* \param control Control for \c res_stasis.
|
||||
*
|
||||
* \return 0 for success.
|
||||
* \return -1 for error.
|
||||
*/
|
||||
int stasis_app_control_progress(struct stasis_app_control *control);
|
||||
|
||||
/*!
|
||||
* \brief Send DTMF to the channel associated with this control.
|
||||
*
|
||||
|
10
main/dsp.c
10
main/dsp.c
@@ -618,12 +618,14 @@ static int tone_detect(struct ast_dsp *dsp, tone_detect_state_t *s, int16_t *amp
|
||||
tone_energy *= 2.0;
|
||||
s->energy *= s->block_size;
|
||||
|
||||
ast_debug(10, "%d Hz tone %2d Ew=%.4E, Et=%.4E, s/n=%10.2f\n", s->freq, s->hit_count, tone_energy, s->energy, tone_energy / (s->energy - tone_energy));
|
||||
hit = 0;
|
||||
/* Add 1 to hit_count when logging, since it doesn't get incremented until later in the loop. */
|
||||
if (TONE_THRESHOLD <= tone_energy
|
||||
&& tone_energy > s->energy * s->threshold) {
|
||||
ast_debug(10, "%d Hz tone Hit! %2d Ew=%.4E, Et=%.4E, s/n=%10.2f\n", s->freq, s->hit_count, tone_energy, s->energy, tone_energy / (s->energy - tone_energy));
|
||||
ast_debug(9, "%d Hz tone Hit! [%d/%d] Ew=%.4E, Et=%.4E, s/n=%10.2f\n", s->freq, s->hit_count + 1, s->hits_required, tone_energy, s->energy, tone_energy / (s->energy - tone_energy));
|
||||
hit = 1;
|
||||
} else {
|
||||
ast_debug(10, "%d Hz tone [%d/%d] Ew=%.4E, Et=%.4E, s/n=%10.2f\n", s->freq, s->hit_count + 1, s->hits_required, tone_energy, s->energy, tone_energy / (s->energy - tone_energy));
|
||||
hit = 0;
|
||||
}
|
||||
|
||||
if (s->hit_count) {
|
||||
@@ -633,11 +635,11 @@ static int tone_detect(struct ast_dsp *dsp, tone_detect_state_t *s, int16_t *amp
|
||||
if (hit == s->last_hit) {
|
||||
if (!hit) {
|
||||
/* Two successive misses. Tone ended */
|
||||
ast_debug(9, "Partial detect expired after %d/%d hits\n", s->hit_count, s->hits_required);
|
||||
s->hit_count = 0;
|
||||
} else if (!s->hit_count) {
|
||||
s->hit_count++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (s->hit_count == s->hits_required) {
|
||||
|
@@ -401,6 +401,26 @@ void ast_ari_channels_ring_stop(struct ast_variable *headers,
|
||||
ast_ari_response_no_content(response);
|
||||
}
|
||||
|
||||
void ast_ari_channels_progress(struct ast_variable *headers,
|
||||
struct ast_ari_channels_progress_args *args,
|
||||
struct ast_ari_response *response)
|
||||
{
|
||||
RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
|
||||
|
||||
control = find_control(response, args->channel_id);
|
||||
if (control == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (channel_state_invalid(control, response)) {
|
||||
return;
|
||||
}
|
||||
|
||||
stasis_app_control_progress(control);
|
||||
|
||||
ast_ari_response_no_content(response);
|
||||
}
|
||||
|
||||
void ast_ari_channels_mute(struct ast_variable *headers,
|
||||
struct ast_ari_channels_mute_args *args,
|
||||
struct ast_ari_response *response)
|
||||
|
@@ -358,6 +358,19 @@ struct ast_ari_channels_ring_stop_args {
|
||||
* \param[out] response HTTP response
|
||||
*/
|
||||
void ast_ari_channels_ring_stop(struct ast_variable *headers, struct ast_ari_channels_ring_stop_args *args, struct ast_ari_response *response);
|
||||
/*! Argument struct for ast_ari_channels_progress() */
|
||||
struct ast_ari_channels_progress_args {
|
||||
/*! Channel's id */
|
||||
const char *channel_id;
|
||||
};
|
||||
/*!
|
||||
* \brief Indicate progress on a channel.
|
||||
*
|
||||
* \param headers HTTP headers
|
||||
* \param args Swagger parameters
|
||||
* \param[out] response HTTP response
|
||||
*/
|
||||
void ast_ari_channels_progress(struct ast_variable *headers, struct ast_ari_channels_progress_args *args, struct ast_ari_response *response);
|
||||
/*! Argument struct for ast_ari_channels_send_dtmf() */
|
||||
struct ast_ari_channels_send_dtmf_args {
|
||||
/*! Channel's id */
|
||||
|
@@ -1157,6 +1157,68 @@ static void ast_ari_channels_ring_stop_cb(
|
||||
}
|
||||
#endif /* AST_DEVMODE */
|
||||
|
||||
fin: __attribute__((unused))
|
||||
return;
|
||||
}
|
||||
/*!
|
||||
* \brief Parameter parsing callback for /channels/{channelId}/progress.
|
||||
* \param ser TCP/TLS session object
|
||||
* \param get_params GET parameters in the HTTP request.
|
||||
* \param path_vars Path variables extracted from the request.
|
||||
* \param headers HTTP headers.
|
||||
* \param body
|
||||
* \param[out] response Response to the HTTP request.
|
||||
*/
|
||||
static void ast_ari_channels_progress_cb(
|
||||
struct ast_tcptls_session_instance *ser,
|
||||
struct ast_variable *get_params, struct ast_variable *path_vars,
|
||||
struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
|
||||
{
|
||||
struct ast_ari_channels_progress_args args = {};
|
||||
struct ast_variable *i;
|
||||
#if defined(AST_DEVMODE)
|
||||
int is_valid;
|
||||
int code;
|
||||
#endif /* AST_DEVMODE */
|
||||
|
||||
for (i = path_vars; i; i = i->next) {
|
||||
if (strcmp(i->name, "channelId") == 0) {
|
||||
args.channel_id = (i->value);
|
||||
} else
|
||||
{}
|
||||
}
|
||||
ast_ari_channels_progress(headers, &args, response);
|
||||
#if defined(AST_DEVMODE)
|
||||
code = response->response_code;
|
||||
|
||||
switch (code) {
|
||||
case 0: /* Implementation is still a stub, or the code wasn't set */
|
||||
is_valid = response->message == NULL;
|
||||
break;
|
||||
case 500: /* Internal Server Error */
|
||||
case 501: /* Not Implemented */
|
||||
case 404: /* Channel not found */
|
||||
case 409: /* Channel not in a Stasis application */
|
||||
case 412: /* Channel in invalid state */
|
||||
is_valid = 1;
|
||||
break;
|
||||
default:
|
||||
if (200 <= code && code <= 299) {
|
||||
is_valid = ast_ari_validate_void(
|
||||
response->message);
|
||||
} else {
|
||||
ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}/progress\n", code);
|
||||
is_valid = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_valid) {
|
||||
ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/progress\n");
|
||||
ast_ari_response_error(response, 500,
|
||||
"Internal Server Error", "Response validation failed");
|
||||
}
|
||||
#endif /* AST_DEVMODE */
|
||||
|
||||
fin: __attribute__((unused))
|
||||
return;
|
||||
}
|
||||
@@ -3145,6 +3207,15 @@ static struct stasis_rest_handlers channels_channelId_ring = {
|
||||
.children = { }
|
||||
};
|
||||
/*! \brief REST handler for /api-docs/channels.json */
|
||||
static struct stasis_rest_handlers channels_channelId_progress = {
|
||||
.path_segment = "progress",
|
||||
.callbacks = {
|
||||
[AST_HTTP_POST] = ast_ari_channels_progress_cb,
|
||||
},
|
||||
.num_children = 0,
|
||||
.children = { }
|
||||
};
|
||||
/*! \brief REST handler for /api-docs/channels.json */
|
||||
static struct stasis_rest_handlers channels_channelId_dtmf = {
|
||||
.path_segment = "dtmf",
|
||||
.callbacks = {
|
||||
@@ -3286,8 +3357,8 @@ static struct stasis_rest_handlers channels_channelId = {
|
||||
[AST_HTTP_POST] = ast_ari_channels_originate_with_id_cb,
|
||||
[AST_HTTP_DELETE] = ast_ari_channels_hangup_cb,
|
||||
},
|
||||
.num_children = 17,
|
||||
.children = { &channels_channelId_continue,&channels_channelId_move,&channels_channelId_redirect,&channels_channelId_answer,&channels_channelId_ring,&channels_channelId_dtmf,&channels_channelId_mute,&channels_channelId_hold,&channels_channelId_moh,&channels_channelId_silence,&channels_channelId_play,&channels_channelId_record,&channels_channelId_variable,&channels_channelId_snoop,&channels_channelId_dial,&channels_channelId_rtp_statistics,&channels_channelId_transfer_progress, }
|
||||
.num_children = 18,
|
||||
.children = { &channels_channelId_continue,&channels_channelId_move,&channels_channelId_redirect,&channels_channelId_answer,&channels_channelId_ring,&channels_channelId_progress,&channels_channelId_dtmf,&channels_channelId_mute,&channels_channelId_hold,&channels_channelId_moh,&channels_channelId_silence,&channels_channelId_play,&channels_channelId_record,&channels_channelId_variable,&channels_channelId_snoop,&channels_channelId_dial,&channels_channelId_rtp_statistics,&channels_channelId_transfer_progress, }
|
||||
};
|
||||
/*! \brief REST handler for /api-docs/channels.json */
|
||||
static struct stasis_rest_handlers channels_externalMedia = {
|
||||
|
@@ -283,7 +283,7 @@ static void populate_cache(void)
|
||||
if (!ast_strlen_zero(name)) {
|
||||
ast_devstate_changed(
|
||||
ast_devstate_val(entry->data),
|
||||
AST_DEVSTATE_CACHABLE, "%s%s\n",
|
||||
AST_DEVSTATE_CACHABLE, "%s%s",
|
||||
DEVICE_STATE_SCHEME_STASIS, name + 1);
|
||||
}
|
||||
}
|
||||
|
@@ -637,6 +637,21 @@ int stasis_app_control_ring_stop(struct stasis_app_control *control)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int app_control_progress(struct stasis_app_control *control,
|
||||
struct ast_channel *chan, void *data)
|
||||
{
|
||||
ast_indicate(control->channel, AST_CONTROL_PROGRESS);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int stasis_app_control_progress(struct stasis_app_control *control)
|
||||
{
|
||||
stasis_app_send_command_async(control, app_control_progress, NULL, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct stasis_app_control_mute_data {
|
||||
enum ast_frame_type frametype;
|
||||
unsigned int direction;
|
||||
|
@@ -772,6 +772,47 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/channels/{channelId}/progress",
|
||||
"description": "Indicate progress on a channel",
|
||||
"operations": [
|
||||
{
|
||||
"httpMethod": "POST",
|
||||
"since": [
|
||||
"22.6.0",
|
||||
"21.11.0",
|
||||
"20.16.0"
|
||||
],
|
||||
"summary": "Indicate progress on a channel.",
|
||||
"nickname": "progress",
|
||||
"responseClass": "void",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "channelId",
|
||||
"description": "Channel's id",
|
||||
"paramType": "path",
|
||||
"required": true,
|
||||
"allowMultiple": false,
|
||||
"dataType": "string"
|
||||
}
|
||||
],
|
||||
"errorResponses": [
|
||||
{
|
||||
"code": 404,
|
||||
"reason": "Channel not found"
|
||||
},
|
||||
{
|
||||
"code": 409,
|
||||
"reason": "Channel not in a Stasis application"
|
||||
},
|
||||
{
|
||||
"code": 412,
|
||||
"reason": "Channel in invalid state"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/channels/{channelId}/dtmf",
|
||||
"description": "Send DTMF to a channel",
|
||||
|
Reference in New Issue
Block a user