summaryrefslogtreecommitdiff
path: root/channels
diff options
context:
space:
mode:
authorGeorge Joseph <gjoseph@digium.com>2017-09-27 10:44:53 -0600
committerGeorge Joseph <gjoseph@digium.com>2018-04-17 10:30:23 -0600
commit4fb7967c7327fd73a93c587f3eca0564201be049 (patch)
tree0fb763353f2152e6f524f259e8f517685f3e7a9e /channels
parent38dae51b788cd7f9f69c88573d6ce769c80f07f0 (diff)
bridge_softmix: Forward TEXT frames
Core bridging and, more specifically, bridge_softmix have been enhanced to relay received frames of type TEXT or TEXT_DATA to all participants in a softmix bridge. res_pjsip_messaging and chan_pjsip have been enhanced to take advantage of this so when res_pjsip_messaging receives an in-dialog MESSAGE message from a user in a conference call, it's relayed to all other participants in the call. res_pjsip_messaging already queues TEXT frames to the channel when it receives an in-dialog MESSAGE from an endpoint and chan_pjsip will send an MESSAGE when it gets a TEXT frame. On a normal point-to-point call, the frames are forwarded between the two correctly. bridge_softmix was not though so messages weren't getting forwarded to conference bridge participants. Even if they were, the bridging code had no way to tell the participants who sent the message so it would look like it came from the bridge itself. * The TEXT frame type doesn't allow storage of any meta data, such as sender, on the frame so a new TEXT_DATA frame type was added that uses the new ast_msg_data structure as its payload. A channel driver can queue a frame of that type when it receives a message from outside. A channel driver can use it for sending messages by implementing the new send_text_data channel tech callback and setting the new AST_CHAN_TP_SEND_TEXT_DATA flag in its tech properties. If set, the bridging/channel core will use it instead of the original send_text callback and it will get the ast_msg_data structure. Channel drivers aren't required to implement this. Even if a TEXT_DATA enabled driver uses it for incoming messages, an outgoing channel driver that doesn't will still have it's send_text callback called with only the message text just as before. * res_pjsip_messaging now creates a TEXT_DATA frame for incoming in-dialog messages and sets the "from" to the display name in the "From" header, or if that's empty, the caller id name from the channel. This allows the chat client user to set a friendly name for the chat. * bridge_softmix now forwards TEXT and TEXT_DATA frames to all participants (except the sender). * A new function "ast_sendtext_data" was added to channel which takes an ast_msg_data structure and calls a channel's send_text_data callback, or if that's not defined, the original send_text callback. * bridge_channel now calls ast_sendtext_data for TEXT_DATA frame types and ast_sendtext for TEXT frame types. * chan_pjsip now uses the "from" name in the ast_msg_data structure (if it exists) to set the "From" header display name on outgoing text messages. Change-Id: Idacf5900bfd5f22ab8cd235aa56dfad090d18489
Diffstat (limited to 'channels')
-rw-r--r--channels/chan_pjsip.c112
1 files changed, 97 insertions, 15 deletions
diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c
index dde7416c3..b4eb711f7 100644
--- a/channels/chan_pjsip.c
+++ b/channels/chan_pjsip.c
@@ -61,6 +61,7 @@
#include "asterisk/features_config.h"
#include "asterisk/pickup.h"
#include "asterisk/test.h"
+#include "asterisk/message.h"
#include "asterisk/res_pjsip.h"
#include "asterisk/res_pjsip_session.h"
@@ -86,6 +87,7 @@ static struct ast_channel *chan_pjsip_request(const char *type, struct ast_forma
static struct ast_channel *chan_pjsip_request_with_stream_topology(const char *type,
struct ast_stream_topology *topology, const struct ast_assigned_ids *assignedids,
const struct ast_channel *requestor, const char *data, int *cause);
+static int chan_pjsip_sendtext_data(struct ast_channel *ast, struct ast_msg_data *msg);
static int chan_pjsip_sendtext(struct ast_channel *ast, const char *text);
static int chan_pjsip_digit_begin(struct ast_channel *ast, char digit);
static int chan_pjsip_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
@@ -109,6 +111,7 @@ struct ast_channel_tech chan_pjsip_tech = {
.requester = chan_pjsip_request,
.requester_with_stream_topology = chan_pjsip_request_with_stream_topology,
.send_text = chan_pjsip_sendtext,
+ .send_text_data = chan_pjsip_sendtext_data,
.send_digit_begin = chan_pjsip_digit_begin,
.send_digit_end = chan_pjsip_digit_end,
.call = chan_pjsip_call,
@@ -125,7 +128,7 @@ struct ast_channel_tech chan_pjsip_tech = {
.queryoption = chan_pjsip_queryoption,
.func_channel_read = pjsip_acf_channel_read,
.get_pvt_uniqueid = chan_pjsip_get_uniqueid,
- .properties = AST_CHAN_TP_WANTSJITTER | AST_CHAN_TP_CREATESJITTER
+ .properties = AST_CHAN_TP_WANTSJITTER | AST_CHAN_TP_CREATESJITTER | AST_CHAN_TP_SEND_TEXT_DATA
};
/*! \brief SIP session interaction functions */
@@ -2539,50 +2542,99 @@ static struct ast_channel *chan_pjsip_request(const char *type, struct ast_forma
struct sendtext_data {
struct ast_sip_session *session;
- char text[0];
+ struct ast_msg_data *msg;
};
static void sendtext_data_destroy(void *obj)
{
struct sendtext_data *data = obj;
- ao2_ref(data->session, -1);
+ ao2_cleanup(data->session);
+ ast_free(data->msg);
}
-static struct sendtext_data* sendtext_data_create(struct ast_sip_session *session, const char *text)
+static struct sendtext_data* sendtext_data_create(struct ast_channel *chan,
+ struct ast_msg_data *msg)
{
- int size = strlen(text) + 1;
- struct sendtext_data *data = ao2_alloc(sizeof(*data)+size, sendtext_data_destroy);
+ struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(chan);
+ struct sendtext_data *data = ao2_alloc(sizeof(*data), sendtext_data_destroy);
if (!data) {
return NULL;
}
- data->session = session;
+ data->msg = ast_msg_data_dup(msg);
+ if (!data->msg) {
+ ao2_cleanup(data);
+ return NULL;
+ }
+ data->session = channel->session;
ao2_ref(data->session, +1);
- ast_copy_string(data->text, text, size);
+
return data;
}
static int sendtext(void *obj)
{
- RAII_VAR(struct sendtext_data *, data, obj, ao2_cleanup);
+ struct sendtext_data *data = obj;
pjsip_tx_data *tdata;
-
- const struct ast_sip_body body = {
+ const char *body_text = ast_msg_data_get_attribute(data->msg, AST_MSG_DATA_ATTR_BODY);
+ const char *content_type = ast_msg_data_get_attribute(data->msg, AST_MSG_DATA_ATTR_CONTENT_TYPE);
+ char *sep;
+ struct ast_sip_body body = {
.type = "text",
.subtype = "plain",
- .body_text = data->text
+ .body_text = body_text,
};
+ if (!ast_strlen_zero(content_type)) {
+ sep = strchr(content_type, '/');
+ if (sep) {
+ *sep = '\0';
+ body.type = content_type;
+ body.subtype = ++sep;
+ }
+ }
+
if (data->session->inv_session->state == PJSIP_INV_STATE_DISCONNECTED) {
ast_log(LOG_ERROR, "Session already DISCONNECTED [reason=%d (%s)]\n",
data->session->inv_session->cause,
pjsip_get_status_text(data->session->inv_session->cause)->ptr);
} else {
- ast_debug(3, "Sending in dialog SIP message\n");
+ pjsip_from_hdr *hdr;
+ pjsip_name_addr *name_addr;
+ const char *from = ast_msg_data_get_attribute(data->msg, AST_MSG_DATA_ATTR_FROM);
+ const char *to = ast_msg_data_get_attribute(data->msg, AST_MSG_DATA_ATTR_TO);
+ int invalidate_tdata = 0;
ast_sip_create_request("MESSAGE", data->session->inv_session->dlg, data->session->endpoint, NULL, NULL, &tdata);
ast_sip_add_body(tdata, &body);
+
+ /*
+ * If we have a 'from' in the msg, set the display name in the From
+ * header to it.
+ */
+ if (!ast_strlen_zero(from)) {
+ hdr = PJSIP_MSG_FROM_HDR(tdata->msg);
+ name_addr = (pjsip_name_addr *) hdr->uri;
+ pj_strdup2(tdata->pool, &name_addr->display, from);
+ invalidate_tdata = 1;
+ }
+
+ /*
+ * If we have a 'to' in the msg, set the display name in the To
+ * header to it.
+ */
+ if (!ast_strlen_zero(to)) {
+ hdr = PJSIP_MSG_TO_HDR(tdata->msg);
+ name_addr = (pjsip_name_addr *) hdr->uri;
+ pj_strdup2(tdata->pool, &name_addr->display, to);
+ invalidate_tdata = 1;
+ }
+
+ if (invalidate_tdata) {
+ pjsip_tx_data_invalidate_msg(tdata);
+ }
+
ast_sip_send_request(tdata, data->session->inv_session->dlg, data->session->endpoint, NULL, NULL);
}
@@ -2590,14 +2642,22 @@ static int sendtext(void *obj)
pjsip_inv_dec_ref(data->session->inv_session);
#endif
+ ao2_cleanup(data);
+
return 0;
}
/*! \brief Function called by core to send text on PJSIP session */
-static int chan_pjsip_sendtext(struct ast_channel *ast, const char *text)
+static int chan_pjsip_sendtext_data(struct ast_channel *ast, struct ast_msg_data *msg)
{
struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(ast);
- struct sendtext_data *data = sendtext_data_create(channel->session, text);
+ struct sendtext_data *data = sendtext_data_create(ast, msg);
+
+ ast_debug(1, "Sending MESSAGE from '%s' to '%s:%s': %s\n",
+ ast_msg_data_get_attribute(msg, AST_MSG_DATA_ATTR_FROM),
+ ast_msg_data_get_attribute(msg, AST_MSG_DATA_ATTR_TO),
+ ast_channel_name(ast),
+ ast_msg_data_get_attribute(msg, AST_MSG_DATA_ATTR_BODY));
if (!data) {
return -1;
@@ -2621,6 +2681,28 @@ static int chan_pjsip_sendtext(struct ast_channel *ast, const char *text)
return 0;
}
+static int chan_pjsip_sendtext(struct ast_channel *ast, const char *text)
+{
+ struct ast_msg_data *msg;
+ int rc;
+ struct ast_msg_data_attribute attrs[] =
+ {
+ {
+ .type = AST_MSG_DATA_ATTR_BODY,
+ .value = (char *)text,
+ }
+ };
+
+ msg = ast_msg_data_alloc(AST_MSG_DATA_SOURCE_TYPE_UNKNOWN, attrs, ARRAY_LEN(attrs));
+ if (!msg) {
+ return -1;
+ }
+ rc = chan_pjsip_sendtext_data(ast, msg);
+ ast_free(msg);
+
+ return rc;
+}
+
/*! \brief Convert SIP hangup causes to Asterisk hangup causes */
static int hangup_sip2cause(int cause)
{