2009-04-02 17:20:52 +00:00
/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (C) 1999 - 2008, Digium, Inc.
*
* Joshua Colp <jcolp@digium.com>
*
* See http://www.asterisk.org for more information about
* the Asterisk project. Please do not directly contact
* any of the maintainers of this project for assistance;
* the project provides a web site, mailing lists and IRC
* channels for your use.
*
* This program is free software, distributed under the terms of
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree.
*/
/*! \file
*
* \brief Pluggable RTP Architecture
*
* \author Joshua Colp <jcolp@digium.com>
*/
#include "asterisk.h"
ASTERISK_FILE_VERSION ( __FILE__ , "$Revision$" )
#include <math.h>
#include "asterisk/channel.h"
#include "asterisk/frame.h"
#include "asterisk/module.h"
#include "asterisk/rtp_engine.h"
#include "asterisk/manager.h"
#include "asterisk/options.h"
#include "asterisk/astobj2.h"
#include "asterisk/pbx.h"
2009-06-19 15:41:24 +00:00
#include "asterisk/translate.h"
2010-07-08 22:08:07 +00:00
#include "asterisk/netsock2.h"
2011-02-22 23:04:49 +00:00
#include "asterisk/_private.h"
2009-04-02 17:20:52 +00:00
2010-06-08 05:29:08 +00:00
struct ast_srtp_res * res_srtp = NULL ;
struct ast_srtp_policy_res * res_srtp_policy = NULL ;
2009-04-02 17:20:52 +00:00
/*! Structure that represents an RTP session (instance) */
struct ast_rtp_instance {
/*! Engine that is handling this RTP instance */
struct ast_rtp_engine * engine ;
/*! Data unique to the RTP engine */
void * data ;
/*! RTP properties that have been set and their value */
int properties [ AST_RTP_PROPERTY_MAX ];
/*! Address that we are expecting RTP to come in to */
2010-07-08 22:08:07 +00:00
struct ast_sockaddr local_address ;
2009-04-02 17:20:52 +00:00
/*! Address that we are sending RTP to */
2010-07-08 22:08:07 +00:00
struct ast_sockaddr remote_address ;
2009-06-18 15:20:17 +00:00
/*! Alternate address that we are receiving RTP from */
2010-07-08 22:08:07 +00:00
struct ast_sockaddr alt_remote_address ;
2009-04-02 17:20:52 +00:00
/*! Instance that we are bridged to if doing remote or local bridging */
struct ast_rtp_instance * bridged ;
/*! Payload and packetization information */
struct ast_rtp_codecs codecs ;
/*! RTP timeout time (negative or zero means disabled, negative value means temporarily disabled) */
int timeout ;
/*! RTP timeout when on hold (negative or zero means disabled, negative value means temporarily disabled). */
int holdtimeout ;
/*! DTMF mode in use */
enum ast_rtp_dtmf_mode dtmf_mode ;
2009-08-16 19:27:39 +00:00
/*! Glue currently in use */
struct ast_rtp_glue * glue ;
/*! Channel associated with the instance */
struct ast_channel * chan ;
2010-06-08 05:29:08 +00:00
/*! SRTP info associated with the instance */
struct ast_srtp * srtp ;
2009-04-02 17:20:52 +00:00
};
/*! List of RTP engines that are currently registered */
static AST_RWLIST_HEAD_STATIC ( engines , ast_rtp_engine );
/*! List of RTP glues */
static AST_RWLIST_HEAD_STATIC ( glues , ast_rtp_glue );
/*! The following array defines the MIME Media type (and subtype) for each
of our codecs, or RTP-specific data type. */
2011-02-22 23:04:49 +00:00
static struct ast_rtp_mime_type {
2009-04-02 17:20:52 +00:00
struct ast_rtp_payload_type payload_type ;
char * type ;
char * subtype ;
unsigned int sample_rate ;
2011-02-22 23:04:49 +00:00
} ast_rtp_mime_types [ 128 ]; /* This will Likely not need to grow any time soon. */
static ast_rwlock_t mime_types_lock ;
static int mime_types_len = 0 ;
2009-04-02 17:20:52 +00:00
/*!
* \brief Mapping between Asterisk codecs and rtp payload types
*
* Static (i.e., well-known) RTP payload types for our "AST_FORMAT..."s:
* also, our own choices for dynamic payload types. This is our master
* table for transmission
*
* See http://www.iana.org/assignments/rtp-parameters for a list of
* assigned values
*/
2011-02-22 23:04:49 +00:00
static struct ast_rtp_payload_type static_RTP_PT [ AST_RTP_MAX_PT ];
static ast_rwlock_t static_RTP_PT_lock ;
2009-04-02 17:20:52 +00:00
int ast_rtp_engine_register2 ( struct ast_rtp_engine * engine , struct ast_module * module )
{
struct ast_rtp_engine * current_engine ;
/* Perform a sanity check on the engine structure to make sure it has the basics */
if ( ast_strlen_zero ( engine -> name ) || ! engine -> new || ! engine -> destroy || ! engine -> write || ! engine -> read ) {
ast_log ( LOG_WARNING , "RTP Engine '%s' failed sanity check so it was not registered. \n " , ! ast_strlen_zero ( engine -> name ) ? engine -> name : "Unknown" );
return - 1 ;
}
/* Link owner module to the RTP engine for reference counting purposes */
engine -> mod = module ;
AST_RWLIST_WRLOCK ( & engines );
/* Ensure that no two modules with the same name are registered at the same time */
AST_RWLIST_TRAVERSE ( & engines , current_engine , entry ) {
if ( ! strcmp ( current_engine -> name , engine -> name )) {
ast_log ( LOG_WARNING , "An RTP engine with the name '%s' has already been registered. \n " , engine -> name );
AST_RWLIST_UNLOCK ( & engines );
return - 1 ;
}
}
/* The engine survived our critique. Off to the list it goes to be used */
AST_RWLIST_INSERT_TAIL ( & engines , engine , entry );
AST_RWLIST_UNLOCK ( & engines );
ast_verb ( 2 , "Registered RTP engine '%s' \n " , engine -> name );
return 0 ;
}
int ast_rtp_engine_unregister ( struct ast_rtp_engine * engine )
{
struct ast_rtp_engine * current_engine = NULL ;
AST_RWLIST_WRLOCK ( & engines );
if (( current_engine = AST_RWLIST_REMOVE ( & engines , engine , entry ))) {
ast_verb ( 2 , "Unregistered RTP engine '%s' \n " , engine -> name );
}
AST_RWLIST_UNLOCK ( & engines );
return current_engine ? 0 : - 1 ;
}
int ast_rtp_glue_register2 ( struct ast_rtp_glue * glue , struct ast_module * module )
{
struct ast_rtp_glue * current_glue = NULL ;
if ( ast_strlen_zero ( glue -> type )) {
return - 1 ;
}
glue -> mod = module ;
AST_RWLIST_WRLOCK ( & glues );
AST_RWLIST_TRAVERSE ( & glues , current_glue , entry ) {
if ( ! strcasecmp ( current_glue -> type , glue -> type )) {
ast_log ( LOG_WARNING , "RTP glue with the name '%s' has already been registered. \n " , glue -> type );
AST_RWLIST_UNLOCK ( & glues );
return - 1 ;
}
}
AST_RWLIST_INSERT_TAIL ( & glues , glue , entry );
AST_RWLIST_UNLOCK ( & glues );
ast_verb ( 2 , "Registered RTP glue '%s' \n " , glue -> type );
return 0 ;
}
int ast_rtp_glue_unregister ( struct ast_rtp_glue * glue )
{
struct ast_rtp_glue * current_glue = NULL ;
AST_RWLIST_WRLOCK ( & glues );
if (( current_glue = AST_RWLIST_REMOVE ( & glues , glue , entry ))) {
ast_verb ( 2 , "Unregistered RTP glue '%s' \n " , glue -> type );
}
AST_RWLIST_UNLOCK ( & glues );
return current_glue ? 0 : - 1 ;
}
static void instance_destructor ( void * obj )
{
struct ast_rtp_instance * instance = obj ;
/* Pass us off to the engine to destroy */
if ( instance -> data && instance -> engine -> destroy ( instance )) {
ast_debug ( 1 , "Engine '%s' failed to destroy RTP instance '%p' \n " , instance -> engine -> name , instance );
return ;
}
2010-09-01 18:52:27 +00:00
if ( instance -> srtp ) {
res_srtp -> destroy ( instance -> srtp );
}
2009-04-02 17:20:52 +00:00
/* Drop our engine reference */
ast_module_unref ( instance -> engine -> mod );
ast_debug ( 1 , "Destroyed RTP instance '%p' \n " , instance );
}
int ast_rtp_instance_destroy ( struct ast_rtp_instance * instance )
{
ao2_ref ( instance , - 1 );
return 0 ;
}
2010-07-08 22:08:07 +00:00
struct ast_rtp_instance * ast_rtp_instance_new ( const char * engine_name ,
2010-12-20 17:15:54 +00:00
struct ast_sched_context * sched , const struct ast_sockaddr * sa ,
2010-07-08 22:08:07 +00:00
void * data )
2009-04-02 17:20:52 +00:00
{
2010-07-08 22:08:07 +00:00
struct ast_sockaddr address = {{ 0 ,}};
2009-04-02 17:20:52 +00:00
struct ast_rtp_instance * instance = NULL ;
struct ast_rtp_engine * engine = NULL ;
AST_RWLIST_RDLOCK ( & engines );
/* If an engine name was specified try to use it or otherwise use the first one registered */
if ( ! ast_strlen_zero ( engine_name )) {
AST_RWLIST_TRAVERSE ( & engines , engine , entry ) {
if ( ! strcmp ( engine -> name , engine_name )) {
break ;
}
}
} else {
engine = AST_RWLIST_FIRST ( & engines );
}
/* If no engine was actually found bail out now */
if ( ! engine ) {
ast_log ( LOG_ERROR , "No RTP engine was found. Do you have one loaded? \n " );
AST_RWLIST_UNLOCK ( & engines );
return NULL ;
}
/* Bump up the reference count before we return so the module can not be unloaded */
ast_module_ref ( engine -> mod );
AST_RWLIST_UNLOCK ( & engines );
/* Allocate a new RTP instance */
if ( ! ( instance = ao2_alloc ( sizeof ( * instance ), instance_destructor ))) {
ast_module_unref ( engine -> mod );
return NULL ;
}
instance -> engine = engine ;
2010-07-08 22:08:07 +00:00
ast_sockaddr_copy ( & instance -> local_address , sa );
ast_sockaddr_copy ( & address , sa );
2009-04-02 17:20:52 +00:00
ast_debug ( 1 , "Using engine '%s' for RTP instance '%p' \n " , engine -> name , instance );
/* And pass it off to the engine to setup */
2009-06-02 13:12:59 +00:00
if ( instance -> engine -> new ( instance , sched , & address , data )) {
2009-04-02 17:20:52 +00:00
ast_debug ( 1 , "Engine '%s' failed to setup RTP instance '%p' \n " , engine -> name , instance );
ao2_ref ( instance , - 1 );
return NULL ;
}
ast_debug ( 1 , "RTP instance '%p' is setup and ready to go \n " , instance );
return instance ;
}
void ast_rtp_instance_set_data ( struct ast_rtp_instance * instance , void * data )
{
instance -> data = data ;
}
void * ast_rtp_instance_get_data ( struct ast_rtp_instance * instance )
{
return instance -> data ;
}
int ast_rtp_instance_write ( struct ast_rtp_instance * instance , struct ast_frame * frame )
{
return instance -> engine -> write ( instance , frame );
}
struct ast_frame * ast_rtp_instance_read ( struct ast_rtp_instance * instance , int rtcp )
{
return instance -> engine -> read ( instance , rtcp );
}
2010-07-08 22:08:07 +00:00
int ast_rtp_instance_set_local_address ( struct ast_rtp_instance * instance ,
const struct ast_sockaddr * address )
2009-04-02 17:20:52 +00:00
{
2010-07-08 22:08:07 +00:00
ast_sockaddr_copy ( & instance -> local_address , address );
2009-04-02 17:20:52 +00:00
return 0 ;
}
2010-07-08 22:08:07 +00:00
int ast_rtp_instance_set_remote_address ( struct ast_rtp_instance * instance ,
const struct ast_sockaddr * address )
2009-04-02 17:20:52 +00:00
{
2010-07-08 22:08:07 +00:00
ast_sockaddr_copy ( & instance -> remote_address , address );
2009-04-02 17:20:52 +00:00
/* moo */
if ( instance -> engine -> remote_address_set ) {
2009-04-10 18:14:47 +00:00
instance -> engine -> remote_address_set ( instance , & instance -> remote_address );
2009-04-02 17:20:52 +00:00
}
return 0 ;
}
2010-07-08 22:08:07 +00:00
int ast_rtp_instance_set_alt_remote_address ( struct ast_rtp_instance * instance ,
const struct ast_sockaddr * address )
2009-06-18 15:20:17 +00:00
{
2010-07-08 22:08:07 +00:00
ast_sockaddr_copy ( & instance -> alt_remote_address , address );
2009-06-18 15:20:17 +00:00
/* oink */
if ( instance -> engine -> alt_remote_address_set ) {
instance -> engine -> alt_remote_address_set ( instance , & instance -> alt_remote_address );
}
return 0 ;
}
2010-11-03 18:43:18 +00:00
int ast_rtp_instance_get_and_cmp_local_address ( struct ast_rtp_instance * instance ,
2010-07-08 22:08:07 +00:00
struct ast_sockaddr * address )
2009-04-02 17:20:52 +00:00
{
2010-07-08 22:08:07 +00:00
if ( ast_sockaddr_cmp ( address , & instance -> local_address ) != 0 ) {
ast_sockaddr_copy ( address , & instance -> local_address );
2009-04-02 17:20:52 +00:00
return 1 ;
}
return 0 ;
}
2010-11-03 18:43:18 +00:00
void ast_rtp_instance_get_local_address ( struct ast_rtp_instance * instance ,
struct ast_sockaddr * address )
{
ast_sockaddr_copy ( address , & instance -> local_address );
}
int ast_rtp_instance_get_and_cmp_remote_address ( struct ast_rtp_instance * instance ,
2010-07-08 22:08:07 +00:00
struct ast_sockaddr * address )
2009-04-02 17:20:52 +00:00
{
2010-07-08 22:08:07 +00:00
if ( ast_sockaddr_cmp ( address , & instance -> remote_address ) != 0 ) {
ast_sockaddr_copy ( address , & instance -> remote_address );
2009-04-02 17:20:52 +00:00
return 1 ;
}
return 0 ;
}
2010-11-03 18:43:18 +00:00
void ast_rtp_instance_get_remote_address ( struct ast_rtp_instance * instance ,
struct ast_sockaddr * address )
{
ast_sockaddr_copy ( address , & instance -> remote_address );
}
2009-04-02 17:20:52 +00:00
void ast_rtp_instance_set_extended_prop ( struct ast_rtp_instance * instance , int property , void * value )
{
if ( instance -> engine -> extended_prop_set ) {
instance -> engine -> extended_prop_set ( instance , property , value );
}
}
void * ast_rtp_instance_get_extended_prop ( struct ast_rtp_instance * instance , int property )
{
if ( instance -> engine -> extended_prop_get ) {
return instance -> engine -> extended_prop_get ( instance , property );
}
return NULL ;
}
void ast_rtp_instance_set_prop ( struct ast_rtp_instance * instance , enum ast_rtp_property property , int value )
{
instance -> properties [ property ] = value ;
if ( instance -> engine -> prop_set ) {
instance -> engine -> prop_set ( instance , property , value );
}
}
int ast_rtp_instance_get_prop ( struct ast_rtp_instance * instance , enum ast_rtp_property property )
{
return instance -> properties [ property ];
}
struct ast_rtp_codecs * ast_rtp_instance_get_codecs ( struct ast_rtp_instance * instance )
{
return & instance -> codecs ;
}
void ast_rtp_codecs_payloads_clear ( struct ast_rtp_codecs * codecs , struct ast_rtp_instance * instance )
{
int i ;
for ( i = 0 ; i < AST_RTP_MAX_PT ; i ++ ) {
codecs -> payloads [ i ]. asterisk_format = 0 ;
2011-02-03 16:22:10 +00:00
codecs -> payloads [ i ]. rtp_code = 0 ;
ast_format_clear ( & codecs -> payloads [ i ]. format );
2009-04-02 17:20:52 +00:00
if ( instance && instance -> engine && instance -> engine -> payload_set ) {
2011-02-03 16:22:10 +00:00
instance -> engine -> payload_set ( instance , i , 0 , NULL , 0 );
2009-04-02 17:20:52 +00:00
}
}
}
void ast_rtp_codecs_payloads_default ( struct ast_rtp_codecs * codecs , struct ast_rtp_instance * instance )
{
int i ;
2011-02-22 23:04:49 +00:00
ast_rwlock_rdlock ( & static_RTP_PT_lock );
2009-04-02 17:20:52 +00:00
for ( i = 0 ; i < AST_RTP_MAX_PT ; i ++ ) {
2011-02-03 16:22:10 +00:00
if ( static_RTP_PT [ i ]. rtp_code || static_RTP_PT [ i ]. asterisk_format ) {
2009-04-02 17:20:52 +00:00
codecs -> payloads [ i ]. asterisk_format = static_RTP_PT [ i ]. asterisk_format ;
2011-02-03 16:22:10 +00:00
codecs -> payloads [ i ]. rtp_code = static_RTP_PT [ i ]. rtp_code ;
ast_format_copy ( & codecs -> payloads [ i ]. format , & static_RTP_PT [ i ]. format );
2009-04-02 17:20:52 +00:00
if ( instance && instance -> engine && instance -> engine -> payload_set ) {
2011-02-03 16:22:10 +00:00
instance -> engine -> payload_set ( instance , i , codecs -> payloads [ i ]. asterisk_format , & codecs -> payloads [ i ]. format , codecs -> payloads [ i ]. rtp_code );
2009-04-02 17:20:52 +00:00
}
}
}
2011-02-22 23:04:49 +00:00
ast_rwlock_unlock ( & static_RTP_PT_lock );
2009-04-02 17:20:52 +00:00
}
void ast_rtp_codecs_payloads_copy ( struct ast_rtp_codecs * src , struct ast_rtp_codecs * dest , struct ast_rtp_instance * instance )
{
int i ;
for ( i = 0 ; i < AST_RTP_MAX_PT ; i ++ ) {
2011-02-03 16:22:10 +00:00
if ( src -> payloads [ i ]. rtp_code || src -> payloads [ i ]. asterisk_format ) {
2009-04-02 17:20:52 +00:00
ast_debug ( 2 , "Copying payload %d from %p to %p \n " , i , src , dest );
dest -> payloads [ i ]. asterisk_format = src -> payloads [ i ]. asterisk_format ;
2011-02-03 16:22:10 +00:00
dest -> payloads [ i ]. rtp_code = src -> payloads [ i ]. rtp_code ;
ast_format_copy ( & dest -> payloads [ i ]. format , & src -> payloads [ i ]. format );
2009-04-02 17:20:52 +00:00
if ( instance && instance -> engine && instance -> engine -> payload_set ) {
2011-02-03 16:22:10 +00:00
instance -> engine -> payload_set ( instance , i , dest -> payloads [ i ]. asterisk_format , & dest -> payloads [ i ]. format , dest -> payloads [ i ]. rtp_code );
2009-04-02 17:20:52 +00:00
}
}
}
}
void ast_rtp_codecs_payloads_set_m_type ( struct ast_rtp_codecs * codecs , struct ast_rtp_instance * instance , int payload )
{
2011-02-22 23:04:49 +00:00
ast_rwlock_rdlock ( & static_RTP_PT_lock );
2011-02-03 16:22:10 +00:00
if ( payload < 0 || payload >= AST_RTP_MAX_PT || ( ! static_RTP_PT [ payload ]. rtp_code && ! static_RTP_PT [ payload ]. asterisk_format )) {
2011-02-22 23:04:49 +00:00
ast_rwlock_unlock ( & static_RTP_PT_lock );
2009-04-02 17:20:52 +00:00
return ;
}
codecs -> payloads [ payload ]. asterisk_format = static_RTP_PT [ payload ]. asterisk_format ;
2011-02-03 16:22:10 +00:00
codecs -> payloads [ payload ]. rtp_code = static_RTP_PT [ payload ]. rtp_code ;
ast_format_copy ( & codecs -> payloads [ payload ]. format , & static_RTP_PT [ payload ]. format );
2009-04-02 17:20:52 +00:00
ast_debug ( 1 , "Setting payload %d based on m type on %p \n " , payload , codecs );
if ( instance && instance -> engine && instance -> engine -> payload_set ) {
2011-02-03 16:22:10 +00:00
instance -> engine -> payload_set ( instance , payload , codecs -> payloads [ payload ]. asterisk_format , & codecs -> payloads [ payload ]. format , codecs -> payloads [ payload ]. rtp_code );
2009-04-02 17:20:52 +00:00
}
2011-02-22 23:04:49 +00:00
ast_rwlock_unlock ( & static_RTP_PT_lock );
2009-04-02 17:20:52 +00:00
}
int ast_rtp_codecs_payloads_set_rtpmap_type_rate ( struct ast_rtp_codecs * codecs , struct ast_rtp_instance * instance , int pt ,
char * mimetype , char * mimesubtype ,
enum ast_rtp_options options ,
unsigned int sample_rate )
{
unsigned int i ;
int found = 0 ;
2009-10-01 23:59:15 +00:00
if ( pt < 0 || pt >= AST_RTP_MAX_PT )
2009-04-02 17:20:52 +00:00
return - 1 ; /* bogus payload type */
2011-02-22 23:04:49 +00:00
ast_rwlock_rdlock ( & mime_types_lock );
for ( i = 0 ; i < mime_types_len ; ++ i ) {
2009-04-02 17:20:52 +00:00
const struct ast_rtp_mime_type * t = & ast_rtp_mime_types [ i ];
if ( strcasecmp ( mimesubtype , t -> subtype )) {
continue ;
}
if ( strcasecmp ( mimetype , t -> type )) {
continue ;
}
/* if both sample rates have been supplied, and they don't match,
2011-04-18 13:42:51 +00:00
* then this not a match; if one has not been supplied, then the
* rates are not compared */
2009-04-02 17:20:52 +00:00
if ( sample_rate && t -> sample_rate &&
( sample_rate != t -> sample_rate )) {
continue ;
}
found = 1 ;
codecs -> payloads [ pt ] = t -> payload_type ;
2011-02-03 16:22:10 +00:00
if (( t -> payload_type . format . id == AST_FORMAT_G726 ) && t -> payload_type . asterisk_format && ( options & AST_RTP_OPT_G726_NONSTANDARD )) {
ast_format_set ( & codecs -> payloads [ pt ]. format , AST_FORMAT_G726_AAL2 , 0 );
2009-04-02 17:20:52 +00:00
}
if ( instance && instance -> engine && instance -> engine -> payload_set ) {
2011-02-03 16:22:10 +00:00
instance -> engine -> payload_set ( instance , pt , codecs -> payloads [ i ]. asterisk_format , & codecs -> payloads [ i ]. format , codecs -> payloads [ i ]. rtp_code );
2009-04-02 17:20:52 +00:00
}
break ;
}
2011-02-22 23:04:49 +00:00
ast_rwlock_unlock ( & mime_types_lock );
2009-04-02 17:20:52 +00:00
return ( found ? 0 : - 2 );
}
int ast_rtp_codecs_payloads_set_rtpmap_type ( struct ast_rtp_codecs * codecs , struct ast_rtp_instance * instance , int payload , char * mimetype , char * mimesubtype , enum ast_rtp_options options )
{
return ast_rtp_codecs_payloads_set_rtpmap_type_rate ( codecs , instance , payload , mimetype , mimesubtype , options , 0 );
}
void ast_rtp_codecs_payloads_unset ( struct ast_rtp_codecs * codecs , struct ast_rtp_instance * instance , int payload )
{
2009-10-01 23:59:15 +00:00
if ( payload < 0 || payload >= AST_RTP_MAX_PT ) {
2009-04-02 17:20:52 +00:00
return ;
}
ast_debug ( 2 , "Unsetting payload %d on %p \n " , payload , codecs );
codecs -> payloads [ payload ]. asterisk_format = 0 ;
2011-02-03 16:22:10 +00:00
codecs -> payloads [ payload ]. rtp_code = 0 ;
ast_format_clear ( & codecs -> payloads [ payload ]. format );
2009-04-02 17:20:52 +00:00
if ( instance && instance -> engine && instance -> engine -> payload_set ) {
2011-02-03 16:22:10 +00:00
instance -> engine -> payload_set ( instance , payload , 0 , NULL , 0 );
2009-04-02 17:20:52 +00:00
}
}
struct ast_rtp_payload_type ast_rtp_codecs_payload_lookup ( struct ast_rtp_codecs * codecs , int payload )
{
struct ast_rtp_payload_type result = { . asterisk_format = 0 , };
2009-10-01 23:59:15 +00:00
if ( payload < 0 || payload >= AST_RTP_MAX_PT ) {
2009-04-02 17:20:52 +00:00
return result ;
}
result . asterisk_format = codecs -> payloads [ payload ]. asterisk_format ;
2011-02-03 16:22:10 +00:00
result . rtp_code = codecs -> payloads [ payload ]. rtp_code ;
ast_format_copy ( & result . format , & codecs -> payloads [ payload ]. format );
2009-04-02 17:20:52 +00:00
2011-02-03 16:22:10 +00:00
if ( ! result . rtp_code && ! result . asterisk_format ) {
2011-02-22 23:04:49 +00:00
ast_rwlock_rdlock ( & static_RTP_PT_lock );
2009-04-02 17:20:52 +00:00
result = static_RTP_PT [ payload ];
2011-02-22 23:04:49 +00:00
ast_rwlock_unlock ( & static_RTP_PT_lock );
2009-04-02 17:20:52 +00:00
}
return result ;
}
2011-02-22 23:04:49 +00:00
struct ast_format * ast_rtp_codecs_get_payload_format ( struct ast_rtp_codecs * codecs , int payload )
{
if ( payload < 0 || payload >= AST_RTP_MAX_PT ) {
return NULL ;
}
if ( ! codecs -> payloads [ payload ]. asterisk_format ) {
return NULL ;
}
return & codecs -> payloads [ payload ]. format ;
}
2011-02-03 16:22:10 +00:00
void ast_rtp_codecs_payload_formats ( struct ast_rtp_codecs * codecs , struct ast_format_cap * astformats , int * nonastformats )
2009-04-02 17:20:52 +00:00
{
int i ;
2011-02-03 16:22:10 +00:00
ast_format_cap_remove_all ( astformats );
* nonastformats = 0 ;
2009-04-02 17:20:52 +00:00
for ( i = 0 ; i < AST_RTP_MAX_PT ; i ++ ) {
2011-02-03 16:22:10 +00:00
if ( codecs -> payloads [ i ]. rtp_code || codecs -> payloads [ i ]. asterisk_format ) {
2009-04-02 17:20:52 +00:00
ast_debug ( 1 , "Incorporating payload %d on %p \n " , i , codecs );
}
if ( codecs -> payloads [ i ]. asterisk_format ) {
2011-02-03 16:22:10 +00:00
ast_format_cap_add ( astformats , & codecs -> payloads [ i ]. format );
2009-04-02 17:20:52 +00:00
} else {
2011-02-03 16:22:10 +00:00
* nonastformats |= codecs -> payloads [ i ]. rtp_code ;
2009-04-02 17:20:52 +00:00
}
}
}
2011-02-03 16:22:10 +00:00
int ast_rtp_codecs_payload_code ( struct ast_rtp_codecs * codecs , int asterisk_format , const struct ast_format * format , int code )
2009-04-02 17:20:52 +00:00
{
int i ;
2011-02-22 23:04:49 +00:00
int res = - 1 ;
2009-04-02 17:20:52 +00:00
for ( i = 0 ; i < AST_RTP_MAX_PT ; i ++ ) {
2011-02-03 16:22:10 +00:00
if ( codecs -> payloads [ i ]. asterisk_format && asterisk_format && format &&
( ast_format_cmp ( format , & codecs -> payloads [ i ]. format ) != AST_FORMAT_CMP_NOT_EQUAL )) {
return i ;
} else if ( ! codecs -> payloads [ i ]. asterisk_format && ! asterisk_format &&
( codecs -> payloads [ i ]. rtp_code == code )) {
2009-04-02 17:20:52 +00:00
return i ;
}
}
2011-02-22 23:04:49 +00:00
ast_rwlock_rdlock ( & static_RTP_PT_lock );
2009-04-02 17:20:52 +00:00
for ( i = 0 ; i < AST_RTP_MAX_PT ; i ++ ) {
2011-02-03 16:22:10 +00:00
if ( static_RTP_PT [ i ]. asterisk_format && asterisk_format && format &&
( ast_format_cmp ( format , & static_RTP_PT [ i ]. format ) != AST_FORMAT_CMP_NOT_EQUAL )) {
2011-02-22 23:04:49 +00:00
res = i ;
break ;
2011-02-03 16:22:10 +00:00
} else if ( ! static_RTP_PT [ i ]. asterisk_format && ! asterisk_format &&
( static_RTP_PT [ i ]. rtp_code == code )) {
2011-02-22 23:04:49 +00:00
res = i ;
break ;
2009-04-02 17:20:52 +00:00
}
}
2011-02-22 23:04:49 +00:00
ast_rwlock_unlock ( & static_RTP_PT_lock );
2009-04-02 17:20:52 +00:00
2011-02-22 23:04:49 +00:00
return res ;
2009-04-02 17:20:52 +00:00
}
2011-02-03 16:22:10 +00:00
const char * ast_rtp_lookup_mime_subtype2 ( const int asterisk_format , struct ast_format * format , int code , enum ast_rtp_options options )
2009-04-02 17:20:52 +00:00
{
int i ;
2011-02-22 23:04:49 +00:00
const char * res = "" ;
2009-04-02 17:20:52 +00:00
2011-02-22 23:04:49 +00:00
ast_rwlock_rdlock ( & mime_types_lock );
for ( i = 0 ; i < mime_types_len ; i ++ ) {
2011-02-03 16:22:10 +00:00
if ( ast_rtp_mime_types [ i ]. payload_type . asterisk_format && asterisk_format && format &&
( ast_format_cmp ( format , & ast_rtp_mime_types [ i ]. payload_type . format ) != AST_FORMAT_CMP_NOT_EQUAL )) {
if (( format -> id == AST_FORMAT_G726_AAL2 ) && ( options & AST_RTP_OPT_G726_NONSTANDARD )) {
2011-02-22 23:04:49 +00:00
res = "G726-32" ;
break ;
2009-04-02 17:20:52 +00:00
} else {
2011-02-22 23:04:49 +00:00
res = ast_rtp_mime_types [ i ]. subtype ;
break ;
2009-04-02 17:20:52 +00:00
}
2011-02-03 16:22:10 +00:00
} else if ( ! ast_rtp_mime_types [ i ]. payload_type . asterisk_format && ! asterisk_format &&
ast_rtp_mime_types [ i ]. payload_type . rtp_code == code ) {
2011-02-22 23:04:49 +00:00
res = ast_rtp_mime_types [ i ]. subtype ;
break ;
2009-04-02 17:20:52 +00:00
}
}
2011-02-22 23:04:49 +00:00
ast_rwlock_unlock ( & mime_types_lock );
2009-04-02 17:20:52 +00:00
2011-02-22 23:04:49 +00:00
return res ;
2009-04-02 17:20:52 +00:00
}
2011-02-03 16:22:10 +00:00
unsigned int ast_rtp_lookup_sample_rate2 ( int asterisk_format , struct ast_format * format , int code )
2009-04-02 17:20:52 +00:00
{
unsigned int i ;
2011-02-22 23:04:49 +00:00
unsigned int res = 0 ;
2009-04-02 17:20:52 +00:00
2011-02-22 23:04:49 +00:00
ast_rwlock_rdlock ( & mime_types_lock );
for ( i = 0 ; i < mime_types_len ; ++ i ) {
2011-02-03 16:22:10 +00:00
if ( ast_rtp_mime_types [ i ]. payload_type . asterisk_format && asterisk_format && format &&
( ast_format_cmp ( format , & ast_rtp_mime_types [ i ]. payload_type . format ) != AST_FORMAT_CMP_NOT_EQUAL )) {
2011-02-22 23:04:49 +00:00
res = ast_rtp_mime_types [ i ]. sample_rate ;
break ;
2011-02-03 16:22:10 +00:00
} else if ( ! ast_rtp_mime_types [ i ]. payload_type . asterisk_format && ! asterisk_format &&
ast_rtp_mime_types [ i ]. payload_type . rtp_code == code ) {
2011-02-22 23:04:49 +00:00
res = ast_rtp_mime_types [ i ]. sample_rate ;
break ;
2009-04-02 17:20:52 +00:00
}
}
2011-02-22 23:04:49 +00:00
ast_rwlock_unlock ( & mime_types_lock );
2009-04-02 17:20:52 +00:00
2011-02-22 23:04:49 +00:00
return res ;
2009-04-02 17:20:52 +00:00
}
2011-02-03 16:22:10 +00:00
char * ast_rtp_lookup_mime_multiple2 ( struct ast_str * buf , struct ast_format_cap * ast_format_capability , int rtp_capability , const int asterisk_format , enum ast_rtp_options options )
2009-04-02 17:20:52 +00:00
{
2009-11-04 14:05:12 +00:00
int found = 0 ;
2011-02-03 16:22:10 +00:00
const char * name ;
2009-04-02 17:20:52 +00:00
if ( ! buf ) {
return NULL ;
}
2011-02-03 16:22:10 +00:00
if ( asterisk_format ) {
struct ast_format tmp_fmt ;
ast_format_cap_iter_start ( ast_format_capability );
while ( ! ast_format_cap_iter_next ( ast_format_capability , & tmp_fmt )) {
name = ast_rtp_lookup_mime_subtype2 ( asterisk_format , & tmp_fmt , 0 , options );
2009-04-02 17:20:52 +00:00
ast_str_append ( & buf , 0 , "%s|" , name );
found = 1 ;
}
2011-02-03 16:22:10 +00:00
ast_format_cap_iter_end ( ast_format_capability );
} else {
int x ;
ast_str_append ( & buf , 0 , "0x%x (" , ( unsigned int ) rtp_capability );
for ( x = 1 ; x < AST_RTP_MAX ; x <<= 1 ) {
if ( rtp_capability & x ) {
name = ast_rtp_lookup_mime_subtype2 ( asterisk_format , NULL , x , options );
ast_str_append ( & buf , 0 , "%s|" , name );
found = 1 ;
}
}
2009-04-02 17:20:52 +00:00
}
ast_str_append ( & buf , 0 , "%s" , found ? ")" : "nothing)" );
return ast_str_buffer ( buf );
}
void ast_rtp_codecs_packetization_set ( struct ast_rtp_codecs * codecs , struct ast_rtp_instance * instance , struct ast_codec_pref * prefs )
{
codecs -> pref = * prefs ;
if ( instance && instance -> engine -> packetization_set ) {
instance -> engine -> packetization_set ( instance , & instance -> codecs . pref );
}
}
int ast_rtp_instance_dtmf_begin ( struct ast_rtp_instance * instance , char digit )
{
return instance -> engine -> dtmf_begin ? instance -> engine -> dtmf_begin ( instance , digit ) : - 1 ;
}
int ast_rtp_instance_dtmf_end ( struct ast_rtp_instance * instance , char digit )
{
return instance -> engine -> dtmf_end ? instance -> engine -> dtmf_end ( instance , digit ) : - 1 ;
}
2010-10-02 02:46:43 +00:00
int ast_rtp_instance_dtmf_end_with_duration ( struct ast_rtp_instance * instance , char digit , unsigned int duration )
{
return instance -> engine -> dtmf_end_with_duration ? instance -> engine -> dtmf_end_with_duration ( instance , digit , duration ) : - 1 ;
}
2009-04-02 17:20:52 +00:00
int ast_rtp_instance_dtmf_mode_set ( struct ast_rtp_instance * instance , enum ast_rtp_dtmf_mode dtmf_mode )
{
if ( ! instance -> engine -> dtmf_mode_set || instance -> engine -> dtmf_mode_set ( instance , dtmf_mode )) {
return - 1 ;
}
instance -> dtmf_mode = dtmf_mode ;
return 0 ;
}
enum ast_rtp_dtmf_mode ast_rtp_instance_dtmf_mode_get ( struct ast_rtp_instance * instance )
{
return instance -> dtmf_mode ;
}
2010-03-12 22:04:51 +00:00
void ast_rtp_instance_update_source ( struct ast_rtp_instance * instance )
2009-04-02 17:20:52 +00:00
{
2010-03-12 22:04:51 +00:00
if ( instance -> engine -> update_source ) {
instance -> engine -> update_source ( instance );
}
}
void ast_rtp_instance_change_source ( struct ast_rtp_instance * instance )
{
if ( instance -> engine -> change_source ) {
instance -> engine -> change_source ( instance );
2009-04-02 17:20:52 +00:00
}
}
int ast_rtp_instance_set_qos ( struct ast_rtp_instance * instance , int tos , int cos , const char * desc )
{
return instance -> engine -> qos ? instance -> engine -> qos ( instance , tos , cos , desc ) : - 1 ;
}
void ast_rtp_instance_stop ( struct ast_rtp_instance * instance )
{
if ( instance -> engine -> stop ) {
instance -> engine -> stop ( instance );
}
}
int ast_rtp_instance_fd ( struct ast_rtp_instance * instance , int rtcp )
{
return instance -> engine -> fd ? instance -> engine -> fd ( instance , rtcp ) : - 1 ;
}
struct ast_rtp_glue * ast_rtp_instance_get_glue ( const char * type )
{
struct ast_rtp_glue * glue = NULL ;
AST_RWLIST_RDLOCK ( & glues );
AST_RWLIST_TRAVERSE ( & glues , glue , entry ) {
if ( ! strcasecmp ( glue -> type , type )) {
break ;
}
}
AST_RWLIST_UNLOCK ( & glues );
return glue ;
}
static enum ast_bridge_result local_bridge_loop ( struct ast_channel * c0 , struct ast_channel * c1 , struct ast_rtp_instance * instance0 , struct ast_rtp_instance * instance1 , int timeoutms , int flags , struct ast_frame ** fo , struct ast_channel ** rc , void * pvt0 , void * pvt1 )
{
enum ast_bridge_result res = AST_BRIDGE_FAILED ;
struct ast_channel * who = NULL , * other = NULL , * cs [ 3 ] = { NULL , };
struct ast_frame * fr = NULL ;
/* Start locally bridging both instances */
if ( instance0 -> engine -> local_bridge && instance0 -> engine -> local_bridge ( instance0 , instance1 )) {
ast_debug ( 1 , "Failed to locally bridge %s to %s, backing out. \n " , c0 -> name , c1 -> name );
ast_channel_unlock ( c0 );
ast_channel_unlock ( c1 );
return AST_BRIDGE_FAILED_NOWARN ;
}
if ( instance1 -> engine -> local_bridge && instance1 -> engine -> local_bridge ( instance1 , instance0 )) {
ast_debug ( 1 , "Failed to locally bridge %s to %s, backing out. \n " , c1 -> name , c0 -> name );
if ( instance0 -> engine -> local_bridge ) {
instance0 -> engine -> local_bridge ( instance0 , NULL );
}
ast_channel_unlock ( c0 );
ast_channel_unlock ( c1 );
return AST_BRIDGE_FAILED_NOWARN ;
}
ast_channel_unlock ( c0 );
ast_channel_unlock ( c1 );
instance0 -> bridged = instance1 ;
instance1 -> bridged = instance0 ;
ast_poll_channel_add ( c0 , c1 );
/* Hop into a loop waiting for a frame from either channel */
cs [ 0 ] = c0 ;
cs [ 1 ] = c1 ;
cs [ 2 ] = NULL ;
for (;;) {
/* If the underlying formats have changed force this bridge to break */
2011-02-03 16:22:10 +00:00
if (( ast_format_cmp ( & c0 -> rawreadformat , & c1 -> rawwriteformat ) == AST_FORMAT_CMP_NOT_EQUAL ) ||
( ast_format_cmp ( & c1 -> rawreadformat , & c0 -> rawwriteformat ) == AST_FORMAT_CMP_NOT_EQUAL )) {
2009-04-02 17:20:52 +00:00
ast_debug ( 1 , "rtp-engine-local-bridge: Oooh, formats changed, backing out \n " );
res = AST_BRIDGE_FAILED_NOWARN ;
break ;
}
/* Check if anything changed */
if (( c0 -> tech_pvt != pvt0 ) ||
( c1 -> tech_pvt != pvt1 ) ||
( c0 -> masq || c0 -> masqr || c1 -> masq || c1 -> masqr ) ||
( c0 -> monitor || c0 -> audiohooks || c1 -> monitor || c1 -> audiohooks )) {
ast_debug ( 1 , "rtp-engine-local-bridge: Oooh, something is weird, backing out \n " );
/* If a masquerade needs to happen we have to try to read in a frame so that it actually happens. Without this we risk being called again and going into a loop */
if (( c0 -> masq || c0 -> masqr ) && ( fr = ast_read ( c0 ))) {
ast_frfree ( fr );
}
if (( c1 -> masq || c1 -> masqr ) && ( fr = ast_read ( c1 ))) {
ast_frfree ( fr );
}
res = AST_BRIDGE_RETRY ;
break ;
}
/* Wait on a channel to feed us a frame */
if ( ! ( who = ast_waitfor_n ( cs , 2 , & timeoutms ))) {
if ( ! timeoutms ) {
res = AST_BRIDGE_RETRY ;
break ;
}
ast_debug ( 2 , "rtp-engine-local-bridge: Ooh, empty read... \n " );
if ( ast_check_hangup ( c0 ) || ast_check_hangup ( c1 )) {
break ;
}
continue ;
}
/* Read in frame from channel */
fr = ast_read ( who );
other = ( who == c0 ) ? c1 : c0 ;
/* Depending on the frame we may need to break out of our bridge */
if ( ! fr || (( fr -> frametype == AST_FRAME_DTMF_BEGIN || fr -> frametype == AST_FRAME_DTMF_END ) &&
(( who == c0 ) && ( flags & AST_BRIDGE_DTMF_CHANNEL_0 )) |
(( who == c1 ) && ( flags & AST_BRIDGE_DTMF_CHANNEL_1 )))) {
/* Record received frame and who */
* fo = fr ;
* rc = who ;
ast_debug ( 1 , "rtp-engine-local-bridge: Ooh, got a %s \n " , fr ? "digit" : "hangup" );
res = AST_BRIDGE_COMPLETE ;
break ;
} else if (( fr -> frametype == AST_FRAME_CONTROL ) && ! ( flags & AST_BRIDGE_IGNORE_SIGS )) {
2009-11-04 14:05:12 +00:00
if (( fr -> subclass . integer == AST_CONTROL_HOLD ) ||
( fr -> subclass . integer == AST_CONTROL_UNHOLD ) ||
( fr -> subclass . integer == AST_CONTROL_VIDUPDATE ) ||
( fr -> subclass . integer == AST_CONTROL_SRCUPDATE ) ||
( fr -> subclass . integer == AST_CONTROL_T38_PARAMETERS )) {
2009-04-02 17:20:52 +00:00
/* If we are going on hold, then break callback mode and P2P bridging */
2009-11-04 14:05:12 +00:00
if ( fr -> subclass . integer == AST_CONTROL_HOLD ) {
2009-04-02 17:20:52 +00:00
if ( instance0 -> engine -> local_bridge ) {
instance0 -> engine -> local_bridge ( instance0 , NULL );
}
if ( instance1 -> engine -> local_bridge ) {
instance1 -> engine -> local_bridge ( instance1 , NULL );
}
instance0 -> bridged = NULL ;
instance1 -> bridged = NULL ;
2009-11-04 14:05:12 +00:00
} else if ( fr -> subclass . integer == AST_CONTROL_UNHOLD ) {
2009-04-02 17:20:52 +00:00
if ( instance0 -> engine -> local_bridge ) {
instance0 -> engine -> local_bridge ( instance0 , instance1 );
}
if ( instance1 -> engine -> local_bridge ) {
instance1 -> engine -> local_bridge ( instance1 , instance0 );
}
instance0 -> bridged = instance1 ;
instance1 -> bridged = instance0 ;
}
2009-11-04 14:05:12 +00:00
ast_indicate_data ( other , fr -> subclass . integer , fr -> data . ptr , fr -> datalen );
2009-04-02 17:20:52 +00:00
ast_frfree ( fr );
2010-05-17 15:36:31 +00:00
} else if ( fr -> subclass . integer == AST_CONTROL_CONNECTED_LINE ) {
if ( ast_channel_connected_line_macro ( who , other , fr , other == c0 , 1 )) {
ast_indicate_data ( other , fr -> subclass . integer , fr -> data . ptr , fr -> datalen );
}
ast_frfree ( fr );
} else if ( fr -> subclass . integer == AST_CONTROL_REDIRECTING ) {
if ( ast_channel_redirecting_macro ( who , other , fr , other == c0 , 1 )) {
ast_indicate_data ( other , fr -> subclass . integer , fr -> data . ptr , fr -> datalen );
}
ast_frfree ( fr );
2009-04-02 17:20:52 +00:00
} else {
* fo = fr ;
* rc = who ;
2009-11-04 14:05:12 +00:00
ast_debug ( 1 , "rtp-engine-local-bridge: Got a FRAME_CONTROL (%d) frame on channel %s \n " , fr -> subclass . integer , who -> name );
2009-04-02 17:20:52 +00:00
res = AST_BRIDGE_COMPLETE ;
break ;
}
} else {
if (( fr -> frametype == AST_FRAME_DTMF_BEGIN ) ||
( fr -> frametype == AST_FRAME_DTMF_END ) ||
( fr -> frametype == AST_FRAME_VOICE ) ||
( fr -> frametype == AST_FRAME_VIDEO ) ||
( fr -> frametype == AST_FRAME_IMAGE ) ||
( fr -> frametype == AST_FRAME_HTML ) ||
( fr -> frametype == AST_FRAME_MODEM ) ||
( fr -> frametype == AST_FRAME_TEXT )) {
ast_write ( other , fr );
}
ast_frfree ( fr );
}
/* Swap priority */
cs [ 2 ] = cs [ 0 ];
cs [ 0 ] = cs [ 1 ];
cs [ 1 ] = cs [ 2 ];
}
/* Stop locally bridging both instances */
if ( instance0 -> engine -> local_bridge ) {
instance0 -> engine -> local_bridge ( instance0 , NULL );
}
if ( instance1 -> engine -> local_bridge ) {
instance1 -> engine -> local_bridge ( instance1 , NULL );
}
instance0 -> bridged = NULL ;
instance1 -> bridged = NULL ;
ast_poll_channel_del ( c0 , c1 );
return res ;
}
2011-02-03 16:22:10 +00:00
static enum ast_bridge_result remote_bridge_loop ( struct ast_channel * c0 ,
struct ast_channel * c1 ,
struct ast_rtp_instance * instance0 ,
struct ast_rtp_instance * instance1 ,
struct ast_rtp_instance * vinstance0 ,
struct ast_rtp_instance * vinstance1 ,
struct ast_rtp_instance * tinstance0 ,
struct ast_rtp_instance * tinstance1 ,
struct ast_rtp_glue * glue0 ,
struct ast_rtp_glue * glue1 ,
struct ast_format_cap * cap0 ,
struct ast_format_cap * cap1 ,
int timeoutms ,
int flags ,
struct ast_frame ** fo ,
struct ast_channel ** rc ,
void * pvt0 ,
void * pvt1 )
2009-04-02 17:20:52 +00:00
{
enum ast_bridge_result res = AST_BRIDGE_FAILED ;
struct ast_channel * who = NULL , * other = NULL , * cs [ 3 ] = { NULL , };
2011-02-03 16:22:10 +00:00
struct ast_format_cap * oldcap0 = ast_format_cap_dup ( cap0 );
struct ast_format_cap * oldcap1 = ast_format_cap_dup ( cap1 );
2010-07-08 22:08:07 +00:00
struct ast_sockaddr ac1 = {{ 0 ,}}, vac1 = {{ 0 ,}}, tac1 = {{ 0 ,}}, ac0 = {{ 0 ,}}, vac0 = {{ 0 ,}}, tac0 = {{ 0 ,}};
struct ast_sockaddr t1 = {{ 0 ,}}, vt1 = {{ 0 ,}}, tt1 = {{ 0 ,}}, t0 = {{ 0 ,}}, vt0 = {{ 0 ,}}, tt0 = {{ 0 ,}};
2009-04-02 17:20:52 +00:00
struct ast_frame * fr = NULL ;
2011-02-03 16:22:10 +00:00
if ( ! oldcap0 || ! oldcap1 ) {
ast_channel_unlock ( c0 );
ast_channel_unlock ( c1 );
goto remote_bridge_cleanup ;
}
2009-04-02 17:20:52 +00:00
/* Test the first channel */
2011-02-03 16:22:10 +00:00
if ( ! ( glue0 -> update_peer ( c0 , instance1 , vinstance1 , tinstance1 , cap1 , 0 ))) {
2009-04-02 17:20:52 +00:00
ast_rtp_instance_get_remote_address ( instance1 , & ac1 );
if ( vinstance1 ) {
ast_rtp_instance_get_remote_address ( vinstance1 , & vac1 );
}
if ( tinstance1 ) {
ast_rtp_instance_get_remote_address ( tinstance1 , & tac1 );
}
} else {
ast_log ( LOG_WARNING , "Channel '%s' failed to talk to '%s' \n " , c0 -> name , c1 -> name );
}
/* Test the second channel */
2011-02-03 16:22:10 +00:00
if ( ! ( glue1 -> update_peer ( c1 , instance0 , vinstance0 , tinstance0 , cap0 , 0 ))) {
2009-04-02 17:20:52 +00:00
ast_rtp_instance_get_remote_address ( instance0 , & ac0 );
if ( vinstance0 ) {
ast_rtp_instance_get_remote_address ( instance0 , & vac0 );
}
if ( tinstance0 ) {
ast_rtp_instance_get_remote_address ( instance0 , & tac0 );
}
} else {
ast_log ( LOG_WARNING , "Channel '%s' failed to talk to '%s' \n " , c1 -> name , c0 -> name );
}
ast_channel_unlock ( c0 );
ast_channel_unlock ( c1 );
instance0 -> bridged = instance1 ;
instance1 -> bridged = instance0 ;
ast_poll_channel_add ( c0 , c1 );
/* Go into a loop handling any stray frames that may come in */
cs [ 0 ] = c0 ;
cs [ 1 ] = c1 ;
cs [ 2 ] = NULL ;
for (;;) {
/* Check if anything changed */
if (( c0 -> tech_pvt != pvt0 ) ||
( c1 -> tech_pvt != pvt1 ) ||
( c0 -> masq || c0 -> masqr || c1 -> masq || c1 -> masqr ) ||
( c0 -> monitor || c0 -> audiohooks || c1 -> monitor || c1 -> audiohooks )) {
ast_debug ( 1 , "Oooh, something is weird, backing out \n " );
res = AST_BRIDGE_RETRY ;
break ;
}
/* Check if they have changed their address */
ast_rtp_instance_get_remote_address ( instance1 , & t1 );
if ( vinstance1 ) {
ast_rtp_instance_get_remote_address ( vinstance1 , & vt1 );
}
if ( tinstance1 ) {
ast_rtp_instance_get_remote_address ( tinstance1 , & tt1 );
}
if ( glue1 -> get_codec ) {
2011-02-03 16:22:10 +00:00
ast_format_cap_remove_all ( cap1 );
glue1 -> get_codec ( c1 , cap1 );
2009-04-02 17:20:52 +00:00
}
ast_rtp_instance_get_remote_address ( instance0 , & t0 );
if ( vinstance0 ) {
ast_rtp_instance_get_remote_address ( vinstance0 , & vt0 );
}
if ( tinstance0 ) {
ast_rtp_instance_get_remote_address ( tinstance0 , & tt0 );
}
if ( glue0 -> get_codec ) {
2011-02-03 16:22:10 +00:00
ast_format_cap_remove_all ( cap0 );
glue0 -> get_codec ( c0 , cap0 );
2009-04-02 17:20:52 +00:00
}
2010-07-08 22:08:07 +00:00
if (( ast_sockaddr_cmp ( & t1 , & ac1 )) ||
( vinstance1 && ast_sockaddr_cmp ( & vt1 , & vac1 )) ||
( tinstance1 && ast_sockaddr_cmp ( & tt1 , & tac1 )) ||
2011-02-03 16:22:10 +00:00
( ! ast_format_cap_identical ( cap1 , oldcap1 ))) {
char tmp_buf [ 512 ] = { 0 , };
2010-07-08 22:08:07 +00:00
ast_debug ( 1 , "Oooh, '%s' changed end address to %s (format %s) \n " ,
c1 -> name , ast_sockaddr_stringify ( & t1 ),
2011-02-03 16:22:10 +00:00
ast_getformatname_multiple ( tmp_buf , sizeof ( tmp_buf ), cap1 ));
2010-07-08 22:08:07 +00:00
ast_debug ( 1 , "Oooh, '%s' changed end vaddress to %s (format %s) \n " ,
c1 -> name , ast_sockaddr_stringify ( & vt1 ),
2011-02-03 16:22:10 +00:00
ast_getformatname_multiple ( tmp_buf , sizeof ( tmp_buf ), cap1 ));
2010-07-08 22:08:07 +00:00
ast_debug ( 1 , "Oooh, '%s' changed end taddress to %s (format %s) \n " ,
c1 -> name , ast_sockaddr_stringify ( & tt1 ),
2011-02-03 16:22:10 +00:00
ast_getformatname_multiple ( tmp_buf , sizeof ( tmp_buf ), cap1 ));
2010-07-08 22:08:07 +00:00
ast_debug ( 1 , "Oooh, '%s' was %s/(format %s) \n " ,
c1 -> name , ast_sockaddr_stringify ( & ac1 ),
2011-02-03 16:22:10 +00:00
ast_getformatname_multiple ( tmp_buf , sizeof ( tmp_buf ), oldcap1 ));
2010-07-08 22:08:07 +00:00
ast_debug ( 1 , "Oooh, '%s' was %s/(format %s) \n " ,
c1 -> name , ast_sockaddr_stringify ( & vac1 ),
2011-02-03 16:22:10 +00:00
ast_getformatname_multiple ( tmp_buf , sizeof ( tmp_buf ), oldcap1 ));
2010-07-08 22:08:07 +00:00
ast_debug ( 1 , "Oooh, '%s' was %s/(format %s) \n " ,
c1 -> name , ast_sockaddr_stringify ( & tac1 ),
2011-02-03 16:22:10 +00:00
ast_getformatname_multiple ( tmp_buf , sizeof ( tmp_buf ), oldcap1 ));
2010-07-08 22:08:07 +00:00
if ( glue0 -> update_peer ( c0 ,
ast_sockaddr_isnull ( & t1 ) ? NULL : instance1 ,
ast_sockaddr_isnull ( & vt1 ) ? NULL : vinstance1 ,
ast_sockaddr_isnull ( & tt1 ) ? NULL : tinstance1 ,
2011-02-03 16:22:10 +00:00
cap1 , 0 )) {
2009-04-02 17:20:52 +00:00
ast_log ( LOG_WARNING , "Channel '%s' failed to update to '%s' \n " , c0 -> name , c1 -> name );
}
2010-07-08 22:08:07 +00:00
ast_sockaddr_copy ( & ac1 , & t1 );
ast_sockaddr_copy ( & vac1 , & vt1 );
ast_sockaddr_copy ( & tac1 , & tt1 );
2011-02-03 16:22:10 +00:00
ast_format_cap_copy ( oldcap1 , cap1 );
2009-04-02 17:20:52 +00:00
}
2010-07-08 22:08:07 +00:00
if (( ast_sockaddr_cmp ( & t0 , & ac0 )) ||
( vinstance0 && ast_sockaddr_cmp ( & vt0 , & vac0 )) ||
( tinstance0 && ast_sockaddr_cmp ( & tt0 , & tac0 )) ||
2011-02-03 16:22:10 +00:00
( ! ast_format_cap_identical ( cap0 , oldcap0 ))) {
char tmp_buf [ 512 ] = { 0 , };
2010-07-08 22:08:07 +00:00
ast_debug ( 1 , "Oooh, '%s' changed end address to %s (format %s) \n " ,
c0 -> name , ast_sockaddr_stringify ( & t0 ),
2011-02-03 16:22:10 +00:00
ast_getformatname_multiple ( tmp_buf , sizeof ( tmp_buf ), cap0 ));
2010-07-08 22:08:07 +00:00
ast_debug ( 1 , "Oooh, '%s' was %s/(format %s) \n " ,
c0 -> name , ast_sockaddr_stringify ( & ac0 ),
2011-02-03 16:22:10 +00:00
ast_getformatname_multiple ( tmp_buf , sizeof ( tmp_buf ), oldcap0 ));
2010-07-08 22:08:07 +00:00
if ( glue1 -> update_peer ( c1 , t0 . len ? instance0 : NULL ,
vt0 . len ? vinstance0 : NULL ,
tt0 . len ? tinstance0 : NULL ,
2011-02-03 16:22:10 +00:00
cap0 , 0 )) {
2009-04-02 17:20:52 +00:00
ast_log ( LOG_WARNING , "Channel '%s' failed to update to '%s' \n " , c1 -> name , c0 -> name );
}
2010-07-08 22:08:07 +00:00
ast_sockaddr_copy ( & ac0 , & t0 );
ast_sockaddr_copy ( & vac0 , & vt0 );
ast_sockaddr_copy ( & tac0 , & tt0 );
2011-02-03 16:22:10 +00:00
ast_format_cap_copy ( oldcap0 , cap0 );
2009-04-02 17:20:52 +00:00
}
/* Wait for frame to come in on the channels */
if ( ! ( who = ast_waitfor_n ( cs , 2 , & timeoutms ))) {
if ( ! timeoutms ) {
res = AST_BRIDGE_RETRY ;
break ;
}
ast_debug ( 1 , "Ooh, empty read... \n " );
if ( ast_check_hangup ( c0 ) || ast_check_hangup ( c1 )) {
break ;
}
continue ;
}
fr = ast_read ( who );
other = ( who == c0 ) ? c1 : c0 ;
if ( ! fr || (( fr -> frametype == AST_FRAME_DTMF_BEGIN || fr -> frametype == AST_FRAME_DTMF_END ) &&
((( who == c0 ) && ( flags & AST_BRIDGE_DTMF_CHANNEL_0 )) ||
(( who == c1 ) && ( flags & AST_BRIDGE_DTMF_CHANNEL_1 ))))) {
/* Break out of bridge */
* fo = fr ;
* rc = who ;
ast_debug ( 1 , "Oooh, got a %s \n " , fr ? "digit" : "hangup" );
res = AST_BRIDGE_COMPLETE ;
break ;
} else if (( fr -> frametype == AST_FRAME_CONTROL ) && ! ( flags & AST_BRIDGE_IGNORE_SIGS )) {
2009-11-04 14:05:12 +00:00
if (( fr -> subclass . integer == AST_CONTROL_HOLD ) ||
( fr -> subclass . integer == AST_CONTROL_UNHOLD ) ||
( fr -> subclass . integer == AST_CONTROL_VIDUPDATE ) ||
( fr -> subclass . integer == AST_CONTROL_SRCUPDATE ) ||
( fr -> subclass . integer == AST_CONTROL_T38_PARAMETERS )) {
if ( fr -> subclass . integer == AST_CONTROL_HOLD ) {
2009-04-02 17:20:52 +00:00
/* If we someone went on hold we want the other side to reinvite back to us */
if ( who == c0 ) {
glue1 -> update_peer ( c1 , NULL , NULL , NULL , 0 , 0 );
} else {
glue0 -> update_peer ( c0 , NULL , NULL , NULL , 0 , 0 );
}
2009-11-04 14:05:12 +00:00
} else if ( fr -> subclass . integer == AST_CONTROL_UNHOLD ) {
2009-04-02 17:20:52 +00:00
/* If they went off hold they should go back to being direct */
if ( who == c0 ) {
2011-02-03 16:22:10 +00:00
glue1 -> update_peer ( c1 , instance0 , vinstance0 , tinstance0 , cap0 , 0 );
2009-04-02 17:20:52 +00:00
} else {
2011-02-03 16:22:10 +00:00
glue0 -> update_peer ( c0 , instance1 , vinstance1 , tinstance1 , cap1 , 0 );
2009-04-02 17:20:52 +00:00
}
}
/* Update local address information */
ast_rtp_instance_get_remote_address ( instance0 , & t0 );
2010-07-08 22:08:07 +00:00
ast_sockaddr_copy ( & ac0 , & t0 );
2009-04-02 17:20:52 +00:00
ast_rtp_instance_get_remote_address ( instance1 , & t1 );
2010-07-08 22:08:07 +00:00
ast_sockaddr_copy ( & ac1 , & t1 );
2009-04-02 17:20:52 +00:00
/* Update codec information */
if ( glue0 -> get_codec && c0 -> tech_pvt ) {
2011-02-03 16:22:10 +00:00
ast_format_cap_remove_all ( cap0 );
ast_format_cap_remove_all ( oldcap0 );
glue0 -> get_codec ( c0 , cap0 );
ast_format_cap_append ( oldcap0 , cap0 );
2009-04-02 17:20:52 +00:00
}
if ( glue1 -> get_codec && c1 -> tech_pvt ) {
2011-02-03 16:22:10 +00:00
ast_format_cap_remove_all ( cap1 );
ast_format_cap_remove_all ( oldcap1 );
glue0 -> get_codec ( c1 , cap1 );
ast_format_cap_append ( oldcap1 , cap1 );
2009-04-02 17:20:52 +00:00
}
2009-11-04 14:05:12 +00:00
ast_indicate_data ( other , fr -> subclass . integer , fr -> data . ptr , fr -> datalen );
2009-04-02 17:20:52 +00:00
ast_frfree ( fr );
2010-05-17 15:36:31 +00:00
} else if ( fr -> subclass . integer == AST_CONTROL_CONNECTED_LINE ) {
if ( ast_channel_connected_line_macro ( who , other , fr , other == c0 , 1 )) {
ast_indicate_data ( other , fr -> subclass . integer , fr -> data . ptr , fr -> datalen );
}
ast_frfree ( fr );
} else if ( fr -> subclass . integer == AST_CONTROL_REDIRECTING ) {
if ( ast_channel_redirecting_macro ( who , other , fr , other == c0 , 1 )) {
ast_indicate_data ( other , fr -> subclass . integer , fr -> data . ptr , fr -> datalen );
}
ast_frfree ( fr );
2009-04-02 17:20:52 +00:00
} else {
* fo = fr ;
* rc = who ;
2009-11-04 14:05:12 +00:00
ast_debug ( 1 , "Got a FRAME_CONTROL (%d) frame on channel %s \n " , fr -> subclass . integer , who -> name );
2011-02-03 16:22:10 +00:00
res = AST_BRIDGE_COMPLETE ;
goto remote_bridge_cleanup ;
2009-04-02 17:20:52 +00:00
}
} else {
if (( fr -> frametype == AST_FRAME_DTMF_BEGIN ) ||
( fr -> frametype == AST_FRAME_DTMF_END ) ||
( fr -> frametype == AST_FRAME_VOICE ) ||
( fr -> frametype == AST_FRAME_VIDEO ) ||
( fr -> frametype == AST_FRAME_IMAGE ) ||
( fr -> frametype == AST_FRAME_HTML ) ||
( fr -> frametype == AST_FRAME_MODEM ) ||
( fr -> frametype == AST_FRAME_TEXT )) {
ast_write ( other , fr );
}
ast_frfree ( fr );
}
/* Swap priority */
cs [ 2 ] = cs [ 0 ];
cs [ 0 ] = cs [ 1 ];
cs [ 1 ] = cs [ 2 ];
}
2011-03-11 06:56:06 +00:00
if ( ast_test_flag ( c0 , AST_FLAG_ZOMBIE )) {
ast_debug ( 1 , "Channel '%s' Zombie cleardown from bridge \n " , c0 -> name );
} else if ( c0 -> tech_pvt != pvt0 ) {
ast_debug ( 1 , "Channel c0->'%s' pvt changed, in bridge with c1->'%s' \n " , c0 -> name , c1 -> name );
} else if ( glue0 != ast_rtp_instance_get_glue ( c0 -> tech -> type )) {
ast_debug ( 1 , "Channel c0->'%s' technology changed, in bridge with c1->'%s' \n " , c0 -> name , c1 -> name );
} else if ( glue0 -> update_peer ( c0 , NULL , NULL , NULL , 0 , 0 )) {
2009-04-02 17:20:52 +00:00
ast_log ( LOG_WARNING , "Channel '%s' failed to break RTP bridge \n " , c0 -> name );
}
2011-03-11 06:56:06 +00:00
if ( ast_test_flag ( c1 , AST_FLAG_ZOMBIE )) {
ast_debug ( 1 , "Channel '%s' Zombie cleardown from bridge \n " , c1 -> name );
} else if ( c1 -> tech_pvt != pvt1 ) {
ast_debug ( 1 , "Channel c1->'%s' pvt changed, in bridge with c0->'%s' \n " , c1 -> name , c0 -> name );
} else if ( glue1 != ast_rtp_instance_get_glue ( c1 -> tech -> type )) {
ast_debug ( 1 , "Channel c1->'%s' technology changed, in bridge with c0->'%s' \n " , c1 -> name , c0 -> name );
} else if ( glue1 -> update_peer ( c1 , NULL , NULL , NULL , 0 , 0 )) {
2009-04-02 17:20:52 +00:00
ast_log ( LOG_WARNING , "Channel '%s' failed to break RTP bridge \n " , c1 -> name );
}
instance0 -> bridged = NULL ;
instance1 -> bridged = NULL ;
ast_poll_channel_del ( c0 , c1 );
2011-02-03 16:22:10 +00:00
remote_bridge_cleanup :
ast_format_cap_destroy ( oldcap0 );
ast_format_cap_destroy ( oldcap1 );
2009-04-02 17:20:52 +00:00
return res ;
}
/*!
* \brief Conditionally unref an rtp instance
*/
static void unref_instance_cond ( struct ast_rtp_instance ** instance )
{
if ( * instance ) {
ao2_ref ( * instance , - 1 );
* instance = NULL ;
}
}
enum ast_bridge_result ast_rtp_instance_bridge ( struct ast_channel * c0 , struct ast_channel * c1 , int flags , struct ast_frame ** fo , struct ast_channel ** rc , int timeoutms )
{
struct ast_rtp_instance * instance0 = NULL , * instance1 = NULL ,
* vinstance0 = NULL , * vinstance1 = NULL ,
* tinstance0 = NULL , * tinstance1 = NULL ;
struct ast_rtp_glue * glue0 , * glue1 ;
2010-07-08 22:08:07 +00:00
struct ast_sockaddr addr1 , addr2 ;
2011-05-03 20:45:32 +00:00
enum ast_rtp_glue_result audio_glue0_res = AST_RTP_GLUE_RESULT_FORBID , video_glue0_res = AST_RTP_GLUE_RESULT_FORBID ;
enum ast_rtp_glue_result audio_glue1_res = AST_RTP_GLUE_RESULT_FORBID , video_glue1_res = AST_RTP_GLUE_RESULT_FORBID ;
2009-04-02 17:20:52 +00:00
enum ast_bridge_result res = AST_BRIDGE_FAILED ;
2011-02-03 16:22:10 +00:00
struct ast_format_cap * cap0 = ast_format_cap_alloc_nolock ();
struct ast_format_cap * cap1 = ast_format_cap_alloc_nolock ();
2009-04-02 17:20:52 +00:00
int unlock_chans = 1 ;
2011-02-03 16:22:10 +00:00
if ( ! cap0 || ! cap1 ) {
unlock_chans = 0 ;
goto done ;
}
2009-04-02 17:20:52 +00:00
/* Lock both channels so we can look for the glue that binds them together */
ast_channel_lock ( c0 );
while ( ast_channel_trylock ( c1 )) {
ast_channel_unlock ( c0 );
usleep ( 1 );
ast_channel_lock ( c0 );
}
/* Ensure neither channel got hungup during lock avoidance */
if ( ast_check_hangup ( c0 ) || ast_check_hangup ( c1 )) {
ast_log ( LOG_WARNING , "Got hangup while attempting to bridge '%s' and '%s' \n " , c0 -> name , c1 -> name );
goto done ;
}
/* Grab glue that binds each channel to something using the RTP engine */
if ( ! ( glue0 = ast_rtp_instance_get_glue ( c0 -> tech -> type )) || ! ( glue1 = ast_rtp_instance_get_glue ( c1 -> tech -> type ))) {
2009-04-08 16:27:36 +00:00
ast_debug ( 1 , "Can't find native functions for channel '%s' \n " , glue0 ? c1 -> name : c0 -> name );
2009-04-02 17:20:52 +00:00
goto done ;
}
audio_glue0_res = glue0 -> get_rtp_info ( c0 , & instance0 );
video_glue0_res = glue0 -> get_vrtp_info ? glue0 -> get_vrtp_info ( c0 , & vinstance0 ) : AST_RTP_GLUE_RESULT_FORBID ;
audio_glue1_res = glue1 -> get_rtp_info ( c1 , & instance1 );
video_glue1_res = glue1 -> get_vrtp_info ? glue1 -> get_vrtp_info ( c1 , & vinstance1 ) : AST_RTP_GLUE_RESULT_FORBID ;
/* If we are carrying video, and both sides are not going to remotely bridge... fail the native bridge */
if ( video_glue0_res != AST_RTP_GLUE_RESULT_FORBID && ( audio_glue0_res != AST_RTP_GLUE_RESULT_REMOTE || video_glue0_res != AST_RTP_GLUE_RESULT_REMOTE )) {
audio_glue0_res = AST_RTP_GLUE_RESULT_FORBID ;
}
if ( video_glue1_res != AST_RTP_GLUE_RESULT_FORBID && ( audio_glue1_res != AST_RTP_GLUE_RESULT_REMOTE || video_glue1_res != AST_RTP_GLUE_RESULT_REMOTE )) {
audio_glue1_res = AST_RTP_GLUE_RESULT_FORBID ;
}
/* If any sort of bridge is forbidden just completely bail out and go back to generic bridging */
if ( audio_glue0_res == AST_RTP_GLUE_RESULT_FORBID || audio_glue1_res == AST_RTP_GLUE_RESULT_FORBID ) {
res = AST_BRIDGE_FAILED_NOWARN ;
goto done ;
}
2010-07-08 22:08:07 +00:00
/* If address families differ, force a local bridge */
ast_rtp_instance_get_remote_address ( instance0 , & addr1 );
ast_rtp_instance_get_remote_address ( instance1 , & addr2 );
if ( addr1 . ss . ss_family != addr2 . ss . ss_family ||
( ast_sockaddr_is_ipv4_mapped ( & addr1 ) != ast_sockaddr_is_ipv4_mapped ( & addr2 ))) {
audio_glue0_res = AST_RTP_GLUE_RESULT_LOCAL ;
audio_glue1_res = AST_RTP_GLUE_RESULT_LOCAL ;
}
2009-04-08 18:12:28 +00:00
/* If we need to get DTMF see if we can do it outside of the RTP stream itself */
if (( flags & AST_BRIDGE_DTMF_CHANNEL_0 ) && instance0 -> properties [ AST_RTP_PROPERTY_DTMF ]) {
res = AST_BRIDGE_FAILED_NOWARN ;
goto done ;
}
if (( flags & AST_BRIDGE_DTMF_CHANNEL_1 ) && instance1 -> properties [ AST_RTP_PROPERTY_DTMF ]) {
res = AST_BRIDGE_FAILED_NOWARN ;
goto done ;
}
2009-04-02 17:20:52 +00:00
/* If we have gotten to a local bridge make sure that both sides have the same local bridge callback and that they are DTMF compatible */
if (( audio_glue0_res == AST_RTP_GLUE_RESULT_LOCAL || audio_glue1_res == AST_RTP_GLUE_RESULT_LOCAL ) && (( instance0 -> engine -> local_bridge != instance1 -> engine -> local_bridge ) || ( instance0 -> engine -> dtmf_compatible && ! instance0 -> engine -> dtmf_compatible ( c0 , instance0 , c1 , instance1 )))) {
res = AST_BRIDGE_FAILED_NOWARN ;
goto done ;
}
/* Make sure that codecs match */
2011-02-03 16:22:10 +00:00
if ( glue0 -> get_codec ){
glue0 -> get_codec ( c0 , cap0 );
}
if ( glue1 -> get_codec ) {
glue1 -> get_codec ( c1 , cap1 );
}
if ( ! ast_format_cap_is_empty ( cap0 ) && ! ast_format_cap_is_empty ( cap1 ) && ! ast_format_cap_has_joint ( cap0 , cap1 )) {
char tmp0 [ 256 ] = { 0 , };
char tmp1 [ 256 ] = { 0 , };
ast_debug ( 1 , "Channel codec0 = %s is not codec1 = %s, cannot native bridge in RTP. \n " ,
ast_getformatname_multiple ( tmp0 , sizeof ( tmp0 ), cap0 ),
ast_getformatname_multiple ( tmp1 , sizeof ( tmp1 ), cap1 ));
2009-04-02 17:20:52 +00:00
res = AST_BRIDGE_FAILED_NOWARN ;
goto done ;
}
2009-08-16 19:27:39 +00:00
instance0 -> glue = glue0 ;
instance1 -> glue = glue1 ;
instance0 -> chan = c0 ;
instance1 -> chan = c1 ;
2009-04-02 17:20:52 +00:00
/* Depending on the end result for bridging either do a local bridge or remote bridge */
if ( audio_glue0_res == AST_RTP_GLUE_RESULT_LOCAL || audio_glue1_res == AST_RTP_GLUE_RESULT_LOCAL ) {
ast_verbose ( VERBOSE_PREFIX_3 "Locally bridging %s and %s \n " , c0 -> name , c1 -> name );
res = local_bridge_loop ( c0 , c1 , instance0 , instance1 , timeoutms , flags , fo , rc , c0 -> tech_pvt , c1 -> tech_pvt );
} else {
ast_verbose ( VERBOSE_PREFIX_3 "Remotely bridging %s and %s \n " , c0 -> name , c1 -> name );
res = remote_bridge_loop ( c0 , c1 , instance0 , instance1 , vinstance0 , vinstance1 ,
2011-02-03 16:22:10 +00:00
tinstance0 , tinstance1 , glue0 , glue1 , cap0 , cap1 , timeoutms , flags ,
2009-04-02 17:20:52 +00:00
fo , rc , c0 -> tech_pvt , c1 -> tech_pvt );
}
2009-08-16 19:27:39 +00:00
instance0 -> glue = NULL ;
instance1 -> glue = NULL ;
instance0 -> chan = NULL ;
instance1 -> chan = NULL ;
2009-04-02 17:20:52 +00:00
unlock_chans = 0 ;
done :
if ( unlock_chans ) {
ast_channel_unlock ( c0 );
ast_channel_unlock ( c1 );
}
2011-02-03 16:22:10 +00:00
ast_format_cap_destroy ( cap1 );
ast_format_cap_destroy ( cap0 );
2009-04-02 17:20:52 +00:00
unref_instance_cond ( & instance0 );
unref_instance_cond ( & instance1 );
unref_instance_cond ( & vinstance0 );
unref_instance_cond ( & vinstance1 );
unref_instance_cond ( & tinstance0 );
unref_instance_cond ( & tinstance1 );
return res ;
}
struct ast_rtp_instance * ast_rtp_instance_get_bridged ( struct ast_rtp_instance * instance )
{
return instance -> bridged ;
}
void ast_rtp_instance_early_bridge_make_compatible ( struct ast_channel * c0 , struct ast_channel * c1 )
{
struct ast_rtp_instance * instance0 = NULL , * instance1 = NULL ,
* vinstance0 = NULL , * vinstance1 = NULL ,
* tinstance0 = NULL , * tinstance1 = NULL ;
struct ast_rtp_glue * glue0 , * glue1 ;
2011-05-03 20:45:32 +00:00
enum ast_rtp_glue_result audio_glue0_res = AST_RTP_GLUE_RESULT_FORBID , video_glue0_res = AST_RTP_GLUE_RESULT_FORBID ;
enum ast_rtp_glue_result audio_glue1_res = AST_RTP_GLUE_RESULT_FORBID , video_glue1_res = AST_RTP_GLUE_RESULT_FORBID ;
2011-02-03 16:22:10 +00:00
struct ast_format_cap * cap0 = ast_format_cap_alloc_nolock ();
struct ast_format_cap * cap1 = ast_format_cap_alloc_nolock ();
2009-04-02 17:20:52 +00:00
int res = 0 ;
/* Lock both channels so we can look for the glue that binds them together */
ast_channel_lock ( c0 );
while ( ast_channel_trylock ( c1 )) {
ast_channel_unlock ( c0 );
usleep ( 1 );
ast_channel_lock ( c0 );
}
2011-02-03 16:22:10 +00:00
if ( ! cap1 || ! cap0 ) {
goto done ;
}
2009-04-02 17:20:52 +00:00
/* Grab glue that binds each channel to something using the RTP engine */
if ( ! ( glue0 = ast_rtp_instance_get_glue ( c0 -> tech -> type )) || ! ( glue1 = ast_rtp_instance_get_glue ( c1 -> tech -> type ))) {
2009-04-08 16:27:36 +00:00
ast_debug ( 1 , "Can't find native functions for channel '%s' \n " , glue0 ? c1 -> name : c0 -> name );
2009-04-02 17:20:52 +00:00
goto done ;
}
audio_glue0_res = glue0 -> get_rtp_info ( c0 , & instance0 );
video_glue0_res = glue0 -> get_vrtp_info ? glue0 -> get_vrtp_info ( c0 , & vinstance0 ) : AST_RTP_GLUE_RESULT_FORBID ;
audio_glue1_res = glue1 -> get_rtp_info ( c1 , & instance1 );
video_glue1_res = glue1 -> get_vrtp_info ? glue1 -> get_vrtp_info ( c1 , & vinstance1 ) : AST_RTP_GLUE_RESULT_FORBID ;
/* If we are carrying video, and both sides are not going to remotely bridge... fail the native bridge */
if ( video_glue0_res != AST_RTP_GLUE_RESULT_FORBID && ( audio_glue0_res != AST_RTP_GLUE_RESULT_REMOTE || video_glue0_res != AST_RTP_GLUE_RESULT_REMOTE )) {
audio_glue0_res = AST_RTP_GLUE_RESULT_FORBID ;
}
if ( video_glue1_res != AST_RTP_GLUE_RESULT_FORBID && ( audio_glue1_res != AST_RTP_GLUE_RESULT_REMOTE || video_glue1_res != AST_RTP_GLUE_RESULT_REMOTE )) {
audio_glue1_res = AST_RTP_GLUE_RESULT_FORBID ;
}
2010-07-29 16:26:13 +00:00
if ( audio_glue0_res == AST_RTP_GLUE_RESULT_REMOTE && ( video_glue0_res == AST_RTP_GLUE_RESULT_FORBID || video_glue0_res == AST_RTP_GLUE_RESULT_REMOTE ) && glue0 -> get_codec ) {
2011-02-03 16:22:10 +00:00
glue0 -> get_codec ( c0 , cap0 );
2009-04-02 17:20:52 +00:00
}
2010-07-29 16:26:13 +00:00
if ( audio_glue1_res == AST_RTP_GLUE_RESULT_REMOTE && ( video_glue1_res == AST_RTP_GLUE_RESULT_FORBID || video_glue1_res == AST_RTP_GLUE_RESULT_REMOTE ) && glue1 -> get_codec ) {
2011-02-03 16:22:10 +00:00
glue1 -> get_codec ( c1 , cap1 );
2009-04-02 17:20:52 +00:00
}
/* If any sort of bridge is forbidden just completely bail out and go back to generic bridging */
if ( audio_glue0_res != AST_RTP_GLUE_RESULT_REMOTE || audio_glue1_res != AST_RTP_GLUE_RESULT_REMOTE ) {
goto done ;
}
/* Make sure we have matching codecs */
2011-02-03 16:22:10 +00:00
if ( ! ast_format_cap_has_joint ( cap0 , cap1 )) {
2009-04-02 17:20:52 +00:00
goto done ;
}
ast_rtp_codecs_payloads_copy ( & instance0 -> codecs , & instance1 -> codecs , instance1 );
if ( vinstance0 && vinstance1 ) {
ast_rtp_codecs_payloads_copy ( & vinstance0 -> codecs , & vinstance1 -> codecs , vinstance1 );
}
if ( tinstance0 && tinstance1 ) {
ast_rtp_codecs_payloads_copy ( & tinstance0 -> codecs , & tinstance1 -> codecs , tinstance1 );
}
res = 0 ;
done :
ast_channel_unlock ( c0 );
ast_channel_unlock ( c1 );
2011-02-03 16:22:10 +00:00
ast_format_cap_destroy ( cap0 );
ast_format_cap_destroy ( cap1 );
2009-04-02 17:20:52 +00:00
unref_instance_cond ( & instance0 );
unref_instance_cond ( & instance1 );
unref_instance_cond ( & vinstance0 );
unref_instance_cond ( & vinstance1 );
unref_instance_cond ( & tinstance0 );
unref_instance_cond ( & tinstance1 );
if ( ! res ) {
ast_debug ( 1 , "Seeded SDP of '%s' with that of '%s' \n " , c0 -> name , c1 ? c1 -> name : "<unspecified>" );
}
}
int ast_rtp_instance_early_bridge ( struct ast_channel * c0 , struct ast_channel * c1 )
{
struct ast_rtp_instance * instance0 = NULL , * instance1 = NULL ,
* vinstance0 = NULL , * vinstance1 = NULL ,
* tinstance0 = NULL , * tinstance1 = NULL ;
struct ast_rtp_glue * glue0 , * glue1 ;
2011-05-03 20:45:32 +00:00
enum ast_rtp_glue_result audio_glue0_res = AST_RTP_GLUE_RESULT_FORBID , video_glue0_res = AST_RTP_GLUE_RESULT_FORBID ;
enum ast_rtp_glue_result audio_glue1_res = AST_RTP_GLUE_RESULT_FORBID , video_glue1_res = AST_RTP_GLUE_RESULT_FORBID ;
2011-02-03 16:22:10 +00:00
struct ast_format_cap * cap0 = ast_format_cap_alloc_nolock ();
struct ast_format_cap * cap1 = ast_format_cap_alloc_nolock ();
2009-04-02 17:20:52 +00:00
int res = 0 ;
/* If there is no second channel just immediately bail out, we are of no use in that scenario */
if ( ! c1 ) {
2011-02-03 16:22:10 +00:00
ast_format_cap_destroy ( cap0 );
ast_format_cap_destroy ( cap1 );
2009-04-02 17:20:52 +00:00
return - 1 ;
}
/* Lock both channels so we can look for the glue that binds them together */
ast_channel_lock ( c0 );
while ( ast_channel_trylock ( c1 )) {
ast_channel_unlock ( c0 );
usleep ( 1 );
ast_channel_lock ( c0 );
}
2011-02-03 16:22:10 +00:00
if ( ! cap1 || ! cap0 ) {
goto done ;
}
2009-04-02 17:20:52 +00:00
/* Grab glue that binds each channel to something using the RTP engine */
if ( ! ( glue0 = ast_rtp_instance_get_glue ( c0 -> tech -> type )) || ! ( glue1 = ast_rtp_instance_get_glue ( c1 -> tech -> type ))) {
ast_log ( LOG_WARNING , "Can't find native functions for channel '%s' \n " , glue0 ? c1 -> name : c0 -> name );
goto done ;
}
audio_glue0_res = glue0 -> get_rtp_info ( c0 , & instance0 );
video_glue0_res = glue0 -> get_vrtp_info ? glue0 -> get_vrtp_info ( c0 , & vinstance0 ) : AST_RTP_GLUE_RESULT_FORBID ;
audio_glue1_res = glue1 -> get_rtp_info ( c1 , & instance1 );
video_glue1_res = glue1 -> get_vrtp_info ? glue1 -> get_vrtp_info ( c1 , & vinstance1 ) : AST_RTP_GLUE_RESULT_FORBID ;
/* If we are carrying video, and both sides are not going to remotely bridge... fail the native bridge */
if ( video_glue0_res != AST_RTP_GLUE_RESULT_FORBID && ( audio_glue0_res != AST_RTP_GLUE_RESULT_REMOTE || video_glue0_res != AST_RTP_GLUE_RESULT_REMOTE )) {
audio_glue0_res = AST_RTP_GLUE_RESULT_FORBID ;
}
if ( video_glue1_res != AST_RTP_GLUE_RESULT_FORBID && ( audio_glue1_res != AST_RTP_GLUE_RESULT_REMOTE || video_glue1_res != AST_RTP_GLUE_RESULT_REMOTE )) {
audio_glue1_res = AST_RTP_GLUE_RESULT_FORBID ;
}
2011-02-03 16:22:10 +00:00
if ( audio_glue0_res == AST_RTP_GLUE_RESULT_REMOTE && ( video_glue0_res == AST_RTP_GLUE_RESULT_FORBID || video_glue0_res == AST_RTP_GLUE_RESULT_REMOTE ) && glue0 -> get_codec ) {
glue0 -> get_codec ( c0 , cap0 );
2009-04-02 17:20:52 +00:00
}
2011-02-03 16:22:10 +00:00
if ( audio_glue1_res == AST_RTP_GLUE_RESULT_REMOTE && ( video_glue1_res == AST_RTP_GLUE_RESULT_FORBID || video_glue1_res == AST_RTP_GLUE_RESULT_REMOTE ) && glue1 -> get_codec ) {
glue1 -> get_codec ( c1 , cap1 );
2009-04-02 17:20:52 +00:00
}
/* If any sort of bridge is forbidden just completely bail out and go back to generic bridging */
if ( audio_glue0_res != AST_RTP_GLUE_RESULT_REMOTE || audio_glue1_res != AST_RTP_GLUE_RESULT_REMOTE ) {
goto done ;
}
/* Make sure we have matching codecs */
2011-02-03 16:22:10 +00:00
if ( ! ast_format_cap_has_joint ( cap0 , cap1 )) {
2009-04-02 17:20:52 +00:00
goto done ;
}
/* Bridge media early */
2011-02-03 16:22:10 +00:00
if ( glue0 -> update_peer ( c0 , instance1 , vinstance1 , tinstance1 , cap1 , 0 )) {
2009-04-02 17:20:52 +00:00
ast_log ( LOG_WARNING , "Channel '%s' failed to setup early bridge to '%s' \n " , c0 -> name , c1 ? c1 -> name : "<unspecified>" );
}
res = 0 ;
done :
ast_channel_unlock ( c0 );
ast_channel_unlock ( c1 );
2011-02-03 16:22:10 +00:00
ast_format_cap_destroy ( cap0 );
ast_format_cap_destroy ( cap1 );
2009-04-02 17:20:52 +00:00
unref_instance_cond ( & instance0 );
unref_instance_cond ( & instance1 );
unref_instance_cond ( & vinstance0 );
unref_instance_cond ( & vinstance1 );
unref_instance_cond ( & tinstance0 );
unref_instance_cond ( & tinstance1 );
if ( ! res ) {
ast_debug ( 1 , "Setting early bridge SDP of '%s' with that of '%s' \n " , c0 -> name , c1 ? c1 -> name : "<unspecified>" );
}
return res ;
}
int ast_rtp_red_init ( struct ast_rtp_instance * instance , int buffer_time , int * payloads , int generations )
{
return instance -> engine -> red_init ? instance -> engine -> red_init ( instance , buffer_time , payloads , generations ) : - 1 ;
}
int ast_rtp_red_buffer ( struct ast_rtp_instance * instance , struct ast_frame * frame )
{
return instance -> engine -> red_buffer ? instance -> engine -> red_buffer ( instance , frame ) : - 1 ;
}
int ast_rtp_instance_get_stats ( struct ast_rtp_instance * instance , struct ast_rtp_instance_stats * stats , enum ast_rtp_instance_stat stat )
{
return instance -> engine -> get_stat ? instance -> engine -> get_stat ( instance , stats , stat ) : - 1 ;
}
char * ast_rtp_instance_get_quality ( struct ast_rtp_instance * instance , enum ast_rtp_instance_stat_field field , char * buf , size_t size )
{
2009-04-10 18:02:44 +00:00
struct ast_rtp_instance_stats stats = { 0 , };
2009-04-02 17:20:52 +00:00
enum ast_rtp_instance_stat stat ;
/* Determine what statistics we will need to retrieve based on field passed in */
if ( field == AST_RTP_INSTANCE_STAT_FIELD_QUALITY ) {
stat = AST_RTP_INSTANCE_STAT_ALL ;
} else if ( field == AST_RTP_INSTANCE_STAT_FIELD_QUALITY_JITTER ) {
stat = AST_RTP_INSTANCE_STAT_COMBINED_JITTER ;
} else if ( field == AST_RTP_INSTANCE_STAT_FIELD_QUALITY_LOSS ) {
stat = AST_RTP_INSTANCE_STAT_COMBINED_LOSS ;
} else if ( field == AST_RTP_INSTANCE_STAT_FIELD_QUALITY_RTT ) {
stat = AST_RTP_INSTANCE_STAT_COMBINED_RTT ;
} else {
return NULL ;
}
/* Attempt to actually retrieve the statistics we need to generate the quality string */
if ( ast_rtp_instance_get_stats ( instance , & stats , stat )) {
return NULL ;
}
/* Now actually fill the buffer with the good information */
if ( field == AST_RTP_INSTANCE_STAT_FIELD_QUALITY ) {
2010-06-07 19:52:39 +00:00
snprintf ( buf , size , "ssrc=%i;themssrc=%u;lp=%u;rxjitter=%f;rxcount=%u;txjitter=%f;txcount=%u;rlp=%u;rtt=%f" ,
2009-04-02 17:20:52 +00:00
stats . local_ssrc , stats . remote_ssrc , stats . rxploss , stats . txjitter , stats . rxcount , stats . rxjitter , stats . txcount , stats . txploss , stats . rtt );
} else if ( field == AST_RTP_INSTANCE_STAT_FIELD_QUALITY_JITTER ) {
snprintf ( buf , size , "minrxjitter=%f;maxrxjitter=%f;avgrxjitter=%f;stdevrxjitter=%f;reported_minjitter=%f;reported_maxjitter=%f;reported_avgjitter=%f;reported_stdevjitter=%f;" ,
stats . local_minjitter , stats . local_maxjitter , stats . local_normdevjitter , sqrt ( stats . local_stdevjitter ), stats . remote_minjitter , stats . remote_maxjitter , stats . remote_normdevjitter , sqrt ( stats . remote_stdevjitter ));
} else if ( field == AST_RTP_INSTANCE_STAT_FIELD_QUALITY_LOSS ) {
snprintf ( buf , size , "minrxlost=%f;maxrxlost=%f;avgrxlost=%f;stdevrxlost=%f;reported_minlost=%f;reported_maxlost=%f;reported_avglost=%f;reported_stdevlost=%f;" ,
stats . local_minrxploss , stats . local_maxrxploss , stats . local_normdevrxploss , sqrt ( stats . local_stdevrxploss ), stats . remote_minrxploss , stats . remote_maxrxploss , stats . remote_normdevrxploss , sqrt ( stats . remote_stdevrxploss ));
} else if ( field == AST_RTP_INSTANCE_STAT_FIELD_QUALITY_RTT ) {
snprintf ( buf , size , "minrtt=%f;maxrtt=%f;avgrtt=%f;stdevrtt=%f;" , stats . minrtt , stats . maxrtt , stats . normdevrtt , stats . stdevrtt );
}
return buf ;
}
void ast_rtp_instance_set_stats_vars ( struct ast_channel * chan , struct ast_rtp_instance * instance )
{
char quality_buf [ AST_MAX_USER_FIELD ], * quality ;
struct ast_channel * bridge = ast_bridged_channel ( chan );
if (( quality = ast_rtp_instance_get_quality ( instance , AST_RTP_INSTANCE_STAT_FIELD_QUALITY , quality_buf , sizeof ( quality_buf )))) {
pbx_builtin_setvar_helper ( chan , "RTPAUDIOQOS" , quality );
if ( bridge ) {
pbx_builtin_setvar_helper ( bridge , "RTPAUDIOQOSBRIDGED" , quality );
}
}
if (( quality = ast_rtp_instance_get_quality ( instance , AST_RTP_INSTANCE_STAT_FIELD_QUALITY_JITTER , quality_buf , sizeof ( quality_buf )))) {
pbx_builtin_setvar_helper ( chan , "RTPAUDIOQOSJITTER" , quality );
if ( bridge ) {
pbx_builtin_setvar_helper ( bridge , "RTPAUDIOQOSJITTERBRIDGED" , quality );
}
}
if (( quality = ast_rtp_instance_get_quality ( instance , AST_RTP_INSTANCE_STAT_FIELD_QUALITY_LOSS , quality_buf , sizeof ( quality_buf )))) {
pbx_builtin_setvar_helper ( chan , "RTPAUDIOQOSLOSS" , quality );
if ( bridge ) {
pbx_builtin_setvar_helper ( bridge , "RTPAUDIOQOSLOSSBRIDGED" , quality );
}
}
if (( quality = ast_rtp_instance_get_quality ( instance , AST_RTP_INSTANCE_STAT_FIELD_QUALITY_RTT , quality_buf , sizeof ( quality_buf )))) {
pbx_builtin_setvar_helper ( chan , "RTPAUDIOQOSRTT" , quality );
if ( bridge ) {
pbx_builtin_setvar_helper ( bridge , "RTPAUDIOQOSRTTBRIDGED" , quality );
}
}
}
2011-02-03 16:22:10 +00:00
int ast_rtp_instance_set_read_format ( struct ast_rtp_instance * instance , struct ast_format * format )
2009-04-02 17:20:52 +00:00
{
return instance -> engine -> set_read_format ? instance -> engine -> set_read_format ( instance , format ) : - 1 ;
}
2011-02-03 16:22:10 +00:00
int ast_rtp_instance_set_write_format ( struct ast_rtp_instance * instance , struct ast_format * format )
2009-04-02 17:20:52 +00:00
{
return instance -> engine -> set_write_format ? instance -> engine -> set_write_format ( instance , format ) : - 1 ;
}
int ast_rtp_instance_make_compatible ( struct ast_channel * chan , struct ast_rtp_instance * instance , struct ast_channel * peer )
{
struct ast_rtp_glue * glue ;
struct ast_rtp_instance * peer_instance = NULL ;
int res = - 1 ;
if ( ! instance -> engine -> make_compatible ) {
return - 1 ;
}
ast_channel_lock ( peer );
if ( ! ( glue = ast_rtp_instance_get_glue ( peer -> tech -> type ))) {
ast_channel_unlock ( peer );
return - 1 ;
}
glue -> get_rtp_info ( peer , & peer_instance );
if ( ! peer_instance || peer_instance -> engine != instance -> engine ) {
ast_channel_unlock ( peer );
2009-04-29 08:51:21 +00:00
ao2_ref ( peer_instance , - 1 );
peer_instance = NULL ;
2009-04-02 17:20:52 +00:00
return - 1 ;
}
res = instance -> engine -> make_compatible ( chan , instance , peer , peer_instance );
ast_channel_unlock ( peer );
2009-04-29 08:51:21 +00:00
ao2_ref ( peer_instance , - 1 );
peer_instance = NULL ;
2009-04-02 17:20:52 +00:00
return res ;
}
2011-02-03 16:22:10 +00:00
void ast_rtp_instance_available_formats ( struct ast_rtp_instance * instance , struct ast_format_cap * to_endpoint , struct ast_format_cap * to_asterisk , struct ast_format_cap * result )
2009-06-19 15:41:24 +00:00
{
2011-02-03 16:22:10 +00:00
if ( instance -> engine -> available_formats ) {
instance -> engine -> available_formats ( instance , to_endpoint , to_asterisk , result );
if ( ! ast_format_cap_is_empty ( result )) {
return ;
}
2009-06-19 15:41:24 +00:00
}
2011-02-03 16:22:10 +00:00
ast_translate_available_formats ( to_endpoint , to_asterisk , result );
2009-06-19 15:41:24 +00:00
}
2009-04-02 17:20:52 +00:00
int ast_rtp_instance_activate ( struct ast_rtp_instance * instance )
{
return instance -> engine -> activate ? instance -> engine -> activate ( instance ) : 0 ;
}
2010-07-08 22:08:07 +00:00
void ast_rtp_instance_stun_request ( struct ast_rtp_instance * instance ,
struct ast_sockaddr * suggestion ,
const char * username )
2009-04-02 17:20:52 +00:00
{
if ( instance -> engine -> stun_request ) {
instance -> engine -> stun_request ( instance , suggestion , username );
}
}
void ast_rtp_instance_set_timeout ( struct ast_rtp_instance * instance , int timeout )
{
instance -> timeout = timeout ;
}
void ast_rtp_instance_set_hold_timeout ( struct ast_rtp_instance * instance , int timeout )
{
instance -> holdtimeout = timeout ;
}
int ast_rtp_instance_get_timeout ( struct ast_rtp_instance * instance )
{
return instance -> timeout ;
}
int ast_rtp_instance_get_hold_timeout ( struct ast_rtp_instance * instance )
{
return instance -> holdtimeout ;
}
2009-08-13 16:44:54 +00:00
struct ast_rtp_engine * ast_rtp_instance_get_engine ( struct ast_rtp_instance * instance )
{
return instance -> engine ;
}
2009-08-16 19:27:39 +00:00
struct ast_rtp_glue * ast_rtp_instance_get_active_glue ( struct ast_rtp_instance * instance )
{
return instance -> glue ;
}
struct ast_channel * ast_rtp_instance_get_chan ( struct ast_rtp_instance * instance )
{
return instance -> chan ;
}
2010-06-08 05:29:08 +00:00
int ast_rtp_engine_register_srtp ( struct ast_srtp_res * srtp_res , struct ast_srtp_policy_res * policy_res )
{
if ( res_srtp || res_srtp_policy ) {
return - 1 ;
}
if ( ! srtp_res || ! policy_res ) {
return - 1 ;
}
res_srtp = srtp_res ;
res_srtp_policy = policy_res ;
return 0 ;
}
void ast_rtp_engine_unregister_srtp ( void )
{
res_srtp = NULL ;
res_srtp_policy = NULL ;
}
int ast_rtp_engine_srtp_is_registered ( void )
{
return res_srtp && res_srtp_policy ;
}
int ast_rtp_instance_add_srtp_policy ( struct ast_rtp_instance * instance , struct ast_srtp_policy * policy )
{
if ( ! res_srtp ) {
return - 1 ;
}
if ( ! instance -> srtp ) {
return res_srtp -> create ( & instance -> srtp , instance , policy );
} else {
return res_srtp -> add_stream ( instance -> srtp , policy );
}
}
struct ast_srtp * ast_rtp_instance_get_srtp ( struct ast_rtp_instance * instance )
{
return instance -> srtp ;
}
2011-02-22 23:04:49 +00:00
static void set_next_mime_type ( const struct ast_format * format , int rtp_code , char * type , char * subtype , unsigned int sample_rate )
{
int x = mime_types_len ;
if ( ARRAY_LEN ( ast_rtp_mime_types ) == mime_types_len ) {
return ;
}
ast_rwlock_wrlock ( & mime_types_lock );
if ( format ) {
ast_rtp_mime_types [ x ]. payload_type . asterisk_format = 1 ;
ast_format_copy ( & ast_rtp_mime_types [ x ]. payload_type . format , format );
} else {
ast_rtp_mime_types [ x ]. payload_type . rtp_code = rtp_code ;
}
ast_rtp_mime_types [ x ]. type = type ;
ast_rtp_mime_types [ x ]. subtype = subtype ;
ast_rtp_mime_types [ x ]. sample_rate = sample_rate ;
mime_types_len ++ ;
ast_rwlock_unlock ( & mime_types_lock );
}
static void add_static_payload ( int map , const struct ast_format * format , int rtp_code )
{
int x ;
ast_rwlock_wrlock ( & static_RTP_PT_lock );
if ( map < 0 ) {
/* find next available dynamic payload slot */
for ( x = 96 ; x < 127 ; x ++ ) {
if ( ! static_RTP_PT [ x ]. asterisk_format && ! static_RTP_PT [ x ]. rtp_code ) {
map = x ;
break ;
}
}
}
if ( map < 0 ) {
ast_log ( LOG_WARNING , "No Dynamic RTP mapping avaliable for format %s \n " , ast_getformatname ( format ));
ast_rwlock_unlock ( & static_RTP_PT_lock );
return ;
}
if ( format ) {
static_RTP_PT [ map ]. asterisk_format = 1 ;
ast_format_copy ( & static_RTP_PT [ map ]. format , format );
} else {
static_RTP_PT [ map ]. rtp_code = rtp_code ;
}
ast_rwlock_unlock ( & static_RTP_PT_lock );
}
int ast_rtp_engine_load_format ( const struct ast_format * format )
{
switch ( format -> id ) {
case AST_FORMAT_SILK :
set_next_mime_type ( format , 0 , "audio" , "SILK" , ast_format_rate ( format ));
add_static_payload ( - 1 , format , 0 );
break ;
default :
break ;
}
return 0 ;
}
int ast_rtp_engine_unload_format ( const struct ast_format * format )
{
int x ;
int y = 0 ;
ast_rwlock_wrlock ( & static_RTP_PT_lock );
/* remove everything pertaining to this format id from the lists */
for ( x = 0 ; x < AST_RTP_MAX_PT ; x ++ ) {
if ( ast_format_cmp ( & static_RTP_PT [ x ]. format , format ) == AST_FORMAT_CMP_EQUAL ) {
memset ( & static_RTP_PT [ x ], 0 , sizeof ( struct ast_rtp_payload_type ));
}
}
ast_rwlock_unlock ( & static_RTP_PT_lock );
ast_rwlock_wrlock ( & mime_types_lock );
/* rebuild the list skipping the items matching this id */
for ( x = 0 ; x < mime_types_len ; x ++ ) {
if ( ast_format_cmp ( & ast_rtp_mime_types [ x ]. payload_type . format , format ) == AST_FORMAT_CMP_EQUAL ) {
continue ;
}
ast_rtp_mime_types [ y ] = ast_rtp_mime_types [ x ];
y ++ ;
}
mime_types_len = y ;
ast_rwlock_unlock ( & mime_types_lock );
return 0 ;
}
int ast_rtp_engine_init ()
{
struct ast_format tmpfmt ;
ast_rwlock_init ( & mime_types_lock );
ast_rwlock_init ( & static_RTP_PT_lock );
/* Define all the RTP mime types available */
set_next_mime_type ( ast_format_set ( & tmpfmt , AST_FORMAT_G723_1 , 0 ), 0 , "audio" , "G723" , 8000 );
set_next_mime_type ( ast_format_set ( & tmpfmt , AST_FORMAT_GSM , 0 ), 0 , "audio" , "GSM" , 8000 );
set_next_mime_type ( ast_format_set ( & tmpfmt , AST_FORMAT_ULAW , 0 ), 0 , "audio" , "PCMU" , 8000 );
set_next_mime_type ( ast_format_set ( & tmpfmt , AST_FORMAT_ULAW , 0 ), 0 , "audio" , "G711U" , 8000 );
set_next_mime_type ( ast_format_set ( & tmpfmt , AST_FORMAT_ALAW , 0 ), 0 , "audio" , "PCMA" , 8000 );
set_next_mime_type ( ast_format_set ( & tmpfmt , AST_FORMAT_ALAW , 0 ), 0 , "audio" , "G711A" , 8000 );
set_next_mime_type ( ast_format_set ( & tmpfmt , AST_FORMAT_G726 , 0 ), 0 , "audio" , "G726-32" , 8000 );
set_next_mime_type ( ast_format_set ( & tmpfmt , AST_FORMAT_ADPCM , 0 ), 0 , "audio" , "DVI4" , 8000 );
set_next_mime_type ( ast_format_set ( & tmpfmt , AST_FORMAT_SLINEAR , 0 ), 0 , "audio" , "L16" , 8000 );
set_next_mime_type ( ast_format_set ( & tmpfmt , AST_FORMAT_SLINEAR16 , 0 ), 0 , "audio" , "L16" , 16000 );
set_next_mime_type ( ast_format_set ( & tmpfmt , AST_FORMAT_LPC10 , 0 ), 0 , "audio" , "LPC" , 8000 );
set_next_mime_type ( ast_format_set ( & tmpfmt , AST_FORMAT_G729A , 0 ), 0 , "audio" , "G729" , 8000 );
set_next_mime_type ( ast_format_set ( & tmpfmt , AST_FORMAT_G729A , 0 ), 0 , "audio" , "G729A" , 8000 );
set_next_mime_type ( ast_format_set ( & tmpfmt , AST_FORMAT_G729A , 0 ), 0 , "audio" , "G.729" , 8000 );
set_next_mime_type ( ast_format_set ( & tmpfmt , AST_FORMAT_SPEEX , 0 ), 0 , "audio" , "speex" , 8000 );
set_next_mime_type ( ast_format_set ( & tmpfmt , AST_FORMAT_SPEEX16 , 0 ), 0 , "audio" , "speex" , 16000 );
set_next_mime_type ( ast_format_set ( & tmpfmt , AST_FORMAT_SPEEX32 , 0 ), 0 , "audio" , "speex" , 32000 );
set_next_mime_type ( ast_format_set ( & tmpfmt , AST_FORMAT_ILBC , 0 ), 0 , "audio" , "iLBC" , 8000 );
/* this is the sample rate listed in the RTP profile for the G.722 codec, *NOT* the actual sample rate of the media stream */
set_next_mime_type ( ast_format_set ( & tmpfmt , AST_FORMAT_G722 , 0 ), 0 , "audio" , "G722" , 8000 );
set_next_mime_type ( ast_format_set ( & tmpfmt , AST_FORMAT_G726_AAL2 , 0 ), 0 , "audio" , "AAL2-G726-32" , 8000 );
set_next_mime_type ( NULL , AST_RTP_DTMF , "audio" , "telephone-event" , 8000 );
set_next_mime_type ( NULL , AST_RTP_CISCO_DTMF , "audio" , "cisco-telephone-event" , 8000 );
set_next_mime_type ( NULL , AST_RTP_CN , "audio" , "CN" , 8000 );
set_next_mime_type ( ast_format_set ( & tmpfmt , AST_FORMAT_JPEG , 0 ), 0 , "video" , "JPEG" , 90000 );
set_next_mime_type ( ast_format_set ( & tmpfmt , AST_FORMAT_PNG , 0 ), 0 , "video" , "PNG" , 90000 );
set_next_mime_type ( ast_format_set ( & tmpfmt , AST_FORMAT_H261 , 0 ), 0 , "video" , "H261" , 90000 );
set_next_mime_type ( ast_format_set ( & tmpfmt , AST_FORMAT_H263 , 0 ), 0 , "video" , "H263" , 90000 );
set_next_mime_type ( ast_format_set ( & tmpfmt , AST_FORMAT_H263_PLUS , 0 ), 0 , "video" , "h263-1998" , 90000 );
set_next_mime_type ( ast_format_set ( & tmpfmt , AST_FORMAT_H264 , 0 ), 0 , "video" , "H264" , 90000 );
set_next_mime_type ( ast_format_set ( & tmpfmt , AST_FORMAT_MP4_VIDEO , 0 ), 0 , "video" , "MP4V-ES" , 90000 );
set_next_mime_type ( ast_format_set ( & tmpfmt , AST_FORMAT_T140RED , 0 ), 0 , "text" , "RED" , 1000 );
set_next_mime_type ( ast_format_set ( & tmpfmt , AST_FORMAT_T140 , 0 ), 0 , "text" , "T140" , 1000 );
set_next_mime_type ( ast_format_set ( & tmpfmt , AST_FORMAT_SIREN7 , 0 ), 0 , "audio" , "G7221" , 16000 );
set_next_mime_type ( ast_format_set ( & tmpfmt , AST_FORMAT_SIREN14 , 0 ), 0 , "audio" , "G7221" , 32000 );
set_next_mime_type ( ast_format_set ( & tmpfmt , AST_FORMAT_G719 , 0 ), 0 , "audio" , "G719" , 48000 );
/* Define the static rtp payload mappings */
add_static_payload ( 0 , ast_format_set ( & tmpfmt , AST_FORMAT_ULAW , 0 ), 0 );
#ifdef USE_DEPRECATED_G726
add_static_payload ( 2 , ast_format_set ( & tmpfmt , AST_FORMAT_G726 , 0 ), 0 ); /* Technically this is G.721, but if Cisco can do it, so can we... */
#endif
add_static_payload ( 3 , ast_format_set ( & tmpfmt , AST_FORMAT_GSM , 0 ), 0 );
add_static_payload ( 4 , ast_format_set ( & tmpfmt , AST_FORMAT_G723_1 , 0 ), 0 );
add_static_payload ( 5 , ast_format_set ( & tmpfmt , AST_FORMAT_ADPCM , 0 ), 0 ); /* 8 kHz */
add_static_payload ( 6 , ast_format_set ( & tmpfmt , AST_FORMAT_ADPCM , 0 ), 0 ); /* 16 kHz */
add_static_payload ( 7 , ast_format_set ( & tmpfmt , AST_FORMAT_LPC10 , 0 ), 0 );
add_static_payload ( 8 , ast_format_set ( & tmpfmt , AST_FORMAT_ALAW , 0 ), 0 );
add_static_payload ( 9 , ast_format_set ( & tmpfmt , AST_FORMAT_G722 , 0 ), 0 );
add_static_payload ( 10 , ast_format_set ( & tmpfmt , AST_FORMAT_SLINEAR , 0 ), 0 ); /* 2 channels */
add_static_payload ( 11 , ast_format_set ( & tmpfmt , AST_FORMAT_SLINEAR , 0 ), 0 ); /* 1 channel */
add_static_payload ( 13 , NULL , AST_RTP_CN );
add_static_payload ( 16 , ast_format_set ( & tmpfmt , AST_FORMAT_ADPCM , 0 ), 0 ); /* 11.025 kHz */
add_static_payload ( 17 , ast_format_set ( & tmpfmt , AST_FORMAT_ADPCM , 0 ), 0 ); /* 22.050 kHz */
add_static_payload ( 18 , ast_format_set ( & tmpfmt , AST_FORMAT_G729A , 0 ), 0 );
add_static_payload ( 19 , NULL , AST_RTP_CN ); /* Also used for CN */
add_static_payload ( 26 , ast_format_set ( & tmpfmt , AST_FORMAT_JPEG , 0 ), 0 );
add_static_payload ( 31 , ast_format_set ( & tmpfmt , AST_FORMAT_H261 , 0 ), 0 );
add_static_payload ( 34 , ast_format_set ( & tmpfmt , AST_FORMAT_H263 , 0 ), 0 );
add_static_payload ( 97 , ast_format_set ( & tmpfmt , AST_FORMAT_ILBC , 0 ), 0 );
add_static_payload ( 98 , ast_format_set ( & tmpfmt , AST_FORMAT_H263_PLUS , 0 ), 0 );
add_static_payload ( 99 , ast_format_set ( & tmpfmt , AST_FORMAT_H264 , 0 ), 0 );
add_static_payload ( 101 , NULL , AST_RTP_DTMF );
add_static_payload ( 102 , ast_format_set ( & tmpfmt , AST_FORMAT_SIREN7 , 0 ), 0 );
add_static_payload ( 103 , ast_format_set ( & tmpfmt , AST_FORMAT_H263_PLUS , 0 ), 0 );
add_static_payload ( 104 , ast_format_set ( & tmpfmt , AST_FORMAT_MP4_VIDEO , 0 ), 0 );
add_static_payload ( 105 , ast_format_set ( & tmpfmt , AST_FORMAT_T140RED , 0 ), 0 ); /* Real time text chat (with redundancy encoding) */
add_static_payload ( 106 , ast_format_set ( & tmpfmt , AST_FORMAT_T140 , 0 ), 0 ); /* Real time text chat */
add_static_payload ( 110 , ast_format_set ( & tmpfmt , AST_FORMAT_SPEEX , 0 ), 0 );
add_static_payload ( 111 , ast_format_set ( & tmpfmt , AST_FORMAT_G726 , 0 ), 0 );
add_static_payload ( 112 , ast_format_set ( & tmpfmt , AST_FORMAT_G726_AAL2 , 0 ), 0 );
add_static_payload ( 115 , ast_format_set ( & tmpfmt , AST_FORMAT_SIREN14 , 0 ), 0 );
add_static_payload ( 116 , ast_format_set ( & tmpfmt , AST_FORMAT_G719 , 0 ), 0 );
add_static_payload ( 117 , ast_format_set ( & tmpfmt , AST_FORMAT_SPEEX16 , 0 ), 0 );
add_static_payload ( 118 , ast_format_set ( & tmpfmt , AST_FORMAT_SLINEAR16 , 0 ), 0 ); /* 16 Khz signed linear */
add_static_payload ( 119 , ast_format_set ( & tmpfmt , AST_FORMAT_SPEEX32 , 0 ), 0 );
add_static_payload ( 121 , NULL , AST_RTP_CISCO_DTMF ); /* Must be type 121 */
return 0 ;
}