]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
Merged revisions 286059 via svnmerge from
authorTerry Wilson <twilson@digium.com>
Fri, 10 Sep 2010 20:35:25 +0000 (20:35 +0000)
committerTerry Wilson <twilson@digium.com>
Fri, 10 Sep 2010 20:35:25 +0000 (20:35 +0000)
https://origsvn.digium.com/svn/asterisk/branches/1.4

........
  r286059 | twilson | 2010-09-10 14:25:08 -0500 (Fri, 10 Sep 2010) | 16 lines

  Inherit CHANNEL() writes to both sides of a Local channel

  Having Local (/n) channels as queue members and setting the language in the
  extension with Set(CHANNEL(language)=fr) sets the language on the Local/...,2
  channel. Hold time report playbacks happen on the Local/...,1 channel and
  therefor do not play in the specified language.

  This patch modifies func_channel_write to call the setoption callback and pass
  the CHANNEL() write info to the callback. chan_local uses this information to
  look up the other side of the channel and apply the same changes to it.

  (closes issue #17673)
  Reported by: Guggemand

  Review: https://reviewboard.asterisk.org/r/903/
........

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

channels/chan_local.c
funcs/func_channel.c
include/asterisk/channel.h
include/asterisk/frame.h
include/asterisk/pbx.h

index 46451776f87f1d6e1c711ba98ad9cca132396810..3b843ce70dc9f97648b1dbe6dd1e251885fa70da 100644 (file)
@@ -77,6 +77,7 @@ static int local_sendtext(struct ast_channel *ast, const char *text);
 static int local_devicestate(void *data);
 static struct ast_channel *local_bridgedchannel(struct ast_channel *chan, struct ast_channel *bridge);
 static int local_queryoption(struct ast_channel *ast, int option, void *data, int *datalen);
+static int local_setoption(struct ast_channel *chan, int option, void *data, int datalen);
 
 /* PBX interface structure for channel registration */
 static const struct ast_channel_tech local_tech = {
@@ -100,6 +101,7 @@ static const struct ast_channel_tech local_tech = {
        .devicestate = local_devicestate,
        .bridged_channel = local_bridgedchannel,
        .queryoption = local_queryoption,
+       .setoption = local_setoption,
 };
 
 struct local_pvt {
@@ -126,6 +128,71 @@ struct local_pvt {
 
 static AST_LIST_HEAD_STATIC(locals, local_pvt);
 
+static int local_setoption(struct ast_channel *chan, int option, void * data, int datalen)
+{
+       int res;
+       struct local_pvt *p;
+       struct ast_channel *otherchan;
+       ast_chan_write_info_t *write_info;
+
+       if (option != AST_OPTION_CHANNEL_WRITE) {
+               return 0;
+       }
+
+       write_info = data;
+
+       if (write_info->version != AST_CHAN_WRITE_INFO_T_VERSION) {
+               ast_log(LOG_ERROR, "The chan_write_info_t type has changed, and this channel hasn't been updated!\n");
+               return -1;
+       }
+
+
+startover:
+       ast_channel_lock(chan);
+
+       p = chan->tech_pvt;
+       if (!p) {
+               ast_channel_unlock(chan);
+               ast_log(LOG_WARNING, "Could not update other side of %s, local_pvt went away.\n", chan->name);
+               return -1;
+       }
+
+       while (ast_mutex_trylock(&p->lock)) {
+               ast_channel_unlock(chan);
+               sched_yield();
+               ast_channel_lock(chan);
+               p = chan->tech_pvt;
+               if (!p) {
+                       ast_channel_unlock(chan);
+                       ast_log(LOG_WARNING, "Could not update other side of %s, local_pvt went away.\n", chan->name);
+                       return -1;
+               }
+       }
+
+       otherchan = (write_info->chan == p->owner) ? p->chan : p->owner;
+
+       if (!otherchan || otherchan == write_info->chan) {
+               ast_mutex_unlock(&p->lock);
+               ast_channel_unlock(chan);
+               ast_log(LOG_WARNING, "Could not update other side of %s, other side went away.\n", chan->name);
+               return 0;
+       }
+
+       if (ast_channel_trylock(otherchan)) {
+               ast_mutex_unlock(&p->lock);
+               ast_channel_unlock(chan);
+               goto startover;
+       }
+
+       res = write_info->write_fn(otherchan, write_info->function, write_info->data, write_info->value);
+
+       ast_channel_unlock(otherchan);
+       ast_mutex_unlock(&p->lock);
+       ast_channel_unlock(chan);
+
+       return res;
+}
+
 /*! \brief Adds devicestate to local channels */
 static int local_devicestate(void *data)
 {
index ecda996165479ae89b681b4c356ebf608c06cde2..57bd21c615e18c0bba25cb54751c388c8682377d 100644 (file)
@@ -278,7 +278,7 @@ static int func_channel_read(struct ast_channel *chan, const char *function,
        return ret;
 }
 
-static int func_channel_write(struct ast_channel *chan, const char *function,
+static int func_channel_write_real(struct ast_channel *chan, const char *function,
                              char *data, const char *value)
 {
        int ret = 0;
@@ -344,6 +344,24 @@ static int func_channel_write(struct ast_channel *chan, const char *function,
        return ret;
 }
 
+static int func_channel_write(struct ast_channel *chan, const char *function, char *data, const char *value)
+{
+       int res;
+       ast_chan_write_info_t write_info = {
+               .version = AST_CHAN_WRITE_INFO_T_VERSION,
+               .write_fn = func_channel_write_real,
+               .chan = chan,
+               .function = function,
+               .data = data,
+               .value = value,
+       };
+
+       res = func_channel_write_real(chan, function, data, value);
+       ast_channel_setoption(chan, AST_OPTION_CHANNEL_WRITE, &write_info, sizeof(write_info), 0);
+
+       return res;
+}
+
 static struct ast_custom_function channel_function = {
        .name = "CHANNEL",
        .read = func_channel_read,
index 208f88402a07a55c804c5a10d7c66ed5f302d791..9345a402d87103238690572d4c3c79d49477b0f9 100644 (file)
@@ -210,6 +210,24 @@ struct ast_callerid {
        int cid_tns;            /*!< Callerid Transit Network Select */
 };
 
+/*! \brief Typedef for a custom read function */
+typedef int (*ast_acf_read_fn_t)(struct ast_channel *, const char *, char *, char *, size_t);
+
+/*! \brief Typedef for a custom write function */
+typedef int (*ast_acf_write_fn_t)(struct ast_channel *, const char *, char *, const char *);
+
+/*! \brief Structure to handle passing func_channel_write info to channels via setoption */
+typedef struct {
+       /*! \brief ast_chan_write_info_t version. Must be incremented if structure is changed */
+       #define AST_CHAN_WRITE_INFO_T_VERSION 1
+       uint32_t version;
+       ast_acf_write_fn_t write_fn;
+       struct ast_channel *chan;
+       const char *function;
+       char *data;
+       const char *value;
+} ast_chan_write_info_t;
+
 /*! \brief
        Structure to describe a channel "technology", ie a channel driver
        See for examples:
index 8d38ffefba1f305185d78033f6e925452bf7cd7d..ed9ff9665afd881f856d952c58cb698ee4b8e769 100644 (file)
@@ -400,6 +400,13 @@ struct ast_control_t38_parameters {
 /*! Explicitly enable or disable echo cancelation for the given channel */
 #define        AST_OPTION_ECHOCAN              8
 
+/*! \brief Handle channel write data
+ * If a channel needs to process the data from a func_channel write operation
+ * after func_channel_write executes, it can define the setoption callback
+ * and process this option. A pointer to an ast_chan_write_info_t will be passed.
+ * */
+#define AST_OPTION_CHANNEL_WRITE 9
+
 /* !
  * Read-only. Allows query current status of T38 on the channel.
  * data: ast_t38state
index 4f2d6facb20bf6ffed9b93da7efa414f3a9a037a..9cffe21b1601a5613896283c6b8662a5d5101f8b 100644 (file)
@@ -90,8 +90,8 @@ struct ast_custom_function {
                AST_STRING_FIELD(seealso);      /*!< See also */
        );
        enum ast_doc_src docsrc;                /*!< Where the documentation come from */
-       int (*read)(struct ast_channel *, const char *, char *, char *, size_t);        /*!< Read function, if read is supported */
-       int (*write)(struct ast_channel *, const char *, char *, const char *);         /*!< Write function, if write is supported */
+       ast_acf_read_fn_t read;         /*!< Read function, if read is supported */
+       ast_acf_write_fn_t write;       /*!< Write function, if write is supported */
        struct ast_module *mod;         /*!< Module this custom function belongs to */
        AST_RWLIST_ENTRY(ast_custom_function) acflist;
 };