[Asterisk-code-review] channel: Add support for writing to a specific stream. (asterisk[master])

Joshua Colp asteriskteam at digium.com
Wed Feb 22 05:44:16 CST 2017


Joshua Colp has uploaded a new change for review. ( https://gerrit.asterisk.org/5058 )

Change subject: channel: Add support for writing to a specific stream.
......................................................................

channel: Add support for writing to a specific stream.

This change adds an ast_write_stream function which allows
writing a frame to a specific media stream. It also moves
ast_write() to using this underneath by writing media
frames provided to it to the default streams of the channel.
Existing functionality (such as audiohooks, framehooks, etc)
are limited to being applied to the default stream only.

ASTERISK-26793

Change-Id: I4df20d1b65bd4d787fce0b4b478e19d2dfea245c
---
M include/asterisk/channel.h
M main/channel.c
M main/channel_internal_api.c
3 files changed, 74 insertions(+), 12 deletions(-)


  git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/58/5058/1

diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h
index 4170a8a..1aa7856f 100644
--- a/include/asterisk/channel.h
+++ b/include/asterisk/channel.h
@@ -670,6 +670,9 @@
 	/*! \brief Write a frame, in standard format (see frame.h) */
 	int (* const write)(struct ast_channel *chan, struct ast_frame *frame);
 
+	/*! \brief Write a frame on a specific stream, in standard format (see frame.h) */
+	int (* const write_stream)(struct ast_channel *chan, int stream_num, struct ast_frame *frame);
+
 	/*! \brief Display or transmit text */
 	int (* const send_text)(struct ast_channel *chan, const char *text);
 
@@ -1967,6 +1970,16 @@
  * \return It returns 1 on success, 0 if not implemented, and -1 on failure.
  */
 int ast_write_text(struct ast_channel *chan, struct ast_frame *frame);
+
+/*!
+ * \brief Write a frame to a stream
+ * This function writes the given frame to the indicated stream on the channel.
+ * \param chan destination channel of the frame
+ * \param stream_num destination stream on the channel
+ * \param frame frame that will be written
+ * \return It returns 0 on success, -1 on failure.
+ */
+int ast_write_stream(struct ast_channel *chan, int stream_num, struct ast_frame *frame);
 
 /*! \brief Send empty audio to prime a channel driver */
 int ast_prod(struct ast_channel *chan);
@@ -4768,4 +4781,17 @@
 struct ast_stream_topology *ast_channel_set_stream_topology(
 	struct ast_channel *chan, struct ast_stream_topology *topology);
 
+/*!
+ * \brief Retrieve the default stream of a specific media type on a channel
+ *
+ * \param channel The channel to get the stream from
+ * \param type The media type of the default stream
+ *
+ * \pre chan is locked
+ *
+ * \retval non-NULL success
+ * \retval NULL failure
+ */
+struct ast_stream *ast_channel_get_default_stream(struct ast_channel *chan, enum ast_media_type type);
+
 #endif /* _ASTERISK_CHANNEL_H */
diff --git a/main/channel.c b/main/channel.c
index 1e7bc56..724ce3f 100644
--- a/main/channel.c
+++ b/main/channel.c
@@ -5125,6 +5125,12 @@
 
 int ast_write(struct ast_channel *chan, struct ast_frame *fr)
 {
+	return ast_write_stream(chan, -1, fr);
+}
+
+int ast_write_stream(struct ast_channel *chan, int stream_num, struct ast_frame *fr)
+{
+	struct ast_stream *stream = NULL, *default_stream = NULL;
 	int res = -1;
 	struct ast_frame *f = NULL;
 	int count = 0;
@@ -5139,13 +5145,25 @@
 		}
 		usleep(1);
 	}
+
 	/* Stop if we're a zombie or need a soft hangup */
-	if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_ZOMBIE) || ast_check_hangup(chan))
+	if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_ZOMBIE) || ast_check_hangup(chan)) {
 		goto done;
+	}
+
+	/* If this frame is writing an audio or video frame get the stream information */
+	if (fr->frametype == AST_FRAME_VOICE || fr->frametype == AST_FRAME_VIDEO) {
+		/* Initially use the default stream unless an explicit stream is provided */
+		stream = default_stream = ast_channel_get_default_stream(chan, ast_format_get_type(fr->subclass.format));
+
+		if (stream_num >= 0) {
+			stream = ast_stream_topology_get_stream(ast_channel_get_stream_topology(chan), stream_num);
+		}
+	}
 
 	/* Perform the framehook write event here. After the frame enters the framehook list
 	 * there is no telling what will happen, how awesome is that!!! */
