Add basic (passthrough, playback, record) support for ITU G.722.1 and G.722.1C (also...
authorKevin P. Fleming <kpfleming@digium.com>
Fri, 13 Feb 2009 13:35:24 +0000 (13:35 +0000)
committerKevin P. Fleming <kpfleming@digium.com>
Fri, 13 Feb 2009 13:35:24 +0000 (13:35 +0000)
This patch adds passthrough, file recording and file playback support for the codecs listed above, with negotiation over SIP/SDP supported. Due to Asterisk's current limitation of treating a codec/bitrate combination as a unique codec, only G.722.1 at 32 kbps and G.722.1C at 48 kbps are supported.

Along the way, some related work was done:

1) The rtpPayloadType structure definition, used as a return result for an API call in rtp.h, was moved from rtp.c to rtp.h so that the API call was actually usable. The only previous used of the API all was chan_h323.c, which had a duplicate of the structure definition instead of doing it the right way.

2) The hardcoded SDP sample rates for various codecs in chan_sip.c were removed, in favor of storing these sample rates in rtp.c along with the codec definitions there. A new API call was added to allow retrieval of the sample rate for a given codec.

3) Some basic 'a=fmtp' parsing for SDP was added to chan_sip, because chan_sip *must* decline any media streams offered for these codecs that are not at the bitrates that we support (otherwise Bad Things (TM) would result).

Review: http://reviewboard.digium.com/r/158/

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

channels/chan_h323.c
channels/chan_sip.c
formats/format_siren14.c [new file with mode: 0644]
formats/format_siren7.c [new file with mode: 0644]
include/asterisk/frame.h
include/asterisk/rtp.h
main/frame.c
main/rtp.c

index f327b9b..051166d 100644 (file)
@@ -1922,15 +1922,6 @@ static struct rtp_info *external_rtp_create(unsigned call_reference, const char
        return info;
 }
 
-/* 
- * Definition taken from rtp.c for rtpPayloadType because we need it here.
- */
-
-struct rtpPayloadType {
-       int isAstFormat;        /* whether the following code is an AST_FORMAT */
-       int code;
-};
-
 /*! \brief
   * Call-back function passing remote ip/port information from H.323 to asterisk
   *
index f0a7fb9..a81b562 100644 (file)
@@ -2286,10 +2286,10 @@ static const char* get_sdp_iterate(int* start, struct sip_request *req, const ch
 static const char *get_sdp(struct sip_request *req, const char *name);
 static int find_sdp(struct sip_request *req);
 static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action);
-static void add_codec_to_sdp(const struct sip_pvt *p, int codec, int sample_rate,
+static void add_codec_to_sdp(const struct sip_pvt *p, int codec,
                             struct ast_str **m_buf, struct ast_str **a_buf,
                             int debug, int *min_packet_size);
-static void add_noncodec_to_sdp(const struct sip_pvt *p, int format, int sample_rate,
+static void add_noncodec_to_sdp(const struct sip_pvt *p, int format,
                                struct ast_str **m_buf, struct ast_str **a_buf,
                                int debug);
 static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int oldsdp);
@@ -7671,22 +7671,17 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
        iterator = req->sdp_start;
        while ((a = get_sdp_iterate(&iterator, req, "a"))[0] != '\0') {
                char mimeSubtype[128];
+               char fmtp_string[64];
+               unsigned int sample_rate;
+
                if (option_debug > 1) {
                        int breakout = FALSE;
-               
+
                        /* If we're debugging, check for unsupported sdp options */
                        if (!strncasecmp(a, "rtcp:", (size_t) 5)) {
                                if (debug)
                                        ast_verbose("Got unsupported a:rtcp in SDP offer \n");
                                breakout = TRUE;
-                       } else if (!strncasecmp(a, "fmtp:", (size_t) 5)) {
-                               /* Format parameters:  Not supported */
-                               /* Note: This is used for codec parameters, like bitrate for
-                                       G722 and video formats for H263 and H264 
-                                       See RFC2327 for an example */
-                               if (debug)
-                                       ast_verbose("Got unsupported a:fmtp in SDP offer \n");
-                               breakout = TRUE;
                        } else if (!strncasecmp(a, "framerate:", (size_t) 10)) {
                                /* Video stuff:  Not supported */
                                if (debug)
@@ -7706,21 +7701,29 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
                        if (breakout)   /* We have a match, skip to next header */
                                continue;
                }
+
                if (!strcasecmp(a, "sendonly")) {
                        if (sendonly == -1)
                                sendonly = 1;
                        continue;
-               } else if (!strcasecmp(a, "inactive")) {
+               }
+
+               if (!strcasecmp(a, "inactive")) {
                        if (sendonly == -1)
                                sendonly = 2;
                        continue;
-               }  else if (!strcasecmp(a, "sendrecv")) {
+               }
+
+               if (!strcasecmp(a, "sendrecv")) {
                        if (sendonly == -1)
                                sendonly = 0;
                        continue;
-               } else if (strlen(a) > 5 && !strncasecmp(a, "ptime", 5)) {
+               }
+
+               if (!strncasecmp(a, "ptime", 5)) {
                        char *tmp = strrchr(a, ':');
                        long int framing = 0;
+
                        if (tmp) {
                                tmp++;
                                framing = strtol(tmp, NULL, 10);
@@ -7744,8 +7747,9 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
                                ast_rtp_codec_setpref(p->rtp, pref);
                        }
                        continue;
-                       
-               } else if (!strncmp(a, red_fmtp, strlen(red_fmtp))) {
+               }
+
+               if (!strncmp(a, red_fmtp, strlen(red_fmtp))) {
                        /* count numbers of generations in fmtp */
                        red_cp = &red_fmtp[strlen(red_fmtp)];
                        strncpy(red_fmtp, a, 100);
@@ -7757,15 +7761,59 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
                                red_cp = strtok(NULL, "/");
                        }
                        red_cp = red_fmtp;
