--- include/asterisk/rtp.h (svn) +++ include/asterisk/rtp.h (working copy) @@ -198,6 +198,8 @@ int ast_rtp_reload(void); +int ast_rtp_set_framems(struct ast_rtp *rtp, int ms); + #if defined(__cplusplus) || defined(c_plusplus) } #endif --- include/asterisk/frame.h (svn) +++ include/asterisk/frame.h (working copy) @@ -270,6 +270,7 @@ }; #define AST_SMOOTHER_FLAG_G729 (1 << 0) +#define AST_SMOOTHER_FLAG_BE (1 << 1) /* Option identifiers and flags */ #define AST_OPTION_FLAG_REQUEST 0 @@ -445,6 +446,7 @@ void ast_smoother_reset(struct ast_smoother *s, int bytes); int __ast_smoother_feed(struct ast_smoother *s, struct ast_frame *f, int swap); struct ast_frame *ast_smoother_read(struct ast_smoother *s); +extern int ast_smoother_test_flag(struct ast_smoother *s, int flag); #define ast_smoother_feed(s,f) __ast_smoother_feed(s, f, 0) #if __BYTE_ORDER == __LITTLE_ENDIAN #define ast_smoother_feed_be(s,f) __ast_smoother_feed(s, f, 1) --- channels/chan_sip.c (svn) +++ channels/chan_sip.c (working copy) @@ -459,6 +459,7 @@ static int srvlookup; /*!< SRV Lookup on or off. Default is off, RFC behavior is on */ static int pedanticsipchecking; /*!< Extra checking ? Default off */ static int autocreatepeer; /*!< Auto creation of peers at registration? Default off. */ +static int global_framems = 0; static int global_relaxdtmf; /*!< Relax DTMF */ static int global_rtptimeout; /*!< Time out call if no RTP */ static int global_rtpholdtimeout; @@ -857,6 +858,8 @@ struct ast_variable *chanvars; /*!< Channel variables to set for inbound call */ struct sip_pvt *next; /*!< Next dialog in chain */ struct sip_invite_param *options; /*!< Options for INVITE */ + int framems; /*!< Packetization */ + struct ast_jb_conf jbconf; } *iflist = NULL; #define FLAG_RESPONSE (1 << 0) @@ -904,6 +907,7 @@ enum transfermodes allowtransfer; /*! SIP Refer restriction scheme */ struct ast_ha *ha; /*!< ACL setting */ struct ast_variable *chanvars; /*!< Variables to set for channel created by user */ + int framems; /*!< Packetization */ int maxcallbitrate; /*!< Maximum Bitrate for a video call */ }; @@ -965,6 +969,7 @@ struct ast_variable *chanvars; /*!< Variables to set for channel created by user */ struct sip_pvt *mwipvt; /*!< Subscription for MWI */ int lastmsg; + int framems; /* Packetization */ }; @@ -2252,6 +2257,12 @@ ast_rtp_setnat(r->vrtp, natflags); ast_rtp_setdtmf(r->vrtp, 0); } + r->framems = peer->framems; + /* Set Frame packetization, use default if it doesn't exist. */ + if (r->rtp && r->framems) { + ast_rtp_set_framems(r->rtp, r->framems); + } + ast_string_field_set(r, peername, peer->username); ast_string_field_set(r, authname, peer->username); ast_string_field_set(r, username, peer->username); @@ -7156,6 +7167,12 @@ ASTOBJ_UNREF(peer, sip_destroy_peer); } if (peer) { + p->framems = peer->framems; + /* Set Frame packetization, use default if it doesn't exist. */ + if (p->rtp && p->framems) { + ast_rtp_set_framems(p->rtp, p->framems); + } + if (!ast_test_flag(&peer->flags[1], SIP_PAGE2_DYNAMIC)) { ast_log(LOG_ERROR, "Peer '%s' is trying to register, but not configured as host=dynamic\n", peer->name); } else { @@ -7883,6 +7900,12 @@ } } p->prefs = user->prefs; + p->framems = user->framems; + /* Set Frame packetization, use default if it doesn't exist. */ + if (p->rtp && p->framems) { + ast_rtp_set_framems(p->rtp, p->framems); + } + /* replace callerid if rpid found, and not restricted */ if (!ast_strlen_zero(rpid_num) && ast_test_flag(&p->flags[0], SIP_TRUSTRPID)) { char *tmp; @@ -7984,6 +8007,12 @@ peer = find_peer(NULL, &p->recv, 1); if (peer) { + p->framems = peer->framems; + /* Set Frame packetization, use default if it doesn't exist. */ + if (p->rtp && p->framems) { + ast_rtp_set_framems(p->rtp, p->framems); + } + if (debug) ast_verbose("Found peer '%s'\n", peer->name); @@ -8930,6 +8959,7 @@ ast_cli(fd, "%s\n",status); ast_cli(fd, " Useragent : %s\n", peer->useragent); ast_cli(fd, " Reg. Contact : %s\n", peer->fullcontact); + ast_cli(fd, " Packetization: %d\n", peer->framems); if (peer->chanvars) { ast_cli(fd, " Variables :\n"); for (v = peer->chanvars ; v ; v = v->next) @@ -14031,6 +14061,7 @@ if (!(user = ast_calloc(1, sizeof(*user)))) return NULL; + user->framems = global_framems; suserobjs++; ASTOBJ_INIT(user); ast_copy_string(user->name, name, sizeof(user->name)); @@ -14099,6 +14130,8 @@ ast_parse_allow_disallow(&user->prefs, &user->capability, v->value, 1); } else if (!strcasecmp(v->name, "disallow")) { ast_parse_allow_disallow(&user->prefs, &user->capability, v->value, 0); + } else if (!strcasecmp(v->name, "packetization")) { + user->framems = atoi(v->value); } else if (!strcasecmp(v->name, "callingpres")) { user->callingpres = ast_parse_caller_presentation(v->value); if (user->callingpres == -1) @@ -14137,6 +14170,7 @@ peer->addr.sin_family = AF_INET; peer->defaddr.sin_family = AF_INET; peer->capability = global_capability; + peer->framems = global_framems; peer->maxcallbitrate = default_maxcallbitrate; peer->rtptimeout = global_rtptimeout; peer->rtpholdtimeout = global_rtpholdtimeout; @@ -14209,6 +14243,8 @@ if (!(peer = ast_calloc(1, sizeof(*peer)))) return NULL; + peer->framems = global_framems; + if (realtime) rpeerobjs++; else @@ -14260,6 +14296,8 @@ ast_set2_flag(&peer->flags[0], ast_true(v->value), SIP_USEREQPHONE); } else if (!strcasecmp(v->name, "fromuser")) { ast_copy_string(peer->fromuser, v->value, sizeof(peer->fromuser)); + } else if (!strcasecmp(v->name, "packetization")) { + peer->framems = atoi(v->value); } else if (!strcasecmp(v->name, "host") || !strcasecmp(v->name, "outboundproxy")) { if (!strcasecmp(v->value, "dynamic")) { if (!strcasecmp(v->name, "outboundproxy") || obproxyfound) { @@ -14550,6 +14588,8 @@ ast_log(LOG_DEBUG, "Setting SIP channel User-Agent Name to %s\n", global_useragent); } else if (!strcasecmp(v->name, "allowtransfer")) { global_allowtransfer = ast_true(v->value) ? TRANSFER_OPENFORALL : TRANSFER_CLOSED; + } else if (!strcasecmp(v->name, "packetization")) { + global_framems = atoi(v->value); } else if (!strcasecmp(v->name, "rtcachefriends")) { ast_set2_flag(&global_flags[1], ast_true(v->value), SIP_PAGE2_RTCACHEFRIENDS); } else if (!strcasecmp(v->name, "rtupdate")) { --- rtp.c (svn) +++ rtp.c (working copy) @@ -121,6 +121,8 @@ int dtmfcount; unsigned int dtmfduration; int nat; + int framems; + int rtplen; unsigned int flags; struct sockaddr_in us; /*!< Socket representation of the local endpoint. */ struct sockaddr_in them; /*!< Socket representation of the remote endpoint. */ @@ -462,6 +464,51 @@ /*! \brief List of current sessions */ static AST_LIST_HEAD_STATIC(protos, ast_rtp_protocol); +struct rtp_codec_table { + int format; + int len; + int defaultms; + int increment; + unsigned int flags; +}; + +struct rtp_codec_table RTP_CODEC_TABLE[] = { + {AST_FORMAT_SLINEAR, 160, 20, 10, AST_SMOOTHER_FLAG_BE}, + {AST_FORMAT_ULAW, 80, 20, 10}, + {AST_FORMAT_ALAW, 80, 20, 10}, + {AST_FORMAT_G726, 40, 20, 10}, + {AST_FORMAT_ILBC, 50, 30, 30}, + {AST_FORMAT_G729A, 10, 20, 10, AST_SMOOTHER_FLAG_G729}, + {AST_FORMAT_GSM, 33, 20, 20}, + {0,0,0,0,0} +}; + +static struct rtp_codec_table *lookup_rtp_smoother_codec(int format, int *ms, int *len) +{ + int x; + int res; + struct rtp_codec_table *ent = NULL; + + *len = 0; + for(x = 0 ; RTP_CODEC_TABLE[x].format ; x++) { + if (RTP_CODEC_TABLE[x].format == format) { + ent = &RTP_CODEC_TABLE[x]; + if (! *ms) { + *ms = ent->defaultms; + } + while((res = (*ms % ent->increment))) { + (*ms)++; + } + while((*len = (*ms / ent->increment) * ent->len) > RTP_MTU) { + *ms -= ent->increment; + } + break; + } + } + + return ent; +} + static void timeval2ntp(struct timeval tv, unsigned int *msw, unsigned int *lsw) { unsigned int sec, usec, frac; @@ -508,6 +555,20 @@ rtp->nat = nat; } +int ast_rtp_set_framems(struct ast_rtp *rtp, int ms) +{ + if (ms) { + if (rtp->smoother) { + ast_smoother_free(rtp->smoother); + rtp->smoother = NULL; + } + + rtp->framems = ms; + } + + return rtp->framems; +} + void ast_rtp_setdtmf(struct ast_rtp *rtp, int dtmf) { ast_set2_flag(rtp, dtmf ? 1 : 0, FLAG_HAS_DTMF); @@ -2328,99 +2389,43 @@ rtp->smoother = NULL; } + + if (!rtp->smoother) { + struct rtp_codec_table *ent; + int ms = rtp->framems; + int len; - switch(subclass) { - case AST_FORMAT_SLINEAR: - if (!rtp->smoother) { - rtp->smoother = ast_smoother_new(320); + if ((ent = lookup_rtp_smoother_codec(subclass, &rtp->framems, &len))) { + + if (rtp->framems != ms) { + ast_log(LOG_DEBUG, "Had to change frame MS from %d to %d\n", ms, rtp->framems); + } + + if (!(rtp->smoother = ast_smoother_new(len))) { + ast_log(LOG_WARNING, "Unable to create smoother ms: %d len: %d:(\n", rtp->framems, len); + return -1; + } + + if (ent->flags) { + ast_smoother_set_flags(rtp->smoother, ent->flags); + } + + ast_log(LOG_DEBUG, "Able to create smoother :) ms: %d len %d\n", rtp->framems, len); } - if (!rtp->smoother) { - ast_log(LOG_WARNING, "Unable to create smoother :(\n"); - return -1; + } + + if (rtp->smoother) { + if (ast_smoother_test_flag(rtp->smoother, AST_SMOOTHER_FLAG_BE)) { + ast_smoother_feed_be(rtp->smoother, _f); + } else { + ast_smoother_feed(rtp->smoother, _f); } - ast_smoother_feed_be(rtp->smoother, _f); - - while((f = ast_smoother_read(rtp->smoother))) + + while((f = ast_smoother_read(rtp->smoother))) { ast_rtp_raw_write(rtp, f, codec); - break; - case AST_FORMAT_ULAW: - case AST_FORMAT_ALAW: - if (!rtp->smoother) { - rtp->smoother = ast_smoother_new(160); - } - if (!rtp->smoother) { - ast_log(LOG_WARNING, "Unable to create smoother :(\n"); - return -1; - } - ast_smoother_feed(rtp->smoother, _f); - - while((f = ast_smoother_read(rtp->smoother))) - ast_rtp_raw_write(rtp, f, codec); - break; - case AST_FORMAT_ADPCM: - case AST_FORMAT_G726: - if (!rtp->smoother) { - rtp->smoother = ast_smoother_new(80); - } - if (!rtp->smoother) { - ast_log(LOG_WARNING, "Unable to create smoother :(\n"); - return -1; - } - ast_smoother_feed(rtp->smoother, _f); - - while((f = ast_smoother_read(rtp->smoother))) - ast_rtp_raw_write(rtp, f, codec); - break; - case AST_FORMAT_G729A: - if (!rtp->smoother) { - rtp->smoother = ast_smoother_new(20); - if (rtp->smoother) - ast_smoother_set_flags(rtp->smoother, AST_SMOOTHER_FLAG_G729); - } - if (!rtp->smoother) { - ast_log(LOG_WARNING, "Unable to create g729 smoother :(\n"); - return -1; - } - ast_smoother_feed(rtp->smoother, _f); - - while((f = ast_smoother_read(rtp->smoother))) - ast_rtp_raw_write(rtp, f, codec); - break; - case AST_FORMAT_GSM: - if (!rtp->smoother) { - rtp->smoother = ast_smoother_new(33); - } - if (!rtp->smoother) { - ast_log(LOG_WARNING, "Unable to create GSM smoother :(\n"); - return -1; - } - ast_smoother_feed(rtp->smoother, _f); - while((f = ast_smoother_read(rtp->smoother))) - ast_rtp_raw_write(rtp, f, codec); - break; - case AST_FORMAT_ILBC: - if (!rtp->smoother) { - rtp->smoother = ast_smoother_new(50); - } - if (!rtp->smoother) { - ast_log(LOG_WARNING, "Unable to create ILBC smoother :(\n"); - return -1; - } - ast_smoother_feed(rtp->smoother, _f); - while((f = ast_smoother_read(rtp->smoother))) - ast_rtp_raw_write(rtp, f, codec); - break; - default: - ast_log(LOG_WARNING, "Not sure about sending format %s packets\n", ast_getformatname(subclass)); - /* fall through to... */ - case AST_FORMAT_H261: - case AST_FORMAT_H263: - case AST_FORMAT_H263_PLUS: - case AST_FORMAT_H264: - case AST_FORMAT_G723_1: - case AST_FORMAT_LPC10: - case AST_FORMAT_SPEEX: - /* Don't buffer outgoing frames; send them one-per-packet: */ + } + } else { + /* Don't buffer outgoing frames; send them one-per-packet: */ if (_f->offset < hdrlen) { f = ast_frdup(_f); } else { --- configs/sip.conf.sample (svn) +++ configs/sip.conf.sample (working copy) @@ -116,6 +116,7 @@ ;compactheaders = yes ; send compact sip headers. ;sipdebug = yes ; Turn on SIP debugging by default, from ; the moment the channel loads this configuration +;packetization = 20 ; The global size in ms of the rtp packets ; ;videosupport=yes ; Turn on support for SIP video ;maxcallbitrate=384 ; Maximum bitrate for video calls (default 384 kb/s) @@ -511,8 +512,8 @@ ;disallow=all ;allow=ulaw ; dtmfmode=inband only works with ulaw or alaw! ;progressinband=no ; Polycom phones don't work properly with "never" +;packetization = 20 ; the size in ms of the rtp packets - ;[pingtel] ;type=friend ;secret=blah --- frame.c (svn) +++ frame.c (working copy) @@ -137,6 +137,11 @@ s->flags = flags; } +int ast_smoother_test_flag(struct ast_smoother *s, int flag) +{ + return (s->flags & flag); +} + int __ast_smoother_feed(struct ast_smoother *s, struct ast_frame *f, int swap) { if (f->frametype != AST_FRAME_VOICE) {