summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoshua Colp <jcolp@digium.com>2017-02-23 19:03:15 +0000
committerGeorge Joseph <gjoseph@digium.com>2017-02-24 10:20:33 -0600
commitc07c6714f270b7689ddd904bd52f547c19b51555 (patch)
treea517a0508a8c5f9fe1fc4554205aae051eef10e7
parent6cc890b880a6d50b3236860c3ab89e26ba59a7d3 (diff)
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
-rw-r--r--include/asterisk/channel.h49
-rw-r--r--include/asterisk/frame.h2
-rw-r--r--main/channel.c60
-rw-r--r--main/frame.c2
4 files changed, 105 insertions, 8 deletions
diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h
index 80476a4e0..f6e09252f 100644
--- a/include/asterisk/channel.h
+++ b/include/asterisk/channel.h
@@ -664,9 +664,33 @@ struct ast_channel_tech {
/*! \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 @@ int ast_waitfor_n_fd(int *fds, int n, int *ms, int *exception);
/*!
* \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 90f8aa086..c56539af4 100644
--- a/include/asterisk/frame.h
+++ b/include/asterisk/frame.h
@@ -181,6 +181,8 @@ struct ast_frame {
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 183f8936f..e3e9561fe 100644
--- a/main/channel.c
+++ b/main/channel.c
@@ -3782,11 +3782,12 @@ static inline int calc_monitor_jump(int samples, int sample_rate, int seek_rate)
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 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
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 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
}
/* 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 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
}
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 @@ done:
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 c284a8e1c..c24cc8f78 100644
--- a/main/frame.c
+++ b/main/frame.c
@@ -222,6 +222,7 @@ struct ast_frame *ast_frisolate(struct ast_frame *fr)
out->len = fr->len;
out->seqno = fr->seqno;
}
+ out->stream_num = fr->stream_num;
} else {
out = fr;
}
@@ -370,6 +371,7 @@ struct ast_frame *ast_frdup(const struct ast_frame *f)
out->ts = f->ts;
out->len = f->len;
out->seqno = f->seqno;
+ out->stream_num = f->stream_num;
return out;
}