Asterisk - The Open Source Telephony Project GIT-master-b023714
Loading...
Searching...
No Matches
Functions | Variables
app_stream_echo.c File Reference

Stream echo application. More...

#include "asterisk.h"
#include "asterisk/app.h"
#include "asterisk/conversions.h"
#include "asterisk/file.h"
#include "asterisk/module.h"
#include "asterisk/channel.h"
#include "asterisk/stream.h"
Include dependency graph for app_stream_echo.c:

Go to the source code of this file.

Functions

static void __reg_module (void)
 
static void __unreg_module (void)
 
struct ast_moduleAST_MODULE_SELF_SYM (void)
 
static int load_module (void)
 
static int stream_echo_exec (struct ast_channel *chan, const char *data)
 
static int stream_echo_perform (struct ast_channel *chan, struct ast_stream_topology *topology, enum ast_media_type type)
 
static struct ast_stream_topologystream_echo_topology_alloc (struct ast_stream_topology *original, unsigned int num, enum ast_media_type type)
 
static int stream_echo_write (struct ast_channel *chan, struct ast_frame *frame, enum ast_media_type type, int one_to_one)
 
static int stream_echo_write_error (struct ast_channel *chan, struct ast_frame *frame, int pos)
 
static int unload_module (void)
 

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Stream Echo Application" , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, .support_level = AST_MODULE_SUPPORT_CORE, }
 
static const char app [] = "StreamEcho"
 
static const struct ast_module_infoast_module_info = &__mod_info
 

Detailed Description

Stream echo application.

Author
Kevin Harwell kharw.nosp@m.ell@.nosp@m.digiu.nosp@m.m.co.nosp@m.m

Definition in file app_stream_echo.c.

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 348 of file app_stream_echo.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 348 of file app_stream_echo.c.

◆ AST_MODULE_SELF_SYM()

struct ast_module * AST_MODULE_SELF_SYM ( void  )

Definition at line 348 of file app_stream_echo.c.

◆ load_module()

static int load_module ( void  )
static

Definition at line 343 of file app_stream_echo.c.

344{
346}
static const char app[]
static int stream_echo_exec(struct ast_channel *chan, const char *data)
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition module.h:640

References app, ast_register_application_xml, and stream_echo_exec().

◆ stream_echo_exec()

static int stream_echo_exec ( struct ast_channel chan,
const char *  data 
)
static

Definition at line 287 of file app_stream_echo.c.

288{
289 int res;
290 unsigned int num = 0;
291 enum ast_media_type type;
292 char *parse;
293 struct ast_stream_topology *topology;
294
296 AST_APP_ARG(num);
298 );
299
300 parse = ast_strdupa(data);
302
303 if (ast_strlen_zero(args.num)) {
304 /*
305 * If a number is not given then no topology is to be created
306 * and renegotiated. The app will just echo back each stream
307 * received to itself.
308 */
310 }
311
312 if (ast_str_to_uint(args.num, &num)) {
313 ast_log(LOG_ERROR, "Failed to parse the first parameter '%s' into a"
314 " greater than or equal to zero\n", args.num);
315 return -1;
316 }
317
320
323 if (!topology) {
324 ast_log(LOG_ERROR, "Unable to create '%u' streams of type '%s' to"
325 " the topology\n", num, ast_codec_media_type2str(type));
326 return -1;
327 }
328
329 res = stream_echo_perform(chan, topology, type);
330
331 if (ast_channel_get_stream_topology(chan) != topology) {
332 ast_stream_topology_free(topology);
333 }
334
335 return res;
336}
static int stream_echo_perform(struct ast_channel *chan, struct ast_stream_topology *topology, enum ast_media_type type)
static struct ast_stream_topology * stream_echo_topology_alloc(struct ast_stream_topology *original, unsigned int num, enum ast_media_type type)
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition astmm.h:298
#define ast_log
Definition astobj2.c:42
static const char type[]
struct ast_stream_topology * ast_channel_get_stream_topology(const struct ast_channel *chan)
Retrieve the topology of streams on a channel.
ast_media_type
Types of media.
Definition codec.h:30
@ AST_MEDIA_TYPE_UNKNOWN
Definition codec.h:31
@ AST_MEDIA_TYPE_VIDEO
Definition codec.h:33
enum ast_media_type ast_media_type_from_str(const char *media_type_str)
Conversion function to take a media string and convert it to a media type.
Definition codec.c:364
const char * ast_codec_media_type2str(enum ast_media_type type)
Conversion function to take a media type and turn it into a string.
Definition codec.c:348
int ast_str_to_uint(const char *str, unsigned int *res)
Convert the given string to an unsigned integer.
Definition conversions.c:56
#define AST_APP_ARG(name)
Define an application argument.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
#define LOG_ERROR
static struct @519 args
#define NULL
Definition resample.c:96
void ast_stream_topology_free(struct ast_stream_topology *topology)
Unreference and destroy a stream topology.
Definition stream.c:746
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition strings.h:65