+                       continue;
+               }
+
+               if (sscanf(a, "fmtp: %u %63s", &codec, fmtp_string) == 2) {
+                       struct rtpPayloadType payload;
+                       unsigned int handled = 0;
+
+                       payload = ast_rtp_lookup_pt(newaudiortp, codec);
+                       if (!payload.code) {
+                               /* it wasn't found, try the video rtp */
+                               payload = ast_rtp_lookup_pt(newvideortp, codec);
+                       }
+                       if (payload.code && payload.isAstFormat) {
+                               unsigned int bit_rate;
+
+                               switch (payload.code) {
+                               case AST_FORMAT_SIREN7:
+                                       if (sscanf(fmtp_string, "bitrate=%u", &bit_rate) == 1) {
+                                               if (bit_rate != 32000) {
+                                                       ast_log(LOG_WARNING, "Got Siren7 offer at %d bps, but only 32000 bps supported; ignoring.\n", bit_rate);
+                                                       ast_rtp_unset_m_type(newaudiortp, codec);
+                                               } else {
+                                                       handled = 1;
+                                               }
+                                       }
+                                       break;
+                               case AST_FORMAT_SIREN14:
+                                       if (sscanf(fmtp_string, "bitrate=%u", &bit_rate) == 1) {
+                                               if (bit_rate != 48000) {
+                                                       ast_log(LOG_WARNING, "Got Siren14 offer at %d bps, but only 48000 bps supported; ignoring.\n", bit_rate);
+                                                       ast_rtp_unset_m_type(newaudiortp, codec);
+                                               } else {
+                                                       handled = 1;
+                                               }
+                                       }
+                                       break;
+                               }
+                       }
+
+                       if (!handled) {
+                               ast_debug(1, "Got unsupported a:%s in SDP offer\n", a);
+                       }
+                       continue;
+               }
 
