summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--channels/chan_h323.c9
-rw-r--r--channels/chan_sip.c166
-rw-r--r--formats/format_siren14.c139
-rw-r--r--formats/format_siren7.c138
-rw-r--r--include/asterisk/frame.h20
-rw-r--r--include/asterisk/rtp.h58
-rw-r--r--main/frame.c33
-rw-r--r--main/rtp.c156
8 files changed, 579 insertions, 140 deletions
diff --git a/channels/chan_h323.c b/channels/chan_h323.c
index f327b9b20..051166d4b 100644
--- a/channels/chan_h323.c
+++ b/channels/chan_h323.c
@@ -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
*
diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index f0a7fb9e3..a81b56289 100644
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -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
index 000000000..109c586fb
--- /dev/null
+++ b/formats/format_siren14.c
@@ -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
index 000000000..0b61a72b2
--- /dev/null
+++ b/formats/format_siren7.c
@@ -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)");
diff --git a/include/asterisk/frame.h b/include/asterisk/frame.h
index 267a820e8..4a18bdbac 100644
--- a/include/asterisk/frame.h
+++ b/include/asterisk/frame.h
@@ -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)
diff --git a/include/asterisk/rtp.h b/include/asterisk/rtp.h
index 800519572..4648a2a34 100644
--- a/include/asterisk/rtp.h
+++ b/include/asterisk/rtp.h
@@ -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);
diff --git a/main/frame.c b/main/frame.c
index 84a2b0a5a..7d950d740 100644
--- a/main/frame.c
+++ b/main/frame.c
@@ -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));
}
diff --git a/main/rtp.c b/main/rtp.c
index a39fc10f2..8240a9fe3 100644
--- a/main/rtp.c
+++ b/main/rtp.c
@@ -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;
}
}
-