mirror of
https://github.com/asterisk/asterisk.git
synced 2025-10-09 14:36:48 +00:00
Compare commits
5 Commits
ff80666aac
...
45646be97a
Author | SHA1 | Date | |
---|---|---|---|
|
45646be97a | ||
|
a96d7fcfaf | ||
|
559ea45ddd | ||
|
2c97fd3ea4 | ||
|
ece6ed9459 |
@@ -2421,6 +2421,7 @@ static void *__analog_ss_thread(void *data)
|
||||
}
|
||||
while (len < AST_MAX_EXTENSION-1) {
|
||||
int is_exten_parking = 0;
|
||||
int is_lastnumredial = 0;
|
||||
|
||||
/* Read digit unless it's supposed to be immediate, in which case the
|
||||
only answer is 's' */
|
||||
@@ -2455,6 +2456,9 @@ static void *__analog_ss_thread(void *data)
|
||||
analog_lock_private(p);
|
||||
ast_copy_string(exten, p->lastexten, sizeof(exten));
|
||||
analog_unlock_private(p);
|
||||
/* If Last Number Redial was used, even if the user might normally be able to dial further
|
||||
* digits for the digits dialed, we should complete the call immediately without delay. */
|
||||
is_lastnumredial = 1;
|
||||
} else {
|
||||
ast_verb(3, "Last Number Redial not possible on channel %d (no saved number)\n", p->channel);
|
||||
res = analog_play_tone(p, idx, ANALOG_TONE_CONGESTION);
|
||||
@@ -2464,7 +2468,7 @@ static void *__analog_ss_thread(void *data)
|
||||
}
|
||||
}
|
||||
if (ast_exists_extension(chan, ast_channel_context(chan), exten, 1, p->cid_num) && !is_exten_parking) {
|
||||
if (!res || !ast_matchmore_extension(chan, ast_channel_context(chan), exten, 1, p->cid_num)) {
|
||||
if (!res || is_lastnumredial || !ast_matchmore_extension(chan, ast_channel_context(chan), exten, 1, p->cid_num)) {
|
||||
if (getforward) {
|
||||
/* Record this as the forwarding extension */
|
||||
analog_lock_private(p);
|
||||
|
@@ -52,6 +52,9 @@
|
||||
This is not intended to be used for securely scrambling
|
||||
audio. It merely renders obfuscates audio on a channel
|
||||
to render it unintelligible, as a privacy enhancement.</para>
|
||||
<example title="Scramble speech in both directions">
|
||||
same => n,Set(SCRAMBLE()=both)
|
||||
</example>
|
||||
</description>
|
||||
<see-also>
|
||||
<ref type="application">ChanSpy</ref>
|
||||
|
@@ -39,7 +39,7 @@
|
||||
#include "asterisk/netsock2.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/taskprocessor.h"
|
||||
#include "asterisk/threadpool.h"
|
||||
#include "asterisk/taskpool.h"
|
||||
#include "asterisk/json.h"
|
||||
#include "asterisk/vector.h"
|
||||
#include "asterisk/cli.h"
|
||||
@@ -83,8 +83,8 @@
|
||||
#define NOTIFY_WIZARD_OBSERVERS(container, callback, ...) \
|
||||
NOTIFY_GENERIC_OBSERVERS(container, sorcery_wizard_observer, callback, __VA_ARGS__)
|
||||
|
||||
/*! \brief Thread pool for observers */
|
||||
static struct ast_threadpool *threadpool;
|
||||
/*! \brief Taskpool for observers */
|
||||
static struct ast_taskpool *taskpool;
|
||||
|
||||
/*! \brief Structure for an internal wizard instance */
|
||||
struct ast_sorcery_internal_wizard {
|
||||
@@ -402,8 +402,8 @@ static struct ast_cli_entry cli_commands[] = {
|
||||
static void sorcery_cleanup(void)
|
||||
{
|
||||
ast_cli_unregister_multiple(cli_commands, ARRAY_LEN(cli_commands));
|
||||
ast_threadpool_shutdown(threadpool);
|
||||
threadpool = NULL;
|
||||
ast_taskpool_shutdown(taskpool);
|
||||
taskpool = NULL;
|
||||
ao2_cleanup(wizards);
|
||||
wizards = NULL;
|
||||
ao2_cleanup(observers);
|
||||
@@ -443,19 +443,20 @@ static void parse_general_options(void)
|
||||
|
||||
int ast_sorcery_init(void)
|
||||
{
|
||||
struct ast_threadpool_options options = {
|
||||
.version = AST_THREADPOOL_OPTIONS_VERSION,
|
||||
struct ast_taskpool_options options = {
|
||||
.version = AST_TASKPOOL_OPTIONS_VERSION,
|
||||
.auto_increment = 1,
|
||||
.max_size = 0,
|
||||
.idle_timeout = 60,
|
||||
.initial_size = 0,
|
||||
.initial_size = 1,
|
||||
.minimum_size = 1,
|
||||
};
|
||||
ast_assert(wizards == NULL);
|
||||
|
||||
parse_general_options();
|
||||
|
||||
threadpool = ast_threadpool_create("sorcery", NULL, &options);
|
||||
if (!threadpool) {
|
||||
taskpool = ast_taskpool_create("sorcery", &options);
|
||||
if (!taskpool) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -807,7 +808,7 @@ static struct ast_sorcery_object_type *sorcery_object_type_alloc(const char *typ
|
||||
/* Create name with seq number appended. */
|
||||
ast_taskprocessor_build_name(tps_name, sizeof(tps_name), "sorcery/%s", type);
|
||||
|
||||
if (!(object_type->serializer = ast_threadpool_serializer(tps_name, threadpool))) {
|
||||
if (!(object_type->serializer = ast_taskpool_serializer(tps_name, taskpool))) {
|
||||
ao2_ref(object_type, -1);
|
||||
return NULL;
|
||||
}
|
||||
|
@@ -311,7 +311,8 @@ static void *bridge_channel_control_thread(void *data)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct ast_channel *prepare_bridge_media_channel(const char *type)
|
||||
static struct ast_channel *prepare_bridge_media_channel(const char *type,
|
||||
struct ast_format *channel_format)
|
||||
{
|
||||
RAII_VAR(struct ast_format_cap *, cap, NULL, ao2_cleanup);
|
||||
struct ast_channel *chan;
|
||||
@@ -321,7 +322,8 @@ static struct ast_channel *prepare_bridge_media_channel(const char *type)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ast_format_cap_append(cap, ast_format_slin, 0);
|
||||
/* This bumps the format's refcount */
|
||||
ast_format_cap_append(cap, channel_format, 0);
|
||||
|
||||
chan = ast_request(type, cap, NULL, NULL, "ARI", NULL);
|
||||
if (!chan) {
|
||||
@@ -407,6 +409,7 @@ static int ari_bridges_play_helper(const char **args_media,
|
||||
|
||||
static void ari_bridges_play_new(const char **args_media,
|
||||
size_t args_media_count,
|
||||
const char *args_format,
|
||||
const char *args_lang,
|
||||
int args_offset_ms,
|
||||
int args_skipms,
|
||||
@@ -424,14 +427,64 @@ static void ari_bridges_play_new(const char **args_media,
|
||||
struct stasis_topic *bridge_topic;
|
||||
struct bridge_channel_control_thread_data *thread_data;
|
||||
pthread_t threadid;
|
||||
struct ast_format *channel_format = NULL;
|
||||
|
||||
struct ast_frame prog = {
|
||||
.frametype = AST_FRAME_CONTROL,
|
||||
.subclass.integer = AST_CONTROL_PROGRESS,
|
||||
};
|
||||
|
||||
/*
|
||||
* Determine the format for the playback channel.
|
||||
* If a format was specified, use that if it's valid.
|
||||
* Otherwise, if the bridge is empty, use slin.
|
||||
* If the bridge has one channel, use that channel's raw write format.
|
||||
* If the bridge has multiple channels, use the slin format that
|
||||
* will handle the highest sample rate of the raw write format of all the channels.
|
||||
*/
|
||||
if (!ast_strlen_zero(args_format)) {
|
||||
channel_format = ast_format_cache_get(args_format);
|
||||
if (!channel_format) {
|
||||
ast_ari_response_error(
|
||||
response, 422, "Unprocessable Entity",
|
||||
"specified announcer_format is unknown on this system");
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* ast_format_cache_get() bumps the refcount but the other calls
|
||||
* to retrieve formats don't so we'll drop this reference.
|
||||
* It'll be bumped again in the prepare_bridge_media_channel() call below.
|
||||
*/
|
||||
ao2_ref(channel_format, -1);
|
||||
} else {
|
||||
ast_bridge_lock(bridge);
|
||||
if (bridge->num_channels == 0) {
|
||||
channel_format = ast_format_slin;
|
||||
} else if (bridge->num_channels == 1) {
|
||||
struct ast_bridge_channel *bc = NULL;
|
||||
bc = AST_LIST_FIRST(&bridge->channels);
|
||||
if (bc) {
|
||||
channel_format = ast_channel_rawwriteformat(bc->chan);
|
||||
}
|
||||
} else {
|
||||
struct ast_bridge_channel *bc = NULL;
|
||||
unsigned int max_sample_rate = 0;
|
||||
AST_LIST_TRAVERSE(&bridge->channels, bc, entry) {
|
||||
struct ast_format *fmt = ast_channel_rawwriteformat(bc->chan);
|
||||
max_sample_rate = MAX(ast_format_get_sample_rate(fmt), max_sample_rate);
|
||||
}
|
||||
channel_format = ast_format_cache_get_slin_by_rate(max_sample_rate);
|
||||
}
|
||||
ast_bridge_unlock(bridge);
|
||||
}
|
||||
|
||||
if (!(play_channel = prepare_bridge_media_channel("Announcer"))) {
|
||||
if (!channel_format) {
|
||||
channel_format = ast_format_slin;
|
||||
}
|
||||
|
||||
play_channel = prepare_bridge_media_channel("Announcer", channel_format);
|
||||
ao2_cleanup(channel_format);
|
||||
if (!play_channel) {
|
||||
ast_ari_response_error(
|
||||
response, 500, "Internal Error", "Could not create playback channel");
|
||||
return;
|
||||
@@ -578,6 +631,7 @@ static void ari_bridges_handle_play(
|
||||
const char *args_bridge_id,
|
||||
const char **args_media,
|
||||
size_t args_media_count,
|
||||
const char *args_format,
|
||||
const char *args_lang,
|
||||
int args_offset_ms,
|
||||
int args_skipms,
|
||||
@@ -608,7 +662,7 @@ static void ari_bridges_handle_play(
|
||||
return;
|
||||
}
|
||||
|
||||
ari_bridges_play_new(args_media, args_media_count, args_lang, args_offset_ms,
|
||||
ari_bridges_play_new(args_media, args_media_count, args_format, args_lang, args_offset_ms,
|
||||
args_skipms, args_playback_id, response, bridge);
|
||||
}
|
||||
|
||||
@@ -620,6 +674,7 @@ void ast_ari_bridges_play(struct ast_variable *headers,
|
||||
ari_bridges_handle_play(args->bridge_id,
|
||||
args->media,
|
||||
args->media_count,
|
||||
args->announcer_format,
|
||||
args->lang,
|
||||
args->offsetms,
|
||||
args->skipms,
|
||||
@@ -634,6 +689,7 @@ void ast_ari_bridges_play_with_id(struct ast_variable *headers,
|
||||
ari_bridges_handle_play(args->bridge_id,
|
||||
args->media,
|
||||
args->media_count,
|
||||
args->announcer_format,
|
||||
args->lang,
|
||||
args->offsetms,
|
||||
args->skipms,
|
||||
@@ -660,6 +716,8 @@ void ast_ari_bridges_record(struct ast_variable *headers,
|
||||
size_t uri_name_maxlen;
|
||||
struct bridge_channel_control_thread_data *thread_data;
|
||||
pthread_t threadid;
|
||||
struct ast_format *file_format = NULL;
|
||||
struct ast_format *channel_format = NULL;
|
||||
|
||||
ast_assert(response != NULL);
|
||||
|
||||
@@ -667,7 +725,34 @@ void ast_ari_bridges_record(struct ast_variable *headers,
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(record_channel = prepare_bridge_media_channel("Recorder"))) {
|
||||
file_format = ast_get_format_for_file_ext(args->format);
|
||||
if (!file_format) {
|
||||
ast_ari_response_error(
|
||||
response, 422, "Unprocessable Entity",
|
||||
"specified format is unknown on this system");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ast_strlen_zero(args->recorder_format)) {
|
||||
channel_format = ast_format_cache_get(args->recorder_format);
|
||||
if (!channel_format) {
|
||||
ast_ari_response_error(
|
||||
response, 422, "Unprocessable Entity",
|
||||
"specified recorder_format is unknown on this system");
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* ast_format_cache_get() bumps the refcount but the other calls
|
||||
* to retrieve formats don't so we'll drop this reference.
|
||||
* It'll be bumped again in the prepare_bridge_media_channel() call below.
|
||||
*/
|
||||
ao2_ref(channel_format, -1);
|
||||
|
||||
} else {
|
||||
channel_format = file_format;
|
||||
}
|
||||
|
||||
if (!(record_channel = prepare_bridge_media_channel("Recorder", channel_format))) {
|
||||
ast_ari_response_error(
|
||||
response, 500, "Internal Server Error", "Failed to create recording channel");
|
||||
return;
|
||||
@@ -728,13 +813,6 @@ void ast_ari_bridges_record(struct ast_variable *headers,
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ast_get_format_for_file_ext(options->format)) {
|
||||
ast_ari_response_error(
|
||||
response, 422, "Unprocessable Entity",
|
||||
"specified format is unknown on this system");
|
||||
return;
|
||||
}
|
||||
|
||||
recording = stasis_app_control_record(control, options);
|
||||
if (recording == NULL) {
|
||||
switch(errno) {
|
||||
|
@@ -285,6 +285,8 @@ struct ast_ari_bridges_play_args {
|
||||
size_t media_count;
|
||||
/*! Parsing context for media. */
|
||||
char *media_parse;
|
||||
/*! Format of the 'Anouncer' channel attached to the bridge. Defaults to the format of the channel in the bridge with the highest sampe rate. */
|
||||
const char *announcer_format;
|
||||
/*! For sounds, selects language for sound. */
|
||||
const char *lang;
|
||||
/*! Number of milliseconds to skip before playing. Only applies to the first URI if multiple media URIs are specified. */
|
||||
@@ -327,6 +329,8 @@ struct ast_ari_bridges_play_with_id_args {
|
||||
size_t media_count;
|
||||
/*! Parsing context for media. */
|
||||
char *media_parse;
|
||||
/*! Format of the 'Anouncer' channel attached to the bridge. Defaults to the format of the channel in the bridge with the highest sampe rate. */
|
||||
const char *announcer_format;
|
||||
/*! For sounds, selects language for sound. */
|
||||
const char *lang;
|
||||
/*! Number of milliseconds to skip before playing. Only applies to the first URI if multiple media URIs are specified. */
|
||||
@@ -363,6 +367,8 @@ struct ast_ari_bridges_record_args {
|
||||
const char *name;
|
||||
/*! Format to encode audio in */
|
||||
const char *format;
|
||||
/*! Format of the 'Recorder' channel attached to the bridge. Defaults to the same format as the 'format' parameter. */
|
||||
const char *recorder_format;
|
||||
/*! Maximum duration of the recording, in seconds. 0 for no limit. */
|
||||
int max_duration_seconds;
|
||||
/*! Maximum duration of silence, in seconds. 0 for no limit. */
|
||||
|
@@ -1044,6 +1044,10 @@ int ast_ari_bridges_play_parse_body(
|
||||
args->media[0] = ast_json_string_get(field);
|
||||
}
|
||||
}
|
||||
field = ast_json_object_get(body, "announcer_format");
|
||||
if (field) {
|
||||
args->announcer_format = ast_json_string_get(field);
|
||||
}
|
||||
field = ast_json_object_get(body, "lang");
|
||||
if (field) {
|
||||
args->lang = ast_json_string_get(field);
|
||||
@@ -1128,6 +1132,9 @@ static void ast_ari_bridges_play_cb(
|
||||
args.media[j] = (vals[j]);
|
||||
}
|
||||
} else
|
||||
if (strcmp(i->name, "announcer_format") == 0) {
|
||||
args.announcer_format = (i->value);
|
||||
} else
|
||||
if (strcmp(i->name, "lang") == 0) {
|
||||
args.lang = (i->value);
|
||||
} else
|
||||
@@ -1164,6 +1171,7 @@ static void ast_ari_bridges_play_cb(
|
||||
case 501: /* Not Implemented */
|
||||
case 404: /* Bridge not found */
|
||||
case 409: /* Bridge not in a Stasis application */
|
||||
case 422: /* The format specified is unknown on this system */
|
||||
is_valid = 1;
|
||||
break;
|
||||
default:
|
||||
@@ -1223,6 +1231,10 @@ int ast_ari_bridges_play_with_id_parse_body(
|
||||
args->media[0] = ast_json_string_get(field);
|
||||
}
|
||||
}
|
||||
field = ast_json_object_get(body, "announcer_format");
|
||||
if (field) {
|
||||
args->announcer_format = ast_json_string_get(field);
|
||||
}
|
||||
field = ast_json_object_get(body, "lang");
|
||||
if (field) {
|
||||
args->lang = ast_json_string_get(field);
|
||||
@@ -1303,6 +1315,9 @@ static void ast_ari_bridges_play_with_id_cb(
|
||||
args.media[j] = (vals[j]);
|
||||
}
|
||||
} else
|
||||
if (strcmp(i->name, "announcer_format") == 0) {
|
||||
args.announcer_format = (i->value);
|
||||
} else
|
||||
if (strcmp(i->name, "lang") == 0) {
|
||||
args.lang = (i->value);
|
||||
} else
|
||||
@@ -1339,6 +1354,7 @@ static void ast_ari_bridges_play_with_id_cb(
|
||||
case 501: /* Not Implemented */
|
||||
case 404: /* Bridge not found */
|
||||
case 409: /* Bridge not in a Stasis application */
|
||||
case 422: /* The format specified is unknown on this system */
|
||||
is_valid = 1;
|
||||
break;
|
||||
default:
|
||||
@@ -1377,6 +1393,10 @@ int ast_ari_bridges_record_parse_body(
|
||||
if (field) {
|
||||
args->format = ast_json_string_get(field);
|
||||
}
|
||||
field = ast_json_object_get(body, "recorder_format");
|
||||
if (field) {
|
||||
args->recorder_format = ast_json_string_get(field);
|
||||
}
|
||||
field = ast_json_object_get(body, "maxDurationSeconds");
|
||||
if (field) {
|
||||
args->max_duration_seconds = ast_json_integer_get(field);
|
||||
@@ -1428,6 +1448,9 @@ static void ast_ari_bridges_record_cb(
|
||||
if (strcmp(i->name, "format") == 0) {
|
||||
args.format = (i->value);
|
||||
} else
|
||||
if (strcmp(i->name, "recorder_format") == 0) {
|
||||
args.recorder_format = (i->value);
|
||||
} else
|
||||
if (strcmp(i->name, "maxDurationSeconds") == 0) {
|
||||
args.max_duration_seconds = atoi(i->value);
|
||||
} else
|
||||
|
@@ -602,10 +602,13 @@ static void handle_outgoing_request(struct ast_sip_session *session, struct pjsi
|
||||
uri = ast_strdupa(ast_str_buffer(buf));
|
||||
ast_str_reset(buf);
|
||||
ast_str_set(&buf, 0, "<%s>", uri);
|
||||
if (!ast_strlen_zero(final_eprofile->location_source)) {
|
||||
ast_str_append(&buf, 0, ";loc-src=%s", final_eprofile->location_source);
|
||||
}
|
||||
uri = ast_strdupa(ast_str_buffer(buf));
|
||||
|
||||
ast_trace(4, "%s: Using URI '%s'\n", session_name, uri);
|
||||
|
||||
|
||||
/* It's almost impossible for add header to fail but you never know */
|
||||
geoloc_hdr = ast_sip_add_header2(tdata, "Geolocation", uri);
|
||||
if (geoloc_hdr == NULL) {
|
||||
|
@@ -490,6 +490,14 @@
|
||||
"allowMultiple": true,
|
||||
"dataType": "string"
|
||||
},
|
||||
{
|
||||
"name": "announcer_format",
|
||||
"description": "Format of the 'Anouncer' channel attached to the bridge. Defaults to the format of the channel in the bridge with the highest sampe rate.",
|
||||
"paramType": "query",
|
||||
"required": false,
|
||||
"allowMultiple": false,
|
||||
"dataType": "string"
|
||||
},
|
||||
{
|
||||
"name": "lang",
|
||||
"description": "For sounds, selects language for sound.",
|
||||
@@ -510,7 +518,6 @@
|
||||
"valueType": "RANGE",
|
||||
"min": 0
|
||||
}
|
||||
|
||||
},
|
||||
{
|
||||
"name": "skipms",
|
||||
@@ -542,6 +549,10 @@
|
||||
{
|
||||
"code": 409,
|
||||
"reason": "Bridge not in a Stasis application"
|
||||
},
|
||||
{
|
||||
"code": 422,
|
||||
"reason": "The format specified is unknown on this system"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -585,6 +596,14 @@
|
||||
"allowMultiple": true,
|
||||
"dataType": "string"
|
||||
},
|
||||
{
|
||||
"name": "announcer_format",
|
||||
"description": "Format of the 'Anouncer' channel attached to the bridge. Defaults to the format of the channel in the bridge with the highest sampe rate.",
|
||||
"paramType": "query",
|
||||
"required": false,
|
||||
"allowMultiple": false,
|
||||
"dataType": "string"
|
||||
},
|
||||
{
|
||||
"name": "lang",
|
||||
"description": "For sounds, selects language for sound.",
|
||||
@@ -628,6 +647,10 @@
|
||||
{
|
||||
"code": 409,
|
||||
"reason": "Bridge not in a Stasis application"
|
||||
},
|
||||
{
|
||||
"code": 422,
|
||||
"reason": "The format specified is unknown on this system"
|
||||
}
|
||||
]
|
||||
|
||||
@@ -672,6 +695,14 @@
|
||||
"allowMultiple": false,
|
||||
"dataType": "string"
|
||||
},
|
||||
{
|
||||
"name": "recorder_format",
|
||||
"description": "Format of the 'Recorder' channel attached to the bridge. Defaults to the same format as the 'format' parameter.",
|
||||
"paramType": "query",
|
||||
"required": false,
|
||||
"allowMultiple": false,
|
||||
"dataType": "string"
|
||||
},
|
||||
{
|
||||
"name": "maxDurationSeconds",
|
||||
"description": "Maximum duration of the recording, in seconds. 0 for no limit.",
|
||||
|
Reference in New Issue
Block a user