[asterisk-commits] channel: Add ast read stream function for reading frames fro... (asterisk[master])

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Mon Feb 27 08:51:27 CST 2017


George Joseph has submitted this change and it was merged. ( https://gerrit.asterisk.org/5079 )

Change subject: channel: Add ast_read_stream function for reading frames from all streams.
......................................................................


channel: Add ast_read_stream function for reading frames from all streams.

This change introduces an ast_read_stream function and callback in
the channel technology which allows reading frames from all streams
and not just the default streams.

The stream number has also been added to frames. This is to allow the
case where frames are queued onto the channel instead of being read
directly from the driver.

This change does impose a restriction on reading though: a chain of
frames can only contain frames from the same stream.

ASTERISK-26816

Change-Id: I5d7dc35e86694df91fd025126f6cfe0453aa38ce
---
M include/asterisk/channel.h
M include/asterisk/frame.h
M main/channel.c
M main/frame.c
4 files changed, 105 insertions(+), 8 deletions(-)

Approvals:
  Kevin Harwell: Looks good to me, approved
  George Joseph: Looks good to me, but someone else must approve
  Anonymous Coward #1000019: Verified



diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h
index 80476a4..f6e0925 100644
--- a/include/asterisk/channel.h
+++ b/include/asterisk/channel.h
@@ -664,8 +664,32 @@
 	/*! \brief Answer the channel */
 	int (* const answer)(struct ast_channel *chan);
 
-	/*! \brief Read a frame, in standard format (see frame.h) */
+	/*!
+	 * \brief Read a frame (or chain of frames from the same stream), in standard format (see frame.h)
+	 *
+	 * \param chan channel to read frames from
+	 *
+	 * \retval non-NULL on success
+	 * \retval NULL on failure
+	 *
+	 * \note Each media frame from this callback will have the stream_num of it changed to the default
+	 *       stream num based on the type of media returned. As a result a multistream capable channel
+	 *       should not implement this callback.
+	 */
 	struct ast_frame * (* const read)(struct ast_channel *chan);
+
+	/*!
+	 * \brief Read a frame (or chain of frames from the same stream), in standard format (see frame.h), with stream num
+	 *
+	 * \param chan channel to read frames from
+	 *
+	 * \retval non-NULL on success
+	 * \retval NULL on failure
+	 *
+	 * \note Each media frame from this callback should contain a stream_num value which is set to the
+	 *       stream that the media frame originated from.
+	 */
+	struct ast_frame * (* const read_stream)(struct ast_channel *chan);
 
 	/*! \brief Write a frame, in standard format (see frame.h) */
 	int (* const write)(struct ast_channel *chan, struct ast_frame *frame);
@@ -1926,14 +1950,37 @@
 
 /*!
  * \brief Reads a frame
+ *
  * \param chan channel to read a frame from
+ *
  * \return Returns a frame, or NULL on error.  If it returns NULL, you
  * best just stop reading frames and assume the channel has been
  * disconnected.
+ *
+ * \note This function will filter frames received from the channel so
+ *       that only frames from the default stream for each media type
+ *       are returned. All other media frames from other streams will
+ *       be absorbed internally and a NULL frame returned instead.
  */
 struct ast_frame *ast_read(struct ast_channel *chan);
 
 /*!
+ * \brief Reads a frame, but does not filter to just the default streams
+ *
+ * \param chan channel to read a frame from
+ *
+ * \return Returns a frame, or NULL on error.  If it returns NULL, you
+ * best just stop reading frames and assume the channel has been
+ * disconnected.
+ *
+ * \note This function will not perform any filtering and will return
+ *       media frames from all streams on the channel. To determine which
+ *       stream a frame originated from the stream_num on it can be
+ *       examined.
+ */
+struct ast_frame *ast_read_stream(struct ast_channel *chan);
+
+/*!
  * \brief Reads a frame, returning AST_FRAME_NULL frame if audio.
  * \param chan channel to read a frame from
  * \return  Returns a frame, or NULL on error.  If it returns NULL, you
diff --git a/include/asterisk/frame.h b/include/asterisk/frame.h
index 90f8aa0..c56539a 100644
--- a/include/asterisk/frame.h
+++ b/include/asterisk/frame.h
@@ -181,6 +181,8 @@
 	long len;
 	/*! Sequence number */
 	int seqno;
+	/*! Stream number the frame originated from */
+	int stream_num;
 };
 
 /*!
diff --git a/main/channel.c b/main/channel.c
index 183f893..e3e9561 100644
--- a/main/channel.c
+++ b/main/channel.c
@@ -3782,11 +3782,12 @@
 	return samples;
 }
 
-static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
+static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio, int dropnondefault)
 {
 	struct ast_frame *f = NULL;	/* the return value */
 	int prestate;
 	int cause = 0;
