From 465adf2bf165ad6b27cd2659ad731ff1d24dfed5 Mon Sep 17 00:00:00 2001 From: Matt O'Gorman Date: Mon, 18 Sep 2006 23:32:57 +0000 Subject: allow for packetization on rtp channel drivers, need to add 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 | 103 +++++++++++++++++++++++++++++++---- channels/chan_skinny.c | 44 ++++++++------- include/asterisk/frame.h | 28 ++++++++++ include/asterisk/rtp.h | 6 ++ main/frame.c | 139 ++++++++++++++++++++++++++++++++++++++++------- main/rtp.c | 138 +++++++++++++++++----------------------------- 6 files changed, 317 insertions(+), 141 deletions(-) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 74c59822e..940653825 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -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")) { diff --git a/channels/chan_skinny.c b/channels/chan_skinny.c index 3d16ab92f..e42a29a2e 100644 --- a/channels/chan_skinny.c +++ b/channels/chan_skinny.c @@ -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); diff --git a/include/asterisk/frame.h b/include/asterisk/frame.h index 0160e3b95..bcc533a95 100644 --- a/include/asterisk/frame.h +++ b/include/asterisk/frame.h @@ -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 diff --git a/include/asterisk/rtp.h b/include/asterisk/rtp.h index 6780c2adc..c332159ec 100644 --- a/include/asterisk/rtp.h +++ b/include/asterisk/rtp.h @@ -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 diff --git a/main/frame.c b/main/frame.c index 07714e07f..be18148a3 100644 --- a/main/frame.c +++ b/main/frame.c @@ -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) { diff --git a/main/rtp.c b/main/rtp.c index 9813ff996..5d426fe52 100644 --- a/main/rtp.c +++ b/main/rtp.c @@ -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); -- cgit v1.2.3