diff options
-rw-r--r-- | channels/chan_local.c | 67 | ||||
-rw-r--r-- | funcs/func_channel.c | 20 | ||||
-rw-r--r-- | include/asterisk/channel.h | 18 | ||||
-rw-r--r-- | include/asterisk/frame.h | 7 | ||||
-rw-r--r-- | include/asterisk/pbx.h | 4 |
5 files changed, 113 insertions, 3 deletions
diff --git a/channels/chan_local.c b/channels/chan_local.c index 46451776f..3b843ce70 100644 --- a/channels/chan_local.c +++ b/channels/chan_local.c @@ -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) { diff --git a/funcs/func_channel.c b/funcs/func_channel.c index ecda99616..57bd21c61 100644 --- a/funcs/func_channel.c +++ b/funcs/func_channel.c @@ -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, diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h index 208f88402..9345a402d 100644 --- a/include/asterisk/channel.h +++ b/include/asterisk/channel.h @@ -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: diff --git a/include/asterisk/frame.h b/include/asterisk/frame.h index 8d38ffefb..ed9ff9665 100644 --- a/include/asterisk/frame.h +++ b/include/asterisk/frame.h @@ -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 diff --git a/include/asterisk/pbx.h b/include/asterisk/pbx.h index 4f2d6facb..9cffe21b1 100644 --- a/include/asterisk/pbx.h +++ b/include/asterisk/pbx.h @@ -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; }; |