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: http://svn.digium.com/svn/asterisk/branches/1.4@286059 f38db490-d61c-443f-a65b-d21fe96a405b
This commit is contained in:
parent
6368131c6c
commit
2d7639134c
|
@ -79,6 +79,7 @@ static int local_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
|
|||
static int local_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen);
|
||||
static int local_sendtext(struct ast_channel *ast, const char *text);
|
||||
static int local_devicestate(void *data);
|
||||
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 = {
|
|||
.send_html = local_sendhtml,
|
||||
.send_text = local_sendtext,
|
||||
.devicestate = local_devicestate,
|
||||
.setoption = local_setoption,
|
||||
};
|
||||
|
||||
struct local_pvt {
|
||||
|
@ -124,6 +126,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)
|
||||
{
|
||||
|
|
|
@ -96,7 +96,7 @@ static int func_channel_read(struct ast_channel *chan, char *function,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int func_channel_write(struct ast_channel *chan, char *function,
|
||||
static int func_channel_write_real(struct ast_channel *chan, char *function,
|
||||
char *data, const char *value)
|
||||
{
|
||||
int ret = 0;
|
||||
|
@ -139,6 +139,24 @@ static int func_channel_write(struct ast_channel *chan, char *function,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int func_channel_write(struct ast_channel *chan, 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",
|
||||
.synopsis = "Gets/sets various pieces of information about the channel.",
|
||||
|
|
|
@ -194,6 +194,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 *, char *, char *, char *, size_t);
|
||||
|
||||
/*! \brief Typedef for a custom write function */
|
||||
typedef int (*ast_acf_write_fn_t)(struct ast_channel *, 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;
|
||||
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:
|
||||
|
|
|
@ -340,6 +340,13 @@ enum ast_control_frame_type {
|
|||
/*! 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
|
||||
|
||||
struct oprmode {
|
||||
struct ast_channel *peer;
|
||||
int mode;
|
||||
|
|
|
@ -71,8 +71,8 @@ struct ast_custom_function {
|
|||
const char *synopsis; /*!< Short description for "show functions" */
|
||||
const char *desc; /*!< Help text that explains it all */
|
||||
const char *syntax; /*!< Syntax description */
|
||||
int (*read)(struct ast_channel *, char *, char *, char *, size_t); /*!< Read function, if read is supported */
|
||||
int (*write)(struct ast_channel *, 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 */
|
||||
AST_LIST_ENTRY(ast_custom_function) acflist;
|
||||
};
|
||||
|
||||
|
|
Reference in New Issue