References args, AST_APP_ARG, ast_channel_get_stream_topology(), ast_codec_media_type2str(), AST_DECLARE_APP_ARGS, ast_log, ast_media_type_from_str(), AST_MEDIA_TYPE_UNKNOWN, AST_MEDIA_TYPE_VIDEO, AST_STANDARD_APP_ARGS, ast_str_to_uint(), ast_strdupa, ast_stream_topology_free(), ast_strlen_zero(), LOG_ERROR, NULL, stream_echo_perform(), stream_echo_topology_alloc(), and type.

Referenced by load_module().

◆ stream_echo_perform()

static int stream_echo_perform ( struct ast_channel chan,
struct ast_stream_topology topology,
enum ast_media_type  type 
)
static

Definition at line 157 of file app_stream_echo.c.

159{
160 int update_sent = 0;
161 int request_change = topology != NULL;
162 int one_to_one = 1;
163
164 while (ast_waitfor(chan, -1) > -1) {
165 struct ast_frame *f;
166
167 if (request_change) {
168 /* Request a change to the new topology */
170 ast_log(LOG_WARNING, "Request stream topology change not supported "
171 "by channel '%s'\n", ast_channel_name(chan));
172 }
173 request_change = 0;
174 }
175
176 f = ast_read_stream(chan);
177 if (!f) {
178 return -1;
179 }
180
181 if ((f->frametype == AST_FRAME_DTMF) && (f->subclass.integer == '#')) {
182 ast_frfree(f);
183 break;
184 }
185
186 f->delivery.tv_sec = 0;
187 f->delivery.tv_usec = 0;
188
189 if (f->frametype == AST_FRAME_CONTROL) {
190 if (f->subclass.integer == AST_CONTROL_VIDUPDATE && !update_sent) {
191 if (stream_echo_write(chan, f, type, one_to_one)) {
192 ast_frfree(f);
193 return -1;
194 }
195 update_sent = 1;
196 } else if (f->subclass.integer == AST_CONTROL_SRCCHANGE) {
197 update_sent = 0;
199 update_sent = 0;
200 one_to_one = 0; /* Switch writing to one to many */
201 }
202 } else if (f->frametype == AST_FRAME_VIDEO && !update_sent){
203 struct ast_frame frame = {
205 .subclass.integer = AST_CONTROL_VIDUPDATE,
206 };
207 stream_echo_write(chan, &frame, type, one_to_one);
208 update_sent = 1;
209 }
210
211 if (f->frametype != AST_FRAME_CONTROL &&
214 stream_echo_write(chan, f, type, one_to_one)) {
215 ast_frfree(f);
216 return -1;
217 }
218
219 ast_frfree(f);
220 }
221
222 return 0;
223}
static int stream_echo_write(struct ast_channel *chan, struct ast_frame *frame, enum ast_media_type type, int one_to_one)
const char * ast_channel_name(const struct ast_channel *chan)
int ast_channel_request_stream_topology_change(struct ast_channel *chan, struct ast_stream_topology *topology, void *change_source)
Request that the stream topology of a channel change.
Definition channel.c:10985
int ast_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
Definition channel.c:3134
struct ast_frame * ast_read_stream(struct ast_channel *chan)
Reads a frame, but does not filter to just the default streams.
Definition channel.c:4230
#define AST_FRAME_DTMF
#define ast_frfree(fr)
@ AST_FRAME_CONTROL
@ AST_CONTROL_VIDUPDATE
@ AST_CONTROL_STREAM_TOPOLOGY_CHANGED
@ AST_CONTROL_SRCCHANGE
#define LOG_WARNING
Data structure associated with a single frame of data.
struct ast_frame_subclass subclass
struct timeval delivery
enum ast_frame_type frametype

References ast_channel_name(), ast_channel_request_stream_topology_change(), AST_CONTROL_SRCCHANGE, AST_CONTROL_STREAM_TOPOLOGY_CHANGED, AST_CONTROL_VIDUPDATE, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_MODEM, AST_FRAME_NULL, AST_FRAME_VIDEO, ast_frfree, ast_log, ast_read_stream(), ast_waitfor(), ast_frame::delivery, ast_frame::frametype, ast_frame_subclass::integer, LOG_WARNING, NULL, stream_echo_write(), ast_frame::subclass, and type.

