X-Git-Url: http://git.eversberg.eu/gitweb.cgi?p=lcr.git;a=blobdiff_plain;f=sip.cpp;h=075447cb347463dde39dffc74678b9fa8e089cb0;hp=c6f36ac0bb50cdfd9a61487152676266c4087547;hb=5566f74eb29be75da44e29ba72ee6f015249ce61;hpb=507d22099d8b7fce31bf2d575f609cc8d94131ea diff --git a/sip.cpp b/sip.cpp index c6f36ac..075447c 100644 --- a/sip.cpp +++ b/sip.cpp @@ -15,27 +15,38 @@ #include #include +#ifndef SOFIA_SIP_GCC_4_8_PATCH_APLLIED +#warning ******************************************************** +#warning Please apply the sofia-sip-gcc-4.8.patch ! +#warning If this issue is already fixed, just remove this check. +#warning ******************************************************** +#error +#endif + #undef NUTAG_AUTO100 unsigned char flip[256]; +int any_sip_interface = 0; + //pthread_mutex_t mutex_msg; su_home_t sip_home[1]; 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; }; static int delete_event(struct lcr_work *work, void *instance, int index); +static int load_timer(struct lcr_timer *timer, void *instance, int index); /* * 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) @@ -61,7 +72,14 @@ Psip::Psip(int type, char *portname, struct port_settings *settings, struct inte p_s_rxpos = 0; p_s_rtp_tx_action = 0; + /* audio */ + memset(&p_s_loadtimer, 0, sizeof(p_s_loadtimer)); + add_timer(&p_s_loadtimer, load_timer, this, 0); + p_s_next_tv_sec = 0; + PDEBUG(DEBUG_SIP, "Created new Psip(%s).\n", portname); + if (!p_s_sip_inst) + FATAL("No SIP instance for interface\n"); } @@ -72,22 +90,26 @@ Psip::~Psip() { PDEBUG(DEBUG_SIP, "Destroyed SIP process(%s).\n", p_name); + del_timer(&p_s_loadtimer); del_work(&p_s_delete); 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"; @@ -139,12 +161,9 @@ struct rtp_x_hdr { #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) @@ -203,6 +222,8 @@ 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 " @@ -227,13 +248,14 @@ static int rtp_decode(class Psip *psip, unsigned char *data, int len) 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; @@ -250,11 +272,24 @@ static int rtp_decode(class Psip *psip, unsigned char *data, int len) return 0; } + /* record audio */ + if (psip->p_record) + psip->record(payload, payload_len, 0); // from down + if (psip->p_tap) + psip->tap(payload, payload_len, 0); // from down + 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++]; + if (psip->p_dov_rx) + psip->dov_rx(payload, payload_len); psip->bridge_tx(payload, payload_len); return 0; @@ -275,7 +310,8 @@ static int rtp_sock_callback(struct lcr_fd *fd, unsigned int what, void *instanc // 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; @@ -302,7 +338,8 @@ static int rtcp_sock_callback(struct lcr_fd *fd, unsigned int what, void *instan } #define RTP_PORT_BASE 30000 -static unsigned int next_udp_port = RTP_PORT_BASE; +#define RTP_PORT_MAX 39998 +static unsigned short next_udp_port = RTP_PORT_BASE; static int rtp_sub_socket_bind(int fd, struct sockaddr_in *sin_local, uint32_t ip, uint16_t port) { @@ -342,13 +379,14 @@ static int rtp_sub_socket_connect(int fd, struct sockaddr_in *sin_local, struct int Psip::rtp_open(void) { - int rc; + int rc, rc2; struct in_addr ia; unsigned int ip; + unsigned short start_port; /* create socket */ rc = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); - if (!rc) { + if (rc < 0) { rtp_close(); return -EIO; } @@ -356,7 +394,7 @@ int Psip::rtp_open(void) register_fd(&p_s_rtp_fd, LCR_FD_READ, rtp_sock_callback, this, 0); rc = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); - if (!rc) { + if (rc < 0) { rtp_close(); return -EIO; } @@ -366,22 +404,41 @@ int Psip::rtp_open(void) /* bind socket */ ip = htonl(INADDR_ANY); ia.s_addr = ip; - for (next_udp_port = next_udp_port % 0xffff; - next_udp_port < 0xffff; next_udp_port += 2) { + start_port = next_udp_port; + while (1) { rc = rtp_sub_socket_bind(p_s_rtp_fd.fd, &p_s_rtp_sin_local, ip, next_udp_port); if (rc != 0) - continue; + goto try_next_port; - rc = rtp_sub_socket_bind(p_s_rtcp_fd.fd, &p_s_rtcp_sin_local, ip, next_udp_port+1); - if (rc == 0) + rc = rtp_sub_socket_bind(p_s_rtcp_fd.fd, &p_s_rtcp_sin_local, ip, next_udp_port + 1); + if (rc == 0) { + p_s_rtp_port_local = next_udp_port; + next_udp_port = (next_udp_port + 2 > RTP_PORT_MAX) ? RTP_PORT_BASE : next_udp_port + 2; break; + } + /* reopen rtp socket and try again with next udp port */ + unregister_fd(&p_s_rtp_fd); + close(p_s_rtp_fd.fd); + p_s_rtp_fd.fd = 0; + rc2 = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (rc2 < 0) { + rtp_close(); + return -EIO; + } + p_s_rtp_fd.fd = rc2; + register_fd(&p_s_rtp_fd, LCR_FD_READ, rtp_sock_callback, this, 0); + +try_next_port: + next_udp_port = (next_udp_port + 2 > RTP_PORT_MAX) ? RTP_PORT_BASE : next_udp_port + 2; + if (next_udp_port == start_port) + break; + /* we must use rc2, in order to preserve rc */ } if (rc < 0) { PDEBUG(DEBUG_SIP, "failed to find port\n"); rtp_close(); return rc; } - p_s_rtp_port_local = next_udp_port; p_s_rtp_ip_local = ntohl(p_s_rtp_sin_local.sin_addr.s_addr); PDEBUG(DEBUG_SIP, "local ip %08x port %d\n", p_s_rtp_ip_local, p_s_rtp_port_local); PDEBUG(DEBUG_SIP, "remote ip %08x port %d\n", p_s_rtp_ip_remote, p_s_rtp_port_remote); @@ -453,6 +510,12 @@ int Psip::rtp_send_frame(unsigned char *data, unsigned int len, uint8_t payload_ int duration; /* in samples */ unsigned char buffer[256]; + /* record audio */ + if (p_record) + record(data, len, 1); // from up + if (p_tap) + tap(data, len, 1); // from up + if (!p_s_rtp_is_connected) { /* drop silently */ return 0; @@ -468,6 +531,8 @@ int Psip::rtp_send_frame(unsigned char *data, unsigned int len, uint8_t payload_ } switch (payload_type) { +#if 0 +we only support alaw and ulaw! case RTP_PT_GSM_FULL: payload_len = 33; duration = 160; @@ -480,8 +545,9 @@ int Psip::rtp_send_frame(unsigned char *data, unsigned int len, uint8_t payload_ 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; @@ -541,6 +607,18 @@ int Psip::rtp_send_frame(unsigned char *data, unsigned int len, uint8_t payload_ /* receive from remote */ int Psip::bridge_rx(unsigned char *data, int len) { + int ret; + + /* don't bridge, if tones are provided */ + if (p_tone_name[0] || p_dov_tx) + return -EBUSY; + + if (p_dov_tx) + return -EBUSY; + + if ((ret = Port::bridge_rx(data, len))) + return ret; + /* write to rx buffer */ while(len--) { p_s_rxdata[p_s_rxpos++] = flip[*data++]; @@ -548,7 +626,7 @@ int Psip::bridge_rx(unsigned char *data, int len) 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); } } @@ -733,11 +811,13 @@ int Psip::message_connect(unsigned int epoint_id, int message_id, union paramete 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; @@ -746,7 +826,8 @@ int Psip::message_connect(unsigned int epoint_id, int message_id, union paramete 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 (!p_s_rtp_is_connected && rtp_connect() < 0) { nua_cancel(p_s_handle, TAG_END()); @@ -775,9 +856,15 @@ int Psip::message_connect(unsigned int epoint_id, int message_id, union paramete "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); + /* NOTE: + * If this response causes corrupt messages, like SDP body inside or + * before header, check if the sofia-sip-gcc-4.8.patch was applied. + * If it is still corrupted, try to disable optimization when compiling + * sofia-sip. + */ nua_respond(p_s_handle, SIP_200_OK, NUTAG_MEDIA_ENABLE(0), SIPTAG_CONTENT_TYPE_STR("application/sdp"), @@ -788,7 +875,7 @@ int Psip::message_connect(unsigned int epoint_id, int message_id, union paramete 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; @@ -863,14 +950,17 @@ int Psip::message_setup(unsigned int epoint_id, int message_id, union parameter 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; + 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; @@ -884,6 +974,7 @@ int Psip::message_setup(unsigned int epoint_id, int message_id, union parameter 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; @@ -893,6 +984,7 @@ int Psip::message_setup(unsigned int epoint_id, int message_id, union parameter } 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; @@ -928,8 +1020,15 @@ int Psip::message_setup(unsigned int epoint_id, int message_id, union parameter 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); @@ -947,7 +1046,7 @@ int Psip::message_setup(unsigned int epoint_id, int message_id, union parameter } 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); @@ -961,7 +1060,7 @@ int Psip::message_setup(unsigned int epoint_id, int message_id, union parameter 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); @@ -1036,7 +1135,7 @@ int Psip::message_notify(unsigned int epoint_id, int message_id, union parameter "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)), @@ -1146,7 +1245,7 @@ int Psip::message_epoint(unsigned int epoint_id, int message_id, union parameter 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; @@ -1206,11 +1305,26 @@ int Psip::parse_sdp(sip_t const *sip, unsigned int *ip, unsigned short *port, ui *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)++; } } @@ -1224,13 +1338,16 @@ int Psip::parse_sdp(sip_t const *sip, unsigned int *ip, unsigned short *port, ui void Psip::i_invite(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 sip_inst *inst = (struct sip_inst *) p_s_sip_inst; - const char *from = "", *to = ""; + const char *from = "", *to = "", *name = ""; + char imsi[16] = ""; int ret; class Endpoint *epoint; struct lcr_msg *message; struct interface *interface; + int media_types[32]; uint8_t payload_types[32]; int payloads = 0; + int media_type; interface = getinterfacebyname(inst->interface_name); if (!interface) { @@ -1238,14 +1355,26 @@ void Psip::i_invite(int status, char const *phrase, nua_t *nua, nua_magic_t *mag return; } - if (sip->sip_from && sip->sip_from->a_url) - from = sip->sip_from->a_url->url_user; - if (sip->sip_to && sip->sip_to->a_url) - to = sip->sip_to->a_url->url_user; + if (sip->sip_from) { + if (sip->sip_from->a_url) + from = sip->sip_from->a_url->url_user; + if (sip->sip_from->a_display) { + name = sip->sip_from->a_display; + if (!strncmp(name, "\"IMSI", 5)) { + strncpy(imsi, name + 5, 15); + imsi[15] = '\0'; + name = ""; + } + } + } + if (sip->sip_to) { + if (sip->sip_to->a_url) + to = sip->sip_to->a_url->url_user; + } 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) { @@ -1253,7 +1382,7 @@ void Psip::i_invite(int status, char const *phrase, nua_t *nua, nua_magic_t *mag /* 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) { @@ -1303,7 +1432,7 @@ void Psip::i_invite(int status, char const *phrase, nua_t *nua, nua_magic_t *mag 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; @@ -1316,6 +1445,12 @@ void Psip::i_invite(int status, char const *phrase, nua_t *nua, nua_magic_t *mag p_callerinfo.ntype = INFO_NTYPE_UNKNOWN; SCPY(p_callerinfo.id, from); add_trace("calling", "number", "%s", from); + SCPY(p_callerinfo.name, name); + if (name[0]) + add_trace("calling", "name", "%s", name); + SCPY(p_callerinfo.imsi, imsi); + if (imsi[0]) + add_trace("calling", "imsi", "%s", imsi); } SCPY(p_callerinfo.interface, inst->interface_name); /* dialing information */ @@ -1372,16 +1507,15 @@ void Psip::i_invite(int status, char const *phrase, nua_t *nua, nua_magic_t *mag 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]; @@ -1389,7 +1523,8 @@ issues: 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; + 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) { nua_respond(nh, SIP_500_INTERNAL_SERVER_ERROR, TAG_END()); @@ -1420,23 +1555,21 @@ issues: "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_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); + add_trace("rtp", "payload", "%s:%d", media_type2name(media_type), 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[]) @@ -1531,6 +1664,7 @@ void Psip::r_invite(int status, char const *phrase, nua_t *nua, nua_magic_t *mag { struct lcr_msg *message; int cause = 0, location = 0; + int media_types[32]; uint8_t payload_types[32]; int payloads = 0; @@ -1545,12 +1679,12 @@ void Psip::r_invite(int status, char const *phrase, nua_t *nua, nua_magic_t *mag 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; } @@ -1603,6 +1737,7 @@ void Psip::r_invite(int status, char const *phrase, nua_t *nua, nua_magic_t *mag 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; } @@ -1625,6 +1760,7 @@ void Psip::r_invite(int status, char const *phrase, nua_t *nua, nua_magic_t *mag 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; } @@ -1776,11 +1912,12 @@ void Psip::rtp_shutdown(void) 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); @@ -1790,7 +1927,10 @@ int sip_init_inst(struct interface *interface) 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); @@ -1815,6 +1955,8 @@ int sip_init_inst(struct interface *interface) PDEBUG(DEBUG_SIP, "SIP interface created (inst=%p)\n", inst); + any_sip_interface = 1; + return 0; } @@ -1833,6 +1975,16 @@ void sip_exit_inst(struct interface *interface) interface->sip_inst = NULL; PDEBUG(DEBUG_SIP, "SIP interface removed\n"); + + /* check if there is any other SIP interface left */ + interface = interface_first; + while (interface) { + if (interface->sip_inst) + break; + interface = interface->next; + } + if (!interface) + any_sip_interface = 0; } extern su_log_t su_log_default[]; @@ -1893,3 +2045,106 @@ static int delete_event(struct lcr_work *work, void *instance, int index) return 0; } + +/* + * generate audio, if no data is received from bridge + */ + +void Psip::set_tone(const char *dir, const char *tone) +{ + Port::set_tone(dir, tone); + + update_load(); +} + +void Psip::update_load(void) +{ + /* don't trigger load event if event already active */ + if (p_s_loadtimer.active) + return; + + /* don't start timer if ... */ + if (!p_tone_name[0] && !p_dov_tx) + return; + + p_s_next_tv_sec = 0; + schedule_timer(&p_s_loadtimer, 0, 0); /* no delay the first time */ +} + +static int load_timer(struct lcr_timer *timer, void *instance, int index) +{ + class Psip *psip = (class Psip *)instance; + + /* stop timer if ... */ + if (!psip->p_tone_name[0] && !psip->p_dov_tx) + return 0; + + psip->load_tx(); + + return 0; +} + +#define SEND_SIP_LEN 160 + +void Psip::load_tx(void) +{ + int diff; + struct timeval current_time; + int tosend = SEND_SIP_LEN, i; + unsigned char buf[SEND_SIP_LEN], *p = buf; + + /* get elapsed */ + gettimeofday(¤t_time, NULL); + if (!p_s_next_tv_sec) { + /* if timer expired the first time, set next expected timeout 160 samples in advance */ + p_s_next_tv_sec = current_time.tv_sec; + p_s_next_tv_usec = current_time.tv_usec + SEND_SIP_LEN * 125; + if (p_s_next_tv_usec >= 1000000) { + p_s_next_tv_usec -= 1000000; + p_s_next_tv_sec++; + } + schedule_timer(&p_s_loadtimer, 0, SEND_SIP_LEN * 125); + } else { + diff = 1000000 * (current_time.tv_sec - p_s_next_tv_sec) + + (current_time.tv_usec - p_s_next_tv_usec); + if (diff < -SEND_SIP_LEN * 125 || diff > SEND_SIP_LEN * 125) { + /* if clock drifts too much, set next timeout event to current timer + 160 */ + diff = 0; + p_s_next_tv_sec = current_time.tv_sec; + p_s_next_tv_usec = current_time.tv_usec + SEND_SIP_LEN * 125; + if (p_s_next_tv_usec >= 1000000) { + p_s_next_tv_usec -= 1000000; + p_s_next_tv_sec++; + } + } else { + /* if diff is positive, it took too long, so next timeout will be earlier */ + p_s_next_tv_usec += SEND_SIP_LEN * 125; + if (p_s_next_tv_usec >= 1000000) { + p_s_next_tv_usec -= 1000000; + p_s_next_tv_sec++; + } + } + schedule_timer(&p_s_loadtimer, 0, SEND_SIP_LEN * 125 - diff); + } + + /* copy tones */ + if (p_tone_name[0]) { + tosend -= read_audio(p, tosend); + } else + if (p_dov_tx) { + tosend -= dov_tx(p, tosend); + } + if (tosend) { + PERROR("buffer is not completely filled\n"); + return; + } + + p = buf; + for (i = 0; i < SEND_SIP_LEN; i++) { + *p = flip[*p]; + p++; + } + /* transmit data via rtp */ + rtp_send_frame(buf, SEND_SIP_LEN, (options.law=='a')?PAYLOAD_TYPE_ALAW:PAYLOAD_TYPE_ULAW); +} +