transport_udp.c
来自「基于sip协议的网络电话源码」· C语言 代码 · 共 705 行 · 第 1/2 页
C
705 行
pj_ioqueue_unregister(udp->rtp_key); udp->rtp_key = NULL; } else if (udp->rtp_sock != PJ_INVALID_SOCKET) { pj_sock_close(udp->rtp_sock); udp->rtp_sock = PJ_INVALID_SOCKET; } if (udp->rtcp_key) { pj_ioqueue_unregister(udp->rtcp_key); udp->rtcp_key = NULL; } else if (udp->rtcp_sock != PJ_INVALID_SOCKET) { pj_sock_close(udp->rtcp_sock); udp->rtcp_sock = PJ_INVALID_SOCKET; } pj_pool_release(udp->pool); return PJ_SUCCESS;}/* Notification from ioqueue about incoming RTP packet */static void on_rx_rtp( pj_ioqueue_key_t *key, pj_ioqueue_op_key_t *op_key, pj_ssize_t bytes_read){ struct transport_udp *udp; pj_status_t status; PJ_UNUSED_ARG(op_key); udp = pj_ioqueue_get_user_data(key); do { void (*cb)(void*,const void*,pj_ssize_t); void *user_data; cb = udp->rtp_cb; user_data = udp->user_data; /* Simulate packet lost on RX direction */ if (udp->rx_drop_pct) { if ((pj_rand() % 100) <= (int)udp->rx_drop_pct) { PJ_LOG(5,(udp->base.name, "RX RTP packet dropped because of pkt lost " "simulation")); goto read_next_packet; } } if (udp->attached && cb) (*cb)(user_data, udp->rtp_pkt, bytes_read); /* See if source address of RTP packet is different than the * configured address, and switch RTP remote address to * source packet address after several consecutive packets * have been received. */ if (bytes_read>0 && (udp->options & PJMEDIA_UDP_NO_SRC_ADDR_CHECKING)==0) { if ((udp->rem_rtp_addr.sin_addr.s_addr != udp->rtp_src_addr.sin_addr.s_addr) || (udp->rem_rtp_addr.sin_port != udp->rtp_src_addr.sin_port)) { udp->rtp_src_cnt++; if (udp->rtp_src_cnt >= PJMEDIA_RTP_NAT_PROBATION_CNT) { /* Set remote RTP address to source address */ udp->rem_rtp_addr = udp->rtp_src_addr; /* Reset counter */ udp->rtp_src_cnt = 0; PJ_LOG(4,(udp->base.name, "Remote RTP address switched to %s:%d", pj_inet_ntoa(udp->rtp_src_addr.sin_addr), pj_ntohs(udp->rtp_src_addr.sin_port))); /* Also update remote RTCP address if actual RTCP source * address is not heard yet. */ if (udp->rtcp_src_addr.sin_addr.s_addr == 0) { pj_uint16_t port; pj_memcpy(&udp->rem_rtcp_addr, &udp->rem_rtp_addr, sizeof(pj_sockaddr_in)); port = (pj_uint16_t) (pj_ntohs(udp->rem_rtp_addr.sin_port)+1); udp->rem_rtcp_addr.sin_port = pj_htons(port); pj_memcpy(&udp->rtcp_src_addr, &udp->rem_rtcp_addr, sizeof(pj_sockaddr_in)); PJ_LOG(4,(udp->base.name, "Remote RTCP address switched to %s:%d", pj_inet_ntoa(udp->rtcp_src_addr.sin_addr), pj_ntohs(udp->rtcp_src_addr.sin_port))); } } } }read_next_packet: bytes_read = sizeof(udp->rtp_pkt); udp->rtp_addrlen = sizeof(pj_sockaddr_in); status = pj_ioqueue_recvfrom(udp->rtp_key, &udp->rtp_read_op, udp->rtp_pkt, &bytes_read, 0, &udp->rtp_src_addr, &udp->rtp_addrlen); if (status != PJ_EPENDING && status != PJ_SUCCESS) bytes_read = -status; } while (status != PJ_EPENDING);}/* Notification from ioqueue about incoming RTCP packet */static void on_rx_rtcp(pj_ioqueue_key_t *key, pj_ioqueue_op_key_t *op_key, pj_ssize_t bytes_read){ struct transport_udp *udp; pj_status_t status; PJ_UNUSED_ARG(op_key); udp = pj_ioqueue_get_user_data(key); do { void (*cb)(void*,const void*,pj_ssize_t); void *user_data; cb = udp->rtcp_cb; user_data = udp->user_data; if (udp->attached && cb) (*cb)(user_data, udp->rtcp_pkt, bytes_read); /* Check if RTCP source address is the same as the configured * remote address, and switch the address when they are * different. */ if (bytes_read>0 && (udp->options & PJMEDIA_UDP_NO_SRC_ADDR_CHECKING)==0 && ((udp->rem_rtcp_addr.sin_addr.s_addr != udp->rtcp_src_addr.sin_addr.s_addr) || (udp->rem_rtcp_addr.sin_port != udp->rtcp_src_addr.sin_port))) { pj_memcpy(&udp->rem_rtcp_addr, &udp->rtcp_src_addr, sizeof(pj_sockaddr_in)); PJ_LOG(4,(udp->base.name, "Remote RTCP address switched to %s:%d", pj_inet_ntoa(udp->rtcp_src_addr.sin_addr), pj_ntohs(udp->rtcp_src_addr.sin_port))); } bytes_read = sizeof(udp->rtcp_pkt); udp->rtcp_addr_len = sizeof(udp->rtcp_src_addr); status = pj_ioqueue_recvfrom(udp->rtcp_key, &udp->rtcp_read_op, udp->rtcp_pkt, &bytes_read, 0, &udp->rtcp_src_addr, &udp->rtcp_addr_len); if (status != PJ_EPENDING && status != PJ_SUCCESS) bytes_read = -status; } while (status != PJ_EPENDING);}/* Called by application to initialize the transport */static pj_status_t transport_attach( pjmedia_transport *tp, void *user_data, const pj_sockaddr_t *rem_addr, const pj_sockaddr_t *rem_rtcp, unsigned addr_len, void (*rtp_cb)(void*, const void*, pj_ssize_t), void (*rtcp_cb)(void*, const void*, pj_ssize_t)){ struct transport_udp *udp = (struct transport_udp*) tp; const pj_sockaddr_in *rtcp_addr; /* Validate arguments */ PJ_ASSERT_RETURN(tp && rem_addr && addr_len, PJ_EINVAL); /* Must not be "attached" to existing application */ PJ_ASSERT_RETURN(!udp->attached, PJ_EINVALIDOP); /* "Attach" the application: */ /* Copy remote RTP address */ pj_memcpy(&udp->rem_rtp_addr, rem_addr, sizeof(pj_sockaddr_in)); /* Copy remote RTP address, if one is specified. */ rtcp_addr = rem_rtcp; if (rtcp_addr && rtcp_addr->sin_addr.s_addr != 0) { pj_memcpy(&udp->rem_rtcp_addr, rem_rtcp, sizeof(pj_sockaddr_in)); } else { int rtcp_port; /* Otherwise guess the RTCP address from the RTP address */ pj_memcpy(&udp->rem_rtcp_addr, rem_addr, sizeof(pj_sockaddr_in)); rtcp_port = pj_ntohs(udp->rem_rtp_addr.sin_port) + 1; udp->rem_rtcp_addr.sin_port = pj_htons((pj_uint16_t)rtcp_port); } /* Save the callbacks */ udp->rtp_cb = rtp_cb; udp->rtcp_cb = rtcp_cb; udp->user_data = user_data; /* Last, mark transport as attached */ udp->attached = PJ_TRUE; return PJ_SUCCESS;}/* Called by application when it no longer needs the transport */static void transport_detach( pjmedia_transport *tp, void *user_data){ struct transport_udp *udp = (struct transport_udp*) tp; pj_assert(tp); if (udp->attached) { /* User data is unreferenced on Release build */ PJ_UNUSED_ARG(user_data); /* As additional checking, check if the same user data is specified */ pj_assert(user_data == udp->user_data); /* First, mark transport as unattached */ udp->attached = PJ_FALSE; /* Clear up application infos from transport */ udp->rtp_cb = NULL; udp->rtcp_cb = NULL; udp->user_data = NULL; }}/* Called by application to send RTP packet */static pj_status_t transport_send_rtp( pjmedia_transport *tp, const void *pkt, pj_size_t size){ struct transport_udp *udp = (struct transport_udp*)tp; pj_ssize_t sent; unsigned id; struct pending_write *pw; pj_status_t status; /* Must be attached */ PJ_ASSERT_RETURN(udp->attached, PJ_EINVALIDOP); /* Check that the size is supported */ PJ_ASSERT_RETURN(size <= RTP_LEN, PJ_ETOOBIG); /* Simulate packet lost on TX direction */ if (udp->tx_drop_pct) { if ((pj_rand() % 100) <= (int)udp->tx_drop_pct) { PJ_LOG(5,(udp->base.name, "TX RTP packet dropped because of pkt lost " "simulation")); return PJ_SUCCESS; } } id = udp->rtp_write_op_id; pw = &udp->rtp_pending_write[id]; /* We need to copy packet to our buffer because when the * operation is pending, caller might write something else * to the original buffer. */ pj_memcpy(pw->buffer, pkt, size); sent = size; status = pj_ioqueue_sendto( udp->rtp_key, &udp->rtp_pending_write[id].op_key, pw->buffer, &sent, 0, &udp->rem_rtp_addr, sizeof(pj_sockaddr_in)); udp->rtp_write_op_id = (udp->rtp_write_op_id + 1) % PJ_ARRAY_SIZE(udp->rtp_pending_write); if (status==PJ_SUCCESS || status==PJ_EPENDING) return PJ_SUCCESS; return status;}/* Called by application to send RTCP packet */static pj_status_t transport_send_rtcp(pjmedia_transport *tp, const void *pkt, pj_size_t size){ struct transport_udp *udp = (struct transport_udp*)tp; pj_ssize_t sent; pj_status_t status; PJ_ASSERT_RETURN(udp->attached, PJ_EINVALIDOP); sent = size; status = pj_ioqueue_sendto( udp->rtcp_key, &udp->rtcp_write_op, pkt, &sent, 0, &udp->rem_rtcp_addr, sizeof(pj_sockaddr_in)); if (status==PJ_SUCCESS || status==PJ_EPENDING) return PJ_SUCCESS; return status;}PJ_DEF(pj_status_t) pjmedia_transport_udp_simulate_lost(pjmedia_transport *tp, pjmedia_dir dir, unsigned pct_lost){ struct transport_udp *udp = (struct transport_udp*)tp; PJ_ASSERT_RETURN(tp && (dir==PJMEDIA_DIR_ENCODING||dir==PJMEDIA_DIR_DECODING) && pct_lost <= 100, PJ_EINVAL); if (dir == PJMEDIA_DIR_ENCODING) udp->tx_drop_pct = pct_lost; else if (dir == PJMEDIA_DIR_DECODING) udp->rx_drop_pct = pct_lost; else return PJ_EINVAL; return PJ_SUCCESS;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?