aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--channels/chan_sip.c2
-rw-r--r--include/asterisk/_private.h7
-rw-r--r--include/asterisk/options.h3
-rw-r--r--main/asterisk.c1
-rw-r--r--main/channel.c112
-rw-r--r--main/loader.c1
6 files changed, 121 insertions, 5 deletions
diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index 689ed477b..6c31841be 100644
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -24324,7 +24324,7 @@ static struct ast_channel *sip_request_call(const char *type, format_t format, c
printf("Setting up to call extension '%s' at '%s'\n", ext ? ext : "<none>", host);
#endif
p->prefcodec = oldformat; /* Format for this call */
- p->jointcapability = oldformat;
+ p->jointcapability = oldformat & p->capability;
sip_pvt_lock(p);
tmpc = sip_new(p, AST_STATE_DOWN, host, requestor ? requestor->linkedid : NULL); /* Place the call */
if (sip_cfg.callevents)
diff --git a/include/asterisk/_private.h b/include/asterisk/_private.h
index 435ee0985..560c8c169 100644
--- a/include/asterisk/_private.h
+++ b/include/asterisk/_private.h
@@ -83,4 +83,11 @@ void ast_process_pending_reloads(void);
*/
int ast_xmldoc_load_documentation(void);
+/*!
+ * \brief Reload genericplc configuration value from codecs.conf
+ *
+ * Implementation is in main/channel.c
+ */
+int ast_plc_reload(void);
+
#endif /* _ASTERISK__PRIVATE_H */
diff --git a/include/asterisk/options.h b/include/asterisk/options.h
index e6147aa1c..2509f4642 100644
--- a/include/asterisk/options.h
+++ b/include/asterisk/options.h
@@ -94,6 +94,8 @@ enum ast_option_flags {
AST_OPT_FLAG_HIDE_CONSOLE_CONNECT = (1 << 28),
/*! Protect the configuration file path with a lock */
AST_OPT_FLAG_LOCK_CONFIG_DIR = (1 << 29),
+ /*! Generic PLC */
+ AST_OPT_FLAG_GENERIC_PLC = (1 << 30),
};
/*! These are the options that set by default when Asterisk starts */
@@ -131,6 +133,7 @@ enum ast_option_flags {
#define ast_opt_force_black_background ast_test_flag(&ast_options, AST_OPT_FLAG_FORCE_BLACK_BACKGROUND)
#define ast_opt_hide_connect ast_test_flag(&ast_options, AST_OPT_FLAG_HIDE_CONSOLE_CONNECT)
#define ast_opt_lock_confdir ast_test_flag(&ast_options, AST_OPT_FLAG_LOCK_CONFIG_DIR)
+#define ast_opt_generic_plc ast_test_flag(&ast_options, AST_OPT_FLAG_GENERIC_PLC)
extern struct ast_flags ast_options;
diff --git a/main/asterisk.c b/main/asterisk.c
index 6751456c1..e81840fc0 100644
--- a/main/asterisk.c
+++ b/main/asterisk.c
@@ -466,6 +466,7 @@ static char *handle_show_settings(struct ast_cli_entry *e, int cmd, struct ast_c
ast_cli(a->fd, " Transcode via SLIN: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_TRANSCODE_VIA_SLIN) ? "Enabled" : "Disabled");
ast_cli(a->fd, " Internal timing: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_INTERNAL_TIMING) ? "Enabled" : "Disabled");
ast_cli(a->fd, " Transmit silence during rec: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_TRANSMIT_SILENCE) ? "Enabled" : "Disabled");
+ ast_cli(a->fd, " Generic PLC: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_GENERIC_PLC) ? "Enabled" : "Disabled");
ast_cli(a->fd, "\n* Subsystems\n");
ast_cli(a->fd, " -------------\n");
diff --git a/main/channel.c b/main/channel.c
index 5850c89de..7866b14e0 100644
--- a/main/channel.c
+++ b/main/channel.c
@@ -4059,6 +4059,86 @@ int ast_write_video(struct ast_channel *chan, struct ast_frame *fr)
return res;
}
+struct plc_ds {
+ /* A buffer in which to store SLIN PLC
+ * samples generated by the generic PLC
+ * functionality in plc.c
+ */
+ int16_t *samples_buf;
+ /* The current number of samples in the
+ * samples_buf
+ */
+ size_t num_samples;
+ plc_state_t plc_state;
+};
+
+static void plc_ds_destroy(void *data)
+{
+ struct plc_ds *plc = data;
+ ast_free(plc->samples_buf);
+ ast_free(plc);
+}
+
+static struct ast_datastore_info plc_ds_info = {
+ .type = "plc",
+ .destroy = plc_ds_destroy,
+};
+
+static void adjust_frame_for_plc(struct ast_channel *chan, struct ast_frame *frame, struct ast_datastore *datastore)
+{
+ int num_new_samples = frame->samples;
+ struct plc_ds *plc = datastore->data;
+
+ /* First, we need to be sure that our buffer is large enough to accomodate
+ * the samples we need to fill in. This will likely only occur on the first
+ * frame we write.
+ */
+ if (plc->num_samples < num_new_samples) {
+ ast_free(plc->samples_buf);
+ plc->samples_buf = ast_calloc(num_new_samples, sizeof(*plc->samples_buf));
+ if (!plc->samples_buf) {
+ ast_channel_datastore_remove(chan, datastore);
+ ast_datastore_free(datastore);
+ return;
+ }
+ plc->num_samples = num_new_samples;
+ }
+
+ if (frame->datalen == 0) {
+ plc_fillin(&plc->plc_state, plc->samples_buf, frame->samples);
+ frame->data.ptr = plc->samples_buf;
+ frame->datalen = num_new_samples * 2;
+ } else {
+ plc_rx(&plc->plc_state, frame->data.ptr, frame->samples);
+ }
+}
+
+static void apply_plc(struct ast_channel *chan, struct ast_frame *frame)
+{
+ struct ast_datastore *datastore;
+ struct plc_ds *plc;
+
+ datastore = ast_channel_datastore_find(chan, &plc_ds_info, NULL);
+ if (datastore) {
+ plc = datastore->data;
+ adjust_frame_for_plc(chan, frame, datastore);
+ return;
+ }
+
+ datastore = ast_datastore_alloc(&plc_ds_info, NULL);
+ if (!datastore) {
+ return;
+ }
+ plc = ast_calloc(1, sizeof(*plc));
+ if (!plc) {
+ ast_datastore_free(datastore);
+ return;
+ }
+ datastore->data = plc;
+ ast_channel_datastore_add(chan, datastore);
+ adjust_frame_for_plc(chan, frame, datastore);
+}
+
int ast_write(struct ast_channel *chan, struct ast_frame *fr)
{
int res = -1;
@@ -4178,6 +4258,10 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr)
if (chan->tech->write == NULL)
break; /*! \todo XXX should return 0 maybe ? */
+ if (ast_opt_generic_plc && fr->subclass.codec == AST_FORMAT_SLINEAR) {
+ apply_plc(chan, fr);
+ }
+
/* If the frame is in the raw write format, then it's easy... just use the frame - otherwise we will have to translate */
if (fr->subclass.codec == chan->rawwriteformat)
f = fr;
@@ -4911,10 +4995,12 @@ static int ast_channel_make_compatible_helper(struct ast_channel *from, struct a
}
/* if the best path is not 'pass through', then
- transcoding is needed; if desired, force transcode path
- to use SLINEAR between channels, but only if there is
- no direct conversion available */
- if ((src != dst) && ast_opt_transcode_via_slin &&
+ * transcoding is needed; if desired, force transcode path
+ * to use SLINEAR between channels, but only if there is
+ * no direct conversion available. If generic PLC is
+ * desired, then transcoding via SLINEAR is a requirement
+ */
+ if ((src != dst) && (ast_opt_generic_plc || ast_opt_transcode_via_slin) &&
(ast_translate_path_steps(dst, src) != 1))
dst = AST_FORMAT_SLINEAR;
if (ast_set_read_format(from, dst) < 0) {
@@ -6567,6 +6653,22 @@ static int ast_channel_hash_cb(const void *obj, const int flags)
return ast_str_case_hash(chan->name);
}
+int ast_plc_reload(void)
+{
+ struct ast_variable *var;
+ struct ast_flags config_flags = { 0 };
+ struct ast_config *cfg = ast_config_load("codecs.conf", config_flags);
+ if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID)
+ return 0;
+ for (var = ast_variable_browse(cfg, "plc"); var; var = var->next) {
+ if (!strcasecmp(var->name, "genericplc")) {
+ ast_set2_flag(&ast_options, ast_true(var->value), AST_OPT_FLAG_GENERIC_PLC);
+ }
+ }
+ ast_config_destroy(cfg);
+ return 0;
+}
+
/*!
* \internal
* \brief Implements the channels provider.
@@ -6649,6 +6751,8 @@ void ast_channels_init(void)
ast_cli_register_multiple(cli_channel, ARRAY_LEN(cli_channel));
ast_data_register_multiple_core(channel_providers, ARRAY_LEN(channel_providers));
+
+ ast_plc_reload();
}
/*! \brief Print call group and pickup group ---*/
diff --git a/main/loader.c b/main/loader.c
index 3c27357aa..f44cef9f5 100644
--- a/main/loader.c
+++ b/main/loader.c
@@ -260,6 +260,7 @@ static struct reload_classes {
{ "udptl", ast_udptl_reload },
{ "indications", ast_indications_reload },
{ "cel", ast_cel_engine_reload },
+ { "plc", ast_plc_reload },
{ NULL, NULL }
};