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
1.4
Matt O'Gorman 19 years ago
parent 9177d1143b
commit 465adf2bf1

@ -543,6 +543,8 @@ static int regobjs = 0; /*!< Registry objects */
static struct ast_flags global_flags[2] = {{0}}; /*!< global SIP_ flags */ 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) */ /*! \brief Protect the SIP dialog list (of sip_pvt's) */
AST_MUTEX_DEFINE_STATIC(iflock); 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 ast_variable *chanvars; /*!< Channel variables to set for inbound call */
struct sip_pvt *next; /*!< Next dialog in chain */ struct sip_pvt *next; /*!< Next dialog in chain */
struct sip_invite_param *options; /*!< Options for INVITE */ struct sip_invite_param *options; /*!< Options for INVITE */
int autoframing;
} *iflist = NULL; } *iflist = NULL;
#define FLAG_RESPONSE (1 << 0) #define FLAG_RESPONSE (1 << 0)
@ -1015,6 +1018,7 @@ struct sip_user {
struct ast_ha *ha; /*!< ACL setting */ struct ast_ha *ha; /*!< ACL setting */
struct ast_variable *chanvars; /*!< Variables to set for channel created by user */ struct ast_variable *chanvars; /*!< Variables to set for channel created by user */
int maxcallbitrate; /*!< Maximum Bitrate for a video call */ 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) */ /*! \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 ast_variable *chanvars; /*!< Variables to set for channel created by user */
struct sip_pvt *mwipvt; /*!< Subscription for MWI */ struct sip_pvt *mwipvt; /*!< Subscription for MWI */
int lastmsg; 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_log(LOG_DEBUG, "Setting NAT on UDPTL to %s\n", natflags ? "On" : "Off");
ast_udptl_setnat(dialog->udptl, natflags); 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, peername, peer->username);
ast_string_field_set(dialog, authname, peer->username); ast_string_field_set(dialog, authname, peer->username);
ast_string_field_set(dialog, username, 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 */ /* XXX This needs to be done per media stream, since it's media stream specific */
iterator = req->sdp_start; iterator = req->sdp_start;
int found_rtpmap_codecs[32];
int last_rtpmap_codec=0;
while ((a = get_sdp_iterate(&iterator, req, "a"))[0] != '\0') { while ((a = get_sdp_iterate(&iterator, req, "a"))[0] != '\0') {
char* mimeSubtype = ast_strdupa(a); /* ensures we have enough space */ char* mimeSubtype = ast_strdupa(a); /* ensures we have enough space */
if (option_debug > 1) { if (option_debug > 1) {
@ -4752,11 +4764,42 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req)
} else if (!strcasecmp(a, "sendrecv")) { } else if (!strcasecmp(a, "sendrecv")) {
sendonly = 0; sendonly = 0;
continue; 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; 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;
} else if (sscanf(a, "rtpmap: %u %[^/]/", &codec, mimeSubtype) == 2) {
/* We have a rtpmap to handle */ /* We have a rtpmap to handle */
if (debug) if (debug)
ast_verbose("Found description format %s for ID %d\n", mimeSubtype, codec); 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 */ /* Note: should really look at the 'freq' and '#chans' params too */
ast_rtp_set_rtpmap_type(newaudiortp, codec, "audio", mimeSubtype, ast_rtp_set_rtpmap_type(newaudiortp, codec, "audio", mimeSubtype,
@ -4764,6 +4807,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req)
if (p->vrtp) if (p->vrtp)
ast_rtp_set_rtpmap_type(newvideortp, codec, "video", mimeSubtype, 0); ast_rtp_set_rtpmap_type(newvideortp, codec, "video", mimeSubtype, 0);
} }
}
if (udptlportno != -1) { if (udptlportno != -1) {
int found = 0, x; int found = 0, x;
@ -5593,12 +5637,19 @@ static void add_codec_to_sdp(const struct sip_pvt *p, int codec, int sample_rate
int debug) int debug)
{ {
int rtp_code; int rtp_code;
struct ast_format_list fmt;
if (debug) if (debug)
ast_verbose("Adding codec 0x%x (%s) to SDP\n", codec, ast_getformatname(codec)); 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) if ((rtp_code = ast_rtp_lookup_code(p->rtp, 1, codec)) == -1)
return; 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(m_buf, m_size, " %d", rtp_code);
ast_build_string(a_buf, a_size, "a=rtpmap:%d %s/%d\r\n", 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, 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) */ /* 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); ast_build_string(a_buf, a_size, "a=fmtp:%d annexb=no\r\n", rtp_code);
} else if (codec == AST_FORMAT_ILBC) { } else if (codec == AST_FORMAT_ILBC) {
/* Add information about us using only 20 ms packetization */ /* Add information about us using only 20/30 ms packetization */
ast_build_string(a_buf, a_size, "a=fmtp:%d mode=20\r\n", rtp_code); 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); respprep(&resp, p, msg, req);
if (p->rtp) { 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); try_suggested_sip_codec(p);
add_sdp(&resp, p); add_sdp(&resp, p);
} else } else
@ -7930,6 +7989,11 @@ static enum check_auth_result register_verify(struct sip_pvt *p, struct sockaddr
ASTOBJ_UNREF(peer, sip_destroy_peer); ASTOBJ_UNREF(peer, sip_destroy_peer);
} }
if (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)) { 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); ast_log(LOG_ERROR, "Peer '%s' is trying to register, but not configured as host=dynamic\n", peer->name);
} else { } else {
@ -8663,6 +8727,11 @@ static enum check_auth_result check_user_full(struct sip_pvt *p, struct sip_requ
} }
} }
p->prefs = user->prefs; 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 */ /* replace callerid if rpid found, and not restricted */
if (!ast_strlen_zero(rpid_num) && ast_test_flag(&p->flags[0], SIP_TRUSTRPID)) { if (!ast_strlen_zero(rpid_num) && ast_test_flag(&p->flags[0], SIP_TRUSTRPID)) {
char *tmp; 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); peer = find_peer(NULL, &p->recv, 1);
if (peer) { if (peer) {
/* Set Frame packetization */
if (p->rtp) {
ast_rtp_codec_setpref(p->rtp, &peer->prefs);
p->autoframing = peer->autoframing;
}
if (debug) if (debug)
ast_verbose("Found peer '%s'\n", peer->name); 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) if (!codec)
break; break;
ast_cli(fd, "%s", ast_getformatname(codec)); ast_cli(fd, "%s", ast_getformatname(codec));
ast_cli(fd, ":%d", pref->framing[x]);
if (x < 31 && ast_codec_pref_index(pref, x + 1)) if (x < 31 && ast_codec_pref_index(pref, x + 1))
ast_cli(fd, ","); 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); ast_parse_allow_disallow(&user->prefs, &user->capability, v->value, 1);
} else if (!strcasecmp(v->name, "disallow")) { } else if (!strcasecmp(v->name, "disallow")) {
ast_parse_allow_disallow(&user->prefs, &user->capability, v->value, 0); 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")) { } else if (!strcasecmp(v->name, "callingpres")) {
user->callingpres = ast_parse_caller_presentation(v->value); user->callingpres = ast_parse_caller_presentation(v->value);
if (user->callingpres == -1) 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); ast_parse_allow_disallow(&peer->prefs, &peer->capability, v->value, 1);
} else if (!strcasecmp(v->name, "disallow")) { } else if (!strcasecmp(v->name, "disallow")) {
ast_parse_allow_disallow(&peer->prefs, &peer->capability, v->value, 0); 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")) { } else if (!strcasecmp(v->name, "rtptimeout")) {
if ((sscanf(v->value, "%d", &peer->rtptimeout) != 1) || (peer->rtptimeout < 0)) { 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); 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); ast_parse_allow_disallow(&default_prefs, &global_capability, v->value, 1);
} else if (!strcasecmp(v->name, "disallow")) { } else if (!strcasecmp(v->name, "disallow")) {
ast_parse_allow_disallow(&default_prefs, &global_capability, v->value, 0); 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")) { } else if (!strcasecmp(v->name, "allowexternaldomains")) {
allow_external_domains = ast_true(v->value); allow_external_domains = ast_true(v->value);
} else if (!strcasecmp(v->name, "autodomain")) { } else if (!strcasecmp(v->name, "autodomain")) {

@ -81,7 +81,8 @@ static const char tdesc[] = "Skinny Client Control Protocol (Skinny)";
static const char config[] = "skinny.conf"; static const char config[] = "skinny.conf";
/* Just about everybody seems to support ulaw, so make it a nice default */ /* 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_PORT 2000
#define DEFAULT_SKINNY_BACKLOG 2 #define DEFAULT_SKINNY_BACKLOG 2
@ -948,6 +949,7 @@ struct skinny_line {
int hookstate; int hookstate;
int nat; int nat;
struct ast_codec_pref prefs;
struct skinny_subchannel *sub; struct skinny_subchannel *sub;
struct skinny_line *next; struct skinny_line *next;
struct skinny_device *parent; struct skinny_device *parent;
@ -980,11 +982,13 @@ static struct skinny_device {
int registered; int registered;
int lastlineinstance; int lastlineinstance;
int lastcallreference; int lastcallreference;
int capability;
struct sockaddr_in addr; struct sockaddr_in addr;
struct in_addr ourip; struct in_addr ourip;
struct skinny_line *lines; struct skinny_line *lines;
struct skinny_speeddial *speeddials; struct skinny_speeddial *speeddials;
struct skinny_addon *addons; struct skinny_addon *addons;
struct ast_codec_pref prefs;
struct ast_ha *ha; struct ast_ha *ha;
struct skinnysession *session; struct skinnysession *session;
struct skinny_device *next; 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 = { static const struct ast_channel_tech skinny_tech = {
.type = "Skinny", .type = "Skinny",
.description = tdesc, .description = tdesc,
.capabilities = AST_FORMAT_ULAW, .capabilities = ((AST_FORMAT_MAX_AUDIO << 1) - 1),
.properties = AST_CHAN_TP_WANTSJITTER | AST_CHAN_TP_CREATESJITTER, .properties = AST_CHAN_TP_WANTSJITTER | AST_CHAN_TP_CREATESJITTER,
.requester = skinny_request, .requester = skinny_request,
.call = skinny_call, .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.conferenceId = htolel(0);
req->data.openreceivechannel.partyId = htolel(sub->callid); 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.capability = htolel(convert_cap(l->capability));
req->data.openreceivechannel.echo = htolel(0); req->data.openreceivechannel.echo = htolel(0);
req->data.openreceivechannel.bitrate = 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 { } else {
ast_copy_string(d->name, cat, sizeof(d->name)); ast_copy_string(d->name, cat, sizeof(d->name));
d->lastlineinstance = 1; d->lastlineinstance = 1;
d->capability = default_capability;
d->prefs = default_prefs;
while(v) { while(v) {
if (!strcasecmp(v->name, "host")) { if (!strcasecmp(v->name, "host")) {
if (ast_get_ip(&d->addr, v->value)) { 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); d->ha = ast_append_ha(v->name, v->value, d->ha);
} else if (!strcasecmp(v->name, "context")) { } else if (!strcasecmp(v->name, "context")) {
ast_copy_string(context, v->value, sizeof(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")) { } else if (!strcasecmp(v->name, "version")) {
ast_copy_string(d->version_id, v->value, sizeof(d->version_id)); ast_copy_string(d->version_id, v->value, sizeof(d->version_id));
} else if (!strcasecmp(v->name, "nat")) { } 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); ast_verbose(VERBOSE_PREFIX_3 "Setting mailbox '%s' on %s@%s\n", mailbox, d->name, l->name);
} }
l->msgstate = -1; l->msgstate = -1;
l->capability = capability; l->capability = d->capability;
l->prefs = d->prefs;
l->parent = d; l->parent = d;
if (!strcasecmp(v->name, "trunk")) { if (!strcasecmp(v->name, "trunk")) {
l->type = TYPE_TRUNK; l->type = TYPE_TRUNK;
@ -2167,6 +2178,10 @@ static void start_rtp(struct skinny_subchannel *sub)
if (sub->vrtp) { if (sub->vrtp) {
ast_rtp_setnat(sub->vrtp, l->nat); 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 */ /* Create the RTP connection */
transmit_connect(d->session, sub); transmit_connect(d->session, sub);
ast_mutex_unlock(&sub->lock); 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->tech_pvt = sub;
tmp->nativeformats = l->capability; tmp->nativeformats = l->capability;
if (!tmp->nativeformats) if (!tmp->nativeformats)
tmp->nativeformats = capability; tmp->nativeformats = default_capability;
fmt = ast_best_codec(tmp->nativeformats); fmt = ast_best_codec(tmp->nativeformats);
if (skinnydebug) if (skinnydebug)
ast_verbose("skinny_new: tmp->nativeformats=%d fmt=%d\n", tmp->nativeformats, fmt); 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.passThruPartyId = htolel(sub->callid);
req->data.startmedia.remoteIp = htolel(d->ourip.s_addr); req->data.startmedia.remoteIp = htolel(d->ourip.s_addr);
req->data.startmedia.remotePort = htolel(ntohs(us.sin_port)); 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.payloadType = htolel(convert_cap(l->capability));
req->data.startmedia.qualifier.precedence = htolel(127); req->data.startmedia.qualifier.precedence = htolel(127);
req->data.startmedia.qualifier.vad = htolel(0); 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; char *dest = data;
oldformat = format; oldformat = format;
format &= capability; format &= default_capability;
if (!format) { if (!format) {
ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%d'\n", format); ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%d'\n", format);
return NULL; return NULL;
@ -4308,7 +4323,6 @@ static int reload_config(void)
int on = 1; int on = 1;
struct ast_config *cfg; struct ast_config *cfg;
struct ast_variable *v; struct ast_variable *v;
int format;
char *cat; char *cat;
struct skinny_device *d; struct skinny_device *d;
int oldport = ntohs(bindaddr.sin_port); int oldport = ntohs(bindaddr.sin_port);
@ -4350,19 +4364,9 @@ static int reload_config(void)
} else if (!strcasecmp(v->name, "dateformat")) { } else if (!strcasecmp(v->name, "dateformat")) {
ast_copy_string(date_format, v->value, sizeof(date_format)); ast_copy_string(date_format, v->value, sizeof(date_format));
} else if (!strcasecmp(v->name, "allow")) { } else if (!strcasecmp(v->name, "allow")) {
format = ast_getformatbyname(v->value); ast_parse_allow_disallow(&default_prefs, &default_capability, v->value, 1);
if (format < 1) {
ast_log(LOG_WARNING, "Cannot allow unknown format '%s'\n", v->value);
} else {
capability |= format;
}
} else if (!strcasecmp(v->name, "disallow")) { } else if (!strcasecmp(v->name, "disallow")) {
format = ast_getformatbyname(v->value); ast_parse_allow_disallow(&default_prefs, &default_capability, v->value, 0);
if (format < 1) {
ast_log(LOG_WARNING, "Cannot disallow unknown format '%s'\n", v->value);
} else {
capability &= ~format;
}
} else if (!strcasecmp(v->name, "bindport") || !strcasecmp(v->name, "port")) { } else if (!strcasecmp(v->name, "bindport") || !strcasecmp(v->name, "port")) {
if (sscanf(v->value, "%d", &ourport) == 1) { if (sscanf(v->value, "%d", &ourport) == 1) {
bindaddr.sin_port = htons(ourport); bindaddr.sin_port = htons(ourport);

@ -38,6 +38,7 @@ extern "C" {
struct ast_codec_pref { struct ast_codec_pref {
char order[32]; char order[32];
char framing[32];
}; };
/*! \page Def_Frame AST Multimedia and signalling frames /*! \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_G729 (1 << 0)
#define AST_SMOOTHER_FLAG_BE (1 << 1)
/* Option identifiers and flags */ /* Option identifiers and flags */
#define AST_OPTION_FLAG_REQUEST 0 #define AST_OPTION_FLAG_REQUEST 0
@ -346,6 +348,23 @@ struct ast_option_header {
uint8_t data[0]; 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 /*! \brief Requests a frame to be allocated
* *
* \param source * \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); struct ast_smoother *ast_smoother_new(int bytes);
void ast_smoother_set_flags(struct ast_smoother *smoother, int flags); void ast_smoother_set_flags(struct ast_smoother *smoother, int flags);
int ast_smoother_get_flags(struct ast_smoother *smoother); 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_free(struct ast_smoother *s);
void ast_smoother_reset(struct ast_smoother *s, int bytes); void ast_smoother_reset(struct ast_smoother *s, int bytes);
int __ast_smoother_feed(struct ast_smoother *s, struct ast_frame *f, int swap); 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. */ the format list is selected, otherwise 0 is returned. */
int ast_codec_choose(struct ast_codec_pref *pref, int formats, int find_best); 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 /*! \brief Parse an "allow" or "deny" line in a channel or device configuration
and update the capabilities mask and pref if provided. and update the capabilities mask and pref if provided.
Video codecs are not added to codec preference lists, since we can not transcode Video codecs are not added to codec preference lists, since we can not transcode

@ -210,6 +210,12 @@ void ast_rtp_init(void);
int ast_rtp_reload(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) #if defined(__cplusplus) || defined(c_plusplus)
} }
#endif #endif

@ -101,24 +101,19 @@ struct ast_smoother {
}; };
/*! \brief Definition of supported media formats (codecs) */ /*! \brief Definition of supported media formats (codecs) */
static struct ast_format_list { static struct ast_format_list AST_FORMAT_LIST[] = { /*!< Bit number: comment - Bit numbers are hard coded in show_codec() */
int visible; /*!< Can we see this entry */ { 1, AST_FORMAT_G723_1 , "g723" , "G.723.1", 24, 30, 300, 30, 30 }, /*!< 1 */
int bits; /*!< bitmask value */ { 1, AST_FORMAT_GSM, "gsm" , "GSM", 33, 20, 60, 20, 20 }, /*!< 2: codec_gsm.c */
char *name; /*!< short name */ { 1, AST_FORMAT_ULAW, "ulaw", "G.711 u-law", 80, 10, 30, 10, 20 }, /*!< 3: codec_ulaw.c */
char *desc; /*!< Description */ { 1, AST_FORMAT_ALAW, "alaw", "G.711 A-law", 80, 10, 30, 10, 20 }, /*!< 4: codec_alaw.c */
} AST_FORMAT_LIST[] = { /*!< Bit number: comment - Bit numbers are hard coded in show_codec() */ { 1, AST_FORMAT_G726, "g726", "G.726 RFC3551", 40, 10, 50, 10, 20 },/*!< 5: codec_g726.c */
{ 1, AST_FORMAT_G723_1 , "g723" , "G.723.1"}, /*!< 1 */ { 1, AST_FORMAT_ADPCM, "adpcm" , "ADPCM", 40, 10, 30, 10, 20 }, /*!< 6: codec_adpcm.c */
{ 1, AST_FORMAT_GSM, "gsm" , "GSM"}, /*!< 2: codec_gsm.c */ { 1, AST_FORMAT_SLINEAR, "slin", "16 bit Signed Linear PCM", 160, 10, 70, 10, 20, AST_SMOOTHER_FLAG_BE }, /*!< 7 */
{ 1, AST_FORMAT_ULAW, "ulaw", "G.711 u-law" }, /*!< 3: codec_ulaw.c */ { 1, AST_FORMAT_LPC10, "lpc10", "LPC10", 7, 20, 20, 20, 20 }, /*!< 8: codec_lpc10.c */
{ 1, AST_FORMAT_ALAW, "alaw", "G.711 A-law" }, /*!< 4: codec_alaw.c */ { 1, AST_FORMAT_G729A, "g729", "G.729A", 10, 10, 230, 10, 20, AST_SMOOTHER_FLAG_G729 }, /*!< 9: Binary commercial distribution */
{ 1, AST_FORMAT_G726, "g726", "G.726 RFC3551" },/*!< 5: codec_g726.c */ { 1, AST_FORMAT_SPEEX, "speex", "SpeeX", 10, 10, 60, 10, 20 }, /*!< 10: codec_speex.c */
{ 1, AST_FORMAT_ADPCM, "adpcm" , "ADPCM"}, /*!< 6: codec_adpcm.c */ { 1, AST_FORMAT_ILBC, "ilbc", "iLBC", 50, 30, 30, 30, 30 }, /*!< 11: codec_ilbc.c */ /* inc=30ms - workaround */
{ 1, AST_FORMAT_SLINEAR, "slin", "16 bit Signed Linear PCM"}, /*!< 7 */ { 1, AST_FORMAT_G726_AAL2, "g726aal2", "G.726 AAL2", 40, 10, 50, 10, 20 }, /*!< 12: codec_g726.c */
{ 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 */
{ 0, 0, "nothing", "undefined" }, { 0, 0, "nothing", "undefined" },
{ 0, 0, "nothing", "undefined" }, { 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; 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) int __ast_smoother_feed(struct ast_smoother *s, struct ast_frame *f, int swap)
{ {
if (f->frametype != AST_FRAME_VOICE) { 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; struct ast_codec_pref oldorder;
int x, y = 0; int x, y = 0;
int slot; int slot;
int size;
if(!pref->order[0]) if(!pref->order[0])
return; 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++) { for (x = 0; x < sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]); x++) {
slot = oldorder.order[x]; slot = oldorder.order[x];
size = oldorder.framing[x];
if(! slot) if(! slot)
break; break;
if(AST_FORMAT_LIST[slot-1].bits != format) if(AST_FORMAT_LIST[slot-1].bits != format) {
pref->order[y++] = slot; 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 */ /*! \brief Pick a codec */
int ast_codec_choose(struct ast_codec_pref *pref, int formats, int find_best) 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 *parse;
char *this; char *this;
int format; int format;
char *psize;
int framems;
parse = ast_strdupa(list); parse = ast_strdupa(list);
while ((this = strsep(&parse, ","))) { 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))) { if (!(format = ast_getformatbyname(this))) {
ast_log(LOG_WARNING, "Cannot %s unknown format '%s'\n", allowing ? "allow" : "disallow", this); ast_log(LOG_WARNING, "Cannot %s unknown format '%s'\n", allowing ? "allow" : "disallow", this);
continue; 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 (pref && (format & AST_FORMAT_AUDIO_MASK)) {
if (strcasecmp(this, "all")) { if (strcasecmp(this, "all")) {
if (allowing) if (allowing) {
ast_codec_pref_append(pref, format); ast_codec_pref_append(pref, format);
ast_codec_pref_setsize(pref, format, framems);
}
else else
ast_codec_pref_remove(pref, format); ast_codec_pref_remove(pref, format);
} else if (!allowing) { } else if (!allowing) {

@ -160,6 +160,7 @@ struct ast_rtp {
int rtp_lookup_code_cache_code; int rtp_lookup_code_cache_code;
int rtp_lookup_code_cache_result; int rtp_lookup_code_cache_result;
struct ast_rtcp *rtcp; struct ast_rtcp *rtcp;
struct ast_codec_pref pref;
struct ast_rtp *bridged; /*!< Who we are Packet bridged to */ 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; 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) int ast_rtp_write(struct ast_rtp *rtp, struct ast_frame *_f)
{ {
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; 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) { if (!rtp->smoother) {
rtp->smoother = ast_smoother_new(160); 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) { if (!(rtp->smoother = ast_smoother_new((fmt.cur_ms * fmt.fr_len) / fmt.inc_ms))) {
ast_log(LOG_WARNING, "Unable to create smoother :(\n"); 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; return -1;
} }
ast_smoother_feed(rtp->smoother, _f); if (fmt.flags)
ast_smoother_set_flags(rtp->smoother, fmt.flags);
while((f = ast_smoother_read(rtp->smoother))) if (option_debug)
ast_rtp_raw_write(rtp, f, codec); 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));
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;
} }
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;
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))) while((f = ast_smoother_read(rtp->smoother)))
ast_rtp_raw_write(rtp, f, codec); ast_rtp_raw_write(rtp, f, codec);
break; } else {
case AST_FORMAT_GSM:
if (!rtp->smoother) {
rtp->smoother = ast_smoother_new(33);
}
if (!rtp->smoother) {
ast_log(LOG_WARNING, "Unable to create GSM smoother :(\n");
return -1;
}
ast_smoother_feed(rtp->smoother, _f);
while((f = ast_smoother_read(rtp->smoother)))
ast_rtp_raw_write(rtp, f, codec);
break;
case AST_FORMAT_ILBC:
if (!rtp->smoother) {
rtp->smoother = ast_smoother_new(50);
}
if (!rtp->smoother) {
ast_log(LOG_WARNING, "Unable to create ILBC smoother :(\n");
return -1;
}
ast_smoother_feed(rtp->smoother, _f);
while((f = ast_smoother_read(rtp->smoother)))
ast_rtp_raw_write(rtp, f, codec);
break;
default:
ast_log(LOG_WARNING, "Not sure about sending format %s packets\n", ast_getformatname(subclass));
/* fall through to... */
case AST_FORMAT_H261:
case AST_FORMAT_H263:
case AST_FORMAT_H263_PLUS:
case AST_FORMAT_H264:
case AST_FORMAT_G723_1:
case AST_FORMAT_LPC10:
case AST_FORMAT_SPEEX:
/* Don't buffer outgoing frames; send them one-per-packet: */ /* Don't buffer outgoing frames; send them one-per-packet: */
if (_f->offset < hdrlen) { if (_f->offset < hdrlen) {
f = ast_frdup(_f); f = ast_frdup(_f);

Loading…
Cancel
Save