⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 transport_udp.c

📁 一个开源的sip源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
    } 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 = (struct transport_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 = (struct transport_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 to get the transport info */
static pj_status_t transport_get_info(pjmedia_transport *tp,
				      pjmedia_sock_info *info)
{
    struct transport_udp *udp = (struct transport_udp*)tp;
    PJ_ASSERT_RETURN(tp && info, PJ_EINVAL);

    info->rtp_sock = udp->rtp_sock;
    info->rtp_addr_name = udp->rtp_addr_name;
    info->rtcp_sock = udp->rtcp_sock;
    info->rtcp_addr_name = udp->rtcp_addr_name;

    return PJ_SUCCESS;
}


/* 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 = (const pj_sockaddr_in*) 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 + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -