diff options
author | Richard Mudgett <rmudgett@digium.com> | 2016-06-10 12:35:33 -0500 |
---|---|---|
committer | Richard Mudgett <rmudgett@digium.com> | 2016-06-10 17:24:00 -0500 |
commit | 5823f279f32244bef2f6389dbe5022c2f73e4685 (patch) | |
tree | b7275909f14b0af0fe273efde733fee2a907472e /channels | |
parent | dde58df3182b7f99714e446a684d8ddb81f759bb (diff) |
chan_rtp: Backport changes from master.
* Deprecate chan_multicast_rtp.
Change-Id: Ib5a45e58c75ee8abd0b4f9575379b5321feb853e
Diffstat (limited to 'channels')
-rw-r--r-- | channels/chan_multicast_rtp.c | 7 | ||||
-rw-r--r-- | channels/chan_rtp.c | 316 |
2 files changed, 258 insertions, 65 deletions
diff --git a/channels/chan_multicast_rtp.c b/channels/chan_multicast_rtp.c index 267baabf1..c45dedf7f 100644 --- a/channels/chan_multicast_rtp.c +++ b/channels/chan_multicast_rtp.c @@ -28,7 +28,8 @@ */ /*** MODULEINFO - <support_level>core</support_level> + <support_level>deprecated</support_level> + <defaultenabled>no</defaultenabled> ***/ #include "asterisk.h" @@ -215,8 +216,8 @@ static int unload_module(void) return 0; } -AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Multicast RTP Paging Channel", - .support_level = AST_MODULE_SUPPORT_CORE, +AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Multicast RTP Paging Channel (use chan_rtp instead)", + .support_level = AST_MODULE_SUPPORT_DEPRECATED, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_CHANNEL_DRIVER, diff --git a/channels/chan_rtp.c b/channels/chan_rtp.c index 267baabf1..0fe66bd20 100644 --- a/channels/chan_rtp.c +++ b/channels/chan_rtp.c @@ -1,7 +1,7 @@ /* * Asterisk -- An open source telephony toolkit. * - * Copyright (C) 2009, Digium, Inc. + * Copyright (C) 2009 - 2014, Digium, Inc. * * Joshua Colp <jcolp@digium.com> * Andreas 'MacBrody' Brodmann <andreas.brodmann@gmail.com> @@ -22,7 +22,7 @@ * \author Joshua Colp <jcolp@digium.com> * \author Andreas 'MacBrody' Broadmann <andreas.brodmann@gmail.com> * - * \brief Multicast RTP Paging Channel + * \brief RTP (Multicast and Unicast) Media Channel * * \ingroup channel_drivers */ @@ -33,54 +33,64 @@ #include "asterisk.h" -ASTERISK_FILE_VERSION(__FILE__, "$Revision$") +ASTERISK_REGISTER_FILE() -#include <fcntl.h> -#include <sys/signal.h> - -#include "asterisk/lock.h" #include "asterisk/channel.h" -#include "asterisk/config.h" #include "asterisk/module.h" #include "asterisk/pbx.h" -#include "asterisk/sched.h" -#include "asterisk/io.h" #include "asterisk/acl.h" -#include "asterisk/callerid.h" -#include "asterisk/file.h" -#include "asterisk/cli.h" #include "asterisk/app.h" #include "asterisk/rtp_engine.h" #include "asterisk/causes.h" - -static const char tdesc[] = "Multicast RTP Paging Channel Driver"; +#include "asterisk/format_cache.h" +#include "asterisk/multicast_rtp.h" /* Forward declarations */ static struct ast_channel *multicast_rtp_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause); -static int multicast_rtp_call(struct ast_channel *ast, const char *dest, int timeout); -static int multicast_rtp_hangup(struct ast_channel *ast); -static struct ast_frame *multicast_rtp_read(struct ast_channel *ast); -static int multicast_rtp_write(struct ast_channel *ast, struct ast_frame *f); +static struct ast_channel *unicast_rtp_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause); +static int rtp_call(struct ast_channel *ast, const char *dest, int timeout); +static int rtp_hangup(struct ast_channel *ast); +static struct ast_frame *rtp_read(struct ast_channel *ast); +static int rtp_write(struct ast_channel *ast, struct ast_frame *f); -/* Channel driver declaration */ +/* Multicast channel driver declaration */ static struct ast_channel_tech multicast_rtp_tech = { .type = "MulticastRTP", - .description = tdesc, + .description = "Multicast RTP Paging Channel Driver", .requester = multicast_rtp_request, - .call = multicast_rtp_call, - .hangup = multicast_rtp_hangup, - .read = multicast_rtp_read, - .write = multicast_rtp_write, + .call = rtp_call, + .hangup = rtp_hangup, + .read = rtp_read, + .write = rtp_write, +}; + +/* Unicast channel driver declaration */ +static struct ast_channel_tech unicast_rtp_tech = { + .type = "UnicastRTP", + .description = "Unicast RTP Media Channel Driver", + .requester = unicast_rtp_request, + .call = rtp_call, + .hangup = rtp_hangup, + .read = rtp_read, + .write = rtp_write, }; /*! \brief Function called when we should read a frame from the channel */ -static struct ast_frame *multicast_rtp_read(struct ast_channel *ast) +static struct ast_frame *rtp_read(struct ast_channel *ast) { - return &ast_null_frame; + struct ast_rtp_instance *instance = ast_channel_tech_pvt(ast); + int fdno = ast_channel_fdno(ast); + + switch (fdno) { + case 0: + return ast_rtp_instance_read(instance, 0); + default: + return &ast_null_frame; + } } /*! \brief Function called when we should write a frame to the channel */ -static int multicast_rtp_write(struct ast_channel *ast, struct ast_frame *f) +static int rtp_write(struct ast_channel *ast, struct ast_frame *f) { struct ast_rtp_instance *instance = ast_channel_tech_pvt(ast); @@ -88,7 +98,7 @@ static int multicast_rtp_write(struct ast_channel *ast, struct ast_frame *f) } /*! \brief Function called when we should actually call the destination */ -static int multicast_rtp_call(struct ast_channel *ast, const char *dest, int timeout) +static int rtp_call(struct ast_channel *ast, const char *dest, int timeout) { struct ast_rtp_instance *instance = ast_channel_tech_pvt(ast); @@ -98,7 +108,7 @@ static int multicast_rtp_call(struct ast_channel *ast, const char *dest, int tim } /*! \brief Function called when we should hang the channel up */ -static int multicast_rtp_hangup(struct ast_channel *ast) +static int rtp_hangup(struct ast_channel *ast) { struct ast_rtp_instance *instance = ast_channel_tech_pvt(ast); @@ -109,41 +119,65 @@ static int multicast_rtp_hangup(struct ast_channel *ast) return 0; } -/*! \brief Function called when we should prepare to call the destination */ +/*! \brief Function called when we should prepare to call the multicast destination */ static struct ast_channel *multicast_rtp_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause) { - char *tmp = ast_strdupa(data), *multicast_type = tmp, *destination, *control; + char *parse; struct ast_rtp_instance *instance; struct ast_sockaddr control_address; struct ast_sockaddr destination_address; struct ast_channel *chan; struct ast_format_cap *caps = NULL; struct ast_format *fmt = NULL; + AST_DECLARE_APP_ARGS(args, + AST_APP_ARG(type); + AST_APP_ARG(destination); + AST_APP_ARG(control); + AST_APP_ARG(options); + ); + struct ast_multicast_rtp_options *mcast_options = NULL; + + if (ast_strlen_zero(data)) { + ast_log(LOG_ERROR, "A multicast type and destination must be given to the 'MulticastRTP' channel\n"); + goto failure; + } + parse = ast_strdupa(data); + AST_NONSTANDARD_APP_ARGS(args, parse, '/'); - fmt = ast_format_cap_get_format(cap, 0); - - ast_sockaddr_setnull(&control_address); + if (ast_strlen_zero(args.type)) { + ast_log(LOG_ERROR, "Type is required for the 'MulticastRTP' channel\n"); + goto failure; + } - /* If no type was given we can't do anything */ - if (ast_strlen_zero(multicast_type)) { + if (ast_strlen_zero(args.destination)) { + ast_log(LOG_ERROR, "Destination is required for the 'MulticastRTP' channel\n"); + goto failure; + } + if (!ast_sockaddr_parse(&destination_address, args.destination, PARSE_PORT_REQUIRE)) { + ast_log(LOG_ERROR, "Destination address '%s' could not be parsed\n", + args.destination); goto failure; } - if (!(destination = strchr(tmp, '/'))) { + ast_sockaddr_setnull(&control_address); + if (!ast_strlen_zero(args.control) + && !ast_sockaddr_parse(&control_address, args.control, PARSE_PORT_REQUIRE)) { + ast_log(LOG_ERROR, "Control address '%s' could not be parsed\n", args.control); goto failure; } - *destination++ = '\0'; - if ((control = strchr(destination, '/'))) { - *control++ = '\0'; - if (!ast_sockaddr_parse(&control_address, control, - PARSE_PORT_REQUIRE)) { - goto failure; - } + mcast_options = ast_multicast_rtp_create_options(args.type, args.options); + if (!mcast_options) { + goto failure; } - if (!ast_sockaddr_parse(&destination_address, destination, - PARSE_PORT_REQUIRE)) { + fmt = ast_multicast_rtp_options_get_format(mcast_options); + if (!fmt) { + fmt = ast_format_cap_get_format(cap, 0); + } + if (!fmt) { + ast_log(LOG_ERROR, "No codec available for sending RTP to '%s'\n", + args.destination); goto failure; } @@ -152,11 +186,17 @@ static struct ast_channel *multicast_rtp_request(const char *type, struct ast_fo goto failure; } - if (!(instance = ast_rtp_instance_new("multicast", NULL, &control_address, multicast_type))) { + instance = ast_rtp_instance_new("multicast", NULL, &control_address, mcast_options); + if (!instance) { + ast_log(LOG_ERROR, + "Could not create '%s' multicast RTP instance for sending media to '%s'\n", + args.type, args.destination); goto failure; } - if (!(chan = ast_channel_alloc(1, AST_STATE_DOWN, "", "", "", "", "", assignedids, requestor, 0, "MulticastRTP/%p", instance))) { + chan = ast_channel_alloc(1, AST_STATE_DOWN, "", "", "", "", "", assignedids, + requestor, 0, "MulticastRTP/%p", instance); + if (!chan) { ast_rtp_instance_destroy(instance); goto failure; } @@ -178,44 +218,196 @@ static struct ast_channel *multicast_rtp_request(const char *type, struct ast_fo ao2_ref(fmt, -1); ao2_ref(caps, -1); + ast_multicast_rtp_free_options(mcast_options); return chan; failure: ao2_cleanup(fmt); ao2_cleanup(caps); + ast_multicast_rtp_free_options(mcast_options); *cause = AST_CAUSE_FAILURE; return NULL; } -/*! \brief Function called when our module is loaded */ -static int load_module(void) +enum { + OPT_RTP_CODEC = (1 << 0), + OPT_RTP_ENGINE = (1 << 1), +}; + +enum { + OPT_ARG_RTP_CODEC, + OPT_ARG_RTP_ENGINE, + /* note: this entry _MUST_ be the last one in the enum */ + OPT_ARG_ARRAY_SIZE +}; + +AST_APP_OPTIONS(unicast_rtp_options, BEGIN_OPTIONS + /*! Set the codec to be used for unicast RTP */ + AST_APP_OPTION_ARG('c', OPT_RTP_CODEC, OPT_ARG_RTP_CODEC), + /*! Set the RTP engine to use for unicast RTP */ + AST_APP_OPTION_ARG('e', OPT_RTP_ENGINE, OPT_ARG_RTP_ENGINE), +END_OPTIONS ); + +/*! \brief Function called when we should prepare to call the unicast destination */ +static struct ast_channel *unicast_rtp_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause) { - if (!(multicast_rtp_tech.capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) { - return AST_MODULE_LOAD_DECLINE; + char *parse; + struct ast_rtp_instance *instance; + struct ast_sockaddr address; + struct ast_sockaddr local_address; + struct ast_channel *chan; + struct ast_format_cap *caps = NULL; + struct ast_format *fmt = NULL; + const char *engine_name; + AST_DECLARE_APP_ARGS(args, + AST_APP_ARG(destination); + AST_APP_ARG(options); + ); + struct ast_flags opts = { 0, }; + char *opt_args[OPT_ARG_ARRAY_SIZE]; + + if (ast_strlen_zero(data)) { + ast_log(LOG_ERROR, "Destination is required for the 'UnicastRTP' channel\n"); + goto failure; } - ast_format_cap_append_by_type(multicast_rtp_tech.capabilities, AST_MEDIA_TYPE_UNKNOWN); - if (ast_channel_register(&multicast_rtp_tech)) { - ast_log(LOG_ERROR, "Unable to register channel class 'MulticastRTP'\n"); - ao2_ref(multicast_rtp_tech.capabilities, -1); - multicast_rtp_tech.capabilities = NULL; - return AST_MODULE_LOAD_DECLINE; + parse = ast_strdupa(data); + AST_NONSTANDARD_APP_ARGS(args, parse, '/'); + + if (ast_strlen_zero(args.destination)) { + ast_log(LOG_ERROR, "Destination is required for the 'UnicastRTP' channel\n"); + goto failure; + } + if (!ast_sockaddr_parse(&address, args.destination, PARSE_PORT_REQUIRE)) { + ast_log(LOG_ERROR, "Destination '%s' could not be parsed\n", args.destination); + goto failure; } - return AST_MODULE_LOAD_SUCCESS; + if (!ast_strlen_zero(args.options) + && ast_app_parse_options(unicast_rtp_options, &opts, opt_args, + ast_strdupa(args.options))) { + ast_log(LOG_ERROR, "'UnicastRTP' channel options '%s' parse error\n", + args.options); + goto failure; + } + + if (ast_test_flag(&opts, OPT_RTP_CODEC) + && !ast_strlen_zero(opt_args[OPT_ARG_RTP_CODEC])) { + fmt = ast_format_cache_get(opt_args[OPT_ARG_RTP_CODEC]); + if (!fmt) { + ast_log(LOG_ERROR, "Codec '%s' not found for sending RTP to '%s'\n", + opt_args[OPT_ARG_RTP_CODEC], args.destination); + goto failure; + } + } else { + fmt = ast_format_cap_get_format(cap, 0); + if (!fmt) { + ast_log(LOG_ERROR, "No codec available for sending RTP to '%s'\n", + args.destination); + goto failure; + } + } + + caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); + if (!caps) { + goto failure; + } + + engine_name = S_COR(ast_test_flag(&opts, OPT_RTP_ENGINE), + opt_args[OPT_ARG_RTP_ENGINE], NULL); + + ast_ouraddrfor(&address, &local_address); + instance = ast_rtp_instance_new(engine_name, NULL, &local_address, NULL); + if (!instance) { + ast_log(LOG_ERROR, + "Could not create %s RTP instance for sending media to '%s'\n", + S_OR(engine_name, "default"), args.destination); + goto failure; + } + + chan = ast_channel_alloc(1, AST_STATE_DOWN, "", "", "", "", "", assignedids, + requestor, 0, "UnicastRTP/%s-%p", args.destination, instance); + if (!chan) { + ast_rtp_instance_destroy(instance); + goto failure; + } + ast_rtp_instance_set_channel_id(instance, ast_channel_uniqueid(chan)); + ast_rtp_instance_set_remote_address(instance, &address); + ast_channel_set_fd(chan, 0, ast_rtp_instance_fd(instance, 0)); + + ast_channel_tech_set(chan, &unicast_rtp_tech); + + ast_format_cap_append(caps, fmt, 0); + ast_channel_nativeformats_set(chan, caps); + ast_channel_set_writeformat(chan, fmt); + ast_channel_set_rawwriteformat(chan, fmt); + ast_channel_set_readformat(chan, fmt); + ast_channel_set_rawreadformat(chan, fmt); + + ast_channel_tech_pvt_set(chan, instance); + + pbx_builtin_setvar_helper(chan, "UNICASTRTP_LOCAL_ADDRESS", + ast_sockaddr_stringify_addr(&local_address)); + ast_rtp_instance_get_local_address(instance, &local_address); + pbx_builtin_setvar_helper(chan, "UNICASTRTP_LOCAL_PORT", + ast_sockaddr_stringify_port(&local_address)); + + ast_channel_unlock(chan); + + ao2_ref(fmt, -1); + ao2_ref(caps, -1); + + return chan; + +failure: + ao2_cleanup(fmt); + ao2_cleanup(caps); + *cause = AST_CAUSE_FAILURE; + return NULL; } /*! \brief Function called when our module is unloaded */ static int unload_module(void) { ast_channel_unregister(&multicast_rtp_tech); - ao2_ref(multicast_rtp_tech.capabilities, -1); + ao2_cleanup(multicast_rtp_tech.capabilities); multicast_rtp_tech.capabilities = NULL; + ast_channel_unregister(&unicast_rtp_tech); + ao2_cleanup(unicast_rtp_tech.capabilities); + unicast_rtp_tech.capabilities = NULL; + return 0; } -AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Multicast RTP Paging Channel", +/*! \brief Function called when our module is loaded */ +static int load_module(void) +{ + if (!(multicast_rtp_tech.capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) { + return AST_MODULE_LOAD_DECLINE; + } + ast_format_cap_append_by_type(multicast_rtp_tech.capabilities, AST_MEDIA_TYPE_UNKNOWN); + if (ast_channel_register(&multicast_rtp_tech)) { + ast_log(LOG_ERROR, "Unable to register channel class 'MulticastRTP'\n"); + unload_module(); + return AST_MODULE_LOAD_DECLINE; + } + + if (!(unicast_rtp_tech.capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) { + unload_module(); + return AST_MODULE_LOAD_DECLINE; + } + ast_format_cap_append_by_type(unicast_rtp_tech.capabilities, AST_MEDIA_TYPE_UNKNOWN); + if (ast_channel_register(&unicast_rtp_tech)) { + ast_log(LOG_ERROR, "Unable to register channel class 'UnicastRTP'\n"); + unload_module(); + return AST_MODULE_LOAD_DECLINE; + } + + return AST_MODULE_LOAD_SUCCESS; +} + +AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "RTP Media Channel", .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, |