summaryrefslogtreecommitdiff
path: root/main
diff options
context:
space:
mode:
authorKevin P. Fleming <kpfleming@digium.com>2009-02-13 13:35:24 +0000
committerKevin P. Fleming <kpfleming@digium.com>2009-02-13 13:35:24 +0000
commit2a53f2ec98d58e6ea32d71877e4b4ca6d9aa4a7d (patch)
tree51f8bb89740396001e20f9f64d9044733305193c /main
parent1981fdac02eb22d615619895ab26b5a955b74e61 (diff)
Add basic (passthrough, playback, record) support for ITU G.722.1 and G.722.1C (also known as Siren7 and Siren14)
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
Diffstat (limited to 'main')
-rw-r--r--main/frame.c33
-rw-r--r--main/rtp.c156
2 files changed, 125 insertions, 64 deletions
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;
}
}
-