diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h index 80476a4e0b1b374753628d1c5ad3bb207f58dc5f..f6e09252f3a1ce8f642381f8539d48771c4bd2f4 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,13 +1950,36 @@ 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 diff --git a/include/asterisk/frame.h b/include/asterisk/frame.h index 90f8aa086c2138ba5967af3bccfc6b2d60f8ccdd..c56539af466b98172b1c6d65c5b323c5c32e96c9 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 183f8936f1205b46da8f47dbdaa650707920517e..e3e9561fe9575fafda305e0ae3e6976bb19fa940 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 c284a8e1cd9d122e3669939cf877634779fdb6e0..c24cc8f78695b35315f660f7b9ee6623fccebf27 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; }