#include <sofia-sip/sdp.h>
#include <sofia-sip/sip_header.h>
+#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 {
- struct interface *interface;
+ char interface_name[64];
+ 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, struct mISDNport *mISDNport, char *portname, struct port_settings *settings, int channel, int exclusive, int mode, struct interface *interface) : PmISDN(type, mISDNport, portname, settings, channel, exclusive, mode)
+Psip::Psip(int type, char *portname, struct port_settings *settings, struct interface *interface) : Port(type, portname, settings, interface)
{
- p_m_s_sip_inst = interface->sip_inst;
- memset(&p_m_s_delete, 0, sizeof(p_m_s_delete));
- add_work(&p_m_s_delete, delete_event, this, 0);
- p_m_s_handle = 0;
- p_m_s_magic = 0;
- memset(&p_m_s_rtp_fd, 0, sizeof(p_m_s_rtp_fd));
- memset(&p_m_s_rtcp_fd, 0, sizeof(p_m_s_rtcp_fd));
- memset(&p_m_s_rtp_sin_local, 0, sizeof(p_m_s_rtp_sin_local));
- memset(&p_m_s_rtcp_sin_local, 0, sizeof(p_m_s_rtcp_sin_local));
- memset(&p_m_s_rtp_sin_remote, 0, sizeof(p_m_s_rtp_sin_remote));
- memset(&p_m_s_rtcp_sin_remote, 0, sizeof(p_m_s_rtcp_sin_remote));
- p_m_s_rtp_ip_local = 0;
- p_m_s_rtp_ip_remote = 0;
- p_m_s_rtp_port_local = 0;
- p_m_s_rtp_port_remote = 0;
- p_m_s_b_sock = -1;
- p_m_s_b_index = -1;
- p_m_s_b_active = 0;
- p_m_s_rxpos = 0;
- p_m_s_rtp_tx_action = 0;
+ p_s_rtp_bridge = 0;
+ if (interface->rtp_bridge)
+ p_s_rtp_bridge = 1;
+ p_s_sip_inst = interface->sip_inst;
+ memset(&p_s_delete, 0, sizeof(p_s_delete));
+ add_work(&p_s_delete, delete_event, this, 0);
+ p_s_handle = 0;
+ p_s_magic = 0;
+ memset(&p_s_rtp_fd, 0, sizeof(p_s_rtp_fd));
+ memset(&p_s_rtcp_fd, 0, sizeof(p_s_rtcp_fd));
+ memset(&p_s_rtp_sin_local, 0, sizeof(p_s_rtp_sin_local));
+ memset(&p_s_rtcp_sin_local, 0, sizeof(p_s_rtcp_sin_local));
+ memset(&p_s_rtp_sin_remote, 0, sizeof(p_s_rtp_sin_remote));
+ memset(&p_s_rtcp_sin_remote, 0, sizeof(p_s_rtcp_sin_remote));
+ p_s_rtp_ip_local = 0;
+ p_s_rtp_ip_remote = 0;
+ p_s_rtp_port_local = 0;
+ p_s_rtp_port_remote = 0;
+ p_s_b_sock = -1;
+ p_s_b_index = -1;
+ p_s_b_active = 0;
+ 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");
}
{
PDEBUG(DEBUG_SIP, "Destroyed SIP process(%s).\n", p_name);
- del_work(&p_m_s_delete);
-
- /* close audio transfer socket */
- if (p_m_s_b_sock > -1)
- bchannel_close();
+ del_timer(&p_s_loadtimer);
+ del_work(&p_s_delete);
rtp_close();
}
+static const char *media_type2name(uint8_t media_type) {
+ switch (media_type) {
+ case MEDIA_TYPE_ULAW:
+ return "PCMU";
+ case MEDIA_TYPE_ALAW:
+ return "PCMA";
+ 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";
+}
static void sip_trace_header(class Psip *sip, const char *message, int direction)
{
#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_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)
uint8_t *payload;
int payload_len;
int x_len;
+ unsigned char *from, *to;
+ int n;
if (len < 12) {
PDEBUG(DEBUG_SIP, "received RTP frame too short (len = %d)\n", 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:
+ case RTP_PT_GSM_HALF:
+ if (payload_len != 14) {
+ PDEBUG(DEBUG_SIP, "received RTP half rate frame with "
+ "payload length != 14 (len = %d)\n",
+ payload_len);
+ return -EINVAL;
+ }
+ break;
+#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;
return 0;
}
- psip->bchannel_send(PH_DATA_REQ, 0, payload, payload_len);
+ /* 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;
}
// 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;
}
#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)
{
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;
}
- p_m_s_rtp_fd.fd = rc;
- register_fd(&p_m_s_rtp_fd, LCR_FD_READ, rtp_sock_callback, this, 0);
+ p_s_rtp_fd.fd = rc;
+ 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;
}
- p_m_s_rtcp_fd.fd = rc;
- register_fd(&p_m_s_rtcp_fd, LCR_FD_READ, rtcp_sock_callback, this, 0);
+ p_s_rtcp_fd.fd = rc;
+ register_fd(&p_s_rtcp_fd, LCR_FD_READ, rtcp_sock_callback, this, 0);
/* 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) {
- rc = rtp_sub_socket_bind(p_m_s_rtp_fd.fd, &p_m_s_rtp_sin_local, ip, next_udp_port);
+ 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) {
+ 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);
- rc = rtp_sub_socket_bind(p_m_s_rtcp_fd.fd, &p_m_s_rtcp_sin_local, ip, next_udp_port+1);
- if (rc == 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_m_s_rtp_port_local = next_udp_port;
- p_m_s_rtp_ip_local = ntohl(p_m_s_rtp_sin_local.sin_addr.s_addr);
- PDEBUG(DEBUG_SIP, "local ip %08x port %d\n", p_m_s_rtp_ip_local, p_m_s_rtp_port_local);
- PDEBUG(DEBUG_SIP, "remote ip %08x port %d\n", p_m_s_rtp_ip_remote, p_m_s_rtp_port_remote);
+ 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);
- return p_m_s_rtp_port_local;
+ return p_s_rtp_port_local;
}
int Psip::rtp_connect(void)
int rc;
struct in_addr ia;
- ia.s_addr = htonl(p_m_s_rtp_ip_remote);
- PDEBUG(DEBUG_SIP, "rtp_connect(ip=%s, port=%u)\n", inet_ntoa(ia), p_m_s_rtp_port_remote);
+ ia.s_addr = htonl(p_s_rtp_ip_remote);
+ PDEBUG(DEBUG_SIP, "rtp_connect(ip=%s, port=%u)\n", inet_ntoa(ia), p_s_rtp_port_remote);
- rc = rtp_sub_socket_connect(p_m_s_rtp_fd.fd, &p_m_s_rtp_sin_local, &p_m_s_rtp_sin_remote, p_m_s_rtp_ip_remote, p_m_s_rtp_port_remote);
+ rc = rtp_sub_socket_connect(p_s_rtp_fd.fd, &p_s_rtp_sin_local, &p_s_rtp_sin_remote, p_s_rtp_ip_remote, p_s_rtp_port_remote);
if (rc < 0)
return rc;
- rc = rtp_sub_socket_connect(p_m_s_rtcp_fd.fd, &p_m_s_rtcp_sin_local, &p_m_s_rtcp_sin_remote, p_m_s_rtp_ip_remote, p_m_s_rtp_port_remote + 1);
+ rc = rtp_sub_socket_connect(p_s_rtcp_fd.fd, &p_s_rtcp_sin_local, &p_s_rtcp_sin_remote, p_s_rtp_ip_remote, p_s_rtp_port_remote + 1);
if (rc < 0)
return rc;
- p_m_s_rtp_ip_local = ntohl(p_m_s_rtp_sin_local.sin_addr.s_addr);
- PDEBUG(DEBUG_SIP, "local ip %08x port %d\n", p_m_s_rtp_ip_local, p_m_s_rtp_port_local);
- PDEBUG(DEBUG_SIP, "remote ip %08x port %d\n", p_m_s_rtp_ip_remote, p_m_s_rtp_port_remote);
- p_m_s_rtp_is_connected = 1;
+ 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);
+ p_s_rtp_is_connected = 1;
return 0;
}
void Psip::rtp_close(void)
{
- if (p_m_s_rtp_fd.fd > 0) {
- unregister_fd(&p_m_s_rtp_fd);
- close(p_m_s_rtp_fd.fd);
- p_m_s_rtp_fd.fd = 0;
+ if (p_s_rtp_fd.fd > 0) {
+ unregister_fd(&p_s_rtp_fd);
+ close(p_s_rtp_fd.fd);
+ p_s_rtp_fd.fd = 0;
}
- if (p_m_s_rtcp_fd.fd > 0) {
- unregister_fd(&p_m_s_rtcp_fd);
- close(p_m_s_rtcp_fd.fd);
- p_m_s_rtcp_fd.fd = 0;
+ if (p_s_rtcp_fd.fd > 0) {
+ unregister_fd(&p_s_rtcp_fd);
+ close(p_s_rtcp_fd.fd);
+ p_s_rtcp_fd.fd = 0;
}
- if (p_m_s_rtp_is_connected) {
+ if (p_s_rtp_is_connected) {
PDEBUG(DEBUG_SIP, "rtp closed\n");
- p_m_s_rtp_is_connected = 0;
+ p_s_rtp_is_connected = 0;
}
}
}
/* encode and send a rtp frame */
-int Psip::rtp_send_frame(unsigned char *data, unsigned int len, int payload_type)
+int Psip::rtp_send_frame(unsigned char *data, unsigned int len, uint8_t payload_type)
{
struct rtp_hdr *rtph;
int payload_len;
int duration; /* in samples */
unsigned char buffer[256];
- if (!p_m_s_rtp_is_connected) {
+ /* 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;
}
- if (!p_m_s_rtp_tx_action) {
+ if (!p_s_rtp_tx_action) {
/* initialize sequences */
- p_m_s_rtp_tx_action = 1;
- p_m_s_rtp_tx_ssrc = rand();
- p_m_s_rtp_tx_sequence = random();
- p_m_s_rtp_tx_timestamp = random();
- memset(&p_m_s_rtp_tx_last_tv, 0, sizeof(p_m_s_rtp_tx_last_tv));
+ p_s_rtp_tx_action = 1;
+ p_s_rtp_tx_ssrc = rand();
+ p_s_rtp_tx_sequence = random();
+ p_s_rtp_tx_timestamp = random();
+ memset(&p_s_rtp_tx_last_tv, 0, sizeof(p_s_rtp_tx_last_tv));
}
switch (payload_type) {
+#if 0
+we only support alaw and ulaw!
case RTP_PT_GSM_FULL:
payload_len = 33;
duration = 160;
payload_len = 31;
duration = 160;
break;
- case RTP_PT_ALAW:
- case RTP_PT_ULAW:
+ case RTP_PT_GSM_HALF:
+ payload_len = 14;
+ duration = 160;
+ break;
+#endif
+ case PAYLOAD_TYPE_ALAW:
+ case PAYLOAD_TYPE_ULAW:
payload_len = len;
duration = len;
break;
long int usec_diff, frame_diff;
gettimeofday(&tv, NULL);
- tv_difference(&tv_diff, &p_m_s_rtp_tx_last_tv, &tv);
- p_m_s_rtp_tx_last_tv = tv;
+ tv_difference(&tv_diff, &p_s_rtp_tx_last_tv, &tv);
+ p_s_rtp_tx_last_tv = tv;
usec_diff = tv_diff.tv_sec * 1000000 + tv_diff.tv_usec;
frame_diff = (usec_diff / 20000);
long int frame_diff_excess = frame_diff - 1;
PDEBUG(DEBUG_SIP, "Correcting frame difference of %ld frames\n", frame_diff_excess);
- p_m_s_rtp_tx_sequence += frame_diff_excess;
- p_m_s_rtp_tx_timestamp += frame_diff_excess * duration;
+ p_s_rtp_tx_sequence += frame_diff_excess;
+ p_s_rtp_tx_timestamp += frame_diff_excess * duration;
}
}
#endif
rtph->csrc_count = 0;
rtph->marker = 0;
rtph->payload_type = payload_type;
- rtph->sequence = htons(p_m_s_rtp_tx_sequence++);
- rtph->timestamp = htonl(p_m_s_rtp_tx_timestamp);
- p_m_s_rtp_tx_timestamp += duration;
- rtph->ssrc = htonl(p_m_s_rtp_tx_ssrc);
+ rtph->sequence = htons(p_s_rtp_tx_sequence++);
+ rtph->timestamp = htonl(p_s_rtp_tx_timestamp);
+ p_s_rtp_tx_timestamp += duration;
+ rtph->ssrc = htonl(p_s_rtp_tx_ssrc);
memcpy(buffer + sizeof(struct rtp_hdr), data, payload_len);
- if (p_m_s_rtp_fd.fd > 0) {
- len = write(p_m_s_rtp_fd.fd, &buffer, sizeof(struct rtp_hdr) + payload_len);
+ if (p_s_rtp_fd.fd > 0) {
+ len = write(p_s_rtp_fd.fd, &buffer, sizeof(struct rtp_hdr) + payload_len);
if (len != sizeof(struct rtp_hdr) + payload_len) {
PDEBUG(DEBUG_SIP, "write result=%d\n", len);
// rtp_close();
return 0;
}
-/*
- * bchannel handling
- */
-
-/* select free bchannel from loopback interface */
-int Psip::hunt_bchannel(void)
-{
- return loop_hunt_bchannel(this, p_m_mISDNport);
-}
-
-/* close SIP side bchannel */
-void Psip::bchannel_close(void)
-{
- if (p_m_s_b_sock > -1) {
- unregister_fd(&p_m_s_b_fd);
- close(p_m_s_b_sock);
- }
- p_m_s_b_sock = -1;
- p_m_s_b_index = -1;
- p_m_s_b_active = 0;
-}
-
-static int b_handler(struct lcr_fd *fd, unsigned int what, void *instance, int index);
-
-/* open external side bchannel */
-int Psip::bchannel_open(int index)
+/* receive from remote */
+int Psip::bridge_rx(unsigned char *data, int len)
{
int ret;
- struct sockaddr_mISDN addr;
- struct mISDNhead act;
-
- if (p_m_s_b_sock > -1) {
- PERROR("Socket already created for index %d\n", index);
- return(-EIO);
- }
-
- /* open socket */
- ret = p_m_s_b_sock = socket(PF_ISDN, SOCK_DGRAM, ISDN_P_B_RAW);
- if (ret < 0) {
- PERROR("Failed to open bchannel-socket for index %d\n", index);
- bchannel_close();
- return(ret);
- }
- memset(&p_m_s_b_fd, 0, sizeof(p_m_s_b_fd));
- p_m_s_b_fd.fd = p_m_s_b_sock;
- register_fd(&p_m_s_b_fd, LCR_FD_READ, b_handler, this, 0);
+ /* don't bridge, if tones are provided */
+ if (p_tone_name[0] || p_dov_tx)
+ return -EBUSY;
- /* bind socket to bchannel */
- addr.family = AF_ISDN;
- addr.dev = mISDNloop.port;
- addr.channel = index+1+(index>15);
- ret = bind(p_m_s_b_sock, (struct sockaddr *)&addr, sizeof(addr));
- if (ret < 0) {
- PERROR("Failed to bind bchannel-socket for index %d\n", index);
- bchannel_close();
- return(ret);
- }
- /* activate bchannel */
- PDEBUG(DEBUG_SIP, "Activating SIP side channel index %i.\n", index);
- act.prim = PH_ACTIVATE_REQ;
- act.id = 0;
- ret = sendto(p_m_s_b_sock, &act, MISDN_HEADER_LEN, 0, NULL, 0);
- if (ret < 0) {
- PERROR("Failed to activate index %d\n", index);
- bchannel_close();
- return(ret);
- }
+ if (p_dov_tx)
+ return -EBUSY;
- p_m_s_b_index = index;
+ if ((ret = Port::bridge_rx(data, len)))
+ return ret;
- return(0);
-}
-
-/* receive from bchannel */
-void Psip::bchannel_receive(struct mISDNhead *hh, unsigned char *data, int len)
-{
/* write to rx buffer */
while(len--) {
- p_m_s_rxdata[p_m_s_rxpos++] = flip[*data++];
- if (p_m_s_rxpos == 160) {
- p_m_s_rxpos = 0;
+ p_s_rxdata[p_s_rxpos++] = flip[*data++];
+ if (p_s_rxpos == 160) {
+ p_s_rxpos = 0;
/* transmit data via rtp */
- rtp_send_frame(p_m_s_rxdata, 160, (options.law=='a')?RTP_PT_ALAW:RTP_PT_ULAW);
- }
- }
-}
-
-/* transmit to bchannel */
-void Psip::bchannel_send(unsigned int prim, unsigned int id, unsigned char *data, int len)
-{
- unsigned char buf[MISDN_HEADER_LEN+len];
- struct mISDNhead *hh = (struct mISDNhead *)buf;
- unsigned char *to = buf + MISDN_HEADER_LEN;
- int n = len;
- int ret;
-
- if (!p_m_s_b_active)
- return;
-
- /* make and send frame */
- hh->prim = prim;
- hh->id = 0;
- while(n--)
- *to++ = flip[*data++];
- ret = sendto(p_m_s_b_sock, buf, MISDN_HEADER_LEN+len, 0, NULL, 0);
- if (ret <= 0)
- PERROR("Failed to send to socket index %d\n", p_m_s_b_index);
-}
-
-/* handle socket input */
-static int b_handler(struct lcr_fd *fd, unsigned int what, void *instance, int index)
-{
- class Psip *psip = (class Psip *)instance;
- int ret;
- unsigned char buffer[2048+MISDN_HEADER_LEN];
- struct mISDNhead *hh = (struct mISDNhead *)buffer;
-
- /* handle message from bchannel */
- if (psip->p_m_s_b_sock > -1) {
- ret = recv(psip->p_m_s_b_sock, buffer, sizeof(buffer), 0);
- if (ret >= (int)MISDN_HEADER_LEN) {
- switch(hh->prim) {
- /* we don't care about confirms, we use rx data to sync tx */
- case PH_DATA_CNF:
- break;
- /* we receive audio data, we respond to it AND we send tones */
- case PH_DATA_IND:
- psip->bchannel_receive(hh, buffer+MISDN_HEADER_LEN, ret-MISDN_HEADER_LEN);
- break;
- case PH_ACTIVATE_IND:
- psip->p_m_s_b_active = 1;
- break;
- case PH_DEACTIVATE_IND:
- psip->p_m_s_b_active = 0;
- break;
- }
- } else {
- if (ret < 0 && errno != EWOULDBLOCK)
- PERROR("Read from GSM port, index %d failed with return code %d\n", ret);
+ 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;
-
- if (rtp_connect() < 0) {
- nua_cancel(p_m_s_handle, TAG_END());
- nua_handle_destroy(p_m_s_handle);
- p_m_s_handle = NULL;
- sip_trace_header(this, "CANCEL", DIRECTION_OUT);
- add_trace("reason", NULL, "failed to connect RTP/RTCP sockts");
- end_trace();
- message = message_create(p_serial, epoint_id, 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_m_s_delete);
- return 0;
+ 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, "payload type %d\n", payload_type);
+ 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);
+ } else {
+ PDEBUG(DEBUG_SIP, "RTP info not given by remote, so we do our own RTP\n");
+ 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());
+ nua_handle_destroy(p_s_handle);
+ p_s_handle = NULL;
+ sip_trace_header(this, "CANCEL", DIRECTION_OUT);
+ add_trace("reason", NULL, "failed to connect RTP/RTCP sockts");
+ end_trace();
+ message = message_create(p_serial, epoint_id, 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 0;
+ }
}
- ia.s_addr = htonl(p_m_s_rtp_ip_local);
+
+ ia.s_addr = htonl(p_s_rtp_ip_local);
SPRINT(sdp_str,
"v=0\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_m_s_rtp_port_local, (options.law=='a')?RTP_PT_ALAW:RTP_PT_ULAW, (options.law=='a')?RTP_PT_ALAW:RTP_PT_ULAW, (options.law=='a')?"PCMA":"PCMU");
+ , 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_m_s_handle, SIP_200_OK,
+ /* 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"),
SIPTAG_PAYLOAD_STR(sdp_str), TAG_END());
sip_trace_header(this, "RESPOND", DIRECTION_OUT);
add_trace("respond", "value", "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", "%s:%d", media_type2name(media_type), payload_type);
end_trace();
return 0;
if (cause_str[0])
add_trace("cause", "value", "%d", cause);
end_trace();
- nua_cancel(p_m_s_handle, TAG_IF(cause_str[0], SIPTAG_REASON_STR(cause_str)), TAG_END());
+ nua_cancel(p_s_handle, TAG_IF(cause_str[0], SIPTAG_REASON_STR(cause_str)), TAG_END());
break;
case PORT_STATE_IN_SETUP:
case PORT_STATE_IN_PROCEEDING:
add_trace("cause", "value", "%d", cause);
add_trace("respond", "value", "%d %s", status, status_text);
end_trace();
- nua_respond(p_m_s_handle, status, status_text, TAG_IF(cause_str[0], SIPTAG_REASON_STR(cause_str)), TAG_END());
- nua_handle_destroy(p_m_s_handle);
- p_m_s_handle = NULL;
- trigger_work(&p_m_s_delete);
+ nua_respond(p_s_handle, status, status_text, TAG_IF(cause_str[0], SIPTAG_REASON_STR(cause_str)), TAG_END());
+ nua_handle_destroy(p_s_handle);
+ p_s_handle = NULL;
+ trigger_work(&p_s_delete);
break;
default:
PDEBUG(DEBUG_SIP, "RELEASE/DISCONNECT will perform nua_bye\n");
if (cause_str[0])
add_trace("cause", "value", "%d", cause);
end_trace();
- nua_bye(p_m_s_handle, TAG_IF(cause_str[0], SIPTAG_REASON_STR(cause_str)), TAG_END());
+ nua_bye(p_s_handle, TAG_IF(cause_str[0], SIPTAG_REASON_STR(cause_str)), TAG_END());
}
if (message_id == MESSAGE_DISCONNECT) {
int Psip::message_setup(unsigned int epoint_id, int message_id, union parameter *param)
{
- struct sip_inst *inst = (struct sip_inst *) p_m_s_sip_inst;
+ struct sip_inst *inst = (struct sip_inst *) p_s_sip_inst;
char from[128];
char to[128];
- const char *local = inst->interface->sip_local_ip;
- const char *remote = inst->interface->sip_remote_ip;
- char sdp_str[256];
+ 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;
- int ret;
- int channel;
+ struct lcr_msg *message;
+ 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;
PDEBUG(DEBUG_SIP, "Doing Setup (inst %p)\n", inst);
- /* release if port is blocked */
- if (p_m_mISDNport->ifport->block) {
- struct lcr_msg *message;
-
- sip_trace_header(this, "INVITE", DIRECTION_OUT);
- add_trace("failure", NULL, "Port blocked.");
- end_trace();
- message = message_create(p_serial, epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
- message->param.disconnectinfo.cause = 27; // temp. unavail.
- message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
- message_put(message);
- new_state(PORT_STATE_RELEASE);
- trigger_work(&p_m_s_delete);
- return 0;
- }
-
- /* hunt channel */
- ret = channel = hunt_bchannel();
- if (ret < 0)
- goto no_channel;
- /* open channel */
- ret = seize_bchannel(channel, 1);
- if (ret < 0) {
- struct lcr_msg *message;
-
- no_channel:
- sip_trace_header(this, "INVITE", DIRECTION_OUT);
- add_trace("failure", NULL, "No internal audio channel available.");
- end_trace();
- message = message_create(p_serial, epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
- message->param.disconnectinfo.cause = 34;
- message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
- message_put(message);
- new_state(PORT_STATE_RELEASE);
- trigger_work(&p_m_s_delete);
- return 0;
- }
- bchannel_event(p_m_mISDNport, p_m_b_index, B_EVENT_USE);
- if (bchannel_open(p_m_b_index))
- goto no_channel;
-
memcpy(&p_dialinginfo, ¶m->setup.dialinginfo, sizeof(p_dialinginfo));
memcpy(&p_callerinfo, ¶m->setup.callerinfo, sizeof(p_callerinfo));
memcpy(&p_redirinfo, ¶m->setup.redirinfo, sizeof(p_redirinfo));
- /* connect to remote RTP */
- if (rtp_open() < 0) {
- struct lcr_msg *message;
-
- PERROR("Failed to open RTP sockets\n");
- /* send release message to endpoit */
- message = message_create(p_serial, epoint_id, 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_m_s_delete);
- return 0;
+ 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;
+ p_s_rtp_port_local = param->setup.rtpinfo.port;
+ 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);
+ } 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;
+
+ /* open local RTP peer (if not bridging) */
+ if (rtp_open() < 0) {
+ PERROR("Failed to open RTP sockets\n");
+ /* send release message to endpoit */
+ message = message_create(p_serial, epoint_id, 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 0;
+ }
}
- SPRINT(from, "sip:%s@%s", param->setup.callerinfo.id, local);
- SPRINT(to, "sip:%s@%s", param->setup.dialinginfo.id, remote);
-
- sip_trace_header(this, "INVITE", DIRECTION_OUT);
- add_trace("from", "uri", "%s", from);
- add_trace("to", "uri", "%s", to);
- add_trace("rtp", "port", "%d,%d", p_m_s_rtp_port_local, p_m_s_rtp_port_local + 1);
- end_trace();
-
- p_m_s_handle = nua_handle(inst->nua, NULL, TAG_END());
- if (!p_m_s_handle) {
- struct lcr_msg *message;
+ p_s_handle = nua_handle(inst->nua, NULL, TAG_END());
+ if (!p_s_handle) {
PERROR("Failed to create handle\n");
/* send release message to endpoit */
message = message_create(p_serial, epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
message_put(message);
new_state(PORT_STATE_RELEASE);
- trigger_work(&p_m_s_delete);
+ trigger_work(&p_s_delete);
return 0;
}
/* apply handle */
sip_trace_header(this, "NEW handle", DIRECTION_IN);
- add_trace("handle", "new", "0x%x", p_m_s_handle);
+ add_trace("handle", "new", "0x%x", p_s_handle);
end_trace();
- inet_pton(AF_INET, local, &p_m_s_rtp_ip_local);
- p_m_s_rtp_ip_local = ntohl(p_m_s_rtp_ip_local);
- ia.s_addr = htonl(p_m_s_rtp_ip_local);
+ if (!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);
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_m_s_rtp_port_local, (options.law=='a')?RTP_PT_ALAW:RTP_PT_ULAW, (options.law=='a')?RTP_PT_ALAW:RTP_PT_ULAW, (options.law=='a')?"PCMA":"PCMU");
+ "m=audio %d RTP/AVP"
+ , inet_ntoa(ia), inet_ntoa(ia), p_s_rtp_port_local);
+ for (i = 0; i < payloads; i++) {
+ SPRINT(pt_str, " %d", payload_types[i]);
+ SCAT(sdp_str, pt_str);
+ }
+ SCAT(sdp_str, "\n");
+ for (i = 0; i < payloads; 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);
+ SPRINT(from, "sip:%s@%s", param->setup.callerinfo.id, local);
+ SPRINT(to, "sip:%s@%s", param->setup.dialinginfo.id, remote);
+
+ sip_trace_header(this, "INVITE", DIRECTION_OUT);
+ add_trace("from", "uri", "%s", from);
+ add_trace("to", "uri", "%s", to);
+ 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", "%s:%d", media_type2name(media_types[i]), payload_types[i]);
+ end_trace();
+
// cseq = sip_cseq_create(sip_home, 123, SIP_METHOD_INVITE);
- nua_invite(p_m_s_handle,
+ nua_invite(p_s_handle,
TAG_IF(from[0], SIPTAG_FROM_STR(from)),
TAG_IF(to[0], SIPTAG_TO_STR(to)),
TAG_IF(cseq, SIPTAG_CSEQ(cseq)),
SIPTAG_PAYLOAD_STR(sdp_str), TAG_END());
new_state(PORT_STATE_OUT_SETUP);
+#if 0
+ PDEBUG(DEBUG_SIP, "do overlap\n");
+ new_state(PORT_STATE_OUT_OVERLAP);
+ message = message_create(p_serial, epoint_id, PORT_TO_EPOINT, MESSAGE_OVERLAP);
+ message_put(message);
+#else
+ PDEBUG(DEBUG_SIP, "do proceeding\n");
+ new_state(PORT_STATE_OUT_PROCEEDING);
+ message = message_create(p_serial, epoint_id, PORT_TO_EPOINT, MESSAGE_PROCEEDING);
+ message_put(message);
+#endif
+
/* attach only if not already */
epointlist = p_epointlist;
while(epointlist) {
return 0;
}
-int Psip::message_epoint(unsigned int epoint_id, int message_id, union parameter *param)
+int Psip::message_notify(unsigned int epoint_id, int message_id, union parameter *param)
{
- class Endpoint *epoint;
-
- if (PmISDN::message_epoint(epoint_id, message_id, param))
- return 1;
+// char sdp_str[256];
+// struct in_addr ia;
- epoint = find_epoint_id(epoint_id);
- if (!epoint) {
- PDEBUG(DEBUG_SIP, "PORT(%s) no endpoint object found where the message is from.\n", p_name);
- return 0;
+ switch (param->notifyinfo.notify) {
+ case INFO_NOTIFY_REMOTE_HOLD:
+#if 0
+ SPRINT(sdp_str,
+ "v=0\n"
+ "o=LCR-Sofia-SIP 0 0 IN IP4 0.0.0.0\n"
+ "s=SIP Call\n"
+ "c=IN IP4 0.0.0.0\n"
+ "t=0 0\n"
+ );
+ PDEBUG(DEBUG_SIP, "Using SDP for hold: %s\n", sdp_str);
+ nua_info(p_s_handle,
+// TAG_IF(from[0], SIPTAG_FROM_STR(from)),
+// TAG_IF(to[0], SIPTAG_TO_STR(to)),
+// TAG_IF(cseq, SIPTAG_CSEQ(cseq)),
+ NUTAG_MEDIA_ENABLE(0),
+ SIPTAG_CONTENT_TYPE_STR("application/sdp"),
+ SIPTAG_PAYLOAD_STR(sdp_str), TAG_END());
+#endif
+ break;
+ case INFO_NOTIFY_REMOTE_RETRIEVAL:
+#if 0
+ 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, 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)),
+// TAG_IF(to[0], SIPTAG_TO_STR(to)),
+// TAG_IF(cseq, SIPTAG_CSEQ(cseq)),
+ NUTAG_MEDIA_ENABLE(0),
+ SIPTAG_CONTENT_TYPE_STR("application/sdp"),
+ SIPTAG_PAYLOAD_STR(sdp_str), TAG_END());
+#endif
+ break;
}
+ return 0;
+}
+
+int Psip::message_dtmf(unsigned int epoint_id, int message_id, union parameter *param)
+{
+ char dtmf_str[64];
+
+ /* prepare DTMF info payload */
+ SPRINT(dtmf_str,
+ "Signal=%c\n"
+ "Duration=160\n"
+ , param->dtmf);
+
+ /* start invite to handle DTMF */
+ nua_info(p_s_handle,
+ NUTAG_MEDIA_ENABLE(0),
+ SIPTAG_CONTENT_TYPE_STR("application/dtmf-relay"),
+ SIPTAG_PAYLOAD_STR(dtmf_str), TAG_END());
+
+ return 0;
+}
+
+/* NOTE: incomplete and not working */
+int Psip::message_information(unsigned int epoint_id, int message_id, union parameter *param)
+{
+ char dtmf_str[64];
+
+ /* prepare DTMF info payload */
+ SPRINT(dtmf_str,
+ "Signal=%s\n"
+ "Duration=160\n"
+ , param->information.id);
+
+ /* start invite to handle DTMF */
+ nua_info(p_s_handle,
+ NUTAG_MEDIA_ENABLE(0),
+ SIPTAG_CONTENT_TYPE_STR("application/dtmf-relay"),
+ SIPTAG_PAYLOAD_STR(dtmf_str), TAG_END());
+
+ return 0;
+}
+
+int Psip::message_epoint(unsigned int epoint_id, int message_id, union parameter *param)
+{
+ if (Port::message_epoint(epoint_id, message_id, param))
+ return 1;
+
switch(message_id) {
case MESSAGE_ALERTING: /* call is ringing on LCR side */
if (p_state != PORT_STATE_IN_SETUP
&& p_state != PORT_STATE_IN_PROCEEDING)
return 0;
- nua_respond(p_m_s_handle, SIP_180_RINGING, TAG_END());
+ nua_respond(p_s_handle, SIP_180_RINGING, TAG_END());
sip_trace_header(this, "RESPOND", DIRECTION_OUT);
add_trace("respond", "value", "180 Ringing");
end_trace();
message_setup(epoint_id, message_id, param);
return 1;
+ case MESSAGE_INFORMATION: /* overlap dialing */
+ if (p_state != PORT_STATE_OUT_OVERLAP)
+ return 0;
+ message_information(epoint_id, message_id, param);
+ return 1;
+
+ case MESSAGE_DTMF: /* DTMF info to be transmitted via INFO transaction */
+ if (p_state == PORT_STATE_CONNECT)
+ message_dtmf(epoint_id, message_id, param);
+ case MESSAGE_NOTIFY: /* notification about remote hold/retrieve */
+ if (p_state == PORT_STATE_CONNECT)
+ message_notify(epoint_id, message_id, param);
+ return(1);
+
default:
PDEBUG(DEBUG_SIP, "PORT(%s) SP port with (caller id %s) received an unsupported message: %d\n", p_name, p_callerinfo.id, message_id);
}
return 0;
}
-int Psip::parse_sdp(sip_t const *sip, unsigned int *ip, unsigned short *port)
+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)
{
- int codec_supported = 0;
+ *payloads = 0;
if (!sip->sip_payload) {
PDEBUG(DEBUG_SIP, "no payload given\n");
conn = m->m_connections;
PDEBUG(DEBUG_SIP, "CONN: address:'%s'\n", conn->c_address);
inet_pton(AF_INET, conn->c_address, ip);
- *ip = ntohl(p_m_s_rtp_ip_remote);
+ *ip = ntohl(p_s_rtp_ip_remote);
} else {
char *p = sip->sip_payload->pl_data;
char addr[16];
if ((p = strchr(addr, '\r'))) *p = '\0';
PDEBUG(DEBUG_SIP, "CONN: address:'%s'\n", addr);
inet_pton(AF_INET, addr, ip);
- *ip = ntohl(p_m_s_rtp_ip_remote);
+ *ip = ntohl(p_s_rtp_ip_remote);
}
for (map = m->m_rtpmaps; map; map = map->rm_next) {
- PDEBUG(DEBUG_SIP, "RTPMAP: coding:'%s' rate='%d'\n", map->rm_encoding, map->rm_rate);
- if (!strcmp(map->rm_encoding, (options.law=='a')?"PCMA":"PCMU") && map->rm_rate == 8000) {
- PDEBUG(DEBUG_SIP, "supported codec found\n");
- codec_supported = 1;
- goto done_codec;
+ 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", "%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)++;
}
}
}
- done_codec:
sdp_parser_free(parser);
- if (!codec_supported)
- return 415;
-
return 0;
}
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[])
{
- const char *from = "", *to = "";
+ struct sip_inst *inst = (struct sip_inst *) p_s_sip_inst;
+ const char *from = "", *to = "", *name = "";
+ char imsi[16] = "";
int ret;
class Endpoint *epoint;
struct lcr_msg *message;
- int channel;
+ 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) {
+ PERROR("Cannot find interface %s.\n", inst->interface_name);
+ 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);
- ret = parse_sdp(sip, &p_m_s_rtp_ip_remote, &p_m_s_rtp_port_remote);
+ sip_trace_header(this, "Payload received", DIRECTION_NONE);
+ 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) {
+ int i;
+
+ /* check if supported payload type exists */
+ for (i = 0; i < payloads; i++) {
+ if (media_types[i] == ((options.law=='a') ? MEDIA_TYPE_ALAW : MEDIA_TYPE_ULAW))
+ break;
+ }
+ if (i == payloads) {
+ add_trace("error", NULL, "Expected LAW payload type (not bridged)");
+ ret = 415;
+ }
+ }
+ }
+ end_trace();
if (ret) {
if (ret == 400)
nua_respond(nh, SIP_400_BAD_REQUEST, TAG_END());
else
nua_respond(nh, SIP_415_UNSUPPORTED_MEDIA, TAG_END());
nua_handle_destroy(nh);
- p_m_s_handle = NULL;
+ p_s_handle = NULL;
sip_trace_header(this, "RESPOND", DIRECTION_OUT);
if (ret == 400)
add_trace("respond", "value", "415 Unsupported Media");
add_trace("reason", NULL, "offered codec does not match");
end_trace();
new_state(PORT_STATE_RELEASE);
- trigger_work(&p_m_s_delete);
+ trigger_work(&p_s_delete);
return;
}
- /* connect to remote RTP */
- if (rtp_open() < 0) {
+ /* open local RTP peer (if not bridging) */
+ if (!p_s_rtp_bridge && rtp_open() < 0) {
nua_respond(nh, SIP_500_INTERNAL_SERVER_ERROR, TAG_END());
nua_handle_destroy(nh);
- p_m_s_handle = NULL;
+ 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 open RTP/RTCP sockts");
end_trace();
new_state(PORT_STATE_RELEASE);
- trigger_work(&p_m_s_delete);
+ trigger_work(&p_s_delete);
return;
}
/* apply handle */
sip_trace_header(this, "NEW handle", DIRECTION_IN);
add_trace("handle", "new", "0x%x", nh);
- p_m_s_handle = nh;
+ p_s_handle = nh;
end_trace();
- /* if blocked, release call */
- if (p_m_mISDNport->ifport->block) {
- nua_respond(nh, SIP_503_SERVICE_UNAVAILABLE, TAG_END());
- nua_handle_destroy(nh);
- p_m_s_handle = NULL;
- sip_trace_header(this, "RESPOND", DIRECTION_OUT);
- add_trace("respond", "value", "503 Service Unavailable");
- add_trace("reason", NULL, "port is blocked");
- end_trace();
- new_state(PORT_STATE_RELEASE);
- trigger_work(&p_m_s_delete);
- return;
- }
sip_trace_header(this, "INVITE", DIRECTION_IN);
- add_trace("RTP", "port", "%d", p_m_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;
p_callerinfo.ntype = INFO_NTYPE_UNKNOWN;
SCPY(p_callerinfo.id, from);
add_trace("calling", "number", "%s", from);
- }
- p_callerinfo.isdn_port = p_m_portnum;
- SCPY(p_callerinfo.interface, p_m_mISDNport->ifport->interface->name);
+ 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 */
if (to[0]) {
p_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
end_trace();
- /* hunt channel */
- ret = channel = hunt_bchannel();
- if (ret < 0)
- goto no_channel;
-
- /* open channel */
- ret = seize_bchannel(channel, 1);
- if (ret < 0) {
- no_channel:
- nua_respond(nh, SIP_480_TEMPORARILY_UNAVAILABLE, TAG_END());
- nua_handle_destroy(nh);
- p_m_s_handle = NULL;
- sip_trace_header(this, "RESPOND", DIRECTION_OUT);
- add_trace("respond", "value", "480 Temporarily Unavailable");
- add_trace("reason", NULL, "no channel");
- end_trace();
- new_state(PORT_STATE_RELEASE);
- trigger_work(&p_m_s_delete);
- return;
- }
- bchannel_event(p_m_mISDNport, p_m_b_index, B_EVENT_USE);
- if (bchannel_open(p_m_b_index))
- goto no_channel;
-
/* create endpoint */
if (p_epointlist)
FATAL("Incoming call but already got an endpoint.\n");
if (!(epoint = new Endpoint(p_serial, 0)))
FATAL("No memory for Endpoint instance\n");
- if (!(epoint->ep_app = new DEFAULT_ENDPOINT_APP(epoint, 0))) //incoming
- FATAL("No memory for Endpoint Application instance\n");
+ 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);
/* send setup message to endpoit */
message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_SETUP);
- message->param.setup.isdn_port = p_m_portnum;
message->param.setup.port_type = p_type;
// message->param.setup.dtmf = 0;
memcpy(&message->param.setup.dialinginfo, &p_dialinginfo, sizeof(struct dialing_info));
// SCPY((char *)message->param.setup.useruser.data, useruser.info);
// message->param.setup.useruser.len = strlen(mncc->useruser.info);
// message->param.setup.useruser.protocol = mncc->useruser.proto;
+ if (p_s_rtp_bridge) {
+ int i;
+
+ PDEBUG(DEBUG_SIP, "sending setup with RTP info\n");
+ message->param.setup.rtpinfo.ip = p_s_rtp_ip_remote;
+ 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.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);
+
+ /* 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");
+ 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());
+ 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, 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());
+ 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", "%s:%d", media_type2name(media_type), payload_type);
+ end_trace();
+ }
}
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[])
add_trace("respond", "value", "200 OK");
end_trace();
// nua_handle_destroy(nh);
- p_m_s_handle = NULL;
+ p_s_handle = NULL;
rtp_close();
free_epointlist(p_epointlist);
}
new_state(PORT_STATE_RELEASE);
- trigger_work(&p_m_s_delete);
+ trigger_work(&p_s_delete);
}
void Psip::i_cancel(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[])
end_trace();
nua_handle_destroy(nh);
- p_m_s_handle = NULL;
+ p_s_handle = NULL;
rtp_close();
free_epointlist(p_epointlist);
}
new_state(PORT_STATE_RELEASE);
- trigger_work(&p_m_s_delete);
+ trigger_work(&p_s_delete);
}
void Psip::r_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[])
PDEBUG(DEBUG_SIP, "bye response received\n");
nua_handle_destroy(nh);
- p_m_s_handle = NULL;
+ p_s_handle = NULL;
rtp_close();
- trigger_work(&p_m_s_delete);
+ trigger_work(&p_s_delete);
}
void Psip::r_cancel(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[])
PDEBUG(DEBUG_SIP, "cancel response received\n");
nua_handle_destroy(nh);
- p_m_s_handle = NULL;
+ p_s_handle = NULL;
rtp_close();
- trigger_work(&p_m_s_delete);
+ trigger_work(&p_s_delete);
}
void Psip::r_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 lcr_msg *message;
int cause = 0, location = 0;
+ int media_types[32];
+ uint8_t payload_types[32];
+ int payloads = 0;
PDEBUG(DEBUG_SIP, "response to invite received (status = %d)\n", status);
add_trace("respond", "value", "%d", status);
end_trace();
+ /* connect audio */
+ if (status == 183 || (status >= 200 && status <= 299)) {
+ 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, media_types, &payloads, sizeof(payload_types));
+ if (!ret) {
+ if (payloads != 1)
+ ret = 415;
+ else if (!p_s_rtp_bridge) {
+ 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;
+ }
+ }
+ }
+ end_trace();
+ if (ret) {
+ nua_cancel(nh, TAG_END());
+ sip_trace_header(this, "CANCEL", DIRECTION_OUT);
+ add_trace("reason", NULL, "accepted codec does not match");
+ end_trace();
+ cause = 88;
+ location = LOCATION_PRIVATE_LOCAL;
+ goto release_with_cause;
+ }
+
+ /* connect to remote RTP (if not bridging) */
+ if (!p_s_rtp_bridge && rtp_connect() < 0) {
+ nua_cancel(nh, TAG_END());
+ sip_trace_header(this, "CANCEL", DIRECTION_OUT);
+ add_trace("reason", NULL, "failed to open RTP/RTCP sockts");
+ end_trace();
+ cause = 31;
+ location = LOCATION_PRIVATE_LOCAL;
+ goto release_with_cause;
+ }
+ }
+
/* process 1xx */
switch (status) {
case 100:
+#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);
message_put(message);
+#endif
return;
case 180:
PDEBUG(DEBUG_SIP, "do alerting\n");
message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_ALERTING);
message_put(message);
return;
+ case 183:
+ PDEBUG(DEBUG_SIP, "do progress\n");
+ message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_PROGRESS);
+ message->param.progressinfo.progress = 8;
+ message->param.progressinfo.location = 10;
+ 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;
+ }
+ message_put(message);
+ return;
default:
if (status < 100 || status > 199)
break;
/* process 2xx */
if (status >= 200 && status <= 299) {
- int ret;
-
- ret = parse_sdp(sip, &p_m_s_rtp_ip_remote, &p_m_s_rtp_port_remote);
- if (ret) {
- if (ret == 400)
- nua_cancel(nh, TAG_END());
- else
- nua_cancel(nh, TAG_END());
- sip_trace_header(this, "CANCEL", DIRECTION_OUT);
- add_trace("reason", NULL, "offered codec does not match");
- end_trace();
- cause = 88;
- location = LOCATION_PRIVATE_LOCAL;
- goto release_with_cause;
- }
-
- /* connect to remote RTP */
- if (rtp_connect() < 0) {
- nua_cancel(nh, TAG_END());
- sip_trace_header(this, "CANCEL", DIRECTION_OUT);
- add_trace("reason", NULL, "failed to open RTP/RTCP sockts");
- end_trace();
- cause = 31;
- location = LOCATION_PRIVATE_LOCAL;
- goto release_with_cause;
- }
-
PDEBUG(DEBUG_SIP, "do connect\n");
nua_ack(nh, TAG_END());
new_state(PORT_STATE_CONNECT);
message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_CONNECT);
+ 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;
+ }
message_put(message);
-
return;
}
-
cause = status2cause(status);
location = LOCATION_BEYOND;
rtp_close();
- trigger_work(&p_m_s_delete);
+ trigger_work(&p_s_delete);
}
static void sip_callback(nua_event_t event, 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 tags[])
if (event == nua_i_invite)
{
char name[64];
+ struct interface *interface = interface_first;
+
/* create call instance */
- SPRINT(name, "%s-%d-in", inst->interface->name, 0);
- if (!(psip = new Psip(PORT_TYPE_SIP_IN, (inst->interface->ifport) ? inst->interface->ifport->mISDNport : NULL, name, NULL, 0, 0, B_MODE_TRANSPARENT, inst->interface)))
+ SPRINT(name, "%s-%d-in", inst->interface_name, 0);
+ while (interface) {
+ if (!strcmp(interface->name, inst->interface_name))
+ break;
+ interface = interface->next;
+ }
+ if (!interface) {
+ PERROR("Cannot find interface %s.\n", inst->interface_name);
+ return;
+ }
+ if (!(psip = new Psip(PORT_TYPE_SIP_IN, name, NULL, interface)))
FATAL("Cannot create Port instance.\n");
} else {
port = port_first;
while(port) {
if ((port->p_type & PORT_CLASS_mISDN_MASK) == PORT_CLASS_SIP) {
psip = (class Psip *)port;
- if (psip->p_m_s_handle == nh) {
+ if (psip->p_s_handle == nh) {
break;
}
}
sip_trace_header(this, "RTP terminated", DIRECTION_IN);
end_trace();
- nua_handle_destroy(p_m_s_handle);
- p_m_s_handle = NULL;
+ nua_handle_destroy(p_s_handle);
+ p_s_handle = NULL;
while(p_epointlist) {
/* send setup message to endpoit */
free_epointlist(p_epointlist);
}
new_state(PORT_STATE_RELEASE);
- trigger_work(&p_m_s_delete);
+ trigger_work(&p_s_delete);
}
int sip_init_inst(struct interface *interface)
{
struct sip_inst *inst = (struct sip_inst *) MALLOC(sizeof(*inst));
+ char local[64];
interface->sip_inst = inst;
- inst->interface = interface;
+ SCPY(inst->interface_name, interface->name);
+ 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);
NUTAG_APPL_METHOD("NOTIFY"),
NUTAG_APPL_METHOD("INFO"),
NUTAG_AUTOACK(0),
+#ifdef NUTAG_AUTO100
NUTAG_AUTO100(0),
+#endif
NUTAG_AUTOALERT(0),
NUTAG_AUTOANSWER(0),
TAG_NULL());
PDEBUG(DEBUG_SIP, "SIP interface created (inst=%p)\n", inst);
+ any_sip_interface = 1;
+
return 0;
}
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[];
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);
+}
+