diff options
author | mmichelson <mmichelson@f38db490-d61c-443f-a65b-d21fe96a405b> | 2010-05-20 15:59:44 +0000 |
---|---|---|
committer | mmichelson <mmichelson@f38db490-d61c-443f-a65b-d21fe96a405b> | 2010-05-20 15:59:44 +0000 |
commit | e5c559bcfb1e1e0359dfe35c2e04455cc187a4d7 (patch) | |
tree | 6c7d6e38741072b9d5b8dca68fbfc1f5349177c3 /main | |
parent | ca3bd71a4ffb3713c2cbbc8e4f24424ddabd5d08 (diff) |
1.4 version of PLC fix.
Analogous to trunk revision 264452, but without the change
to chan_sip since it is not necessary in this branch.
git-svn-id: http://svn.digium.com/svn/asterisk/branches/1.4@264541 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'main')
-rw-r--r-- | main/channel.c | 111 | ||||
-rw-r--r-- | main/loader.c | 1 |
2 files changed, 108 insertions, 4 deletions
diff --git a/main/channel.c b/main/channel.c index 65c428494..f7c122feb 100644 --- a/main/channel.c +++ b/main/channel.c @@ -2854,6 +2854,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_channel_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 = plc->samples_buf; + frame->datalen = num_new_samples * 2; + } else { + plc_rx(&plc->plc_state, frame->data, 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_channel_datastore_alloc(&plc_ds_info, NULL); + if (!datastore) { + return; + } + plc = ast_calloc(1, sizeof(*plc)); + if (!plc) { + ast_channel_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; @@ -2963,6 +3043,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; @@ -3629,10 +3713,12 @@ int ast_channel_make_compatible(struct ast_channel *chan, struct ast_channel *pe } /* 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(peer, dst) < 0) { @@ -4932,9 +5018,26 @@ void ast_moh_cleanup(struct ast_channel *chan) ast_moh_cleanup_ptr(chan); } +int ast_plc_reload(void) +{ + struct ast_variable *var; + struct ast_config *cfg = ast_config_load("codecs.conf"); + if (!cfg) + 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, sizeof(cli_channel) / sizeof(struct ast_cli_entry)); + + ast_plc_reload(); } /*! \brief Print call group and pickup group ---*/ diff --git a/main/loader.c b/main/loader.c index 5d79e5371..a79a2cf43 100644 --- a/main/loader.c +++ b/main/loader.c @@ -258,6 +258,7 @@ static struct reload_classes { { "rtp", ast_rtp_reload }, { "http", ast_http_reload }, { "logger", logger_reload }, + { "plc", ast_plc_reload }, { NULL, NULL } }; |