summaryrefslogtreecommitdiff
path: root/channels
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 /channels
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 'channels')
-rw-r--r--channels/chan_h323.c9
-rw-r--r--channels/chan_sip.c166
2 files changed, 108 insertions, 67 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");