mirror of
https://github.com/asterisk/asterisk.git
synced 2025-09-03 11:25:35 +00:00
res_ari_channels: Add ring operation, dtmf operation, hangup reasons, and tweak early media.
The ring operation sends ringing to the specified channel it is invoked on. The dtmf operation can be used to send DTMF digits to the specified channel of a specific length with a wait time in between. Finally hangup reasons allow you to specify why a channel is being hung up (busy, congestion). Early media behavior has also been tweaked slightly. When playing media to a channel it will no longer automatically answer. If it has not been answered a progress indication is sent instead. (closes issue ASTERISK-22701) Reported by: Matt Jordan Review: https://reviewboard.asterisk.org/r/2916/ ........ Merged revisions 402358 from http://svn.asterisk.org/svn/asterisk/branches/12 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@402359 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
@@ -273,6 +273,31 @@ void stasis_app_control_clear_roles(struct stasis_app_control *control);
|
|||||||
*/
|
*/
|
||||||
int stasis_app_control_continue(struct stasis_app_control *control, const char *context, const char *extension, int priority);
|
int stasis_app_control_continue(struct stasis_app_control *control, const char *context, const char *extension, int priority);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Indicate ringing 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_ring(struct stasis_app_control *control);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Send DTMF to the channel associated with this control.
|
||||||
|
*
|
||||||
|
* \param control Control for \c res_stasis.
|
||||||
|
* \param dtmf DTMF string.
|
||||||
|
* \param before Amount of time to wait before sending DTMF digits.
|
||||||
|
* \param between Amount of time between each DTMF digit.
|
||||||
|
* \param duration Amount of time each DTMF digit lasts for.
|
||||||
|
* \param after Amount of time to wait after sending DTMF digits.
|
||||||
|
*
|
||||||
|
* \return 0 for success.
|
||||||
|
* \return -1 for error.
|
||||||
|
*/
|
||||||
|
int stasis_app_control_dtmf(struct stasis_app_control *control, const char *dtmf, int before, int between, unsigned int duration, int after);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Mute the channel associated with this control.
|
* \brief Mute the channel associated with this control.
|
||||||
*
|
*
|
||||||
|
@@ -40,6 +40,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
|||||||
#include "asterisk/stasis_app_playback.h"
|
#include "asterisk/stasis_app_playback.h"
|
||||||
#include "asterisk/stasis_app_recording.h"
|
#include "asterisk/stasis_app_recording.h"
|
||||||
#include "asterisk/stasis_channels.h"
|
#include "asterisk/stasis_channels.h"
|
||||||
|
#include "asterisk/causes.h"
|
||||||
#include "resource_channels.h"
|
#include "resource_channels.h"
|
||||||
|
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
@@ -123,6 +124,22 @@ void ast_ari_answer_channel(struct ast_variable *headers,
|
|||||||
ast_ari_response_no_content(response);
|
ast_ari_response_no_content(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ast_ari_ring_channel(struct ast_variable *headers,
|
||||||
|
struct ast_ring_channel_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;
|
||||||
|
}
|
||||||
|
|
||||||
|
stasis_app_control_ring(control);
|
||||||
|
|
||||||
|
ast_ari_response_no_content(response);
|
||||||
|
}
|
||||||
|
|
||||||
void ast_ari_mute_channel(struct ast_variable *headers, struct ast_mute_channel_args *args, struct ast_ari_response *response)
|
void ast_ari_mute_channel(struct ast_variable *headers, struct ast_mute_channel_args *args, struct ast_ari_response *response)
|
||||||
{
|
{
|
||||||
RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
|
RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
|
||||||
@@ -195,6 +212,27 @@ void ast_ari_unmute_channel(struct ast_variable *headers, struct ast_unmute_chan
|
|||||||
ast_ari_response_no_content(response);
|
ast_ari_response_no_content(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ast_ari_send_dtmfchannel(struct ast_variable *headers, struct ast_send_dtmfchannel_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 (ast_strlen_zero(args->dtmf)) {
|
||||||
|
ast_ari_response_error(
|
||||||
|
response, 400, "Bad Request",
|
||||||
|
"DTMF is required");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
stasis_app_control_dtmf(control, args->dtmf, args->before, args->between, args->duration, args->after);
|
||||||
|
|
||||||
|
ast_ari_response_no_content(response);
|
||||||
|
}
|
||||||
|
|
||||||
void ast_ari_hold_channel(struct ast_variable *headers, struct ast_hold_channel_args *args, struct ast_ari_response *response)
|
void ast_ari_hold_channel(struct ast_variable *headers, struct ast_hold_channel_args *args, struct ast_ari_response *response)
|
||||||
{
|
{
|
||||||
RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
|
RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
|
||||||
@@ -501,6 +539,7 @@ void ast_ari_delete_channel(struct ast_variable *headers,
|
|||||||
struct ast_ari_response *response)
|
struct ast_ari_response *response)
|
||||||
{
|
{
|
||||||
RAII_VAR(struct ast_channel *, chan, NULL, ao2_cleanup);
|
RAII_VAR(struct ast_channel *, chan, NULL, ao2_cleanup);
|
||||||
|
int cause;
|
||||||
|
|
||||||
chan = ast_channel_get_by_name(args->channel_id);
|
chan = ast_channel_get_by_name(args->channel_id);
|
||||||
if (chan == NULL) {
|
if (chan == NULL) {
|
||||||
@@ -510,6 +549,20 @@ void ast_ari_delete_channel(struct ast_variable *headers,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ast_strlen_zero(args->reason) || !strcmp(args->reason, "normal")) {
|
||||||
|
cause = AST_CAUSE_NORMAL;
|
||||||
|
} else if (!strcmp(args->reason, "busy")) {
|
||||||
|
cause = AST_CAUSE_BUSY;
|
||||||
|
} else if (!strcmp(args->reason, "congestion")) {
|
||||||
|
cause = AST_CAUSE_CONGESTION;
|
||||||
|
} else {
|
||||||
|
ast_ari_response_error(
|
||||||
|
response, 400, "Invalid Reason",
|
||||||
|
"Invalid reason for hangup provided");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ast_channel_hangupcause_set(chan, cause);
|
||||||
ast_softhangup(chan, AST_SOFTHANGUP_EXPLICIT);
|
ast_softhangup(chan, AST_SOFTHANGUP_EXPLICIT);
|
||||||
|
|
||||||
ast_ari_response_no_content(response);
|
ast_ari_response_no_content(response);
|
||||||
|
@@ -96,6 +96,8 @@ void ast_ari_get_channel(struct ast_variable *headers, struct ast_get_channel_ar
|
|||||||
struct ast_delete_channel_args {
|
struct ast_delete_channel_args {
|
||||||
/*! \brief Channel's id */
|
/*! \brief Channel's id */
|
||||||
const char *channel_id;
|
const char *channel_id;
|
||||||
|
/*! \brief Reason for hanging up the channel */
|
||||||
|
const char *reason;
|
||||||
};
|
};
|
||||||
/*!
|
/*!
|
||||||
* \brief Delete (i.e. hangup) a channel.
|
* \brief Delete (i.e. hangup) a channel.
|
||||||
@@ -137,6 +139,42 @@ struct ast_answer_channel_args {
|
|||||||
* \param[out] response HTTP response
|
* \param[out] response HTTP response
|
||||||
*/
|
*/
|
||||||
void ast_ari_answer_channel(struct ast_variable *headers, struct ast_answer_channel_args *args, struct ast_ari_response *response);
|
void ast_ari_answer_channel(struct ast_variable *headers, struct ast_answer_channel_args *args, struct ast_ari_response *response);
|
||||||
|
/*! \brief Argument struct for ast_ari_ring_channel() */
|
||||||
|
struct ast_ring_channel_args {
|
||||||
|
/*! \brief Channel's id */
|
||||||
|
const char *channel_id;
|
||||||
|
};
|
||||||
|
/*!
|
||||||
|
* \brief Indicate ringing to a channel.
|
||||||
|
*
|
||||||
|
* \param headers HTTP headers
|
||||||
|
* \param args Swagger parameters
|
||||||
|
* \param[out] response HTTP response
|
||||||
|
*/
|
||||||
|
void ast_ari_ring_channel(struct ast_variable *headers, struct ast_ring_channel_args *args, struct ast_ari_response *response);
|
||||||
|
/*! \brief Argument struct for ast_ari_send_dtmfchannel() */
|
||||||
|
struct ast_send_dtmfchannel_args {
|
||||||
|
/*! \brief Channel's id */
|
||||||
|
const char *channel_id;
|
||||||
|
/*! \brief DTMF To send. */
|
||||||
|
const char *dtmf;
|
||||||
|
/*! \brief Amount of time to wait before DTMF digits (specified in milliseconds) start. */
|
||||||
|
int before;
|
||||||
|
/*! \brief Amount of time in between DTMF digits (specified in milliseconds). */
|
||||||
|
int between;
|
||||||
|
/*! \brief Length of each DTMF digit (specified in milliseconds). */
|
||||||
|
int duration;
|
||||||
|
/*! \brief Amount of time to wait after DTMF digits (specified in milliseconds) end. */
|
||||||
|
int after;
|
||||||
|
};
|
||||||
|
/*!
|
||||||
|
* \brief Send provided DTMF to a given channel.
|
||||||
|
*
|
||||||
|
* \param headers HTTP headers
|
||||||
|
* \param args Swagger parameters
|
||||||
|
* \param[out] response HTTP response
|
||||||
|
*/
|
||||||
|
void ast_ari_send_dtmfchannel(struct ast_variable *headers, struct ast_send_dtmfchannel_args *args, struct ast_ari_response *response);
|
||||||
/*! \brief Argument struct for ast_ari_mute_channel() */
|
/*! \brief Argument struct for ast_ari_mute_channel() */
|
||||||
struct ast_mute_channel_args {
|
struct ast_mute_channel_args {
|
||||||
/*! \brief Channel's id */
|
/*! \brief Channel's id */
|
||||||
|
@@ -253,6 +253,12 @@ static void ast_ari_delete_channel_cb(
|
|||||||
int code;
|
int code;
|
||||||
#endif /* AST_DEVMODE */
|
#endif /* AST_DEVMODE */
|
||||||
|
|
||||||
|
for (i = get_params; i; i = i->next) {
|
||||||
|
if (strcmp(i->name, "reason") == 0) {
|
||||||
|
args.reason = (i->value);
|
||||||
|
} else
|
||||||
|
{}
|
||||||
|
}
|
||||||
for (i = path_vars; i; i = i->next) {
|
for (i = path_vars; i; i = i->next) {
|
||||||
if (strcmp(i->name, "channelId") == 0) {
|
if (strcmp(i->name, "channelId") == 0) {
|
||||||
args.channel_id = (i->value);
|
args.channel_id = (i->value);
|
||||||
@@ -269,6 +275,7 @@ static void ast_ari_delete_channel_cb(
|
|||||||
break;
|
break;
|
||||||
case 500: /* Internal Server Error */
|
case 500: /* Internal Server Error */
|
||||||
case 501: /* Not Implemented */
|
case 501: /* Not Implemented */
|
||||||
|
case 400: /* Invalid reason for hangup provided */
|
||||||
case 404: /* Channel not found */
|
case 404: /* Channel not found */
|
||||||
is_valid = 1;
|
is_valid = 1;
|
||||||
break;
|
break;
|
||||||
@@ -417,6 +424,141 @@ static void ast_ari_answer_channel_cb(
|
|||||||
}
|
}
|
||||||
#endif /* AST_DEVMODE */
|
#endif /* AST_DEVMODE */
|
||||||
|
|
||||||
|
fin: __attribute__((unused))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/*!
|
||||||
|
* \brief Parameter parsing callback for /channels/{channelId}/ring.
|
||||||
|
* \param get_params GET parameters in the HTTP request.
|
||||||
|
* \param path_vars Path variables extracted from the request.
|
||||||
|
* \param headers HTTP headers.
|
||||||
|
* \param[out] response Response to the HTTP request.
|
||||||
|
*/
|
||||||
|
static void ast_ari_ring_channel_cb(
|
||||||
|
struct ast_variable *get_params, struct ast_variable *path_vars,
|
||||||
|
struct ast_variable *headers, struct ast_ari_response *response)
|
||||||
|
{
|
||||||
|
struct ast_ring_channel_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_ring_channel(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 */
|
||||||
|
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}/ring\n", code);
|
||||||
|
is_valid = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_valid) {
|
||||||
|
ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/ring\n");
|
||||||
|
ast_ari_response_error(response, 500,
|
||||||
|
"Internal Server Error", "Response validation failed");
|
||||||
|
}
|
||||||
|
#endif /* AST_DEVMODE */
|
||||||
|
|
||||||
|
fin: __attribute__((unused))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/*!
|
||||||
|
* \brief Parameter parsing callback for /channels/{channelId}/dtmf.
|
||||||
|
* \param get_params GET parameters in the HTTP request.
|
||||||
|
* \param path_vars Path variables extracted from the request.
|
||||||
|
* \param headers HTTP headers.
|
||||||
|
* \param[out] response Response to the HTTP request.
|
||||||
|
*/
|
||||||
|
static void ast_ari_send_dtmfchannel_cb(
|
||||||
|
struct ast_variable *get_params, struct ast_variable *path_vars,
|
||||||
|
struct ast_variable *headers, struct ast_ari_response *response)
|
||||||
|
{
|
||||||
|
struct ast_send_dtmfchannel_args args = {};
|
||||||
|
struct ast_variable *i;
|
||||||
|
#if defined(AST_DEVMODE)
|
||||||
|
int is_valid;
|
||||||
|
int code;
|
||||||
|
#endif /* AST_DEVMODE */
|
||||||
|
|
||||||
|
for (i = get_params; i; i = i->next) {
|
||||||
|
if (strcmp(i->name, "dtmf") == 0) {
|
||||||
|
args.dtmf = (i->value);
|
||||||
|
} else
|
||||||
|
if (strcmp(i->name, "before") == 0) {
|
||||||
|
args.before = atoi(i->value);
|
||||||
|
} else
|
||||||
|
if (strcmp(i->name, "between") == 0) {
|
||||||
|
args.between = atoi(i->value);
|
||||||
|
} else
|
||||||
|
if (strcmp(i->name, "duration") == 0) {
|
||||||
|
args.duration = atoi(i->value);
|
||||||
|
} else
|
||||||
|
if (strcmp(i->name, "after") == 0) {
|
||||||
|
args.after = atoi(i->value);
|
||||||
|
} else
|
||||||
|
{}
|
||||||
|
}
|
||||||
|
for (i = path_vars; i; i = i->next) {
|
||||||
|
if (strcmp(i->name, "channelId") == 0) {
|
||||||
|
args.channel_id = (i->value);
|
||||||
|
} else
|
||||||
|
{}
|
||||||
|
}
|
||||||
|
ast_ari_send_dtmfchannel(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 400: /* DTMF is required */
|
||||||
|
case 404: /* Channel not found */
|
||||||
|
case 409: /* Channel not in a Stasis application */
|
||||||
|
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}/dtmf\n", code);
|
||||||
|
is_valid = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_valid) {
|
||||||
|
ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/dtmf\n");
|
||||||
|
ast_ari_response_error(response, 500,
|
||||||
|
"Internal Server Error", "Response validation failed");
|
||||||
|
}
|
||||||
|
#endif /* AST_DEVMODE */
|
||||||
|
|
||||||
fin: __attribute__((unused))
|
fin: __attribute__((unused))
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1096,6 +1238,24 @@ static struct stasis_rest_handlers channels_channelId_answer = {
|
|||||||
.children = { }
|
.children = { }
|
||||||
};
|
};
|
||||||
/*! \brief REST handler for /api-docs/channels.{format} */
|
/*! \brief REST handler for /api-docs/channels.{format} */
|
||||||
|
static struct stasis_rest_handlers channels_channelId_ring = {
|
||||||
|
.path_segment = "ring",
|
||||||
|
.callbacks = {
|
||||||
|
[AST_HTTP_POST] = ast_ari_ring_channel_cb,
|
||||||
|
},
|
||||||
|
.num_children = 0,
|
||||||
|
.children = { }
|
||||||
|
};
|
||||||
|
/*! \brief REST handler for /api-docs/channels.{format} */
|
||||||
|
static struct stasis_rest_handlers channels_channelId_dtmf = {
|
||||||
|
.path_segment = "dtmf",
|
||||||
|
.callbacks = {
|
||||||
|
[AST_HTTP_POST] = ast_ari_send_dtmfchannel_cb,
|
||||||
|
},
|
||||||
|
.num_children = 0,
|
||||||
|
.children = { }
|
||||||
|
};
|
||||||
|
/*! \brief REST handler for /api-docs/channels.{format} */
|
||||||
static struct stasis_rest_handlers channels_channelId_mute = {
|
static struct stasis_rest_handlers channels_channelId_mute = {
|
||||||
.path_segment = "mute",
|
.path_segment = "mute",
|
||||||
.callbacks = {
|
.callbacks = {
|
||||||
@@ -1169,8 +1329,8 @@ static struct stasis_rest_handlers channels_channelId = {
|
|||||||
[AST_HTTP_GET] = ast_ari_get_channel_cb,
|
[AST_HTTP_GET] = ast_ari_get_channel_cb,
|
||||||
[AST_HTTP_DELETE] = ast_ari_delete_channel_cb,
|
[AST_HTTP_DELETE] = ast_ari_delete_channel_cb,
|
||||||
},
|
},
|
||||||
.num_children = 9,
|
.num_children = 11,
|
||||||
.children = { &channels_channelId_continue,&channels_channelId_answer,&channels_channelId_mute,&channels_channelId_unmute,&channels_channelId_hold,&channels_channelId_moh,&channels_channelId_play,&channels_channelId_record,&channels_channelId_variable, }
|
.children = { &channels_channelId_continue,&channels_channelId_answer,&channels_channelId_ring,&channels_channelId_dtmf,&channels_channelId_mute,&channels_channelId_unmute,&channels_channelId_hold,&channels_channelId_moh,&channels_channelId_play,&channels_channelId_record,&channels_channelId_variable, }
|
||||||
};
|
};
|
||||||
/*! \brief REST handler for /api-docs/channels.{format} */
|
/*! \brief REST handler for /api-docs/channels.{format} */
|
||||||
static struct stasis_rest_handlers channels = {
|
static struct stasis_rest_handlers channels = {
|
||||||
|
@@ -273,7 +273,7 @@ static void play_on_channel(struct stasis_app_playback *playback,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (ast_channel_state(chan) != AST_STATE_UP) {
|
if (ast_channel_state(chan) != AST_STATE_UP) {
|
||||||
ast_answer(chan);
|
ast_indicate(chan, AST_CONTROL_PROGRESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ast_begins_with(playback->media, SOUND_URI_SCHEME)) {
|
if (ast_begins_with(playback->media, SOUND_URI_SCHEME)) {
|
||||||
|
@@ -38,6 +38,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
|||||||
#include "asterisk/frame.h"
|
#include "asterisk/frame.h"
|
||||||
#include "asterisk/pbx.h"
|
#include "asterisk/pbx.h"
|
||||||
#include "asterisk/musiconhold.h"
|
#include "asterisk/musiconhold.h"
|
||||||
|
#include "asterisk/app.h"
|
||||||
|
|
||||||
struct stasis_app_control {
|
struct stasis_app_control {
|
||||||
ast_cond_t wait_cond;
|
ast_cond_t wait_cond;
|
||||||
@@ -280,6 +281,66 @@ int stasis_app_control_continue(struct stasis_app_control *control, const char *
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct stasis_app_control_dtmf_data {
|
||||||
|
int before;
|
||||||
|
int between;
|
||||||
|
unsigned int duration;
|
||||||
|
int after;
|
||||||
|
char dtmf[];
|
||||||
|
};
|
||||||
|
|
||||||
|
static void *app_control_dtmf(struct stasis_app_control *control,
|
||||||
|
struct ast_channel *chan, void *data)
|
||||||
|
{
|
||||||
|
RAII_VAR(struct stasis_app_control_dtmf_data *, dtmf_data, data, ast_free);
|
||||||
|
|
||||||
|
if (dtmf_data->before) {
|
||||||
|
ast_safe_sleep(chan, dtmf_data->before);
|
||||||
|
}
|
||||||
|
|
||||||
|
ast_dtmf_stream(chan, NULL, dtmf_data->dtmf, dtmf_data->between, dtmf_data->duration);
|
||||||
|
|
||||||
|
if (dtmf_data->after) {
|
||||||
|
ast_safe_sleep(chan, dtmf_data->after);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int stasis_app_control_dtmf(struct stasis_app_control *control, const char *dtmf, int before, int between, unsigned int duration, int after)
|
||||||
|
{
|
||||||
|
struct stasis_app_control_dtmf_data *dtmf_data;
|
||||||
|
|
||||||
|
if (!(dtmf_data = ast_calloc(1, sizeof(*dtmf_data) + strlen(dtmf) + 1))) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
dtmf_data->before = before;
|
||||||
|
dtmf_data->between = between;
|
||||||
|
dtmf_data->duration = duration;
|
||||||
|
dtmf_data->after = after;
|
||||||
|
strcpy(dtmf_data->dtmf, dtmf);
|
||||||
|
|
||||||
|
stasis_app_send_command_async(control, app_control_dtmf, dtmf_data);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *app_control_ring(struct stasis_app_control *control,
|
||||||
|
struct ast_channel *chan, void *data)
|
||||||
|
{
|
||||||
|
ast_indicate(control->channel, AST_CONTROL_RINGING);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int stasis_app_control_ring(struct stasis_app_control *control)
|
||||||
|
{
|
||||||
|
stasis_app_send_command_async(control, app_control_ring, NULL);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
struct stasis_app_control_mute_data {
|
struct stasis_app_control_mute_data {
|
||||||
enum ast_frame_type frametype;
|
enum ast_frame_type frametype;
|
||||||
unsigned int direction;
|
unsigned int direction;
|
||||||
|
@@ -138,9 +138,30 @@
|
|||||||
"required": true,
|
"required": true,
|
||||||
"allowMultiple": false,
|
"allowMultiple": false,
|
||||||
"dataType": "string"
|
"dataType": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "reason",
|
||||||
|
"description": "Reason for hanging up the channel",
|
||||||
|
"paramType": "query",
|
||||||
|
"required": false,
|
||||||
|
"allowMultiple": false,
|
||||||
|
"dataType": "string",
|
||||||
|
"defalutValue": "normal",
|
||||||
|
"allowableValues": {
|
||||||
|
"valueType": "LIST",
|
||||||
|
"values": [
|
||||||
|
"normal",
|
||||||
|
"busy",
|
||||||
|
"congestion"
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"errorResponses": [
|
"errorResponses": [
|
||||||
|
{
|
||||||
|
"code": 400,
|
||||||
|
"reason": "Invalid reason for hangup provided"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"code": 404,
|
"code": 404,
|
||||||
"reason": "Channel not found"
|
"reason": "Channel not found"
|
||||||
@@ -237,6 +258,118 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"path": "/channels/{channelId}/ring",
|
||||||
|
"description": "Send a ringing indication to a channel",
|
||||||
|
"operations": [
|
||||||
|
{
|
||||||
|
"httpMethod": "POST",
|
||||||
|
"summary": "Indicate ringing to a channel.",
|
||||||
|
"nickname": "ringChannel",
|
||||||
|
"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"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "/channels/{channelId}/dtmf",
|
||||||
|
"description": "Send DTMF to a channel",
|
||||||
|
"operations": [
|
||||||
|
{
|
||||||
|
"httpMethod": "POST",
|
||||||
|
"summary": "Send provided DTMF to a given channel.",
|
||||||
|
"nickname": "sendDTMFChannel",
|
||||||
|
"responseClass": "void",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "channelId",
|
||||||
|
"description": "Channel's id",
|
||||||
|
"paramType": "path",
|
||||||
|
"required": true,
|
||||||
|
"allowMultiple": false,
|
||||||
|
"dataType": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "dtmf",
|
||||||
|
"description": "DTMF To send.",
|
||||||
|
"paramType": "query",
|
||||||
|
"required": false,
|
||||||
|
"allowMultiple": false,
|
||||||
|
"dataType": "string"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "before",
|
||||||
|
"description": "Amount of time to wait before DTMF digits (specified in milliseconds) start.",
|
||||||
|
"paramType": "query",
|
||||||
|
"required": false,
|
||||||
|
"allowMultiple": false,
|
||||||
|
"dataType": "int",
|
||||||
|
"defaultValue": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "between",
|
||||||
|
"description": "Amount of time in between DTMF digits (specified in milliseconds).",
|
||||||
|
"paramType": "query",
|
||||||
|
"required": false,
|
||||||
|
"allowMultiple": false,
|
||||||
|
"dataType": "int",
|
||||||
|
"defaultValue": 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "duration",
|
||||||
|
"description": "Length of each DTMF digit (specified in milliseconds).",
|
||||||
|
"paramType": "query",
|
||||||
|
"required": false,
|
||||||
|
"allowMultiple": false,
|
||||||
|
"dataType": "int",
|
||||||
|
"defaultValue": 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "after",
|
||||||
|
"description": "Amount of time to wait after DTMF digits (specified in milliseconds) end.",
|
||||||
|
"paramType": "query",
|
||||||
|
"required": false,
|
||||||
|
"allowMultiple": false,
|
||||||
|
"dataType": "int",
|
||||||
|
"defaultValue": 0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"errorResponses": [
|
||||||
|
{
|
||||||
|
"code": 400,
|
||||||
|
"reason": "DTMF is required"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 404,
|
||||||
|
"reason": "Channel not found"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 409,
|
||||||
|
"reason": "Channel not in a Stasis application"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"path": "/channels/{channelId}/mute",
|
"path": "/channels/{channelId}/mute",
|
||||||
"description": "Mute a channel",
|
"description": "Mute a channel",
|
||||||
|
Reference in New Issue
Block a user