]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
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 74c59822e924f1d0ed32e306e61a3d95302ad50d..940653825b885c3063fee4f543cc7067db4e3b42 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 3d16ab92f65e6fa13f3d283d3093d48fe09736e8..e42a29a2e62e88c8aa0b7992220f1ead546d398b 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 0160e3b951fc042e81d79926402318405a77d7e0..bcc533a95aa0669f68640e58275177688d53b371 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 6780c2adc97f97d52d9b752a03183a8b8a1dd8ca..c332159ecca6ef12651bd3148f6ee81077f789c8 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 07714e07f185babd5b1d6639048e86e718dccb96..be18148a38baa623c2763d7857712d0e3a617be4 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 9813ff9962d07f23b0e6052a8e4fe1283c815732..5d426fe5262f39802a105fb22fa01c08dcbb2ffd 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);