struct sip_inst {
char interface_name[64];
- char local_ip[16];
- char remote_ip[16];
+ char local_peer[32];
+ char remote_peer[32];
su_root_t *root;
nua_t *nua;
};
/*
* initialize SIP port
*/
-Psip::Psip(int type, char *portname, struct port_settings *settings, struct interface *interface) : Port(type, portname, settings)
+Psip::Psip(int type, char *portname, struct port_settings *settings, struct interface *interface) : Port(type, portname, settings, interface)
{
p_s_rtp_bridge = 0;
if (interface->rtp_bridge)
p_s_rtp_tx_action = 0;
PDEBUG(DEBUG_SIP, "Created new Psip(%s).\n", portname);
+ if (!p_s_sip_inst)
+ FATAL("No SIP instance for interface\n");
}
rtp_close();
}
-const char *payload_type2name(uint8_t payload_type) {
- switch (payload_type) {
- case 0:
+static const char *media_type2name(uint8_t media_type) {
+ switch (media_type) {
+ case MEDIA_TYPE_ULAW:
return "PCMU";
- case 8:
+ case MEDIA_TYPE_ALAW:
return "PCMA";
- case 3:
- case 96:
- case 97:
- case 98:
+ case MEDIA_TYPE_GSM:
return "GSM";
+ case MEDIA_TYPE_GSM_HR:
+ return "GSM-HR";
+ case MEDIA_TYPE_GSM_EFR:
+ return "GSM-EFR";
+ case MEDIA_TYPE_AMR:
+ return "AMR";
}
return "UKN";
#define RTP_VERSION 2
-#define RTP_PT_ULAW 0
-#define RTP_PT_ALAW 8
-#define RTP_PT_GSM_FULL 3
-#define RTP_PT_GSM_HALF 96
-#define RTP_PT_GSM_EFR 97
-#define RTP_PT_GSM_AMR 98
+#define PAYLOAD_TYPE_ULAW 0
+#define PAYLOAD_TYPE_ALAW 8
+#define PAYLOAD_TYPE_GSM 3
/* decode an rtp frame */
static int rtp_decode(class Psip *psip, unsigned char *data, int len)
}
switch (rtph->payload_type) {
+#if 0
+we only support alaw and ulaw!
case RTP_PT_GSM_FULL:
if (payload_len != 33) {
PDEBUG(DEBUG_SIP, "received RTP full rate frame with "
return -EINVAL;
}
break;
- case RTP_PT_ALAW:
+#endif
+ case PAYLOAD_TYPE_ALAW:
if (options.law != 'a') {
PDEBUG(DEBUG_SIP, "received Alaw, but we don't do Alaw\n");
return -EINVAL;
}
break;
- case RTP_PT_ULAW:
+ case PAYLOAD_TYPE_ULAW:
if (options.law == 'a') {
PDEBUG(DEBUG_SIP, "received Ulaw, but we don't do Ulaw\n");
return -EINVAL;
n = payload_len;
from = payload;
to = payload;
+ if (psip->p_echotest) {
+ /* echo rtp data we just received */
+ psip->rtp_send_frame(from, n, (options.law=='a')?PAYLOAD_TYPE_ALAW:PAYLOAD_TYPE_ULAW);
+ return 0;
+ }
while(n--)
*to++ = flip[*from++];
psip->bridge_tx(payload, payload_len);
// psip->rtp_shutdown();
return len;
}
- rc = rtp_decode(psip, buffer, len);
+ if (psip->p_s_rtp_is_connected)
+ rc = rtp_decode(psip, buffer, len);
}
return rc;
// psip->rtp_shutdown();
return len;
}
- PDEBUG(DEBUG_SIP, "rtcp!");
+ PDEBUG(DEBUG_SIP, "rtcp!\n");
}
return 0;
}
switch (payload_type) {
+#if 0
+we only support alaw and ulaw!
case RTP_PT_GSM_FULL:
payload_len = 33;
duration = 160;
payload_len = 14;
duration = 160;
break;
- case RTP_PT_ALAW:
- case RTP_PT_ULAW:
+#endif
+ case PAYLOAD_TYPE_ALAW:
+ case PAYLOAD_TYPE_ULAW:
payload_len = len;
duration = len;
break;
p_s_rxpos = 0;
/* transmit data via rtp */
- rtp_send_frame(p_s_rxdata, 160, (options.law=='a')?RTP_PT_ALAW:RTP_PT_ULAW);
+ rtp_send_frame(p_s_rxdata, 160, (options.law=='a')?PAYLOAD_TYPE_ALAW:PAYLOAD_TYPE_ULAW);
}
}
char sdp_str[256];
struct in_addr ia;
struct lcr_msg *message;
+ int media_type;
unsigned char payload_type;
if (param->connectinfo.rtpinfo.port) {
PDEBUG(DEBUG_SIP, "RTP info given by remote, forward that\n");
p_s_rtp_bridge = 1;
+ media_type = param->connectinfo.rtpinfo.media_types[0];
payload_type = param->connectinfo.rtpinfo.payload_types[0];
p_s_rtp_ip_local = param->connectinfo.rtpinfo.ip;
p_s_rtp_port_local = param->connectinfo.rtpinfo.port;
PDEBUG(DEBUG_SIP, "remote ip %08x port %d\n", p_s_rtp_ip_remote, p_s_rtp_port_remote);
} else {
PDEBUG(DEBUG_SIP, "RTP info not given by remote, so we do our own RTP\n");
- payload_type = (options.law=='a') ? RTP_PT_ALAW : RTP_PT_ULAW;
+ media_type = (options.law=='a') ? MEDIA_TYPE_ALAW : MEDIA_TYPE_ULAW;
+ payload_type = (options.law=='a') ? PAYLOAD_TYPE_ALAW : PAYLOAD_TYPE_ULAW;
/* open local RTP peer (if not bridging) */
- if (rtp_connect() < 0) {
+ if (!p_s_rtp_is_connected && rtp_connect() < 0) {
nua_cancel(p_s_handle, TAG_END());
nua_handle_destroy(p_s_handle);
p_s_handle = NULL;
"t=0 0\n"
"m=audio %d RTP/AVP %d\n"
"a=rtpmap:%d %s/8000\n"
- , inet_ntoa(ia), inet_ntoa(ia), p_s_rtp_port_local, payload_type, payload_type, payload_type2name(payload_type));
+ , inet_ntoa(ia), inet_ntoa(ia), p_s_rtp_port_local, payload_type, payload_type, media_type2name(media_type));
PDEBUG(DEBUG_SIP, "Using SDP response: %s\n", sdp_str);
nua_respond(p_s_handle, SIP_200_OK,
add_trace("reason", NULL, "call connected");
add_trace("rtp", "ip", "%s", inet_ntoa(ia));
add_trace("rtp", "port", "%d,%d", p_s_rtp_port_local, p_s_rtp_port_local + 1);
- add_trace("rtp", "payload", "%d", payload_type);
+ add_trace("rtp", "payload", "%s:%d", media_type2name(media_type), payload_type);
end_trace();
return 0;
struct sip_inst *inst = (struct sip_inst *) p_s_sip_inst;
char from[128];
char to[128];
- const char *local = inst->local_ip;
- const char *remote = inst->remote_ip;
- char sdp_str[256], pt_str[32];
+ const char *local = inst->local_peer;
+ char local_ip[16];
+ const char *remote = inst->remote_peer;
+ char sdp_str[512], pt_str[32];
struct in_addr ia;
struct epoint_list *epointlist;
sip_cseq_t *cseq = NULL;
struct lcr_msg *message;
- unsigned char lcr_payload = { (options.law=='a') ? RTP_PT_ALAW : RTP_PT_ULAW };
+ int lcr_media = { (options.law=='a') ? MEDIA_TYPE_ALAW : MEDIA_TYPE_ULAW };
+ unsigned char lcr_payload = { (options.law=='a') ? PAYLOAD_TYPE_ALAW : PAYLOAD_TYPE_ULAW };
+ int *media_types;
unsigned char *payload_types;
int payloads = 0;
int i;
if (param->setup.rtpinfo.port) {
PDEBUG(DEBUG_SIP, "RTP info given by remote, forward that\n");
p_s_rtp_bridge = 1;
+ media_types = param->setup.rtpinfo.media_types;
payload_types = param->setup.rtpinfo.payload_types;
payloads = param->setup.rtpinfo.payloads;
p_s_rtp_ip_local = param->setup.rtpinfo.ip;
} else {
PDEBUG(DEBUG_SIP, "RTP info not given by remote, so we do our own RTP\n");
p_s_rtp_bridge = 0;
+ media_types = &lcr_media;
payload_types = &lcr_payload;
payloads = 1;
end_trace();
if (!p_s_rtp_ip_local) {
- PDEBUG(DEBUG_SIP, "RTP local IP not known, so we use our local SIP ip %s\n", local);
- inet_pton(AF_INET, local, &p_s_rtp_ip_local);
+ char *p;
+
+ /* extract IP from local peer */
+ SCPY(local_ip, local);
+ p = strchr(local_ip, ':');
+ if (p)
+ *p = '\0';
+ PDEBUG(DEBUG_SIP, "RTP local IP not known, so we use our local SIP ip %s\n", local_ip);
+ inet_pton(AF_INET, local_ip, &p_s_rtp_ip_local);
p_s_rtp_ip_local = ntohl(p_s_rtp_ip_local);
}
ia.s_addr = htonl(p_s_rtp_ip_local);
}
SCAT(sdp_str, "\n");
for (i = 0; i < payloads; i++) {
- SPRINT(pt_str, "a=rtpmap:%d %s/8000\n", payload_types[i], payload_type2name(payload_types[i]));
+ SPRINT(pt_str, "a=rtpmap:%d %s/8000\n", payload_types[i], media_type2name(media_types[i]));
SCAT(sdp_str, pt_str);
}
PDEBUG(DEBUG_SIP, "Using SDP for invite: %s\n", sdp_str);
add_trace("rtp", "ip", "%s", inet_ntoa(ia));
add_trace("rtp", "port", "%d,%d", p_s_rtp_port_local, p_s_rtp_port_local + 1);
for (i = 0; i < payloads; i++)
- add_trace("rtp", "payload", "%d", payload_types[i]);
+ add_trace("rtp", "payload", "%s:%d", media_type2name(media_types[i]), payload_types[i]);
end_trace();
// cseq = sip_cseq_create(sip_home, 123, SIP_METHOD_INVITE);
"t=0 0\n"
"m=audio %d RTP/AVP %d\n"
"a=rtpmap:%d %s/8000\n"
- , inet_ntoa(ia), inet_ntoa(ia), p_s_rtp_port_local, p_s_rtp_payload_type, p_s_rtp_payload_type, payload_type2name(p_s_rtp_payload_type));
+ , inet_ntoa(ia), inet_ntoa(ia), p_s_rtp_port_local, p_s_rtp_payload_type, p_s_rtp_payload_type, media_type2name(p_s_rtp_media_type));
PDEBUG(DEBUG_SIP, "Using SDP for rertieve: %s\n", sdp_str);
nua_info(p_s_handle,
// TAG_IF(from[0], SIPTAG_FROM_STR(from)),
return 0;
}
-int Psip::parse_sdp(sip_t const *sip, unsigned int *ip, unsigned short *port, uint8_t *payload_types, int *payloads, int max_payloads)
+int Psip::parse_sdp(sip_t const *sip, unsigned int *ip, unsigned short *port, uint8_t *payload_types, int *media_types, int *payloads, int max_payloads)
{
*payloads = 0;
*ip = ntohl(p_s_rtp_ip_remote);
}
for (map = m->m_rtpmaps; map; map = map->rm_next) {
+ int media_type = 0;
+
PDEBUG(DEBUG_SIP, "RTPMAP: coding:'%s' rate='%d' pt='%d'\n", map->rm_encoding, map->rm_rate, map->rm_pt);
/* append to payload list, if there is space */
- add_trace("rtp", "payload", "%d", map->rm_pt);
- if (*payloads <= max_payloads) {
+ add_trace("rtp", "payload", "%s:%d", map->rm_encoding, map->rm_pt);
+ if (map->rm_pt == PAYLOAD_TYPE_ALAW)
+ media_type = MEDIA_TYPE_ALAW;
+ else if (map->rm_pt == PAYLOAD_TYPE_ULAW)
+ media_type = MEDIA_TYPE_ULAW;
+ else if (map->rm_pt == PAYLOAD_TYPE_GSM)
+ media_type = MEDIA_TYPE_GSM;
+ else if (!strcmp(map->rm_encoding, "GSM-EFR"))
+ media_type = MEDIA_TYPE_GSM_EFR;
+ else if (!strcmp(map->rm_encoding, "AMR"))
+ media_type = MEDIA_TYPE_AMR;
+ else if (!strcmp(map->rm_encoding, "GSM-HR"))
+ media_type = MEDIA_TYPE_GSM_HR;
+ if (media_type && *payloads <= max_payloads) {
*payload_types++ = map->rm_pt;
+ *media_types++ = media_type;
(*payloads)++;
}
}
class Endpoint *epoint;
struct lcr_msg *message;
struct interface *interface;
+ int media_types[32];
uint8_t payload_types[32];
int payloads = 0;
PDEBUG(DEBUG_SIP, "invite received (%s->%s)\n", from, to);
sip_trace_header(this, "Payload received", DIRECTION_NONE);
- ret = parse_sdp(sip, &p_s_rtp_ip_remote, &p_s_rtp_port_remote, payload_types, &payloads, sizeof(payload_types));
+ ret = parse_sdp(sip, &p_s_rtp_ip_remote, &p_s_rtp_port_remote, payload_types, media_types, &payloads, sizeof(payload_types));
if (!ret) {
/* if no RTP bridge, we must support LAW codec, otherwise we forward what we have */
if (!p_s_rtp_bridge) {
/* check if supported payload type exists */
for (i = 0; i < payloads; i++) {
- if (payload_types[i] == ((options.law=='a') ? RTP_PT_ALAW : RTP_PT_ULAW))
+ if (media_types[i] == ((options.law=='a') ? MEDIA_TYPE_ALAW : MEDIA_TYPE_ULAW))
break;
}
if (i == payloads) {
end_trace();
sip_trace_header(this, "INVITE", DIRECTION_IN);
- add_trace("RTP", "port", "%d", p_s_rtp_port_remote);
+ add_trace("rtp", "port", "%d", p_s_rtp_port_remote);
/* caller information */
if (!from[0]) {
p_callerinfo.present = INFO_PRESENT_NOTAVAIL;
epoint->ep_app = new_endpointapp(epoint, 0, interface->app); //incoming
epointlist_new(epoint->ep_serial);
+#ifdef NUTAG_AUTO100
/* send trying (proceeding) */
nua_respond(nh, SIP_100_TRYING, TAG_END());
sip_trace_header(this, "RESPOND", DIRECTION_OUT);
add_trace("respond", "value", "100 Trying");
end_trace();
+#endif
new_state(PORT_STATE_IN_PROCEEDING);
message->param.setup.rtpinfo.port = p_s_rtp_port_remote;
/* add codecs to setup message */
for (i = 0; i < payloads; i++) {
- message->param.setup.rtpinfo.payload_types[message->param.setup.rtpinfo.payloads++] = payload_types[i];
- if (message->param.setup.rtpinfo.payloads == sizeof(message->param.setup.rtpinfo.payload_types))
+ message->param.setup.rtpinfo.media_types[i] = media_types[i];
+ message->param.setup.rtpinfo.payload_types[i] = payload_types[i];
+ if (i == sizeof(message->param.setup.rtpinfo.payload_types))
break;
}
+ message->param.setup.rtpinfo.payloads = i;
}
message_put(message);
+
+#if 0
+issues:
+- send tones that are clocked with timer, unless data is received from bridge
+ /* send progress, if tones are available and if we don't bridge */
+ if (!p_s_rtp_bridge && interface->is_tones == IS_YES) {
+ char sdp_str[256];
+ struct in_addr ia;
+ unsigned char payload_type;
+
+ PDEBUG(DEBUG_SIP, "Connecting audio, since we have tones available\n");
+ payload_type = (options.law=='a') ? RTP_PT_ALAW : RTP_PT_ULAW;
+ /* open local RTP peer (if not bridging) */
+ if (rtp_connect() < 0) {
+ nua_respond(nh, SIP_500_INTERNAL_SERVER_ERROR, TAG_END());
+ nua_handle_destroy(nh);
+ p_s_handle = NULL;
+ sip_trace_header(this, "RESPOND", DIRECTION_OUT);
+ add_trace("respond", "value", "500 Internal Server Error");
+ add_trace("reason", NULL, "failed to connect RTP/RTCP sockts");
+ end_trace();
+ new_state(PORT_STATE_RELEASE);
+ trigger_work(&p_s_delete);
+ message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_RELEASE);
+ message->param.disconnectinfo.cause = 41;
+ message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
+ message_put(message);
+ new_state(PORT_STATE_RELEASE);
+ trigger_work(&p_s_delete);
+ return;
+ }
+
+ ia.s_addr = htonl(p_s_rtp_ip_local);
+
+ SPRINT(sdp_str,
+ "v=0\n"
+ "o=LCR-Sofia-SIP 0 0 IN IP4 %s\n"
+ "s=SIP Call\n"
+ "c=IN IP4 %s\n"
+ "t=0 0\n"
+ "m=audio %d RTP/AVP %d\n"
+ "a=rtpmap:%d %s/8000\n"
+ , inet_ntoa(ia), inet_ntoa(ia), p_s_rtp_port_local, payload_type, payload_type, payload_type2name(payload_type));
+ PDEBUG(DEBUG_SIP, "Using SDP response: %s\n", sdp_str);
+
+ nua_respond(p_s_handle, SIP_183_SESSION_PROGRESS,
+ NUTAG_MEDIA_ENABLE(0),
+ SIPTAG_CONTENT_TYPE_STR("application/sdp"),
+ SIPTAG_PAYLOAD_STR(sdp_str), TAG_END());
+ new_state(PORT_STATE_CONNECT);
+ sip_trace_header(this, "RESPOND", DIRECTION_OUT);
+ add_trace("respond", "value", "183 SESSION PROGRESS");
+ add_trace("reason", NULL, "audio available");
+ add_trace("rtp", "ip", "%s", inet_ntoa(ia));
+ add_trace("rtp", "port", "%d,%d", p_s_rtp_port_local, p_s_rtp_port_local + 1);
+ add_trace("rtp", "payload", "%d", payload_type);
+ end_trace();
+ }
+#endif
}
void Psip::i_bye(int status, char const *phrase, nua_t *nua, nua_magic_t *magic, nua_handle_t *nh, nua_hmagic_t *hmagic, sip_t const *sip, tagi_t tagss[])
{
struct lcr_msg *message;
int cause = 0, location = 0;
+ int media_types[32];
uint8_t payload_types[32];
int payloads = 0;
int ret;
sip_trace_header(this, "Payload received", DIRECTION_NONE);
- ret = parse_sdp(sip, &p_s_rtp_ip_remote, &p_s_rtp_port_remote, payload_types, &payloads, sizeof(payload_types));
+ ret = parse_sdp(sip, &p_s_rtp_ip_remote, &p_s_rtp_port_remote, payload_types, media_types, &payloads, sizeof(payload_types));
if (!ret) {
if (payloads != 1)
ret = 415;
else if (!p_s_rtp_bridge) {
- if (payload_types[0] != ((options.law=='a') ? RTP_PT_ALAW : RTP_PT_ULAW)) {
+ if (media_types[0] != ((options.law=='a') ? MEDIA_TYPE_ALAW : MEDIA_TYPE_ULAW)) {
add_trace("error", NULL, "Expected LAW payload type (not bridged)");
ret = 415;
}
/* process 1xx */
switch (status) {
case 100:
-#ifdef NUTAG_AUTO100
+#if 0
PDEBUG(DEBUG_SIP, "do proceeding\n");
new_state(PORT_STATE_OUT_PROCEEDING);
message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_PROCEEDING);
if (p_s_rtp_bridge) {
message->param.progressinfo.rtpinfo.ip = p_s_rtp_ip_remote;
message->param.progressinfo.rtpinfo.port = p_s_rtp_port_remote;
+ message->param.progressinfo.rtpinfo.media_types[0] = media_types[0];
message->param.progressinfo.rtpinfo.payload_types[0] = payload_types[0];
message->param.progressinfo.rtpinfo.payloads = 1;
}
if (p_s_rtp_bridge) {
message->param.connectinfo.rtpinfo.ip = p_s_rtp_ip_remote;
message->param.connectinfo.rtpinfo.port = p_s_rtp_port_remote;
+ message->param.connectinfo.rtpinfo.media_types[0] = media_types[0];
message->param.connectinfo.rtpinfo.payload_types[0] = payload_types[0];
message->param.connectinfo.rtpinfo.payloads = 1;
}
int sip_init_inst(struct interface *interface)
{
struct sip_inst *inst = (struct sip_inst *) MALLOC(sizeof(*inst));
+ char local[64];
interface->sip_inst = inst;
SCPY(inst->interface_name, interface->name);
- SCPY(inst->local_ip, interface->sip_local_ip);
- SCPY(inst->remote_ip, interface->sip_remote_ip);
+ SCPY(inst->local_peer, interface->sip_local_peer);
+ SCPY(inst->remote_peer, interface->sip_remote_peer);
/* init root object */
inst->root = su_root_create(inst);
return -EINVAL;
}
- inst->nua = nua_create(inst->root, sip_callback, inst, TAG_NULL());
+ SPRINT(local, "sip:%s",inst->local_peer);
+ if (!strchr(inst->local_peer, ':'))
+ SCAT(local, ":5060");
+ inst->nua = nua_create(inst->root, sip_callback, inst, NUTAG_URL(local), TAG_END());
if (!inst->nua) {
PERROR("Failed to create SIP stack object\n");
sip_exit_inst(interface);