allow for packetization on rtp channel drivers, need to add
authorMatt O'Gorman <mogorman@digium.com>
Mon, 18 Sep 2006 23:32:57 +0000 (23:32 +0000)
committerMatt O'Gorman <mogorman@digium.com>
Mon, 18 Sep 2006 23:32:57 +0000 (23:32 +0000)
option for setting our own packetization as apposed to just doing
what is asked.

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@43243 65c4cc65-6c06-0410-ace0-fbb531ad65f3

channels/chan_sip.c
channels/chan_skinny.c
include/asterisk/frame.h
include/asterisk/rtp.h
main/frame.c
main/rtp.c

index 74c5982..9406538 100644 (file)
@@ -543,6 +543,8 @@ static int regobjs = 0;                  /*!< Registry objects */
 
 static struct ast_flags global_flags[2] = {{0}};        /*!< global SIP_ flags */
 
+static int global_autoframing = 0;
+
 /*! \brief Protect the SIP dialog list (of sip_pvt's) */
 AST_MUTEX_DEFINE_STATIC(iflock);
 
@@ -966,6 +968,7 @@ static struct sip_pvt {
        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 autoframing;
 } *iflist = NULL;
 
 #define FLAG_RESPONSE (1 << 0)
@@ -1015,6 +1018,7 @@ struct sip_user {
        struct ast_ha *ha;              /*!< ACL setting */
        struct ast_variable *chanvars;  /*!< Variables to set for channel created by user */
        int maxcallbitrate;             /*!< Maximum Bitrate for a video call */
+       int autoframing;
 };
 
 /*! \brief Structure for SIP peer data, we place calls to peers if registered  or fixed IP address (host) */
@@ -1077,6 +1081,7 @@ struct sip_peer {
        struct ast_variable *chanvars;  /*!<  Variables to set for channel created by user */
        struct sip_pvt *mwipvt;         /*!<  Subscription for MWI */
        int lastmsg;
+       int autoframing;
 };
 
 
@@ -2541,6 +2546,11 @@ static int create_addr_from_peer(struct sip_pvt *dialog, struct sip_peer *peer)
                        ast_log(LOG_DEBUG, "Setting NAT on UDPTL to %s\n", natflags ? "On" : "Off");
                ast_udptl_setnat(dialog->udptl, natflags);
        }
+       /* Set Frame packetization */
+       if (dialog->rtp) {
+               ast_rtp_codec_setpref(dialog->rtp, &dialog->prefs);
+               dialog->autoframing = peer->autoframing;
+       }
        ast_string_field_set(dialog, peername, peer->username);
        ast_string_field_set(dialog, authname, peer->username);
        ast_string_field_set(dialog, username, peer->username);
@@ -4702,6 +4712,8 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req)
         */
        /* XXX This needs to be done per media stream, since it's media stream specific */
        iterator = req->sdp_start;
