]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
1.4 version of PLC fix.
authorMark Michelson <mmichelson@digium.com>
Thu, 20 May 2010 15:59:44 +0000 (15:59 +0000)
committerMark Michelson <mmichelson@digium.com>
Thu, 20 May 2010 15:59:44 +0000 (15:59 +0000)
Analogous to trunk revision 264452, but without the change
to chan_sip since it is not necessary in this branch.

git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/1.4@264541 65c4cc65-6c06-0410-ace0-fbb531ad65f3

include/asterisk/channel.h
include/asterisk/options.h
main/channel.c
main/loader.c

index e205a83e92e3f30bb16a09d349b6d3b7a9d1b369..6d872818ba7de6af2d4c550ed947f6ee689e41b7 100644 (file)
@@ -1467,6 +1467,12 @@ void ast_channel_whisper_stop(struct ast_channel *chan);
  */
 char *ast_channel_reason2str(int reason);
 
+/*!
+ * \brief Reload genericplc configuration value from codecs.conf
+ *
+ * Implementation is in main/channel.c
+ */
+int ast_plc_reload(void);
 
 #if defined(__cplusplus) || defined(c_plusplus)
 }
index 086cd28d7756102788389c8763ffd4c34746994a..c3300660626ec5f3a0f29aae2cca5bf5ef08bf89 100644 (file)
@@ -80,7 +80,9 @@ enum ast_option_flags {
        /*! Always fork, even if verbose or debug settings are non-zero */
        AST_OPT_FLAG_ALWAYS_FORK = (1 << 21),
        /*! Disable log/verbose output to remote consoles */
-       AST_OPT_FLAG_MUTE = (1 << 22)
+       AST_OPT_FLAG_MUTE = (1 << 22),
+       /*! Generic PLC */
+       AST_OPT_FLAG_GENERIC_PLC = (1 << 23),
 };
 
 /*! These are the options that set by default when Asterisk starts */
@@ -113,6 +115,7 @@ enum ast_option_flags {
 #define ast_opt_internal_timing                ast_test_flag(&ast_options, AST_OPT_FLAG_INTERNAL_TIMING)
 #define ast_opt_always_fork            ast_test_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK)
 #define ast_opt_mute                   ast_test_flag(&ast_options, AST_OPT_FLAG_MUTE)
+#define ast_opt_generic_plc         ast_test_flag(&ast_options, AST_OPT_FLAG_GENERIC_PLC)
 
 extern struct ast_flags ast_options;
 
index 65c42849441655dafa4a7af94f2a45834a662904..f7c122feb1e407796b56cb29081e5f9d0890d646 100644 (file)
@@ -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 ---*/
index 5d79e53714741a849d5405a96716270cf8e778b0..a79a2cf43b27d0412df8fc31b4272109a80b78d5 100644 (file)
@@ -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 }
 };