[Asterisk-code-review] core: Add ast read stream function for reading frames from a... (asterisk[master])

Joshua Colp asteriskteam at digium.com
Thu Feb 23 15:19:38 CST 2017


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

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

core: 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, 70 insertions(+), 8 deletions(-)


  git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/79/5079/1

diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h
index 80476a4..7e66a7d 100644
--- a/include/asterisk/channel.h
+++ b/include/asterisk/channel.h
@@ -664,8 +664,11 @@
 	/*! \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) */
 	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), from all streams */
+	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);
@@ -1934,6 +1937,15 @@
 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.
+ */
+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: newchange
Gerrit-Change-Id: I5d7dc35e86694df91fd025126f6cfe0453aa38ce
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