|
|
|
|
@ -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 ---*/
|
|
|
|
|
|