Referenced by stream_echo_exec().

◆ stream_echo_topology_alloc()

static struct ast_stream_topology * stream_echo_topology_alloc ( struct ast_stream_topology original,
unsigned int  num,
enum ast_media_type  type 
)
static

Definition at line 225 of file app_stream_echo.c.

227{
228 int i, n = num;
230
231 if (!res) {
232 return NULL;
233 }
234
235 /*
236 * Clone every stream of a type not matching the given one. If the type
237 * matches clone only the first stream found for the given type. Then for
238 * that stream clone it again up to num - 1 times. Ignore any other streams
239 * of the same matched type in the original topology.
240 *
241 * So for instance if the original stream contains 1 audio stream and 2 video
242 * streams (video stream 'A' and video stream 'B'), num is '3', and the given
243 * type is 'video' then the resulting topology will contain a clone of the
244 * audio stream along with 3 clones of video stream 'A'. Video stream 'B' is
245 * not copied over.
246 */
247 for (i = 0; i < ast_stream_topology_get_count(original); ++i) {
248 struct ast_stream *stream = ast_stream_topology_get_stream(original, i);
249
250 if (!n && ast_stream_get_type(stream) == type) {
251 /* Don't copy any[more] of the given type */
252 continue;
253 }
254
256 /* Don't copy removed/declined streams */
257 continue;
258 }
259
260 do {
261 stream = ast_stream_clone(stream, NULL);
262
263 if (!stream || ast_stream_topology_append_stream(res, stream) < 0) {
264 ast_stream_free(stream);
266 return NULL;
267 }
268
269 if (ast_stream_get_type(stream) != type) {
270 /* Do not multiply non matching streams */
271 break;
272 }
273
274 /*
275 * Since num is not zero yet (i.e. this is first stream found to
276 * match on the type) and the types match then loop num - 1 times
277 * cloning the same stream.
278 */
279 ast_stream_set_state(stream, n == num ?
281 } while (--n);
282 }
283
284 return res;
285}
struct ast_stream_topology * ast_stream_topology_alloc(void)
Create a stream topology.
Definition stream.c:652
@ AST_STREAM_STATE_REMOVED
Set when the stream has been removed/declined.
Definition stream.h:78
@ AST_STREAM_STATE_SENDRECV
Set when the stream is sending and receiving media.
Definition stream.h:82
@ AST_STREAM_STATE_SENDONLY
Set when the stream is sending media only.
Definition stream.h:86
void ast_stream_set_state(struct ast_stream *stream, enum ast_stream_state state)
Set the state of a stream.
Definition stream.c:380
int ast_stream_topology_append_stream(struct ast_stream_topology *topology, struct ast_stream *stream)
Append a stream to the topology.
Definition stream.c:751
struct ast_stream * ast_stream_clone(const struct ast_stream *stream, const char *name)
Create a deep clone of an existing stream.
Definition stream.c:257
struct ast_stream * ast_stream_topology_get_stream(const struct ast_stream_topology *topology, unsigned int position)
Get a specific stream from the topology.
Definition stream.c:791
int ast_stream_topology_get_count(const struct ast_stream_topology *topology)
Get the number of streams in a topology.
Definition stream.c:768
enum ast_stream_state ast_stream_get_state(const struct ast_stream *stream)
Get the current state of a stream.
Definition stream.c:373
enum ast_media_type ast_stream_get_type(const struct ast_stream *stream)
Get the media type of a stream.
Definition stream.c:316
void ast_stream_free(struct ast_stream *stream)
Destroy a media stream representation.
Definition stream.c:292

References ast_stream_clone(), ast_stream_free(), ast_stream_get_state(), ast_stream_get_type(), ast_stream_set_state(), AST_STREAM_STATE_REMOVED, AST_STREAM_STATE_SENDONLY, AST_STREAM_STATE_SENDRECV, ast_stream_topology_alloc(), ast_stream_topology_append_stream(), ast_stream_topology_free(), ast_stream_topology_get_count(), ast_stream_topology_get_stream(), NULL, and type.

Referenced by stream_echo_exec().

◆ stream_echo_write()

static int stream_echo_write ( struct ast_channel chan,
struct ast_frame frame,
enum ast_media_type  type,
int  one_to_one 
)
static

Definition at line 102 of file app_stream_echo.c.

