diff options
-rw-r--r-- | channels/chan_sip.c | 2 | ||||
-rw-r--r-- | include/asterisk/_private.h | 7 | ||||
-rw-r--r-- | include/asterisk/options.h | 3 | ||||
-rw-r--r-- | main/asterisk.c | 1 | ||||
-rw-r--r-- | main/channel.c | 112 | ||||
-rw-r--r-- | main/loader.c | 1 |
6 files changed, 121 insertions, 5 deletions
diff --git a/channels/chan_sip.c b/channels/chan_sip.c index eec004aab..6736ab86c 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -23297,7 +23297,7 @@ static struct ast_channel *sip_request_call(const char *type, int format, void * 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); /* Place the call */ if (sip_cfg.callevents) diff --git a/include/asterisk/_private.h b/include/asterisk/_private.h index 1258f03df..b630375fc 100644 --- a/include/asterisk/_private.h +++ b/include/asterisk/_private.h @@ -78,4 +78,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 45b896a64..f7d99e27e 100644 --- a/include/asterisk/options.h +++ b/include/asterisk/options.h @@ -92,6 +92,8 @@ enum ast_option_flags { AST_OPT_FLAG_FORCE_BLACK_BACKGROUND = (1 << 27), /*! Hide remote console connect messages on console */ AST_OPT_FLAG_HIDE_CONSOLE_CONNECT = (1 << 28), + /*! Generic PLC */ + AST_OPT_FLAG_GENERIC_PLC = (1 << 30), }; /*! These are the options that set by default when Asterisk starts */ @@ -128,6 +130,7 @@ enum ast_option_flags { #define ast_opt_light_background ast_test_flag(&ast_options, AST_OPT_FLAG_LIGHT_BACKGROUND) #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_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 8e20a7f6b..60737ed67 100644 --- a/main/asterisk.c +++ b/main/asterisk.c @@ -464,6 +464,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 d201510ad..d8a83034d 100644 --- a/main/channel.c +++ b/main/channel.c @@ -3418,6 +3418,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; @@ -3533,6 +3613,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 == 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 == chan->rawwriteformat) f = fr; @@ -4201,10 +4285,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) { @@ -5583,9 +5669,27 @@ void ast_moh_cleanup(struct ast_channel *chan) ast_moh_cleanup_ptr(chan); } +int ast_plc_reload(void) +{ + struct ast_variable *var; + struct ast_flags config_flags = { 0 }; + struct ast_config *cfg = ast_config_load2("codecs.conf", "channel", 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; +} + void ast_channels_init(void) { ast_cli_register_multiple(cli_channel, ARRAY_LEN(cli_channel)); + + ast_plc_reload(); } /*! \brief Print call group and pickup group ---*/ diff --git a/main/loader.c b/main/loader.c index 7e0598d19..704eb76e4 100644 --- a/main/loader.c +++ b/main/loader.c @@ -260,6 +260,7 @@ static struct reload_classes { { "dsp", ast_dsp_reload}, { "udptl", ast_udptl_reload }, { "indications", ast_indications_reload }, + { "plc", ast_plc_reload }, { NULL, NULL } }; |