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

This commit is contained in:
George Joseph 2017-02-27 08:51:26 -06:00 committed by Gerrit Code Review
commit df22d297a6
4 changed files with 105 additions and 8 deletions

View File

@ -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

View File

@ -181,6 +181,8 @@ struct ast_frame {
long len;
/*! Sequence number */
int seqno;
/*! Stream number the frame originated from */
int stream_num;
};
/*!

View File

@ -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)

View File

@ -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;
}