-	if (!(fr = ast_framehook_list_write_event(ast_channel_framehooks(chan), fr))) {
+	if ((stream == default_stream) && !(fr = ast_framehook_list_write_event(ast_channel_framehooks(chan), fr))) {
 		res = 0;
 		goto done;
 	}
@@ -5231,17 +5249,20 @@
 		break;
 	case AST_FRAME_VIDEO:
 		/* XXX Handle translation of video codecs one day XXX */
-		res = (ast_channel_tech(chan)->write_video == NULL) ? 0 :
-			ast_channel_tech(chan)->write_video(chan, fr);
+		if (ast_channel_tech(chan)->write_stream) {
+			res = ast_channel_tech(chan)->write_stream(chan, ast_stream_get_position(stream), fr);
+		} else if ((stream == default_stream) && ast_channel_tech(chan)->write) {
+			res = ast_channel_tech(chan)->write(chan, fr);
+		} else {
+			res = 0;
+
+		}
 		break;
 	case AST_FRAME_MODEM:
 		res = (ast_channel_tech(chan)->write == NULL) ? 0 :
 			ast_channel_tech(chan)->write(chan, fr);
 		break;
 	case AST_FRAME_VOICE:
-		if (ast_channel_tech(chan)->write == NULL)
-			break;	/*! \todo XXX should return 0 maybe ? */
-
 		if (ast_opt_generic_plc && ast_format_cmp(fr->subclass.format, ast_format_slin) == AST_FORMAT_CMP_EQUAL) {
 			apply_plc(chan, fr);
 		}
@@ -5250,7 +5271,7 @@
 		 * Send frame to audiohooks if present, if frametype is linear (else, later as per
 		 * previous behavior)
 		 */
-		if (ast_channel_audiohooks(chan)) {
+		if ((stream == default_stream) && ast_channel_audiohooks(chan)) {
 			if (ast_format_cache_is_slinear(fr->subclass.format)) {
 				struct ast_frame *old_frame;
 				hooked = 1;
@@ -5263,7 +5284,7 @@
 		}
 
 		/* If the frame is in the raw write format, then it's easy... just use the frame - otherwise we will have to translate */
-		if (ast_format_cmp(fr->subclass.format, ast_channel_rawwriteformat(chan)) == AST_FORMAT_CMP_EQUAL) {
+		if ((stream != default_stream) || ast_format_cmp(fr->subclass.format, ast_channel_rawwriteformat(chan)) == AST_FORMAT_CMP_EQUAL) {
 			f = fr;
 		} else {
 			if (ast_format_cmp(ast_channel_writeformat(chan), fr->subclass.format) != AST_FORMAT_CMP_EQUAL) {
@@ -5299,7 +5320,7 @@
 			break;
 		}
 
-		if (ast_channel_audiohooks(chan) && !hooked) {
+		if ((stream == default_stream) && ast_channel_audiohooks(chan) && !hooked) {
 			struct ast_frame *prev = NULL, *new_frame, *cur, *dup;
 			int freeoldlist = 0;
 
@@ -5348,7 +5369,7 @@
 		/* the translator on chan->writetrans may have returned multiple frames
 		   from the single frame we passed in; if so, feed each one of them to the
 		   monitor */
-		if (ast_channel_monitor(chan) && ast_channel_monitor(chan)->write_stream) {
+		if ((stream == default_stream) && ast_channel_monitor(chan) && ast_channel_monitor(chan)->write_stream) {
 			struct ast_frame *cur;
 
 			for (cur = f; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
@@ -5415,7 +5436,13 @@
 			/* reset f so the code below doesn't attempt to free it */
 			f = NULL;
 		} else {
-			res = ast_channel_tech(chan)->write(chan, f);
+			if (ast_channel_tech(chan)->write_stream) {
+				res = ast_channel_tech(chan)->write_stream(chan, ast_stream_get_position(stream), f);
+			} else if ((stream == default_stream) && ast_channel_tech(chan)->write) {
+				res = ast_channel_tech(chan)->write(chan, f);
+			} else {
+				res = 0;
+			}
 		}
 		break;
 	case AST_FRAME_NULL:
diff --git a/main/channel_internal_api.c b/main/channel_internal_api.c
index 1934eb9..362bd1a 100644
--- a/main/channel_internal_api.c
+++ b/main/channel_internal_api.c
@@ -1816,6 +1816,15 @@
 	return new_topology;
 }
 
+struct ast_stream *ast_channel_get_default_stream(struct ast_channel *chan,
+	enum ast_media_type type)
+{
+	ast_assert(chan != NULL);
+	ast_assert(type < AST_MEDIA_TYPE_END);
+
+	return chan->default_streams[type];
+}
+
 void ast_channel_internal_swap_stream_topology(struct ast_channel *chan1,
 	struct ast_channel *chan2)
 {

-- 
To view, visit https://gerrit.asterisk.org/5058
To unsubscribe, visit https://gerrit.asterisk.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I4df20d1b65bd4d787fce0b4b478e19d2dfea245c
Gerrit-PatchSet: 1
Gerrit-Project: asterisk
Gerrit-Branch: master
Gerrit-Owner: Joshua Colp <jcolp at digium.com>



More information about the asterisk-code-review mailing list