55 #include "asterisk/multicast_rtp.h"
60 #define LINKSYS_MCAST_STARTCMD 6
63 #define LINKSYS_MCAST_STOPCMD 7
98 struct timeval txcore;
102 #define MAX_TIMESTAMP_SKEW 640
105 OPT_CODEC = (1 << 0),
135 char *opt_args[OPT_ARG_ARRAY_SIZE];
146 mcast_options =
ast_calloc(1,
sizeof(*mcast_options)
148 + strlen(
S_OR(options,
"")) + 2);
149 if (!mcast_options) {
153 pos = mcast_options->
buf;
157 mcast_options->type = pos;
158 pos += strlen(type) + 1;
160 if (!ast_strlen_zero(options)) {
161 strcpy(pos, options);
163 mcast_options->options = pos;
166 mcast_options->opt_args, mcast_options->options)) {
167 ast_log(LOG_WARNING,
"Error parsing multicast RTP options\n");
172 return mcast_options;
177 ast_free(mcast_options);
182 if (ast_test_flag(&mcast_options->opts, OPT_CODEC)
183 && !ast_strlen_zero(mcast_options->opt_args[OPT_ARG_CODEC])) {
207 static int set_type(
struct multicast_rtp *multicast,
const char *type)
209 if (!strcasecmp(type,
"basic")) {
211 }
else if (!strcasecmp(type,
"linksys")) {
214 ast_log(LOG_WARNING,
"Unrecognized multicast type '%s' specified.\n", type);
221 static void set_ttl(
int sock,
const char *ttl_str)
225 if (ast_strlen_zero(ttl_str)) {
229 ast_debug(3,
"Setting multicast TTL to %s\n", ttl_str);
231 if (sscanf(ttl_str,
"%30d", &ttl) < 1) {
232 ast_log(LOG_WARNING,
"Invalid multicast ttl option '%s'\n", ttl_str);
236 if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL, &ttl,
sizeof(ttl)) < 0) {
237 ast_log(LOG_WARNING,
"Could not set multicast ttl to '%s': %s\n",
238 ttl_str, strerror(errno));
242 static void set_loop(
int sock,
const char *loop_str)
246 if (ast_strlen_zero(loop_str)) {
250 ast_debug(3,
"Setting multicast loop to %s\n", loop_str);
252 if (sscanf(loop_str,
"%30hhu", &loop) < 1) {
253 ast_log(LOG_WARNING,
"Invalid multicast loop option '%s'\n", loop_str);
257 if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_LOOP, &loop,
sizeof(loop)) < 0) {
258 ast_log(LOG_WARNING,
"Could not set multicast loop to '%s': %s\n",
259 loop_str, strerror(errno));
263 static void set_if(
int sock,
const char *if_str)
265 struct in_addr iface;
267 if (ast_strlen_zero(if_str)) {
271 ast_debug(3,
"Setting multicast if to %s\n", if_str);
273 if (!inet_aton(if_str, &iface)) {
274 ast_log(LOG_WARNING,
"Cannot parse if option '%s'\n", if_str);
277 if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, &iface,
sizeof(iface)) < 0) {
278 ast_log(LOG_WARNING,
"Could not set multicast if to '%s': %s\n",
279 if_str, strerror(errno));
289 if (!(multicast =
ast_calloc(1,
sizeof(*multicast)))) {
293 if (set_type(multicast, mcast_options->type)) {
298 if ((multicast->
socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
303 if (ast_test_flag(&mcast_options->opts, OPT_LOOP)) {
304 set_loop(multicast->
socket, mcast_options->opt_args[OPT_ARG_LOOP]);
307 if (ast_test_flag(&mcast_options->opts, OPT_TTL)) {
308 set_ttl(multicast->
socket, mcast_options->opt_args[OPT_ARG_TTL]);
311 if (ast_test_flag(&mcast_options->opts, OPT_IF)) {
312 set_if(multicast->
socket, mcast_options->opt_args[OPT_ARG_IF]);
315 multicast->
ssrc = ast_random();
322 static int rtp_get_rate(
struct ast_format *format)
328 static unsigned int calc_txstamp(
struct multicast_rtp *rtp,
struct timeval *delivery)
335 rtp->txcore.tv_usec -= rtp->txcore.tv_usec % 20000;
344 return (
unsigned int) ms;
351 .command = htonl(command),
366 ast_log(LOG_WARNING,
"Cannot send control packet for IPv6 "
367 "remote address.\n");
375 ast_sendto(multicast->
socket, &control_packet,
sizeof(control_packet), 0, &control_address);
376 ast_sendto(multicast->
socket, &control_packet,
sizeof(control_packet), 0, &control_address);
402 if (multicast->smoother) {
403 ast_smoother_free(multicast->smoother);
416 unsigned int ms = calc_txstamp(multicast, &frame->
delivery);
417 unsigned char *rtpheader;
420 int hdrlen = 12, mark = 0;
427 multicast->lastts = frame->
ts * rate;
430 int pred = multicast->lastts + frame->
samples;
433 multicast->lastts = multicast->lastts + ms * rate;
435 int delta = abs((
int) multicast->lastts - pred);
437 multicast->lastts = pred;
439 ast_debug(3,
"Difference is %d, ms is %u\n", delta, ms);
446 rtpheader = (
unsigned char *)(frame->
data.ptr - hdrlen);
448 put_unaligned_uint32(rtpheader, htonl((2 << 30) | (codec << 16) | (multicast->
seqno) | (mark << 23)));
449 put_unaligned_uint32(rtpheader + 4, htonl(multicast->lastts));
450 put_unaligned_uint32(rtpheader + 8, htonl(multicast->
ssrc));
453 multicast->
seqno = 0xFFFF & (multicast->
seqno + 1);
459 ast_log(LOG_ERROR,
"Multicast RTP Transmission error to %s: %s\n",
493 if (!framing_ms && (smoother_flags & AST_SMOOTHER_FLAG_FORCED)) {
499 if (!multicast->smoother) {
500 ast_log(LOG_WARNING,
"Unable to create smoother: format %s ms: %u len %u\n",
504 ast_smoother_set_flags(multicast->smoother, smoother_flags);
508 if (multicast->smoother) {
509 if (ast_smoother_test_flag(multicast->smoother, AST_SMOOTHER_FLAG_BE)) {
510 ast_smoother_feed_be(multicast->smoother, frame);
512 ast_smoother_feed(multicast->smoother, frame);
515 while ((f = ast_smoother_read(multicast->smoother)) && f->
data.ptr) {
522 if (frame->
offset < hdrlen) {
546 static int load_module(
void)
548 if (ast_rtp_engine_register(&multicast_rtp_engine)) {
555 static int unload_module(
void)
562 AST_MODULE_INFO(
ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER,
"Multicast RTP Engine",
563 .support_level = AST_MODULE_SUPPORT_CORE,
565 .unload = unload_module,
struct ast_multicast_rtp_options * ast_multicast_rtp_create_options(const char *type, const char *options)
Create multicast RTP options.
static int multicast_send_control_packet(struct ast_rtp_instance *instance, struct multicast_rtp *multicast, int command)
Helper function which populates a control packet with useful information and sends it...
#define ast_frdup(fr)
Copies a frame.
Structure for a Linksys control packet.
ssize_t ast_sendto(int sockfd, const void *buf, size_t len, int flags, const struct ast_sockaddr *dest_addr)
Wrapper around sendto(2) that uses ast_sockaddr.
Asterisk locking-related definitions:
multicast_type
Type of paging to do.
Asterisk main include file. File version handling, generic pbx functions.
static int rtp_raw_write(struct ast_rtp_instance *instance, struct ast_frame *frame, int codec)
struct ast_rtp_codecs * ast_rtp_instance_get_codecs(struct ast_rtp_instance *instance)
Get the codecs structure of an RTP instance.
#define MAX_TIMESTAMP_SKEW
int ast_tvzero(const struct timeval t)
Returns true if the argument is 0,0.
uint32_t ast_sockaddr_ipv4(const struct ast_sockaddr *addr)
Get an IPv4 address of an ast_sockaddr.
void ast_multicast_rtp_free_options(struct ast_multicast_rtp_options *mcast_options)
Free multicast RTP options.
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Socket address structure.
Asterisk internal frame definitions.
int ast_rtp_codecs_payload_code_tx(struct ast_rtp_codecs *codecs, int asterisk_format, const struct ast_format *format, int code)
Retrieve a tx mapped payload type based on whether it is an Asterisk format and the code...
unsigned int ast_rtp_codecs_get_framing(struct ast_rtp_codecs *codecs)
Get the framing used for a set of codecs.
struct ast_frame_subclass subclass
#define AST_APP_OPTIONS(holder, options...)
Declares an array of options for an application.
static int ast_sockaddr_isnull(const struct ast_sockaddr *addr)
Checks if the ast_sockaddr is null. "null" in this sense essentially means uninitialized, or having a 0 length.
#define ast_sockaddr_port(addr)
Get the port number of a socket address.
Configuration File Parser.
Structure for a multicast paging instance.
Handle unaligned data access.
General Asterisk PBX channel definitions.
int ast_rtp_engine_unregister(struct ast_rtp_engine *engine)
Unregister an RTP engine.
void ast_rtp_instance_set_data(struct ast_rtp_instance *instance, void *data)
Set the data portion of an RTP instance.
Access Control of various sorts.
Asterisk internal frame definitions.
#define ast_debug(level,...)
Log a DEBUG message.
#define LINKSYS_MCAST_STARTCMD
int ast_app_parse_options(const struct ast_app_option *options, struct ast_flags *flags, char **args, char *optstr)
Parses a string containing application options and sets flags/arguments.
Core PBX routines and definitions.
static int multicast_rtp_write(struct ast_rtp_instance *instance, struct ast_frame *frame)
Function called to broadcast some audio on a multicast instance.
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
#define AST_APP_OPTION_ARG(option, flagno, argno)
Declares an application option that accepts an argument.
static int multicast_rtp_activate(struct ast_rtp_instance *instance)
Function called to indicate that audio is now going to flow.
#define LINKSYS_MCAST_STOPCMD
static char * ast_sockaddr_stringify(const struct ast_sockaddr *addr)
Wrapper around ast_sockaddr_stringify_fmt() with default format.
struct ast_format * ast_multicast_rtp_options_get_format(struct ast_multicast_rtp_options *mcast_options)
Get format specified in multicast options.
union ast_frame::@224 data
#define ast_calloc(num, len)
A wrapper for calloc()
void * ast_rtp_instance_get_data(struct ast_rtp_instance *instance)
Get the data portion of an RTP instance.
static struct ast_frame * multicast_rtp_read(struct ast_rtp_instance *instance, int rtcp)
Function called to read from a multicast instance.
Module has failed to load, may be in an inconsistent state.
void ast_rtp_instance_get_local_address(struct ast_rtp_instance *instance, struct ast_sockaddr *address)
Get the local address that we are expecting RTP on.
Structure used to handle boolean flags.
struct ast_frame ast_null_frame
static int multicast_rtp_destroy(struct ast_rtp_instance *instance)
Function called to destroy a multicast instance.
Standard Command Line Interface.
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Data structure associated with a single frame of data.
static int multicast_rtp_new(struct ast_rtp_instance *instance, struct ast_sched_context *sched, struct ast_sockaddr *addr, void *data)
Function called to create a new multicast instance.
enum ast_frame_type frametype
struct ast_format * format
#define ASTERISK_GPL_KEY
The text the key() function should return.
Pluggable RTP Architecture.
Asterisk module definitions.
#define ast_rtp_instance_get_remote_address(instance, address)
Get the address of the remote endpoint that we are sending RTP to.
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
int ast_sockaddr_is_ipv6(const struct ast_sockaddr *addr)
Determine if this is an IPv6 address.