Asterisk - The Open Source Telephony Project GIT-master-9647a4f
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, int stream_num, struct ast_frame *frame)
 
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 352 of file app_stream_echo.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 352 of file app_stream_echo.c.

◆ AST_MODULE_SELF_SYM()

struct ast_module * AST_MODULE_SELF_SYM ( void  )

Definition at line 352 of file app_stream_echo.c.

◆ load_module()

static int load_module ( void  )
static

Definition at line 347 of file app_stream_echo.c.

348{
350}
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 291 of file app_stream_echo.c.

292{
293 int res;
294 unsigned int num = 0;
295 enum ast_media_type type;
296 char *parse;
297 struct ast_stream_topology *topology;
298
300 AST_APP_ARG(num);
302 );
303
304 parse = ast_strdupa(data);
306
307 if (ast_strlen_zero(args.num)) {
308 /*
309 * If a number is not given then no topology is to be created
310 * and renegotiated. The app will just echo back each stream
311 * received to itself.
312 */
314 }
315
316 if (ast_str_to_uint(args.num, &num)) {
317 ast_log(LOG_ERROR, "Failed to parse the first parameter '%s' into a"
318 " greater than or equal to zero\n", args.num);
319 return -1;
320 }
321
324
327 if (!topology) {
328 ast_log(LOG_ERROR, "Unable to create '%u' streams of type '%s' to"
329 " the topology\n", num, ast_codec_media_type2str(type));
330 return -1;
331 }
332
333 res = stream_echo_perform(chan, topology, type);
334
335 if (ast_channel_get_stream_topology(chan) != topology) {
336 ast_stream_topology_free(topology);
337 }
338
339 return res;
340}
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 161 of file app_stream_echo.c.

163{
164 int update_sent = 0;
165 int request_change = topology != NULL;
166 int one_to_one = 1;
167
168 while (ast_waitfor(chan, -1) > -1) {
169 struct ast_frame *f;
170
171 if (request_change) {
172 /* Request a change to the new topology */
174 ast_log(LOG_WARNING, "Request stream topology change not supported "
175 "by channel '%s'\n", ast_channel_name(chan));
176 }
177 request_change = 0;
178 }
179
180 f = ast_read_stream(chan);
181 if (!f) {
182 return -1;
183 }
184
185 if ((f->frametype == AST_FRAME_DTMF) && (f->subclass.integer == '#')) {
186 ast_frfree(f);
187 break;
188 }
189
190 f->delivery.tv_sec = 0;
191 f->delivery.tv_usec = 0;
192
193 if (f->frametype == AST_FRAME_CONTROL) {
194 if (f->subclass.integer == AST_CONTROL_VIDUPDATE && !update_sent) {
195 if (stream_echo_write(chan, f, type, one_to_one)) {
196 ast_frfree(f);
197 return -1;
198 }
199 update_sent = 1;
200 } else if (f->subclass.integer == AST_CONTROL_SRCCHANGE) {
201 update_sent = 0;
203 update_sent = 0;
204 one_to_one = 0; /* Switch writing to one to many */
205 }
206 } else if (f->frametype == AST_FRAME_VIDEO && !update_sent){
207 struct ast_frame frame = {
209 .subclass.integer = AST_CONTROL_VIDUPDATE,
210 };
211 stream_echo_write(chan, &frame, type, one_to_one);
212 update_sent = 1;
213 }
214
215 if (f->frametype != AST_FRAME_CONTROL &&
218 stream_echo_write(chan, f, type, one_to_one)) {
219 ast_frfree(f);
220 return -1;
221 }
222
223 ast_frfree(f);
224 }
225
226 return 0;
227}
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:11014
int ast_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
Definition channel.c:3159
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:4255
#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 229 of file app_stream_echo.c.

