diff options
Diffstat (limited to 'main')
-rw-r--r-- | main/bridge_channel.c | 31 | ||||
-rw-r--r-- | main/channel.c | 76 | ||||
-rw-r--r-- | main/frame.c | 3 | ||||
-rw-r--r-- | main/message.c | 142 |
4 files changed, 237 insertions, 15 deletions
diff --git a/main/bridge_channel.c b/main/bridge_channel.c index 3aac5eb25..eb4b9ad0e 100644 --- a/main/bridge_channel.c +++ b/main/bridge_channel.c @@ -56,6 +56,7 @@ #include "asterisk/test.h" #include "asterisk/sem.h" #include "asterisk/stream.h" +#include "asterisk/message.h" /*! * \brief Used to queue an action frame onto a bridge channel and write an action frame into a bridge. @@ -1055,6 +1056,20 @@ int ast_bridge_channel_queue_frame(struct ast_bridge_channel *bridge_channel, st return 0; } + if (DEBUG_ATLEAST(1)) { + if (fr->frametype == AST_FRAME_TEXT) { + ast_log(LOG_DEBUG, "Queuing TEXT frame to '%s': %*.s\n", ast_channel_name(bridge_channel->chan), + fr->datalen, (char *)fr->data.ptr); + } else if (fr->frametype == AST_FRAME_TEXT_DATA) { + struct ast_msg_data *msg = fr->data.ptr; + ast_log(LOG_DEBUG, "Queueing TEXT_DATA frame 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(bridge_channel->chan), + ast_msg_data_get_attribute(msg, AST_MSG_DATA_ATTR_BODY)); + } + } + AST_LIST_INSERT_TAIL(&bridge_channel->wr_queue, dup, frame_list); if (ast_alertpipe_write(bridge_channel->alert_pipe)) { ast_log(LOG_ERROR, "We couldn't write alert pipe for %p(%s)... something is VERY wrong\n", @@ -2349,6 +2364,7 @@ static void bridge_channel_handle_write(struct ast_bridge_channel *bridge_channe struct ast_frame *fr; struct sync_payload *sync_payload; int num; + struct ast_msg_data *msg; ast_bridge_channel_lock(bridge_channel); @@ -2381,6 +2397,7 @@ static void bridge_channel_handle_write(struct ast_bridge_channel *bridge_channe AST_LIST_TRAVERSE_SAFE_END; ast_bridge_channel_unlock(bridge_channel); + if (!fr) { /* * Wait some to reduce CPU usage from a tight loop @@ -2404,6 +2421,20 @@ static void bridge_channel_handle_write(struct ast_bridge_channel *bridge_channe break; case AST_FRAME_NULL: break; + case AST_FRAME_TEXT: + ast_debug(1, "Sending TEXT frame to '%s': %*.s\n", + ast_channel_name(bridge_channel->chan), fr->datalen, (char *)fr->data.ptr); + ast_sendtext(bridge_channel->chan, fr->data.ptr); + break; + case AST_FRAME_TEXT_DATA: + msg = (struct ast_msg_data *)fr->data.ptr; + ast_debug(1, "Sending TEXT_DATA frame 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(bridge_channel->chan), + ast_msg_data_get_attribute(msg, AST_MSG_DATA_ATTR_BODY)); + ast_sendtext_data(bridge_channel->chan, msg); + break; default: /* Assume that there is no mapped stream for this */ num = -1; diff --git a/main/channel.c b/main/channel.c index 815d5dbfe..a23dfa10c 100644 --- a/main/channel.c +++ b/main/channel.c @@ -73,6 +73,7 @@ #include "asterisk/stasis_channels.h" #include "asterisk/max_forwards.h" #include "asterisk/stream.h" +#include "asterisk/message.h" /*** DOCUMENTATION ***/ @@ -1492,6 +1493,7 @@ int ast_is_deferrable_frame(const struct ast_frame *frame) case AST_FRAME_BRIDGE_ACTION_SYNC: case AST_FRAME_CONTROL: case AST_FRAME_TEXT: + case AST_FRAME_TEXT_DATA: case AST_FRAME_IMAGE: case AST_FRAME_HTML: return 1; @@ -2767,6 +2769,7 @@ int __ast_answer(struct ast_channel *chan, unsigned int delay) case AST_FRAME_VOICE: case AST_FRAME_VIDEO: case AST_FRAME_TEXT: + case AST_FRAME_TEXT_DATA: case AST_FRAME_DTMF_BEGIN: case AST_FRAME_DTMF_END: case AST_FRAME_IMAGE: @@ -4652,9 +4655,11 @@ char *ast_recvtext(struct ast_channel *chan, int timeout) return buf; } -int ast_sendtext(struct ast_channel *chan, const char *text) +int ast_sendtext_data(struct ast_channel *chan, struct ast_msg_data *msg) { int res = 0; + const char *body = ast_msg_data_get_attribute(msg, AST_MSG_DATA_ATTR_BODY); + const char *content_type = ast_msg_data_get_attribute(msg, AST_MSG_DATA_ATTR_CONTENT_TYPE); ast_channel_lock(chan); /* Stop if we're a zombie or need a soft hangup */ @@ -4663,35 +4668,76 @@ int ast_sendtext(struct ast_channel *chan, const char *text) return -1; } - if (ast_strlen_zero(text)) { - ast_channel_unlock(chan); - return 0; - } - CHECK_BLOCKING(chan); - if (ast_channel_tech(chan)->write_text && (ast_format_cap_has_type(ast_channel_nativeformats(chan), AST_MEDIA_TYPE_TEXT))) { + if (ast_channel_tech(chan)->write_text + && (ast_strlen_zero(content_type) || strcasecmp(content_type, "text/plain") == 0) + && (ast_format_cap_has_type(ast_channel_nativeformats(chan), AST_MEDIA_TYPE_TEXT))) { struct ast_frame f; + size_t body_len = strlen(body) + 1; + /* Process as T.140 text (moved here from ast_sendtext() */ memset(&f, 0, sizeof(f)); - f.frametype = AST_FRAME_TEXT; f.src = "DIALPLAN"; - f.mallocd = AST_MALLOCD_DATA; - f.datalen = strlen(text); - f.data.ptr = ast_strdup(text); f.subclass.format = ast_format_t140; - + f.frametype = AST_FRAME_TEXT; + f.datalen = body_len; + f.mallocd = AST_MALLOCD_DATA; + f.data.ptr = ast_strdup(body); if (f.data.ptr) { res = ast_channel_tech(chan)->write_text(chan, &f); - ast_frfree(&f); + } else { + res = -1; } - } else if (ast_channel_tech(chan)->send_text) { - res = ast_channel_tech(chan)->send_text(chan, text); + ast_frfree(&f); + } else if ((ast_channel_tech(chan)->properties & AST_CHAN_TP_SEND_TEXT_DATA) + && ast_channel_tech(chan)->send_text_data) { + /* Send enhanced message to a channel driver that supports it */ + ast_debug(1, "Sending TEXT_DATA 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(chan), body); + res = ast_channel_tech(chan)->send_text_data(chan, msg); + } else if (ast_channel_tech(chan)->send_text + && (ast_strlen_zero(content_type) || strcasecmp(content_type, "text/plain") == 0)) { + /* Send the body of an enhanced message to a channel driver that supports only a char str */ + ast_debug(1, "Sending TEXT to %s: %s\n", ast_channel_name(chan), body); + res = ast_channel_tech(chan)->send_text(chan, body); + } else { + ast_debug(1, "Channel technology does not support sending text on channel '%s'\n", + ast_channel_name(chan)); + res = -1; } ast_clear_flag(ast_channel_flags(chan), AST_FLAG_BLOCKING); ast_channel_unlock(chan); return res; } +int ast_sendtext(struct ast_channel *chan, 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, + } + }; + + if (ast_strlen_zero(text)) { + return 0; + } + + msg = ast_msg_data_alloc(AST_MSG_DATA_SOURCE_TYPE_UNKNOWN, attrs, ARRAY_LEN(attrs)); + if (!msg) { + return -1; + } + rc = ast_sendtext_data(chan, msg); + ast_free(msg); + + return rc; +} + int ast_senddigit_begin(struct ast_channel *chan, char digit) { /* Device does not support DTMF tones, lets fake diff --git a/main/frame.c b/main/frame.c index dd47f42d0..383571f65 100644 --- a/main/frame.c +++ b/main/frame.c @@ -593,6 +593,9 @@ void ast_frame_type2str(enum ast_frame_type frame_type, char *ftype, size_t len) case AST_FRAME_TEXT: ast_copy_string(ftype, "Text", len); break; + case AST_FRAME_TEXT_DATA: + ast_copy_string(ftype, "Text Data", len); + break; case AST_FRAME_IMAGE: ast_copy_string(ftype, "Image", len); break; diff --git a/main/message.c b/main/message.c index ac7965ea7..b7d14f1e8 100644 --- a/main/message.c +++ b/main/message.c @@ -1348,6 +1348,148 @@ int ast_msg_send(struct ast_msg *msg, const char *to, const char *from) return res; } +/*! + * \brief Structure used to transport a message through the frame core + * \since 13.22.0 + * \since 15.5.0 + */ +struct ast_msg_data { + /*! The length of this structure plus the actual length of the allocated buffer */ + size_t length; + enum ast_msg_data_source_type source; + /*! These are indices into the buffer where teh attribute starts */ + int attribute_value_offsets[__AST_MSG_DATA_ATTR_LAST]; + /*! The buffer containing the NULL separated attributes */ + char buf[0]; +}; + +#define ATTRIBUTE_UNSET -1 + +struct ast_msg_data *ast_msg_data_alloc(enum ast_msg_data_source_type source, + struct ast_msg_data_attribute attributes[], size_t count) +{ + struct ast_msg_data *msg; + size_t len = sizeof(*msg); + size_t i; + size_t current_offset = 0; + enum ast_msg_data_attribute_type attr_type; + + if (!attributes) { + ast_assert(attributes != NULL); + return NULL; + } + + if (!count) { + ast_assert(count > 0); + return NULL; + } + + /* Calculate the length required for the buffer */ + for (i=0; i < count; i++) { + if (!attributes[i].value) { + ast_assert(attributes[i].value != NULL); + return NULL; + } + len += (strlen(attributes[i].value) + 1); + } + + msg = ast_calloc(1, len); + if (!msg) { + return NULL; + } + msg->source = source; + msg->length = len; + + /* Mark all of the attributes as unset */ + for (attr_type = 0; attr_type < __AST_MSG_DATA_ATTR_LAST; attr_type++) { + msg->attribute_value_offsets[attr_type] = ATTRIBUTE_UNSET; + } + + /* Set the ones we have and increment the offset */ + for (i=0; i < count; i++) { + len = (strlen(attributes[i].value) + 1); + strcpy(msg->buf + current_offset, attributes[i].value); /* Safe */ + msg->attribute_value_offsets[attributes[i].type] = current_offset; + current_offset += len; + } + + return msg; +} + +struct ast_msg_data *ast_msg_data_dup(struct ast_msg_data *msg) +{ + struct ast_msg_data *dest; + + if (!msg) { + ast_assert(msg != NULL); + return NULL; + } + + dest = ast_malloc(msg->length); + if (!dest) { + return NULL; + } + memcpy(dest, msg, msg->length); + + return dest; +} + +size_t ast_msg_data_get_length(struct ast_msg_data *msg) +{ + if (!msg) { + ast_assert(msg != NULL); + return 0; + } + + return msg->length; +} + +enum ast_msg_data_source_type ast_msg_data_get_source_type(struct ast_msg_data *msg) +{ + if (!msg) { + ast_assert(msg != NULL); + return AST_MSG_DATA_SOURCE_TYPE_UNKNOWN; + } + + return msg->source; +} + +const char *ast_msg_data_get_attribute(struct ast_msg_data *msg, + enum ast_msg_data_attribute_type attribute_type) +{ + if (!msg) { + ast_assert(msg != NULL); + return ""; + } + + if (msg->attribute_value_offsets[attribute_type] > ATTRIBUTE_UNSET) { + return msg->buf + msg->attribute_value_offsets[attribute_type]; + } + + return ""; +} + +int ast_msg_data_queue_frame(struct ast_channel *channel, struct ast_msg_data *msg) +{ + struct ast_frame f; + + if (!channel) { + ast_assert(channel != NULL); + return -1; + } + + if (!msg) { + ast_assert(msg != NULL); + return -1; + } + + memset(&f, 0, sizeof(f)); + f.frametype = AST_FRAME_TEXT_DATA; + f.data.ptr = msg; + f.datalen = msg->length; + return ast_queue_frame(channel, &f); +} + int ast_msg_tech_register(const struct ast_msg_tech *tech) { const struct ast_msg_tech *match; |