+	struct ast_stream *stream = NULL, *default_stream = NULL;
 
 	/* this function is very long so make sure there is only one return
 	 * point at the end (there are only two exceptions to this).
@@ -3943,6 +3944,13 @@
 			default:
 				break;
 			}
+		} else if (!(ast_channel_tech(chan)->properties & AST_CHAN_TP_MULTISTREAM) && (
+			f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO)) {
+			/* Since this channel driver does not support multistream determine the default stream this frame
+			 * originated from and update the frame to include it.
+			 */
+			stream = default_stream = ast_channel_get_default_stream(chan, ast_format_get_type(f->subclass.format));
+			f->stream_num = ast_stream_get_position(stream);
 		}
 	} else {
 		ast_channel_blocker_set(chan, pthread_self());
@@ -3955,15 +3963,43 @@
 			}
 			/* Clear the exception flag */
 			ast_clear_flag(ast_channel_flags(chan), AST_FLAG_EXCEPTION);
-		} else if (ast_channel_tech(chan) && ast_channel_tech(chan)->read)
+		} else if (ast_channel_tech(chan) && ast_channel_tech(chan)->read_stream) {
+			f = ast_channel_tech(chan)->read_stream(chan);
+
+			/* This channel driver supports multistream so the stream_num on the frame is valid, the only
+			 * thing different is that we need to find the default stream so we know whether to invoke the
+			 * default stream logic or not (such as transcoding).
+			 */
+			if (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO) {
+				stream = ast_stream_topology_get_stream(ast_channel_get_stream_topology(chan), f->stream_num);
+				default_stream = ast_channel_get_default_stream(chan, ast_format_get_type(f->subclass.format));
+			}
+		} else if (ast_channel_tech(chan) && ast_channel_tech(chan)->read) {
 			f = ast_channel_tech(chan)->read(chan);
+
+			/* Since this channel driver does not support multistream determine the default stream this frame
+			 * originated from and update the frame to include it.
+			 */
+			if (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO) {
+				stream = default_stream = ast_channel_get_default_stream(chan, ast_format_get_type(f->subclass.format));
+				f->stream_num = ast_stream_get_position(stream);
+			}
+		}
 		else
 			ast_log(LOG_WARNING, "No read routine on channel %s\n", ast_channel_name(chan));
 	}
 
-	/* Perform the framehook read event here. After the frame enters the framehook list
-	 * there is no telling what will happen, <insert mad scientist laugh here>!!! */
-	f = ast_framehook_list_read_event(ast_channel_framehooks(chan), f);
+	if (dropnondefault && stream != default_stream) {
+		/* If the frame originates from a non-default stream and the caller can not handle other streams
+		 * absord the frame and replace it with a null one instead.
+		 */
+		ast_frfree(f);
+		f = &ast_null_frame;
+	} else if (stream == default_stream) {
+		/* Perform the framehook read event here. After the frame enters the framehook list
+		 * there is no telling what will happen, <insert mad scientist laugh here>!!! */
+		f = ast_framehook_list_read_event(ast_channel_framehooks(chan), f);
+	}
 
 	/*
 	 * Reset the recorded file descriptor that triggered this read so that we can
@@ -4162,6 +4198,11 @@
 			}
 			break;
 		case AST_FRAME_VOICE:
+			/* If media was received from a non-default stream don't perform any actions, let it just go through */
+			if (stream != default_stream) {
+				break;
+			}
+
 			/* The EMULATE_DTMF flag must be cleared here as opposed to when the duration
 			 * is reached , because we want to make sure we pass at least one
 			 * voice frame through before starting the next digit, to ensure a gap
@@ -4396,12 +4437,17 @@
 
 struct ast_frame *ast_read(struct ast_channel *chan)
 {
-	return __ast_read(chan, 0);
+	return __ast_read(chan, 0, 1);
+}
+
+struct ast_frame *ast_read_stream(struct ast_channel *chan)
+{
+	return __ast_read(chan, 0, 0);
 }
 
 struct ast_frame *ast_read_noaudio(struct ast_channel *chan)
 {
-	return __ast_read(chan, 1);
+	return __ast_read(chan, 1, 1);
 }
 
 int ast_indicate(struct ast_channel *chan, int condition)
diff --git a/main/frame.c b/main/frame.c
index c284a8e..c24cc8f 100644
--- a/main/frame.c
+++ b/main/frame.c
@@ -222,6 +222,7 @@
 			out->len = fr->len;
 			out->seqno = fr->seqno;
 		}
+		out->stream_num = fr->stream_num;
 	} else {
 		out = fr;
 	}
@@ -370,6 +371,7 @@
 	out->ts = f->ts;
 	out->len = f->len;
 	out->seqno = f->seqno;
+	out->stream_num = f->stream_num;
 	return out;
 }
 

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

Gerrit-MessageType: merged
Gerrit-Change-Id: I5d7dc35e86694df91fd025126f6cfe0453aa38ce
Gerrit-PatchSet: 4
Gerrit-Project: asterisk
Gerrit-Branch: master
Gerrit-Owner: Joshua Colp <jcolp at digium.com>
Gerrit-Reviewer: Anonymous Coward #1000019
Gerrit-Reviewer: George Joseph <gjoseph at digium.com>
Gerrit-Reviewer: Joshua Colp <jcolp at digium.com>
Gerrit-Reviewer: Kevin Harwell <kharwell at digium.com>



More information about the asterisk-commits mailing list