231{
232 int i, n = num;
234
235 if (!res) {
236 return NULL;
237 }
238
239 /*
240 * Clone every stream of a type not matching the given one. If the type
241 * matches clone only the first stream found for the given type. Then for
242 * that stream clone it again up to num - 1 times. Ignore any other streams
243 * of the same matched type in the original topology.
244 *
245 * So for instance if the original stream contains 1 audio stream and 2 video
246 * streams (video stream 'A' and video stream 'B'), num is '3', and the given
247 * type is 'video' then the resulting topology will contain a clone of the
248 * audio stream along with 3 clones of video stream 'A'. Video stream 'B' is
249 * not copied over.
250 */
251 for (i = 0; i < ast_stream_topology_get_count(original); ++i) {
252 struct ast_stream *stream = ast_stream_topology_get_stream(original, i);
253
254 if (!n && ast_stream_get_type(stream) == type) {
255 /* Don't copy any[more] of the given type */
256 continue;
257 }
258
260 /* Don't copy removed/declined streams */
261 continue;
262 }
263
264 do {
265 stream = ast_stream_clone(stream, NULL);
266
267 if (!stream || ast_stream_topology_append_stream(res, stream) < 0) {
268 ast_stream_free(stream);
270 return NULL;
271 }
272
273 if (ast_stream_get_type(stream) != type) {
274 /* Do not multiply non matching streams */
275 break;
276 }
277
278 /*
279 * Since num is not zero yet (i.e. this is first stream found to
280 * match on the type) and the types match then loop num - 1 times
281 * cloning the same stream.
282 */
283 ast_stream_set_state(stream, n == num ?
285 } while (--n);
286 }
287
288 return res;
289}
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 106 of file app_stream_echo.c.

108{
109 int i;
110 int num;
111 struct ast_stream_topology *topology;
112
113 /*
114 * Since this is an echo application if we get a frame in on a stream
115 * we simply want to echo it back out onto the same stream number.
116 */
117 num = ast_channel_is_multistream(chan) ? frame->stream_num : -1;
118 if (ast_write_stream(chan, num, frame)) {
119 return stream_echo_write_error(chan, num, frame);
120 }
121
122 /*
123 * If the frame's type and given type don't match, or we are operating in
124 * a one to one stream echo mode then there is nothing left to do.
125 *
126 * Note, if the channel is not multi-stream capable then one_to_one will
127 * always be true, so it is safe to also not check for that here too.
128 */
129 if (one_to_one || !frame->subclass.format ||
131 return 0;
132 }
133
134 /*
135 * However, if we are operating in a single stream echoed to many stream
136 * mode, and the frame's type matches the given type then we also need to
137 * find the other streams of the same type and write out to those streams
138 * as well.
139 *
140 * If we are here, then it's accepted that whatever stream number the frame
141 * was read from for the given type is the only one set to send/receive,
142 * while the others of the same type are set to receive only. Since we
143 * shouldn't assume any order to the streams, we'll loop back through all
144 * streams in the channel's topology writing only to those of the same type.
145 * And, of course also not the stream which has already been written to.
146 */
147 topology = ast_channel_get_stream_topology(chan);
148
149 for (i = 0; i < ast_stream_topology_get_count(topology); ++i) {
150 struct ast_stream *stream = ast_stream_topology_get_stream(topology, i);
151 if (num != i && ast_stream_get_type(stream) == type) {
152 if (ast_write_stream(chan, i, frame)) {
153 return stream_echo_write_error(chan, i, frame);
154 }
155 }
156 }
157
158 return 0;
159}
static int stream_echo_write_error(struct ast_channel *chan, int stream_num, struct ast_frame *frame)
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:5144
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,
int  stream_num,
struct ast_frame frame 
)
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 = stream_num < 0 ?
92
93 if (!stream) {
94 return -1;
95 }
96
98
99 ast_log(LOG_ERROR, "%s - unable to write frame type '%s' to stream type '%s' at "
100 "position '%d'\n", ast_channel_name(chan), frame_type, media_type,
102
103 return -1;
104}
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 342 of file app_stream_echo.c.

343{
345}
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 352 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 352 of file app_stream_echo.c.