+       int found_rtpmap_codecs[32];
+       int last_rtpmap_codec=0;
        while ((a = get_sdp_iterate(&iterator, req, "a"))[0] != '\0') {
                char* mimeSubtype = ast_strdupa(a); /* ensures we have enough space */
                if (option_debug > 1) {
@@ -4752,17 +4764,49 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req)
                }  else if (!strcasecmp(a, "sendrecv")) {
                        sendonly = 0;
                        continue;
-               } else if (sscanf(a, "rtpmap: %u %[^/]/", &codec, mimeSubtype) != 2) 
+               } else if (strlen(a) > 5 && !strncasecmp(a, "ptime", 5)) {
+                       char *tmp = strrchr(a, ':');
+                       long int framing = 0;
+                       if (tmp) {
+                               tmp++;
+                               framing = strtol(tmp, NULL, 10);
+                               if (framing == LONG_MIN || framing == LONG_MAX) {
+                                       framing = 0;
+                                       ast_log(LOG_DEBUG, "Can't read framing from SDP: %s\n", a);
+                               }
+                       }
+                       if (framing && last_rtpmap_codec) {
+                               if (p->autoframing || global_autoframing) {
+                                       struct ast_codec_pref *pref = ast_rtp_codec_getpref(p->rtp);
+                                       int codec_n;
+                                       int format = 0;
+                                       for (codec_n = 0; codec_n < last_rtpmap_codec; codec_n++) {
+                                               format = ast_rtp_codec_getformat(found_rtpmap_codecs[codec_n]);
+                                               if (!format)    /* non-codec or not found */
+                                                       continue;
+                                               if (option_debug)
+                                                       ast_log(LOG_DEBUG, "Setting framing for %d to %ld\n", format, framing);
+                                               ast_codec_pref_setsize(pref, format, framing);
+                                       }
+                                       ast_rtp_codec_setpref(p->rtp, pref);
+                               }
+                       }
+                       memset(&found_rtpmap_codecs, 0, sizeof(found_rtpmap_codecs));
+                       last_rtpmap_codec = 0;
                        continue;
-               /* We have a rtpmap to handle */
-               if (debug)
-                       ast_verbose("Found description format %s for ID %d\n", mimeSubtype, codec);
+               } else if (sscanf(a, "rtpmap: %u %[^/]/", &codec, mimeSubtype) == 2) {
+                       /* We have a rtpmap to handle */
+                       if (debug)
+                               ast_verbose("Found description format %s for ID %d\n", mimeSubtype, codec);
+                       found_rtpmap_codecs[last_rtpmap_codec] = codec;
+                       last_rtpmap_codec++;
 
-               /* Note: should really look at the 'freq' and '#chans' params too */
-               ast_rtp_set_rtpmap_type(newaudiortp, codec, "audio", mimeSubtype,
+                       /* Note: should really look at the 'freq' and '#chans' params too */
+                       ast_rtp_set_rtpmap_type(newaudiortp, codec, "audio", mimeSubtype,
                                        ast_test_flag(&p->flags[0], SIP_G726_NONSTANDARD) ? AST_RTP_OPT_G726_NONSTANDARD : 0);
-               if (p->vrtp)
-                       ast_rtp_set_rtpmap_type(newvideortp, codec, "video", mimeSubtype, 0);
+                       if (p->vrtp)
+                               ast_rtp_set_rtpmap_type(newvideortp, codec, "video", mimeSubtype, 0);
+               }
        }
        
        if (udptlportno != -1) {
@@ -5593,12 +5637,19 @@ static void add_codec_to_sdp(const struct sip_pvt *p, int codec, int sample_rate
                             int debug)
 {
        int rtp_code;
+       struct ast_format_list fmt;
+
 
        if (debug)
                ast_verbose("Adding codec 0x%x (%s) to SDP\n", codec, ast_getformatname(codec));
        if ((rtp_code = ast_rtp_lookup_code(p->rtp, 1, codec)) == -1)
                return;
 
+       if (p->rtp) {
+               struct ast_codec_pref *pref = ast_rtp_codec_getpref(p->rtp);
+               fmt = ast_codec_pref_getsize(pref, codec);
+       } else /* I dont see how you couldn't have p->rtp, but good to check for and error out if not there like earlier code */
+               return;
        ast_build_string(m_buf, m_size, " %d", rtp_code);
        ast_build_string(a_buf, a_size, "a=rtpmap:%d %s/%d\r\n", rtp_code,
                         ast_rtp_lookup_mime_subtype(1, codec,
@@ -5608,9 +5659,12 @@ static void add_codec_to_sdp(const struct sip_pvt *p, int codec, int sample_rate
                /* Indicate that we don't support VAD (G.729 annex B) */
                ast_build_string(a_buf, a_size, "a=fmtp:%d annexb=no\r\n", rtp_code);
        } else if (codec == AST_FORMAT_ILBC) {
-               /* Add information about us using only 20 ms packetization */
-               ast_build_string(a_buf, a_size, "a=fmtp:%d mode=20\r\n", rtp_code);
-       
+               /* Add information about us using only 20/30 ms packetization */
+               ast_build_string(a_buf, a_size, "a=fmtp:%d mode=%d\r\n", rtp_code, fmt.cur_ms);
+       }
+
+       if (codec != AST_FORMAT_ILBC) {
+               ast_build_string(a_buf, a_size, "a=ptime:%d\r\n", fmt.cur_ms);
        }
 }
 
@@ -6084,6 +6138,11 @@ static int transmit_response_with_sdp(struct sip_pvt *p, const char *msg, const
        }
        respprep(&resp, p, msg, req);
        if (p->rtp) {
+               if (!p->autoframing && !ast_test_flag(&p->flags[0], SIP_OUTGOING)) {
+                       if (option_debug)
+                               ast_log(LOG_DEBUG, "Setting framing from config on incoming call\n");
+                       ast_rtp_codec_setpref(p->rtp, &p->prefs);
+               }
                try_suggested_sip_codec(p);     
                add_sdp(&resp, p);
        } else 
@@ -7930,6 +7989,11 @@ static enum check_auth_result register_verify(struct sip_pvt *p, struct sockaddr
                        ASTOBJ_UNREF(peer, sip_destroy_peer);
        }
        if (peer) {
+               /* Set Frame packetization */
+               if (p->rtp) {
+                       ast_rtp_codec_setpref(p->rtp, &peer->prefs);
+                       p->autoframing = peer->autoframing;
+               }
                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 {
@@ -8663,6 +8727,11 @@ static enum check_auth_result check_user_full(struct sip_pvt *p, struct sip_requ
                        }
                }
                p->prefs = user->prefs;
+               /* Set Frame packetization */
+               if (p->rtp) {
+                       ast_rtp_codec_setpref(p->rtp, &p->prefs);
+                       p->autoframing = user->autoframing;
+               }
                /* replace callerid if rpid found, and not restricted */
                if (!ast_strlen_zero(rpid_num) && ast_test_flag(&p->flags[0], SIP_TRUSTRPID)) {
                        char *tmp;
@@ -8771,6 +8840,11 @@ static enum check_auth_result check_user_full(struct sip_pvt *p, struct sip_requ
                        peer = find_peer(NULL, &p->recv, 1);
 
                if (peer) {
+                       /* Set Frame packetization */
+                       if (p->rtp) {
+                               ast_rtp_codec_setpref(p->rtp, &peer->prefs);
+                               p->autoframing = peer->autoframing;
+                       }
                        if (debug)
                                ast_verbose("Found peer '%s'\n", peer->name);
 
@@ -9528,6 +9602,7 @@ static void print_codec_to_cli(int fd, struct ast_codec_pref *pref)
                if (!codec)
                        break;
                ast_cli(fd, "%s", ast_getformatname(codec));
+               ast_cli(fd, ":%d", pref->framing[x]);
                if (x < 31 && ast_codec_pref_index(pref, x + 1))
                        ast_cli(fd, ",");
        }
@@ -15167,6 +15242,8 @@ static struct sip_user *build_user(const char *name, struct ast_variable *v, int
                        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, "autoframing")) {
+                       user->autoframing = ast_true(v->value);
                } else if (!strcasecmp(v->name, "callingpres")) {
                        user->callingpres = ast_parse_caller_presentation(v->value);
                        if (user->callingpres == -1)
@@ -15446,6 +15523,8 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str
                        ast_parse_allow_disallow(&peer->prefs, &peer->capability, v->value, 1);
                } else if (!strcasecmp(v->name, "disallow")) {
                        ast_parse_allow_disallow(&peer->prefs, &peer->capability, v->value, 0);
+               } else if (!strcasecmp(v->name, "autoframing")) {
+                       peer->autoframing = ast_true(v->value);
                } else if (!strcasecmp(v->name, "rtptimeout")) {
                        if ((sscanf(v->value, "%d", &peer->rtptimeout) != 1) || (peer->rtptimeout < 0)) {
                                ast_log(LOG_WARNING, "'%s' is not a valid RTP hold time at line %d.  Using default.\n", v->value, v->lineno);
@@ -15807,6 +15886,8 @@ static int reload_config(enum channelreloadreason reason)
                        ast_parse_allow_disallow(&default_prefs, &global_capability, v->value, 1);
                } else if (!strcasecmp(v->name, "disallow")) {
                        ast_parse_allow_disallow(&default_prefs, &global_capability, v->value, 0);
+               } else if (!strcasecmp(v->name, "autoframing")) {
+                       global_autoframing = ast_true(v->value);
                } else if (!strcasecmp(v->name, "allowexternaldomains")) {
                        allow_external_domains = ast_true(v->value);
                } else if (!strcasecmp(v->name, "autodomain")) {
index 3d16ab9..e42a29a 100644 (file)
@@ -81,7 +81,8 @@ static const char tdesc[] = "Skinny Client Control Protocol (Skinny)";
 static const char config[] = "skinny.conf";
 
 /* Just about everybody seems to support ulaw, so make it a nice default */
-static int capability = AST_FORMAT_ULAW;
+static int default_capability = AST_FORMAT_ULAW;
+static struct ast_codec_pref default_prefs;
 
 #define DEFAULT_SKINNY_PORT    2000
 #define DEFAULT_SKINNY_BACKLOG 2
@@ -948,6 +949,7 @@ struct skinny_line {
        int hookstate;
        int nat;
 
+       struct ast_codec_pref prefs;
        struct skinny_subchannel *sub;
        struct skinny_line *next;
        struct skinny_device *parent;
@@ -980,11 +982,13 @@ static struct skinny_device {
        int registered;
        int lastlineinstance;
        int lastcallreference;
+       int capability;
        struct sockaddr_in addr;
        struct in_addr ourip;
        struct skinny_line *lines;
        struct skinny_speeddial *speeddials;
        struct skinny_addon *addons;
+       struct ast_codec_pref prefs;
        struct ast_ha *ha;
        struct skinnysession *session;
        struct skinny_device *next;
@@ -1022,7 +1026,7 @@ static int skinny_senddigit_end(struct ast_channel *ast, char digit);
 static const struct ast_channel_tech skinny_tech = {
        .type = "Skinny",
        .description = tdesc,
-       .capabilities = AST_FORMAT_ULAW,
+       .capabilities = ((AST_FORMAT_MAX_AUDIO << 1) - 1),
        .properties = AST_CHAN_TP_WANTSJITTER | AST_CHAN_TP_CREATESJITTER,
        .requester = skinny_request,
        .call = skinny_call,
@@ -1407,7 +1411,7 @@ static void transmit_connect(struct skinnysession *s, struct skinny_subchannel *
 
        req->data.openreceivechannel.conferenceId = htolel(0);
        req->data.openreceivechannel.partyId = htolel(sub->callid);
-       req->data.openreceivechannel.packets = htolel(20);
+       req->data.openreceivechannel.packets = htolel(l->prefs.framing[0]);
        req->data.openreceivechannel.capability = htolel(convert_cap(l->capability));
        req->data.openreceivechannel.echo = htolel(0);
        req->data.openreceivechannel.bitrate = htolel(0);
@@ -1927,6 +1931,8 @@ static struct skinny_device *build_device(const char *cat, struct ast_variable *
        } else {
                ast_copy_string(d->name, cat, sizeof(d->name));
                d->lastlineinstance = 1;
+               d->capability = default_capability;
+               d->prefs = default_prefs;
                while(v) {
                        if (!strcasecmp(v->name, "host")) {
                                if (ast_get_ip(&d->addr, v->value)) {
@@ -1941,6 +1947,10 @@ static struct skinny_device *build_device(const char *cat, struct ast_variable *
                                d->ha = ast_append_ha(v->name, v->value, d->ha);
                        } else if (!strcasecmp(v->name, "context")) {
                                ast_copy_string(context, v->value, sizeof(context));
+                       } else if (!strcasecmp(v->name, "allow")) {
+                               ast_parse_allow_disallow(&d->prefs, &d->capability, v->value, 1);
+                       } else if (!strcasecmp(v->name, "disallow")) {
+                               ast_parse_allow_disallow(&d->prefs, &d->capability, v->value, 0);
                        } else if (!strcasecmp(v->name, "version")) {
                                ast_copy_string(d->version_id, v->value, sizeof(d->version_id));
                        } else if (!strcasecmp(v->name, "nat")) {
@@ -2040,7 +2050,8 @@ static struct skinny_device *build_device(const char *cat, struct ast_variable *
                                                        ast_verbose(VERBOSE_PREFIX_3 "Setting mailbox '%s' on %s@%s\n", mailbox, d->name, l->name);
                                        }
                                        l->msgstate = -1;
-                                       l->capability = capability;
+                                       l->capability = d->capability;
+                                       l->prefs = d->prefs;
                                        l->parent = d;
                                        if (!strcasecmp(v->name, "trunk")) {
                                                l->type = TYPE_TRUNK;
@@ -2167,6 +2178,10 @@ static void start_rtp(struct skinny_subchannel *sub)
        if (sub->vrtp) {
                ast_rtp_setnat(sub->vrtp, l->nat);
        }
+       /* Set Frame packetization */
+       if (sub->rtp)
+               ast_rtp_codec_setpref(sub->rtp, &l->prefs);
+
        /* Create the RTP connection */
        transmit_connect(d->session, sub);
        ast_mutex_unlock(&sub->lock);
@@ -2680,7 +2695,7 @@ static struct ast_channel *skinny_new(struct skinny_line *l, int state)
                tmp->tech_pvt = sub;
                tmp->nativeformats = l->capability;
                if (!tmp->nativeformats)
-                       tmp->nativeformats = capability;
+                       tmp->nativeformats = default_capability;
                fmt = ast_best_codec(tmp->nativeformats);
                if (skinnydebug)
                        ast_verbose("skinny_new: tmp->nativeformats=%d fmt=%d\n", tmp->nativeformats, fmt);
@@ -3566,7 +3581,7 @@ static int handle_open_receive_channel_ack_message(struct skinny_req *req, struc
        req->data.startmedia.passThruPartyId = htolel(sub->callid);
        req->data.startmedia.remoteIp = htolel(d->ourip.s_addr);
        req->data.startmedia.remotePort = htolel(ntohs(us.sin_port));
-       req->data.startmedia.packetSize = htolel(20);
+       req->data.startmedia.packetSize = htolel(l->prefs.framing[0]);
        req->data.startmedia.payloadType = htolel(convert_cap(l->capability));
        req->data.startmedia.qualifier.precedence = htolel(127);
        req->data.startmedia.qualifier.vad = htolel(0);
@@ -4277,7 +4292,7 @@ static struct ast_channel *skinny_request(const char *type, int format, void *da
        char *dest = data;
 
        oldformat = format;
-       format &= capability;
+       format &= default_capability;
        if (!format) {
                ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%d'\n", format);
                return NULL;
@@ -4308,7 +4323,6 @@ static int reload_config(void)
        int on = 1;
        struct ast_config *cfg;
        struct ast_variable *v;
-       int format;
        char *cat;
        struct skinny_device *d;
        int oldport = ntohs(bindaddr.sin_port);
@@ -4350,19 +4364,9 @@ static int reload_config(void)
                } else if (!strcasecmp(v->name, "dateformat")) {
                        ast_copy_string(date_format, v->value, sizeof(date_format));
                } else if (!strcasecmp(v->name, "allow")) {
-                       format = ast_getformatbyname(v->value);
-                       if (format < 1) {
-                               ast_log(LOG_WARNING, "Cannot allow unknown format '%s'\n", v->value);
-                       } else {
-                               capability |= format;
-                       }
+                       ast_parse_allow_disallow(&default_prefs, &default_capability, v->value, 1);
                } else if (!strcasecmp(v->name, "disallow")) {
-                       format = ast_getformatbyname(v->value);
-                       if (format < 1) {
-                               ast_log(LOG_WARNING, "Cannot disallow unknown format '%s'\n", v->value);
-                       } else {
-                               capability &= ~format;
-                       }
+                       ast_parse_allow_disallow(&default_prefs, &default_capability, v->value, 0);
                } else if (!strcasecmp(v->name, "bindport") || !strcasecmp(v->name, "port")) {
                        if (sscanf(v->value, "%d", &ourport) == 1) {
                                bindaddr.sin_port = htons(ourport);
index 0160e3b..bcc533a 100644 (file)
@@ -38,6 +38,7 @@ extern "C" {
 
 struct ast_codec_pref {
        char order[32];
+       char framing[32];
 };
 
 /*! \page Def_Frame AST Multimedia and signalling frames
@@ -281,6 +282,7 @@ enum ast_control_frame_type {
 };
 
 #define AST_SMOOTHER_FLAG_G729         (1 << 0)
+#define AST_SMOOTHER_FLAG_BE           (1 << 1)
 
 /* Option identifiers and flags */
 #define AST_OPTION_FLAG_REQUEST                0
@@ -346,6 +348,23 @@ struct ast_option_header {
                uint8_t data[0];
 };
 
+
+/*! \brief Definition of supported media formats (codecs) */
+struct ast_format_list {
+       int visible;    /*!< Can we see this entry */
+       int bits;       /*!< bitmask value */
+       char *name;     /*!< short name */
+       char *desc;     /*!< Description */
+       int fr_len;     /*!< Single frame length in bytes */
+       int min_ms;     /*!< Min value */
+       int max_ms;     /*!< Max value */
+       int inc_ms;     /*!< Increment */
+       int def_ms;     /*!< Default value */
+       unsigned int flags;     /*!< Smoother flags */
+       int cur_ms;     /*!< Current value */
+};
+
+
 /*! \brief  Requests a frame to be allocated 
  * 
  * \param source 
@@ -436,6 +455,7 @@ struct ast_format_list *ast_get_format_list(size_t *size);
 struct ast_smoother *ast_smoother_new(int bytes);
 void ast_smoother_set_flags(struct ast_smoother *smoother, int flags);
 int ast_smoother_get_flags(struct ast_smoother *smoother);
+int ast_smoother_test_flag(struct ast_smoother *s, int flag);
 void ast_smoother_free(struct ast_smoother *s);
 void ast_smoother_reset(struct ast_smoother *s, int bytes);
 int __ast_smoother_feed(struct ast_smoother *s, struct ast_frame *f, int swap);
@@ -482,6 +502,14 @@ int ast_codec_pref_append(struct ast_codec_pref *pref, int format);
    the format list is selected, otherwise 0 is returned. */
 int ast_codec_choose(struct ast_codec_pref *pref, int formats, int find_best);
 
+/*! \brief Set packet size for codec
+*/
+int ast_codec_pref_setsize(struct ast_codec_pref *pref, int format, int framems);
+
+/*! \brief Get packet size for codec
+*/
+struct ast_format_list ast_codec_pref_getsize(struct ast_codec_pref *pref, int format);
+
 /*! \brief Parse an "allow" or "deny" line in a channel or device configuration 
         and update the capabilities mask and pref if provided.
        Video codecs are not added to codec preference lists, since we can not transcode
index 6780c2a..c332159 100644 (file)
@@ -210,6 +210,12 @@ void ast_rtp_init(void);
 
 int ast_rtp_reload(void);
 
+int ast_rtp_codec_setpref(struct ast_rtp *rtp, struct ast_codec_pref *prefs);
+
+struct ast_codec_pref *ast_rtp_codec_getpref(struct ast_rtp *rtp);
+
+int ast_rtp_codec_getformat(int pt);
+
 #if defined(__cplusplus) || defined(c_plusplus)
 }
 #endif
index 07714e0..be18148 100644 (file)
@@ -101,24 +101,19 @@ struct ast_smoother {
 };
 
 /*! \brief Definition of supported media formats (codecs) */
-static struct ast_format_list {
-       int visible;    /*!< Can we see this entry */
-       int bits;       /*!< bitmask value */
-       char *name;     /*!< short name */
-       char *desc;     /*!< Description */
-} AST_FORMAT_LIST[] = {                                        /*!< Bit number: comment  - Bit numbers are hard coded in show_codec() */
-       { 1, AST_FORMAT_G723_1 , "g723" , "G.723.1"},   /*!<  1 */
-       { 1, AST_FORMAT_GSM, "gsm" , "GSM"},            /*!<  2: codec_gsm.c */
-       { 1, AST_FORMAT_ULAW, "ulaw", "G.711 u-law" },  /*!<  3: codec_ulaw.c */
-       { 1, AST_FORMAT_ALAW, "alaw", "G.711 A-law" },  /*!<  4: codec_alaw.c */
-       { 1, AST_FORMAT_G726, "g726", "G.726 RFC3551" },/*!<  5: codec_g726.c */
-       { 1, AST_FORMAT_ADPCM, "adpcm" , "ADPCM"},      /*!<  6: codec_adpcm.c */
-       { 1, AST_FORMAT_SLINEAR, "slin",  "16 bit Signed Linear PCM"},  /*!< 7 */
-       { 1, AST_FORMAT_LPC10, "lpc10", "LPC10" },      /*!<  8: codec_lpc10.c */
-       { 1, AST_FORMAT_G729A, "g729", "G.729A" },      /*!<  9: Binary commercial distribution */
-       { 1, AST_FORMAT_SPEEX, "speex", "SpeeX" },      /*!< 10: codec_speex.c */
-       { 1, AST_FORMAT_ILBC, "ilbc", "iLBC"},          /*!< 11: codec_ilbc.c */
-       { 1, AST_FORMAT_G726_AAL2, "g726aal2", "G.726 AAL2" },  /*!<  12: codec_g726.c */
+static struct ast_format_list AST_FORMAT_LIST[] = {                                    /*!< Bit number: comment  - Bit numbers are hard coded in show_codec() */
+       { 1, AST_FORMAT_G723_1 , "g723" , "G.723.1", 24, 30, 300, 30, 30 },     /*!<  1 */
+       { 1, AST_FORMAT_GSM, "gsm" , "GSM", 33, 20, 60, 20, 20 },               /*!<  2: codec_gsm.c */
+       { 1, AST_FORMAT_ULAW, "ulaw", "G.711 u-law", 80, 10, 30, 10, 20 },      /*!<  3: codec_ulaw.c */
+       { 1, AST_FORMAT_ALAW, "alaw", "G.711 A-law", 80, 10, 30, 10, 20 },      /*!<  4: codec_alaw.c */
+       { 1, AST_FORMAT_G726, "g726", "G.726 RFC3551", 40, 10, 50, 10, 20 },/*!<  5: codec_g726.c */
+       { 1, AST_FORMAT_ADPCM, "adpcm" , "ADPCM", 40, 10, 30, 10, 20 }, /*!<  6: codec_adpcm.c */
+       { 1, AST_FORMAT_SLINEAR, "slin", "16 bit Signed Linear PCM", 160, 10, 70, 10, 20, AST_SMOOTHER_FLAG_BE },       /*!< 7 */
+       { 1, AST_FORMAT_LPC10, "lpc10", "LPC10", 7, 20, 20, 20, 20 },   /*!<  8: codec_lpc10.c */ 
+       { 1, AST_FORMAT_G729A, "g729", "G.729A", 10, 10, 230, 10, 20, AST_SMOOTHER_FLAG_G729 }, /*!<  9: Binary commercial distribution */
+       { 1, AST_FORMAT_SPEEX, "speex", "SpeeX", 10, 10, 60, 10, 20 },  /*!< 10: codec_speex.c */
+       { 1, AST_FORMAT_ILBC, "ilbc", "iLBC", 50, 30, 30, 30, 30 },             /*!< 11: codec_ilbc.c */ /* inc=30ms - workaround */
+       { 1, AST_FORMAT_G726_AAL2, "g726aal2", "G.726 AAL2", 40, 10, 50, 10, 20 },      /*!<  12: codec_g726.c */
        { 0, 0, "nothing", "undefined" },
        { 0, 0, "nothing", "undefined" },
        { 0, 0, "nothing", "undefined" },
@@ -164,6 +159,11 @@ void ast_smoother_set_flags(struct ast_smoother *s, int flags)
        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) {
@@ -1099,6 +1099,7 @@ void ast_codec_pref_remove(struct ast_codec_pref *pref, int format)
        struct ast_codec_pref oldorder;
        int x, y = 0;
        int slot;
+       int size;
 
        if(!pref->order[0])
                return;
@@ -1108,10 +1109,13 @@ void ast_codec_pref_remove(struct ast_codec_pref *pref, int format)
 
        for (x = 0; x < sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]); x++) {
                slot = oldorder.order[x];
+               size = oldorder.framing[x];
                if(! slot)
                        break;
-               if(AST_FORMAT_LIST[slot-1].bits != format)
-                       pref->order[y++] = slot;
+               if(AST_FORMAT_LIST[slot-1].bits != format) {
+                       pref->order[y] = slot;
+                       pref->framing[y++] = size;
+               }
        }
        
 }
@@ -1143,6 +1147,84 @@ int ast_codec_pref_append(struct ast_codec_pref *pref, int format)
 }
 
 
+/*! \brief Set packet size for codec */
+int ast_codec_pref_setsize(struct ast_codec_pref *pref, int format, int framems)
+{
+       int x, index = -1;
+
+       for (x = 0; x < sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]); x++) {
+               if(AST_FORMAT_LIST[x].bits == format) {
+                       index = x;
+                       break;
+               }
+       }
+
+       if(index < 0)
+               return -1;
+
+       /* size validation */
+       if(!framems)
+               framems = AST_FORMAT_LIST[index].def_ms;
+
+       if(AST_FORMAT_LIST[index].inc_ms && framems % AST_FORMAT_LIST[index].inc_ms) /* avoid division by zero */
+               framems -= framems % AST_FORMAT_LIST[index].inc_ms;
+
+       if(framems < AST_FORMAT_LIST[index].min_ms)
+               framems = AST_FORMAT_LIST[index].min_ms;
+
+       if(framems > AST_FORMAT_LIST[index].max_ms)
+               framems = AST_FORMAT_LIST[index].max_ms;
+
+
+       for (x = 0; x < sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]); x++) {
+               if(pref->order[x] == (index + 1)) {
+                       pref->framing[x] = framems;
+                       break;
+               }
+       }
+
+       return x;
+}
+
+/*! \brief Get packet size for codec */
+struct ast_format_list ast_codec_pref_getsize(struct ast_codec_pref *pref, int format)
+{
+       int x, index = -1, framems = 0;
+       struct ast_format_list fmt;
+
+       for (x = 0; x < sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]); x++) {
+               if(AST_FORMAT_LIST[x].bits == format) {
+                       fmt = AST_FORMAT_LIST[x];
+                       index = x;
+                       break;
+               }
+       }
+
+       for (x = 0; x < sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]); x++) {
+               if(pref->order[x] == (index + 1)) {
+                       framems = pref->framing[x];
+                       break;
+               }
+       }
+
+       /* size validation */
+       if(!framems)
+               framems = AST_FORMAT_LIST[index].def_ms;
+
+       if(AST_FORMAT_LIST[index].inc_ms && framems % AST_FORMAT_LIST[index].inc_ms) /* avoid division by zero */
+               framems -= framems % AST_FORMAT_LIST[index].inc_ms;
+
+       if(framems < AST_FORMAT_LIST[index].min_ms)
+               framems = AST_FORMAT_LIST[index].min_ms;
+
+       if(framems > AST_FORMAT_LIST[index].max_ms)
+               framems = AST_FORMAT_LIST[index].max_ms;
+
+       fmt.cur_ms = framems;
+
+       return fmt;
+}
+
 /*! \brief Pick a codec */
 int ast_codec_choose(struct ast_codec_pref *pref, int formats, int find_best)
 {
@@ -1172,9 +1254,22 @@ void ast_parse_allow_disallow(struct ast_codec_pref *pref, int *mask, const char
        char *parse;
        char *this;
        int format;
+       char *psize;
+       int framems;
 
        parse = ast_strdupa(list);
        while ((this = strsep(&parse, ","))) {
+               framems = 0;
+               if ((psize = strrchr(this, ':'))) {
+                       *psize = '\0';
+                       psize++;
+                       if (option_debug)
+                               ast_log(LOG_DEBUG,"Packetization for codec: %s is %s\n", this, psize);
+                       framems = strtol(psize,NULL,10);
+                       if (framems == LONG_MIN || framems == LONG_MAX) {
+                               framems = 0;
+                       }
+               }
                if (!(format = ast_getformatbyname(this))) {
                        ast_log(LOG_WARNING, "Cannot %s unknown format '%s'\n", allowing ? "allow" : "disallow", this);
                        continue;
@@ -1192,8 +1287,10 @@ void ast_parse_allow_disallow(struct ast_codec_pref *pref, int *mask, const char
                 */
                if (pref && (format & AST_FORMAT_AUDIO_MASK)) {
                        if (strcasecmp(this, "all")) {
-                               if (allowing)
+                               if (allowing) {
                                        ast_codec_pref_append(pref, format);
+                                       ast_codec_pref_setsize(pref, format, framems);
+                               }
                                else
                                        ast_codec_pref_remove(pref, format);
                        } else if (!allowing) {
index 9813ff9..5d426fe 100644 (file)
@@ -160,6 +160,7 @@ struct ast_rtp {
        int rtp_lookup_code_cache_code;
        int rtp_lookup_code_cache_result;
        struct ast_rtcp *rtcp;
+       struct ast_codec_pref pref;
        struct ast_rtp *bridged;        /*!< Who we are Packet bridged to */
 };
 
@@ -2480,6 +2481,35 @@ static int ast_rtp_raw_write(struct ast_rtp *rtp, struct ast_frame *f, int codec
        return 0;
 }
 
+int ast_rtp_codec_setpref(struct ast_rtp *rtp, struct ast_codec_pref *prefs)
+{
+       int x;
+       for (x = 0; x < 32; x++) {  /* Ugly way */
+               rtp->pref.order[x] = prefs->order[x];
+               rtp->pref.framing[x] = prefs->framing[x];
+       }
+       if (rtp->smoother)
+               ast_smoother_free(rtp->smoother);
+       rtp->smoother = NULL;
+       return 0;
+}
+
+struct ast_codec_pref *ast_rtp_codec_getpref(struct ast_rtp *rtp)
+{
+       return &rtp->pref;
+}
+
+int ast_rtp_codec_getformat(int pt)
+{
+       if (pt < 0 || pt > MAX_RTP_PT)
+               return 0; /* bogus payload type */
+
+       if (static_RTP_PT[pt].isAstFormat)
+               return static_RTP_PT[pt].code;
+       else
+               return 0;
+}
+
 int ast_rtp_write(struct ast_rtp *rtp, struct ast_frame *_f)
 {
        struct ast_frame *f;
@@ -2522,99 +2552,29 @@ int ast_rtp_write(struct ast_rtp *rtp, struct ast_frame *_f)
                rtp->smoother = NULL;
        }
 
-
-       switch(subclass) {
-       case AST_FORMAT_SLINEAR:
-               if (!rtp->smoother) {
-                       rtp->smoother = ast_smoother_new(320);
-               }
-               if (!rtp->smoother) {
-                       ast_log(LOG_WARNING, "Unable to create smoother :(\n");
-                       return -1;
-               }
-               ast_smoother_feed_be(rtp->smoother, _f);
-               
-               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:
-       case AST_FORMAT_G726_AAL2:
-               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) {
+               struct ast_format_list fmt = ast_codec_pref_getsize(&rtp->pref, subclass);
+               if (fmt.inc_ms) { /* if codec parameters is set / avoid division by zero */
+                       if (!(rtp->smoother = ast_smoother_new((fmt.cur_ms * fmt.fr_len) / fmt.inc_ms))) {
+                               ast_log(LOG_WARNING, "Unable to create smoother: format: %d ms: %d len: %d\n", subclass, fmt.cur_ms, ((fmt.cur_ms * fmt.fr_len) / fmt.inc_ms));
+                               return -1;
+                       }
+                       if (fmt.flags)
+                               ast_smoother_set_flags(rtp->smoother, fmt.flags);
+                       if (option_debug)
+                               ast_log(LOG_DEBUG, "Created smoother: format: %d ms: %d len: %d\n", subclass, fmt.cur_ms, ((fmt.cur_ms * fmt.fr_len) / fmt.inc_ms));
                }
-               if (!rtp->smoother) {
-                       ast_log(LOG_WARNING, "Unable to create ILBC 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(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:
+       } else {
                /* Don't buffer outgoing frames; send them one-per-packet: */
                if (_f->offset < hdrlen) {
                        f = ast_frdup(_f);