104{
105 int i;
106 int num;
107 struct ast_stream_topology *topology;
108
109 /*
110 * Since this is an echo application if we get a frame in on a stream
111 * we simply want to echo it back out onto the same stream number.
112 */
113 num = ast_channel_is_multistream(chan) ? frame->stream_num : -1;
114 if (ast_write_stream(chan, num, frame)) {
115 return stream_echo_write_error(chan, frame, num);
116 }
117
118 /*
119 * If the frame's type and given type don't match, or we are operating in
120 * a one to one stream echo mode then there is nothing left to do.
121 *
122 * Note, if the channel is not multi-stream capable then one_to_one will
123 * always be true, so it is safe to also not check for that here too.
124 */
125 if (one_to_one || !frame->subclass.format ||
127 return 0;
128 }
129
130 /*
131 * However, if we are operating in a single stream echoed to many stream
132 * mode, and the frame's type matches the given type then we also need to
133 * find the other streams of the same type and write out to those streams
134 * as well.
135 *
136 * If we are here, then it's accepted that whatever stream number the frame
137 * was read from for the given type is the only one set to send/receive,
138 * while the others of the same type are set to receive only. Since we
139 * shouldn't assume any order to the streams, we'll loop back through all
140 * streams in the channel's topology writing only to those of the same type.
141 * And, of course also not the stream which has already been written to.
142 */
143 topology = ast_channel_get_stream_topology(chan);
144
145 for (i = 0; i < ast_stream_topology_get_count(topology); ++i) {
146 struct ast_stream *stream = ast_stream_topology_get_stream(topology, i);
147 if (num != i && ast_stream_get_type(stream) == type) {
148 if (ast_write_stream(chan, i, frame)) {
149 return stream_echo_write_error(chan, frame, i);
150 }
151 }
152 }
153
154 return 0;
155}
static int stream_echo_write_error(struct ast_channel *chan, struct ast_frame *frame, int pos)
int ast_write_stream(struct ast_channel *chan, int stream_num, struct ast_frame *frame)
Write a frame to a stream This function writes the given frame to the indicated stream on the channel...
Definition channel.c:5119
int ast_channel_is_multistream(struct ast_channel *chan)
Determine if a channel is multi-stream capable.
enum ast_media_type ast_format_get_type(const struct ast_format *format)
Get the media type of a format.
Definition format.c:354
struct ast_format * format

References ast_channel_get_stream_topology(), ast_channel_is_multistream(), ast_format_get_type(), ast_stream_get_type(), ast_stream_topology_get_count(), ast_stream_topology_get_stream(), ast_write_stream(), ast_frame_subclass::format, stream_echo_write_error(), ast_frame::stream_num, ast_frame::subclass, and type.

Referenced by stream_echo_perform().

◆ stream_echo_write_error()

static int stream_echo_write_error ( struct ast_channel chan,
struct ast_frame frame,
int  pos 
)
static

Definition at line 81 of file app_stream_echo.c.

82{
83 char frame_type[32];
84 const char *media_type;
85 struct ast_stream *stream;
86
88
89 stream = pos < 0 ?
92
94
95 ast_log(LOG_ERROR, "%s - unable to write frame type '%s' to stream type '%s' at "
96 "position '%d'\n", ast_channel_name(chan), frame_type, media_type,
98
99 return -1;
100}
struct ast_stream * ast_channel_get_default_stream(struct ast_channel *chan, enum ast_media_type type)
Retrieve the default stream of a specific media type on a channel.
frame_type
char * ast_frame_type2str(enum ast_frame_type frame_type, char *ftype, size_t len)
Copy the discription of a frame type into the provided string.
Definition main/frame.c:671
int ast_stream_get_position(const struct ast_stream *stream)
Get the position of the stream in the topology.
Definition stream.c:500

References ast_channel_get_default_stream(), ast_channel_get_stream_topology(), ast_channel_name(), ast_codec_media_type2str(), ast_format_get_type(), ast_frame_type2str(), ast_log, ast_stream_get_position(), ast_stream_get_type(), ast_stream_topology_get_stream(), ast_frame_subclass::format, ast_frame::frametype, LOG_ERROR, and ast_frame::subclass.

Referenced by stream_echo_write().

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 338 of file app_stream_echo.c.

339{
341}
int ast_unregister_application(const char *app)
Unregister an application.
Definition pbx_app.c:392

References app, and ast_unregister_application().

Variable Documentation

◆ __mod_info

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Stream Echo Application" , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, .support_level = AST_MODULE_SUPPORT_CORE, }
static

Definition at line 348 of file app_stream_echo.c.

◆ app

const char app[] = "StreamEcho"
static

Definition at line 79 of file app_stream_echo.c.

Referenced by load_module(), and unload_module().

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 348 of file app_stream_echo.c.