-               } else if (sscanf(a, "rtpmap: %u %127[^/]/", &codec, mimeSubtype) == 2) {
+               if (sscanf(a, "rtpmap: %u %127[^/]/%u", &codec, mimeSubtype, &sample_rate) == 3) {
                        /* We have a rtpmap to handle */
 
                        if (last_rtpmap_codec < SDP_MAX_RTPMAP_CODECS) {
-                               /* Note: should really look at the 'freq' and '#chans' params too */
+                               /* Note: should really look at the '#chans' params too */
                                /* Note: This should all be done in the context of the m= above */
                                if (!strncasecmp(mimeSubtype, "H26", 3) || !strncasecmp(mimeSubtype, "MP4", 3)) {         /* Video */
-                                       if(ast_rtp_set_rtpmap_type(newvideortp, codec, "video", mimeSubtype, 0) != -1) {
+                                       if (ast_rtp_set_rtpmap_type_rate(newvideortp, codec, "video", mimeSubtype, 0, sample_rate) != -1) {
                                                if (debug)
                                                        ast_verbose("Found video description format %s for ID %d\n", mimeSubtype, codec);
                                                found_rtpmap_codecs[last_rtpmap_codec] = codec;
@@ -7787,11 +7835,12 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
                                                sprintf(red_fmtp, "fmtp:%d ", red_pt); 
 
                                                if (debug)
-                                                       ast_verbose("Red submimetype has payload type: %d\n", red_pt);
+                                                       ast_verbose("RED submimetype has payload type: %d\n", red_pt);
                                        }
                                } else {                                          /* Must be audio?? */
-                                       if(ast_rtp_set_rtpmap_type(newaudiortp, codec, "audio", mimeSubtype,
-                                                                  ast_test_flag(&p->flags[0], SIP_G726_NONSTANDARD) ? AST_RTP_OPT_G726_NONSTANDARD : 0) != -1) {
+                                       if (ast_rtp_set_rtpmap_type_rate(newaudiortp, codec, "audio", mimeSubtype,
+                                                                        ast_test_flag(&p->flags[0], SIP_G726_NONSTANDARD) ? AST_RTP_OPT_G726_NONSTANDARD : 0,
+                                                                        sample_rate) != -1) {
                                                if (debug)
                                                        ast_verbose("Found audio description format %s for ID %d\n", mimeSubtype, codec);
                                                found_rtpmap_codecs[last_rtpmap_codec] = codec;
@@ -8895,7 +8944,7 @@ static int add_vidupdate(struct sip_request *req)
 }
 
 /*! \brief Add codec offer to SDP offer/answer body in INVITE or 200 OK */
-static void add_codec_to_sdp(const struct sip_pvt *p, int codec, int sample_rate,
+static void add_codec_to_sdp(const struct sip_pvt *p, int codec,
                             struct ast_str **m_buf, struct ast_str **a_buf,
                             int debug, int *min_packet_size)
 {
@@ -8915,18 +8964,31 @@ static void add_codec_to_sdp(const struct sip_pvt *p, int codec, int sample_rate
                return;
        ast_str_append(m_buf, 0, " %d", rtp_code);
        ast_str_append(a_buf, 0, "a=rtpmap:%d %s/%d\r\n", rtp_code,
-                        ast_rtp_lookup_mime_subtype(1, codec,
-                                                    ast_test_flag(&p->flags[0], SIP_G726_NONSTANDARD) ? AST_RTP_OPT_G726_NONSTANDARD : 0),
-                        sample_rate);
-       if (codec == AST_FORMAT_G729A) {
+                      ast_rtp_lookup_mime_subtype(1, codec,
+                                                  ast_test_flag(&p->flags[0], SIP_G726_NONSTANDARD) ? AST_RTP_OPT_G726_NONSTANDARD : 0),
+                      ast_rtp_lookup_sample_rate(1, codec));
+
+       switch (codec) {
+       case AST_FORMAT_G729A:
                /* Indicate that we don't support VAD (G.729 annex B) */
                ast_str_append(a_buf, 0, "a=fmtp:%d annexb=no\r\n", rtp_code);
-       } else if (codec == AST_FORMAT_G723_1) {
+               break;
+       case AST_FORMAT_G723_1:
                /* Indicate that we don't support VAD (G.723.1 annex A) */
                ast_str_append(a_buf, 0, "a=fmtp:%d annexa=no\r\n", rtp_code);
-       } else if (codec == AST_FORMAT_ILBC) {
+               break;
+       case AST_FORMAT_ILBC:
                /* Add information about us using only 20/30 ms packetization */
                ast_str_append(a_buf, 0, "a=fmtp:%d mode=%d\r\n", rtp_code, fmt.cur_ms);
+               break;
+       case AST_FORMAT_SIREN7:
+               /* Indicate that we only expect 32Kbps */
+               ast_str_append(a_buf, 0, "a=fmtp:%d bitrate=32000\r\n", rtp_code);
+               break;
+       case AST_FORMAT_SIREN14:
+               /* Indicate that we only expect 48Kbps */
+               ast_str_append(a_buf, 0, "a=fmtp:%d bitrate=48000\r\n", rtp_code);
+               break;
        }
 
        if (fmt.cur_ms && (fmt.cur_ms < *min_packet_size))
@@ -8939,7 +9001,7 @@ static void add_codec_to_sdp(const struct sip_pvt *p, int codec, int sample_rate
 
 /*! \brief Add video codec offer to SDP offer/answer body in INVITE or 200 OK */
 /* This is different to the audio one now so we can add more caps later */
-static void add_vcodec_to_sdp(const struct sip_pvt *p, int codec, int sample_rate,
+static void add_vcodec_to_sdp(const struct sip_pvt *p, int codec,
                             struct ast_str **m_buf, struct ast_str **a_buf,
                             int debug, int *min_packet_size)
 {
@@ -8956,12 +9018,13 @@ static void add_vcodec_to_sdp(const struct sip_pvt *p, int codec, int sample_rat
 
        ast_str_append(m_buf, 0, " %d", rtp_code);
        ast_str_append(a_buf, 0, "a=rtpmap:%d %s/%d\r\n", rtp_code,
-                        ast_rtp_lookup_mime_subtype(1, codec, 0), sample_rate);
+                      ast_rtp_lookup_mime_subtype(1, codec, 0),
+                      ast_rtp_lookup_sample_rate(1, codec));
        /* Add fmtp code here */
 }
 
 /*! \brief Add text codec offer to SDP offer/answer body in INVITE or 200 OK */
-static void add_tcodec_to_sdp(const struct sip_pvt *p, int codec, int sample_rate,
+static void add_tcodec_to_sdp(const struct sip_pvt *p, int codec,
                             struct ast_str **m_buf, struct ast_str **a_buf,
                             int debug, int *min_packet_size)
 {
@@ -8978,11 +9041,12 @@ static void add_tcodec_to_sdp(const struct sip_pvt *p, int codec, int sample_rat
 
        ast_str_append(m_buf, 0, " %d", rtp_code);
        ast_str_append(a_buf, 0, "a=rtpmap:%d %s/%d\r\n", rtp_code,
-                        ast_rtp_lookup_mime_subtype(1, codec, 0), sample_rate);
+                      ast_rtp_lookup_mime_subtype(1, codec, 0),
+                      ast_rtp_lookup_sample_rate(1, codec));
        /* Add fmtp code here */
 
        if (codec == AST_FORMAT_T140RED) {
-               ast_str_append(a_buf, 0, "a=fmtp:%d %d/%d/%d\r\n", rtp_code, 
+               ast_str_append(a_buf, 0, "a=fmtp:%d %d/%d/%d\r\n", rtp_code,
                         ast_rtp_lookup_code(p->trtp, 1, AST_FORMAT_T140),
                         ast_rtp_lookup_code(p->trtp, 1, AST_FORMAT_T140),
                         ast_rtp_lookup_code(p->trtp, 1, AST_FORMAT_T140));
@@ -9107,7 +9171,7 @@ static int add_t38_sdp(struct sip_request *resp, struct sip_pvt *p)
 
 
 /*! \brief Add RFC 2833 DTMF offer to SDP */
-static void add_noncodec_to_sdp(const struct sip_pvt *p, int format, int sample_rate,
+static void add_noncodec_to_sdp(const struct sip_pvt *p, int format,
                                struct ast_str **m_buf, struct ast_str **a_buf,
                                int debug)
 {
@@ -9120,8 +9184,8 @@ static void add_noncodec_to_sdp(const struct sip_pvt *p, int format, int sample_
 
        ast_str_append(m_buf, 0, " %d", rtp_code);
        ast_str_append(a_buf, 0, "a=rtpmap:%d %s/%d\r\n", rtp_code,
-                        ast_rtp_lookup_mime_subtype(0, format, 0),
-                        sample_rate);
+                      ast_rtp_lookup_mime_subtype(0, format, 0),
+                      ast_rtp_lookup_sample_rate(0, format));
        if (format == AST_RTP_DTMF)     /* Indicate we support DTMF and FLASH... */
                ast_str_append(a_buf, 0, "a=fmtp:%d 0-16\r\n", rtp_code);
 }
@@ -9162,13 +9226,6 @@ static void get_our_media_address(struct sip_pvt *p, int needvideo,
 
 }
 
-/*!
- * \note G.722 actually is supposed to specified as 8 kHz, even though it is
- * really 16 kHz.  Update this macro for other formats as they are added in
- * the future.
- */
-#define SDP_SAMPLE_RATE(x) 8000
-
 /*! \brief Add Session Description Protocol message 
 
     If oldsdp is TRUE, then the SDP version number is not incremented. This mechanism
@@ -9340,9 +9397,7 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int
        if (capability & p->prefcodec) {
                int codec = p->prefcodec & AST_FORMAT_AUDIO_MASK;
 
-               add_codec_to_sdp(p, codec, SDP_SAMPLE_RATE(codec),
-                                &m_audio, &a_audio,
-                                debug, &min_audio_packet_size);
+               add_codec_to_sdp(p, codec, &m_audio, &a_audio, debug, &min_audio_packet_size);
                alreadysent |= codec;
        }
 
@@ -9359,9 +9414,7 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int
                if (alreadysent & codec)
                        continue;
 
-               add_codec_to_sdp(p, codec, SDP_SAMPLE_RATE(codec),
-                                &m_audio, &a_audio,
-                                debug, &min_audio_packet_size);
+               add_codec_to_sdp(p, codec, &m_audio, &a_audio, debug, &min_audio_packet_size);
                alreadysent |= codec;
        }
 
@@ -9374,14 +9427,11 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int
                        continue;
 
                if (x & AST_FORMAT_AUDIO_MASK)
-                       add_codec_to_sdp(p, x, SDP_SAMPLE_RATE(x),
-                                &m_audio, &a_audio, debug, &min_audio_packet_size);
-               else if (x & AST_FORMAT_VIDEO_MASK) 
-                       add_vcodec_to_sdp(p, x, 90000,
-                                &m_video, &a_video, debug, &min_video_packet_size);
+                       add_codec_to_sdp(p, x, &m_audio, &a_audio, debug, &min_audio_packet_size);
+               else if (x & AST_FORMAT_VIDEO_MASK)
+                       add_vcodec_to_sdp(p, x, &m_video, &a_video, debug, &min_video_packet_size);
                else if (x & AST_FORMAT_TEXT_MASK)
-                       add_tcodec_to_sdp(p, x, 1000,
-                                &m_text, &a_text, debug, &min_text_packet_size);
+                       add_tcodec_to_sdp(p, x, &m_text, &a_text, debug, &min_text_packet_size);
        }
 
        /* Now add DTMF RFC2833 telephony-event as a codec */
@@ -9389,7 +9439,7 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int
                if (!(p->jointnoncodeccapability & x))
                        continue;
 
-               add_noncodec_to_sdp(p, x, 8000, &m_audio, &a_audio, debug);
+               add_noncodec_to_sdp(p, x, &m_audio, &a_audio, debug);
        }
 
        ast_debug(3, "-- Done with adding codecs to SDP\n");
diff --git a/formats/format_siren14.c b/formats/format_siren14.c
new file mode 100644 (file)
index 0000000..109c586
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 1999 - 2008, Anthony Minessale and Digium, Inc.
+ * Anthony Minessale (anthmct@yahoo.com)
+ * Kevin P. Fleming <kpfleming@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief ITU G.722.1 Annex C (Siren14, licensed from Polycom) format, 48kbps bitrate only
+ * \arg File name extensions: siren14
+ * \ingroup formats
+ */
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "asterisk/mod_format.h"
+#include "asterisk/module.h"
+#include "asterisk/endian.h"
+
+#define BUF_SIZE       120             /* 20 milliseconds == 120 bytes, 640 samples */
+#define SAMPLES_TO_BYTES(x)    ((typeof(x)) x / ((float) 640 / 120))
+#define BYTES_TO_SAMPLES(x)    ((typeof(x)) x * ((float) 640 / 120))
+
+static struct ast_frame *siren14read(struct ast_filestream *s, int *whennext)
+{
+       int res;
+       /* Send a frame from the file to the appropriate channel */
+
+       s->fr.frametype = AST_FRAME_VOICE;
+       s->fr.subclass = AST_FORMAT_SIREN14;
+       s->fr.mallocd = 0;
+       AST_FRAME_SET_BUFFER(&s->fr, s->buf, AST_FRIENDLY_OFFSET, BUF_SIZE);
+       if ((res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) != s->fr.datalen) {
+               if (res)
+                       ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno));
+               return NULL;
+       }
+       *whennext = s->fr.samples = BYTES_TO_SAMPLES(res);
+       ast_log(LOG_DEBUG, "Read frame of %d bytes and %d samples\n", res, s->fr.samples);
+       return &s->fr;
+}
+
+static int siren14write(struct ast_filestream *fs, struct ast_frame *f)
+{
+       int res;
+
+       if (f->frametype != AST_FRAME_VOICE) {
+               ast_log(LOG_WARNING, "Asked to write non-voice frame!\n");
+               return -1;
+       }
+       if (f->subclass != AST_FORMAT_SIREN14) {
+               ast_log(LOG_WARNING, "Asked to write non-Siren14 frame (%d)!\n", f->subclass);
+               return -1;
+       }
+       if ((res = fwrite(f->data.ptr, 1, f->datalen, fs->f)) != f->datalen) {
+               ast_log(LOG_WARNING, "Bad write (%d/%d): %s\n", res, f->datalen, strerror(errno));
+               return -1;
+       }
+       return 0;
+}
+
+static int siren14seek(struct ast_filestream *fs, off_t sample_offset, int whence)
+{
+       off_t offset = 0, min = 0, cur, max;
+
+       sample_offset = SAMPLES_TO_BYTES(sample_offset);
+
+       cur = ftello(fs->f);
+
+       fseeko(fs->f, 0, SEEK_END);
+
+       max = ftello(fs->f);
+
+       if (whence == SEEK_SET)
+               offset = sample_offset;
+       else if (whence == SEEK_CUR || whence == SEEK_FORCECUR)
+               offset = sample_offset + cur;
+       else if (whence == SEEK_END)
+               offset = max - sample_offset;
+
+       if (whence != SEEK_FORCECUR)
+               offset = (offset > max) ? max : offset;
+
+       /* always protect against seeking past begining. */
+       offset = (offset < min) ? min : offset;
+
+       return fseeko(fs->f, offset, SEEK_SET);
+}
+
+static int siren14trunc(struct ast_filestream *fs)
+{
+       return ftruncate(fileno(fs->f), ftello(fs->f));
+}
+
+static off_t siren14tell(struct ast_filestream *fs)
+{
+       return BYTES_TO_SAMPLES(ftello(fs->f));
+}
+
+static const struct ast_format siren14_f = {
+       .name = "siren14",
+       .exts = "siren14",
+       .format = AST_FORMAT_SIREN14,
+       .write = siren14write,
+       .seek = siren14seek,
+       .trunc = siren14trunc,
+       .tell = siren14tell,
+       .read = siren14read,
+       .buf_size = BUF_SIZE + AST_FRIENDLY_OFFSET,
+};
+
+static int load_module(void)
+{
+       if (ast_format_register(&siren14_f))
+               return AST_MODULE_LOAD_DECLINE;
+
+       return AST_MODULE_LOAD_SUCCESS;
+}
+
+static int unload_module(void)
+{
+       return ast_format_unregister(siren14_f.name);
+}      
+
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "ITU G.722.1 Annex C (Siren14, licensed from Polycom)");
diff --git a/formats/format_siren7.c b/formats/format_siren7.c
new file mode 100644 (file)
index 0000000..0b61a72
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 1999 - 2008, Anthony Minessale and Digium, Inc.
+ * Anthony Minessale (anthmct@yahoo.com)
+ * Kevin P. Fleming <kpfleming@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief ITU G.722.1 (Siren7, licensed from Polycom) format, 32kbps bitrate only
+ * \arg File name extensions: siren7
+ * \ingroup formats
+ */
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "asterisk/mod_format.h"
+#include "asterisk/module.h"
+#include "asterisk/endian.h"
+
+#define BUF_SIZE       80              /* 20 milliseconds == 80 bytes, 320 samples */
+#define SAMPLES_TO_BYTES(x)    x / (320 / 80)
+#define BYTES_TO_SAMPLES(x)    x * (320 / 80)
+
+static struct ast_frame *siren7read(struct ast_filestream *s, int *whennext)
+{
+       int res;
+       /* Send a frame from the file to the appropriate channel */
+
+       s->fr.frametype = AST_FRAME_VOICE;
+       s->fr.subclass = AST_FORMAT_SIREN7;
+       s->fr.mallocd = 0;
+       AST_FRAME_SET_BUFFER(&s->fr, s->buf, AST_FRIENDLY_OFFSET, BUF_SIZE);
+       if ((res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) != s->fr.datalen) {
+               if (res)
+                       ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno));
+               return NULL;
+       }
+       *whennext = s->fr.samples = BYTES_TO_SAMPLES(res);
+       return &s->fr;
+}
+
+static int siren7write(struct ast_filestream *fs, struct ast_frame *f)
+{
+       int res;
+
+       if (f->frametype != AST_FRAME_VOICE) {
+               ast_log(LOG_WARNING, "Asked to write non-voice frame!\n");
+               return -1;
+       }
+       if (f->subclass != AST_FORMAT_SIREN7) {
+               ast_log(LOG_WARNING, "Asked to write non-Siren7 frame (%d)!\n", f->subclass);
+               return -1;
+       }
+       if ((res = fwrite(f->data.ptr, 1, f->datalen, fs->f)) != f->datalen) {
+               ast_log(LOG_WARNING, "Bad write (%d/%d): %s\n", res, f->datalen, strerror(errno));
+               return -1;
+       }
+       return 0;
+}
+
+static int siren7seek(struct ast_filestream *fs, off_t sample_offset, int whence)
+{
+       off_t offset = 0, min = 0, cur, max;
+
+       sample_offset = SAMPLES_TO_BYTES(sample_offset);
+
+       cur = ftello(fs->f);
+
+       fseeko(fs->f, 0, SEEK_END);
+
+       max = ftello(fs->f);
+
+       if (whence == SEEK_SET)
+               offset = sample_offset;
+       else if (whence == SEEK_CUR || whence == SEEK_FORCECUR)
+               offset = sample_offset + cur;
+       else if (whence == SEEK_END)
+               offset = max - sample_offset;
+
+       if (whence != SEEK_FORCECUR)
+               offset = (offset > max) ? max : offset;
+
+       /* always protect against seeking past begining. */
+       offset = (offset < min) ? min : offset;
+
+       return fseeko(fs->f, offset, SEEK_SET);
+}
+
+static int siren7trunc(struct ast_filestream *fs)
+{
+       return ftruncate(fileno(fs->f), ftello(fs->f));
+}
+
+static off_t siren7tell(struct ast_filestream *fs)
+{
+       return BYTES_TO_SAMPLES(ftello(fs->f));
+}
+
+static const struct ast_format siren7_f = {
+       .name = "siren7",
+       .exts = "siren7",
+       .format = AST_FORMAT_SIREN7,
+       .write = siren7write,
+       .seek = siren7seek,
+       .trunc = siren7trunc,
+       .tell = siren7tell,
+       .read = siren7read,
+       .buf_size = BUF_SIZE + AST_FRIENDLY_OFFSET,
+};
+
+static int load_module(void)
+{
+       if (ast_format_register(&siren7_f))
+               return AST_MODULE_LOAD_DECLINE;
+
+       return AST_MODULE_LOAD_SUCCESS;
+}
+
+static int unload_module(void)
+{
+       return ast_format_unregister(siren7_f.name);
+}      
+
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "ITU G.722.1 (Siren7, licensed from Polycom)");
index 267a820..4a18bdb 100644 (file)
@@ -259,6 +259,10 @@ extern struct ast_frame ast_null_frame;
 #define AST_FORMAT_G726                (1 << 11)
 /*! G.722 */
 #define AST_FORMAT_G722                (1 << 12)
+/*! G.722.1 (also known as Siren7, 32kbps assumed) */
+#define AST_FORMAT_SIREN7      (1 << 13)
+/*! G.722.1 Annex C (also known as Siren14, 48kbps assumed) */
+#define AST_FORMAT_SIREN14     (1 << 14)
 /*! Raw 16-bit Signed Linear (16000 Hz) PCM */
 #define AST_FORMAT_SLINEAR16   (1 << 15)
 /*! Maximum audio mask */
@@ -523,8 +527,8 @@ struct ast_frame *ast_smoother_read(struct ast_smoother *s);
 #endif
 /*@} Doxygen marker */
 
-struct ast_format_list *ast_get_format_list_index(int index);
-struct ast_format_list *ast_get_format_list(size_t *size);
+const struct ast_format_list *ast_get_format_list_index(int index);
+const struct ast_format_list *ast_get_format_list(size_t *size);
 void ast_frame_dump(const char *name, struct ast_frame *f, char *prefix);
 
 /*! \page AudioCodecPref Audio Codec Preferences
@@ -630,10 +634,16 @@ int ast_frame_slinear_sum(struct ast_frame *f1, struct ast_frame *f2);
  */
 static force_inline int ast_format_rate(int format)
 {
-       if (format == AST_FORMAT_G722 || format == AST_FORMAT_SLINEAR16)
+       switch (format) {
+       case AST_FORMAT_G722:
+       case AST_FORMAT_SLINEAR16:
+       case AST_FORMAT_SIREN7:
                return 16000;
-
-       return 8000;
+       case AST_FORMAT_SIREN14:
+               return 32000;
+       default:
+               return 8000;
+       }
 }
 
 #if defined(__cplusplus) || defined(c_plusplus)
index 8005195..4648a2a 100644 (file)
@@ -84,6 +84,12 @@ struct ast_rtp;
 /*! T.140 Redundancy structure*/
 struct rtp_red;
 
+/*! \brief The value of each payload format mapping: */
+struct rtpPayloadType {
+       int isAstFormat;                /*!< whether the following code is an AST_FORMAT */
+       int code;
+};
+
 /*! \brief This is the structure that binds a channel (SIP/Jingle/H.323) to the RTP subsystem 
 */
 struct ast_rtp_protocol {
@@ -136,7 +142,7 @@ size_t ast_rtp_alloc_size(void);
  * \param io
  * \param rtcpenable
  * \param callbackmode
- * \returns A representation (structure) of an RTP session.
+ * \return A representation (structure) of an RTP session.
  */
 struct ast_rtp *ast_rtp_new(struct sched_context *sched, struct io_context *io, int rtcpenable, int callbackmode);
 
@@ -150,7 +156,7 @@ struct ast_rtp *ast_rtp_new(struct sched_context *sched, struct io_context *io,
  * \param rtcpenable
  * \param callbackmode
  * \param in
- * \returns A representation (structure) of an RTP session.
+ * \return A representation (structure) of an RTP session.
  */
 struct ast_rtp *ast_rtp_new_with_bindaddr(struct sched_context *sched, struct io_context *io, int rtcpenable, int callbackmode, struct in_addr in);
 
@@ -209,22 +215,66 @@ void ast_rtp_set_m_type(struct ast_rtp* rtp, int pt);
 /*! \brief clear payload type */
 void ast_rtp_unset_m_type(struct ast_rtp* rtp, int pt);
 
-/*! \brief Initiate payload type to a known MIME media type for a codec */
+/*! \brief Set payload type to a known MIME media type for a codec
+ *
+ * \param rtp RTP structure to modify
+ * \param pt Payload type entry to modify
+ * \param mimeType top-level MIME type of media stream (typically "audio", "video", "text", etc.)
+ * \param mimeSubtype MIME subtype of media stream (typically a codec name)
+ * \param options Zero or more flags from the ast_rtp_options enum
+ *
+ * This function 'fills in' an entry in the list of possible formats for
+ * a media stream associated with an RTP structure.
+ *
+ * \retval 0 on success
+ * \retval -1 if the payload type is out of range
+ * \retval -2 if the mimeType/mimeSubtype combination was not found
+ */
 int ast_rtp_set_rtpmap_type(struct ast_rtp* rtp, int pt,
                             char *mimeType, char *mimeSubtype,
                             enum ast_rtp_options options);
 
+/*! \brief Set payload type to a known MIME media type for a codec with a specific sample rate
+ *
+ * \param rtp RTP structure to modify
+ * \param pt Payload type entry to modify
+ * \param mimeType top-level MIME type of media stream (typically "audio", "video", "text", etc.)
+ * \param mimeSubtype MIME subtype of media stream (typically a codec name)
+ * \param options Zero or more flags from the ast_rtp_options enum
+ * \param sample_rate The sample rate of the media stream
+ *
+ * This function 'fills in' an entry in the list of possible formats for
+ * a media stream associated with an RTP structure.
+ *
+ * \retval 0 on success
+ * \retval -1 if the payload type is out of range
+ * \retval -2 if the mimeType/mimeSubtype combination was not found
+ */
+int ast_rtp_set_rtpmap_type_rate(struct ast_rtp* rtp, int pt,
+                                char *mimeType, char *mimeSubtype,
+                                enum ast_rtp_options options,
+                                unsigned int sample_rate);
+
 /*! \brief  Mapping between RTP payload format codes and Asterisk codes: */
 struct rtpPayloadType ast_rtp_lookup_pt(struct ast_rtp* rtp, int pt);
 int ast_rtp_lookup_code(struct ast_rtp* rtp, int isAstFormat, int code);
 
 void ast_rtp_get_current_formats(struct ast_rtp* rtp,
-                            int* astFormats, int* nonAstFormats);
+                                int* astFormats, int* nonAstFormats);
 
 /*! \brief  Mapping an Asterisk code into a MIME subtype (string): */
 const char *ast_rtp_lookup_mime_subtype(int isAstFormat, int code,
                                        enum ast_rtp_options options);
 
+/*! \brief Get the sample rate associated with known RTP payload types
+ *
+ * \param isAstFormat True if the value in the 'code' parameter is an AST_FORMAT value
+ * \param code Format code, either from AST_FORMAT list or from AST_RTP list
+ *
+ * \return the sample rate if the format was found, zero if it was not found
+ */
+unsigned int ast_rtp_lookup_sample_rate(int isAstFormat, int code);
+
 /*! \brief Build a string of MIME subtype names from a capability list */
 char *ast_rtp_lookup_mime_multiple(char *buf, size_t size, const int capability,
                                   const int isAstFormat, enum ast_rtp_options options);
index 84a2b0a..7d950d7 100644 (file)
@@ -98,7 +98,7 @@ struct ast_smoother {
 };
 
 /*! \brief Definition of supported media formats (codecs) */
-static struct ast_format_list AST_FORMAT_LIST[] = {
+static const struct ast_format_list AST_FORMAT_LIST[] = {
        { AST_FORMAT_G723_1 , "g723", 8000, "G.723.1", 20, 30, 300, 30, 30 },                                  /*!< G723.1 */
        { AST_FORMAT_GSM, "gsm", 8000, "GSM", 33, 20, 300, 20, 20 },                                           /*!< codec_gsm.c */
        { AST_FORMAT_ULAW, "ulaw", 8000, "G.711 u-law", 80, 10, 150, 10, 20 },                                 /*!< codec_ulaw.c */
@@ -120,8 +120,10 @@ static struct ast_format_list AST_FORMAT_LIST[] = {
        { AST_FORMAT_H263_PLUS, "h263p", 0, "H.263+ Video" },                                                  /*!< H.263plus passthrough support See format_h263.c */
        { AST_FORMAT_H264, "h264", 0, "H.264 Video" },                                                         /*!< Passthrough support, see format_h263.c */
        { AST_FORMAT_MP4_VIDEO, "mpeg4", 0, "MPEG4 Video" },                                                   /*!< Passthrough support for MPEG4 */
-       { AST_FORMAT_T140RED, "red", 1, "T.140 Realtime Text with redundancy"},                                 /*!< Redundant T.140 Realtime Text */
+       { AST_FORMAT_T140RED, "red", 1, "T.140 Realtime Text with redundancy"},                                /*!< Redundant T.140 Realtime Text */
        { AST_FORMAT_T140, "t140", 0, "Passthrough T.140 Realtime Text" },                                     /*!< Passthrough support for T.140 Realtime Text */
+       { AST_FORMAT_SIREN7, "siren7", 16000, "ITU G.722.1 (Siren7, licensed from Polycom)", 80, 20, 80, 20, 20 },                      /*!< Binary commercial distribution */
+       { AST_FORMAT_SIREN14, "siren14", 32000, "ITU G.722.1 Annex C, (Siren14, licensed from Polycom)", 120, 20, 80, 20, 20 }, /*!< Binary commercial distribution */
 };
 
 struct ast_frame ast_null_frame = { AST_FRAME_NULL, };
@@ -505,12 +507,12 @@ void ast_swapcopy_samples(void *dst, const void *src, int samples)
 }
 
 
-struct ast_format_list *ast_get_format_list_index(int idx) 
+const struct ast_format_list *ast_get_format_list_index(int idx) 
 {
        return &AST_FORMAT_LIST[idx];
 }
 
-struct ast_format_list *ast_get_format_list(size_t *size) 
+const struct ast_format_list *ast_get_format_list(size_t *size) 
 {
        *size = ARRAY_LEN(AST_FORMAT_LIST);
        return AST_FORMAT_LIST;
@@ -564,6 +566,8 @@ static struct ast_codec_alias_table {
        { "slinear", "slin"},
        { "slinear16", "slin16"},
        { "g723.1", "g723"},
+       { "g722.1", "siren7"},
+       { "g722.1c", "siren14"},
 };
 
 static const char *ast_expand_codec_alias(const char *in)
@@ -1407,7 +1411,8 @@ static int speex_samples(unsigned char *data, int len)
 
 int ast_codec_get_samples(struct ast_frame *f)
 {
-       int samples=0;
+       int samples = 0;
+
        switch(f->subclass) {
        case AST_FORMAT_SPEEX:
                samples = speex_samples(f->data.ptr, f->datalen);
@@ -1443,6 +1448,14 @@ int ast_codec_get_samples(struct ast_frame *f)
        case AST_FORMAT_G726_AAL2:
                samples = f->datalen * 2;
                break;
+       case AST_FORMAT_SIREN7:
+               /* 16,000 samples per second at 32kbps is 4,000 bytes per second */
+               samples = f->datalen * (16000 / 4000);
+               break;
+       case AST_FORMAT_SIREN14:
+               /* 32,000 samples per second at 48kbps is 6,000 bytes per second */
+               samples = (int) f->datalen * ((float) 32000 / 6000);
+               break;
        default:
                ast_log(LOG_WARNING, "Unable to calculate samples for format %s\n", ast_getformatname(f->subclass));
        }
@@ -1453,7 +1466,7 @@ int ast_codec_get_len(int format, int samples)
 {
        int len = 0;
 
-       /* XXX Still need speex, g723, and lpc10 XXX */ 
+       /* XXX Still need speex, and lpc10 XXX */       
        switch(format) {
        case AST_FORMAT_G723_1:
                len = (samples / 240) * 20;
@@ -1481,6 +1494,14 @@ int ast_codec_get_len(int format, int samples)
        case AST_FORMAT_G726_AAL2:
                len = samples / 2;
                break;
+       case AST_FORMAT_SIREN7:
+               /* 16,000 samples per second at 32kbps is 4,000 bytes per second */
+               len = samples / (16000 / 4000);
+               break;
+       case AST_FORMAT_SIREN14:
+               /* 32,000 samples per second at 48kbps is 6,000 bytes per second */
+               len = (int) samples / ((float) 32000 / 6000);
+               break;
        default:
                ast_log(LOG_WARNING, "Unable to calculate sample length for format %s\n", ast_getformatname(format));
        }
index a39fc10..8240a9f 100644 (file)
@@ -97,12 +97,6 @@ enum strict_rtp_state {
  * RTP session is defined on page 9 of RFC 3550: "An association among a set of participants communicating with RTP.  A participant may be involved in multiple RTP sessions at the same time [...]"
  *
  */
-/*! \brief The value of each payload format mapping: */
-struct rtpPayloadType {
-       int isAstFormat;        /*!< whether the following code is an AST_FORMAT */
-       int code;
-};
-
 
 /*! \brief RTP session description */
 struct ast_rtp {
@@ -1832,7 +1826,7 @@ struct ast_frame *ast_rtp_read(struct ast_rtp *rtp)
                /* Add timing data to let ast_generic_bridge() put the frame into a jitterbuf */
                ast_set_flag(&rtp->f, AST_FRFLAG_HAS_TIMING_INFO);
                rtp->f.ts = timestamp / 8;
-               rtp->f.len = rtp->f.samples / ( (ast_format_rate(rtp->f.subclass) == 16000) ? 16 : 8 );
+               rtp->f.len = rtp->f.samples / ((ast_format_rate(rtp->f.subclass) / 1000));
        } else if (rtp->f.subclass & AST_FORMAT_VIDEO_MASK) {
                /* Video -- samples is # of samples vs. 90000 */
                if (!rtp->lastividtimestamp)
@@ -1863,40 +1857,46 @@ struct ast_frame *ast_rtp_read(struct ast_rtp *rtp)
 
 /* The following array defines the MIME Media type (and subtype) for each
    of our codecs, or RTP-specific data type. */
-static struct {
+static const struct mimeType {
        struct rtpPayloadType payloadType;
-       char* type;
-       char* subtype;
+       char *type;
+       char *subtype;
+       unsigned int sample_rate;
 } mimeTypes[] = {
-       {{1, AST_FORMAT_G723_1}, "audio", "G723"},
-       {{1, AST_FORMAT_GSM}, "audio", "GSM"},
-       {{1, AST_FORMAT_ULAW}, "audio", "PCMU"},
-       {{1, AST_FORMAT_ULAW}, "audio", "G711U"},
-       {{1, AST_FORMAT_ALAW}, "audio", "PCMA"},
-       {{1, AST_FORMAT_ALAW}, "audio", "G711A"},
-       {{1, AST_FORMAT_G726}, "audio", "G726-32"},
-       {{1, AST_FORMAT_ADPCM}, "audio", "DVI4"},
-       {{1, AST_FORMAT_SLINEAR}, "audio", "L16"},
-       {{1, AST_FORMAT_LPC10}, "audio", "LPC"},
-       {{1, AST_FORMAT_G729A}, "audio", "G729"},
-       {{1, AST_FORMAT_G729A}, "audio", "G729A"},
-       {{1, AST_FORMAT_G729A}, "audio", "G.729"},
-       {{1, AST_FORMAT_SPEEX}, "audio", "speex"},
-       {{1, AST_FORMAT_ILBC}, "audio", "iLBC"},
-       {{1, AST_FORMAT_G722}, "audio", "G722"},
-       {{1, AST_FORMAT_G726_AAL2}, "audio", "AAL2-G726-32"},
-       {{0, AST_RTP_DTMF}, "audio", "telephone-event"},
-       {{0, AST_RTP_CISCO_DTMF}, "audio", "cisco-telephone-event"},
-       {{0, AST_RTP_CN}, "audio", "CN"},
-       {{1, AST_FORMAT_JPEG}, "video", "JPEG"},
-       {{1, AST_FORMAT_PNG}, "video", "PNG"},
-       {{1, AST_FORMAT_H261}, "video", "H261"},
-       {{1, AST_FORMAT_H263}, "video", "H263"},
-       {{1, AST_FORMAT_H263_PLUS}, "video", "h263-1998"},
-       {{1, AST_FORMAT_H264}, "video", "H264"},
-       {{1, AST_FORMAT_MP4_VIDEO}, "video", "MP4V-ES"},
-       {{1, AST_FORMAT_T140RED}, "text", "RED"},
-       {{1, AST_FORMAT_T140}, "text", "T140"},
+       {{1, AST_FORMAT_G723_1}, "audio", "G723", 8000},
+       {{1, AST_FORMAT_GSM}, "audio", "GSM", 8000},
+       {{1, AST_FORMAT_ULAW}, "audio", "PCMU", 8000},
+       {{1, AST_FORMAT_ULAW}, "audio", "G711U", 8000},
+       {{1, AST_FORMAT_ALAW}, "audio", "PCMA", 8000},
+       {{1, AST_FORMAT_ALAW}, "audio", "G711A", 8000},
+       {{1, AST_FORMAT_G726}, "audio", "G726-32", 8000},
+       {{1, AST_FORMAT_ADPCM}, "audio", "DVI4", 8000},
+       {{1, AST_FORMAT_SLINEAR}, "audio", "L16", 8000},
+       {{1, AST_FORMAT_LPC10}, "audio", "LPC", 8000},
+       {{1, AST_FORMAT_G729A}, "audio", "G729", 8000},
+       {{1, AST_FORMAT_G729A}, "audio", "G729A", 8000},
+       {{1, AST_FORMAT_G729A}, "audio", "G.729", 8000},
+       {{1, AST_FORMAT_SPEEX}, "audio", "speex", 8000},
+       {{1, AST_FORMAT_ILBC}, "audio", "iLBC", 8000},
+       /* this is the sample rate listed in the RTP profile for the G.722
+          codec, *NOT* the actual sample rate of the media stream
+       */
+       {{1, AST_FORMAT_G722}, "audio", "G722", 8000},
+       {{1, AST_FORMAT_G726_AAL2}, "audio", "AAL2-G726-32", 8000},
+       {{0, AST_RTP_DTMF}, "audio", "telephone-event", 8000},
+       {{0, AST_RTP_CISCO_DTMF}, "audio", "cisco-telephone-event", 8000},
+       {{0, AST_RTP_CN}, "audio", "CN", 8000},
+       {{1, AST_FORMAT_JPEG}, "video", "JPEG", 90000},
+       {{1, AST_FORMAT_PNG}, "video", "PNG", 90000},
+       {{1, AST_FORMAT_H261}, "video", "H261", 90000},
+       {{1, AST_FORMAT_H263}, "video", "H263", 90000},
+       {{1, AST_FORMAT_H263_PLUS}, "video", "h263-1998", 90000},
+       {{1, AST_FORMAT_H264}, "video", "H264", 90000},
+       {{1, AST_FORMAT_MP4_VIDEO}, "video", "MP4V-ES", 90000},
+       {{1, AST_FORMAT_T140RED}, "text", "RED", 1000},
+       {{1, AST_FORMAT_T140}, "text", "T140", 1000},
+       {{1, AST_FORMAT_SIREN7}, "audio", "G7221", 16000},
+       {{1, AST_FORMAT_SIREN14}, "audio", "G7221", 32000},
 };
 
 /*! 
@@ -1909,7 +1909,7 @@ static struct {
  * See http://www.iana.org/assignments/rtp-parameters for a list of
  * assigned values
  */
-static struct rtpPayloadType static_RTP_PT[MAX_RTP_PT] = {
+static const struct rtpPayloadType static_RTP_PT[MAX_RTP_PT] = {
        [0] = {1, AST_FORMAT_ULAW},
 #ifdef USE_DEPRECATED_G726
        [2] = {1, AST_FORMAT_G726}, /* Technically this is G.721, but if Cisco can do it, so can we... */
@@ -1935,6 +1935,7 @@ static struct rtpPayloadType static_RTP_PT[MAX_RTP_PT] = {
        [98] = {1, AST_FORMAT_H263_PLUS},
        [99] = {1, AST_FORMAT_H264},
        [101] = {0, AST_RTP_DTMF},
+       [102] = {1, AST_FORMAT_SIREN7},
        [103] = {1, AST_FORMAT_H263_PLUS},
        [104] = {1, AST_FORMAT_MP4_VIDEO},
        [105] = {1, AST_FORMAT_T140RED},        /* Real time text chat (with redundancy encoding) */
@@ -1942,6 +1943,7 @@ static struct rtpPayloadType static_RTP_PT[MAX_RTP_PT] = {
        [110] = {1, AST_FORMAT_SPEEX},
        [111] = {1, AST_FORMAT_G726},
        [112] = {1, AST_FORMAT_G726_AAL2},
+       [115] = {1, AST_FORMAT_SIREN14},
        [121] = {0, AST_RTP_CISCO_DTMF}, /* Must be type 121 */
 };
 
@@ -2211,35 +2213,61 @@ void ast_rtp_unset_m_type(struct ast_rtp* rtp, int pt)
  * an SDP "a=rtpmap:" line.
  * \return 0 if the MIME type was found and set, -1 if it wasn't found
  */
-int ast_rtp_set_rtpmap_type(struct ast_rtp *rtp, int pt,
-                            char *mimeType, char *mimeSubtype,
-                            enum ast_rtp_options options)
+int ast_rtp_set_rtpmap_type_rate(struct ast_rtp *rtp, int pt,
+                                char *mimeType, char *mimeSubtype,
+                                enum ast_rtp_options options,
+                                unsigned int sample_rate)
 {
        unsigned int i;
        int found = 0;
 
-       if (pt < 0 || pt > MAX_RTP_PT) 
+       if (pt < 0 || pt > MAX_RTP_PT)
                return -1; /* bogus payload type */
-       
+
        rtp_bridge_lock(rtp);
 
        for (i = 0; i < ARRAY_LEN(mimeTypes); ++i) {
-               if (strcasecmp(mimeSubtype, mimeTypes[i].subtype) == 0 &&
-                   strcasecmp(mimeType, mimeTypes[i].type) == 0) {
-                       found = 1;
-                       rtp->current_RTP_PT[pt] = mimeTypes[i].payloadType;
-                       if ((mimeTypes[i].payloadType.code == AST_FORMAT_G726) &&
-                           mimeTypes[i].payloadType.isAstFormat &&
-                           (options & AST_RTP_OPT_G726_NONSTANDARD))
-                               rtp->current_RTP_PT[pt].code = AST_FORMAT_G726_AAL2;
-                       break;
+               const struct mimeType *t = &mimeTypes[i];
+
+               if (strcasecmp(mimeSubtype, t->subtype)) {
+                       continue;
+               }
+
+               if (strcasecmp(mimeType, t->type)) {
+                       continue;
+               }
+
+               /* if both sample rates have been supplied, and they don't match,
+                  then this not a match; if one has not been supplied, then the
+                  rates are not compared */
+               if (sample_rate && t->sample_rate &&
+                   (sample_rate != t->sample_rate)) {
+                       continue;
+               }
+
+               found = 1;
+               rtp->current_RTP_PT[pt] = t->payloadType;
+
+               if ((t->payloadType.code == AST_FORMAT_G726) &&
+                   t->payloadType.isAstFormat &&
+                   (options & AST_RTP_OPT_G726_NONSTANDARD)) {
+                       rtp->current_RTP_PT[pt].code = AST_FORMAT_G726_AAL2;
                }
+
+               break;
        }
 
        rtp_bridge_unlock(rtp);
 
-       return (found ? 0 : -1);
-} 
+       return (found ? 0 : -2);
+}
+
+int ast_rtp_set_rtpmap_type(struct ast_rtp *rtp, int pt,
+                           char *mimeType, char *mimeSubtype,
+                           enum ast_rtp_options options)
+{
+       return ast_rtp_set_rtpmap_type_rate(rtp, pt, mimeType, mimeSubtype, options, 0);
+}
 
 /*! \brief Return the union of all of the codecs that were set by rtp_set...() calls 
  * They're returned as two distinct sets: AST_FORMATs, and AST_RTPs */
@@ -2344,6 +2372,19 @@ const char *ast_rtp_lookup_mime_subtype(const int isAstFormat, const int code,
        return "";
 }
 
+unsigned int ast_rtp_lookup_sample_rate(int isAstFormat, int code)
+{
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_LEN(mimeTypes); ++i) {
+               if ((mimeTypes[i].payloadType.code == code) && (mimeTypes[i].payloadType.isAstFormat == isAstFormat)) {
+                       return mimeTypes[i].sample_rate;
+               }
+       }
+
+       return 0;
+}
+
 char *ast_rtp_lookup_mime_multiple(char *buf, size_t size, const int capability,
                                   const int isAstFormat, enum ast_rtp_options options)
 {
@@ -4773,9 +4814,8 @@ void red_buffer_t140(struct ast_rtp *rtp, struct ast_frame *f)
 {
        if (f->datalen > -1) {
                struct rtp_red *red = rtp->red;
-               memcpy(&red->buf_data[red->t140.datalen], f->data.ptr, f->datalen); 
+               memcpy(&red->buf_data[red->t140.datalen], f->data.ptr, f->datalen);
                red->t140.datalen += f->datalen;
                red->t140.ts = f->ts;
        }
 }
-