www.pudn.com > rtp&rtcp.rar > rtp_sendDlg.cpp, change:2002-11-01,size:12086b


// rtp_sendDlg.cpp : implementation file 
// 
 
#include "stdafx.h" 
#include "rtp_send.h" 
#include "rtp_sendDlg.h" 
 
#include <time.h> 
#include <sys/timeb.h> 
#include <math.h> 
 
 
//WM_DATASEND用于发送子进程向主界面提供发送状态信息, 
//该消息的两个参数分别传动时间戳和序列号 
#define	WM_DATASEND WM_USER+200 
//定义数据流的采样频率,在本例中仅仅是根据发送字符串 
//的长度计算出来的每秒钟需发送的字节数 
//注意:两个数据流的发送速率是不一样的, 
//数据流1每20ms发送一个数据报;数据流2每10ms发送一个数据报 
#define STREAM_1_SAMPLE_FREQ 500.0/1000.0 
#define STREAM_2_SAMPLE_FREQ 500.0/1000.0 
 
 
//定义需要的数据结构-begin 
/* Type sizes */ 
typedef unsigned long int u_int32; 
typedef unsigned short int u_int16; 
typedef unsigned char u_int8; 
// 32-bit sequence number 
typedef u_int16 RtpSeqNumber; 
// Middle 32-bit of NTP 
typedef u_int32 RtpTime; 
// 32-bit source number 
typedef u_int32 RtpSrc; 
 
// RTP packet header 
struct RtpHeaderStruct 
{ 
	u_int32 version : 2;	// protocal version 
	u_int32 padding : 1;	// padding flag - for encryption 
    u_int32 extension : 1;	// header extension flag 
    u_int32 count : 4;		// csrc count 
    u_int32 marker : 1;		// marker bit - for profile 
    u_int32 type : 7;		// payload type 
    u_int32 sequence : 16;	// sequence number of this packet 
    RtpTime timestamp;		// timestamp of this packet 
    RtpSrc ssrc;			// source of packet 
    RtpSrc startOfCsrc;		// list of contributing sources 
}; 
typedef struct RtpHeaderStruct RTP_HEADER; 
 
// RTCP header 
struct RtcpHeaderStruct 
{ 
	u_int32 version : 2;	// protocal version 
    u_int32 padding : 1;	// padding flag 
    u_int32 count : 5;		// depending on packet type 
    u_int32 type : 8;		// type of RTCP packet 
    u_int32 length : 16;	// lenght of RTCP packet in octlets minus 1 
}; 
typedef struct RtcpHeaderStruct RTCP_HEADER; 
//定义需要的数据结构-end 
 
 
#ifdef _DEBUG 
#define new DEBUG_NEW 
#undef THIS_FILE 
static char THIS_FILE[] = __FILE__; 
#endif 
 
//用于进程控制,每启动一个进程+1 
volatile int threadController = 0; 
//全局变量用来存放数据流中数据报的序列号 
DWORD rtp_sequence_1 = 0, rtp_sequence_2 = 0; 
//全局变量用来存放数据流中数据报的时间戳 
//根据数据流的速率定义每个数据包时间戳的增量,此处定义为数据报中字节的数目 
//根据我们对数据流1和数据流2取样频率的定义可知: 
//数据流1相邻两个数据报之间时间戳差值为10; 
//数据流2相邻两个数据报之间时间戳差值为5 
RtpTime rtp_timestamp_1 = 0 , rtp_timestamp_2 = 0; 
//数据流的同步源标识 
RtpSrc rtp_SSRC_1 = 0,rtp_SSRC_2 = 0; 
//存放每个数据报生成的时候的系统时间 
double rtp_sampletime_1 = 0 , rtp_sampletime_2 = 0; 
//系统时钟频率 
double dfFreq = 0;  
//用于存放系统时间有关信息的全局变量 
LARGE_INTEGER liTime;  
boolean IsRandomDelay = false; 
 
//获取NTP时间戳信息,64比特 
LONGLONG GetMillisecondsSince1900() 
{ 
	FILETIME ft; 
	GetSystemTimeAsFileTime(&ft); 
	return *((LONGLONG *)&ft) / 10000 - LONGLONG(9435484800000); 
} 
 
//根据全局变量中存放的上一数据报的时间戳、序列号填写下一个数据报 
void WriteRtpHeader(RTP_HEADER *rtp_header, 
					DWORD *rtp_sequence, 
					RtpTime *rtp_timestamp, 
					RtpSrc *rtp_SSRC, 
					double *rtp_sampletime, 
					double stream_sample_freq) 
{ 
	rtp_header->version = 1; 
	rtp_header->padding = 0; 
	rtp_header->extension = 0; 
	rtp_header->count = 1; 
	rtp_header->marker = 0; 
	rtp_header->type = 0; 
	rtp_header->sequence = *rtp_sequence; 
	rtp_header->ssrc = *rtp_SSRC; 
	*rtp_sequence = *rtp_sequence + 1; 
	//获取当前时间信息 
	QueryPerformanceCounter(&liTime);  
	*rtp_timestamp = *rtp_timestamp  
		+ floor( (liTime.QuadPart * 1000 - *rtp_sampletime) / dfFreq * stream_sample_freq); 
	*rtp_sampletime = liTime.QuadPart * 1000.0; 
	rtp_header->timestamp = *rtp_timestamp;  
} 
 
void PrintRtpHeader(RTP_HEADER *rtp_header) 
{ 
	printf("-> rtp timestampe is:%hu\n",rtp_header->timestamp); 
	printf("-> rtp sequence is:%d\n",rtp_header->sequence); 
} 
 
 
///////////////////////////////////////////////////////////////////////////// 
// CRtp_sendDlg dialog 
 
CRtp_sendDlg::CRtp_sendDlg(CWnd* pParent /*=NULL*/) 
	: CDialog(CRtp_sendDlg::IDD, pParent) 
{ 
	//{{AFX_DATA_INIT(CRtp_sendDlg) 
	//}}AFX_DATA_INIT 
	// Note that LoadIcon does not require a subsequent DestroyIcon in Win32 
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); 
} 
 
void CRtp_sendDlg::DoDataExchange(CDataExchange* pDX) 
{ 
	CDialog::DoDataExchange(pDX); 
	//{{AFX_DATA_MAP(CRtp_sendDlg) 
	DDX_Control(pDX, IDC_LIST_Status, m_status); 
	//}}AFX_DATA_MAP 
} 
 
BEGIN_MESSAGE_MAP(CRtp_sendDlg, CDialog) 
	//{{AFX_MSG_MAP(CRtp_sendDlg) 
	ON_WM_PAINT() 
	ON_WM_QUERYDRAGICON() 
	ON_BN_CLICKED(IDOK, OnQuit) 
	ON_BN_CLICKED(IDC_BUTTON_Send_Single_Normal, OnBUTTONSendSingleNormal) 
	ON_BN_CLICKED(IDC_BUTTON_Send_Multi_Normal, OnBUTTONSendMultiNormal) 
	ON_BN_CLICKED(IDC_BUTTON_Send_Single_Random_Delay, OnBUTTONSendSingleRandomDelay) 
	//}}AFX_MSG_MAP 
	ON_MESSAGE(WM_DATASEND,OnDataSend)			//有数据输入 
END_MESSAGE_MAP() 
 
///////////////////////////////////////////////////////////////////////////// 
// CRtp_sendDlg message handlers 
 
BOOL CRtp_sendDlg::OnInitDialog() 
{ 
	CDialog::OnInitDialog(); 
 
	// Set the icon for this dialog.  The framework does this automatically 
	//  when the application's main window is not a dialog 
	SetIcon(m_hIcon, TRUE);			// Set big icon 
	SetIcon(m_hIcon, FALSE);		// Set small icon 
	 
	//Added by xhChen--begin 
	//初始化Winsock 
	WORD wVersionRequested; 
	WSAData  wsaData; 
	int err;  
	wVersionRequested = MAKEWORD( 2, 0 );  
	err = WSAStartup( wVersionRequested, &wsaData ); 
	if ( err != 0 ) return 0; 
	if ( LOBYTE( wsaData.wVersion ) != 2 || HIBYTE( wsaData.wVersion ) != 0 ) { 
		WSACleanup( ); 
		return 0;  
	}	 
	//产生一个随机序列号 
	srand( (unsigned)time( NULL ) ); 
	rtp_sequence_1 = rand(); 
	rtp_sequence_2 = rand(); 
	rtp_timestamp_1 = rand(); 
	rtp_timestamp_2 = rand(); 
	rtp_SSRC_1 = rand(); 
	rtp_SSRC_2 = rand(); 
	//获取系统时钟频率,这个时钟频率将用于计算时间戳 
	QueryPerformanceFrequency(&liTime);  
	dfFreq = (double)liTime.QuadPart;  
 
	//Added by xhChen--end 
 
	 
	return TRUE;  // return TRUE  unless you set the focus to a control 
} 
 
// If you add a minimize button to your dialog, you will need the code below 
//  to draw the icon.  For MFC applications using the document/view model, 
//  this is automatically done for you by the framework. 
 
void CRtp_sendDlg::OnPaint()  
{ 
	if (IsIconic()) 
	{ 
		CPaintDC dc(this); // device context for painting 
 
		SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0); 
 
		// Center icon in client rectangle 
		int cxIcon = GetSystemMetrics(SM_CXICON); 
		int cyIcon = GetSystemMetrics(SM_CYICON); 
		CRect rect; 
		GetClientRect(&rect); 
		int x = (rect.Width() - cxIcon + 1) / 2; 
		int y = (rect.Height() - cyIcon + 1) / 2; 
 
		// Draw the icon 
		dc.DrawIcon(x, y, m_hIcon); 
	} 
	else 
	{ 
		CDialog::OnPaint(); 
	} 
} 
 
// The system calls this to obtain the cursor to display while the user drags 
//  the minimized window. 
HCURSOR CRtp_sendDlg::OnQueryDragIcon() 
{ 
	return (HCURSOR) m_hIcon; 
} 
 
void CRtp_sendDlg::OnQuit()  
{ 
	//winsock退出 
	WSACleanup( ); 
	CDialog::OnOK();	 
} 
 
//发送第一个媒体流数据 
HANDLE SendStreamProc_1_normal(LPVOID param) 
{ 
	char SendBuf[80]={0}; 
	int iDataLen; 
	char SendValue[10]; 
	int ret; 
	int i,j; 
	SOCKET s;		// Our TCP socket handle 
	SOCKADDR_IN addr;	// The host's address 
	RTP_HEADER rtp_header; 
 
	// Create a UDP socket 
	s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 
	// Error? 
	if(s == SOCKET_ERROR) 
	{ 
		AfxMessageBox("Error Call to socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)"); 
		exit(1); 
	} 
 
	// Fill in the host information 
	addr.sin_family = AF_INET; 
	addr.sin_port = htons(7778); 
	addr.sin_addr.s_addr = inet_addr("127.0.0.1"); 
 
	//获取窗口句柄以发送消息 
	CWnd *pWnd=CWnd::FindWindow(NULL,"RTP数据报发送");  
	for(j=0;j<10;j++){SendValue[j]=64;} 
	for(i=0;i<10;i++){ 
		//填充发送缓冲区 
		WriteRtpHeader(&rtp_header, 
			&rtp_sequence_1, 
			&rtp_timestamp_1, 
			&rtp_SSRC_1, 
			&rtp_sampletime_1, 
			STREAM_1_SAMPLE_FREQ); 
		PrintRtpHeader(&rtp_header); 
		memcpy(SendBuf,&rtp_header,sizeof(rtp_header)); 
		// Copy the pre-defined message into a buffer 
		for(j=0;j<10;j++){SendValue[j] = SendValue[j] + 1;} 
		memcpy(SendBuf+sizeof(rtp_header),&SendValue,10); 
		iDataLen = sizeof(rtp_header)+10; 
		// Ready to send data 
		if(IsRandomDelay){Sleep(rand()%32);} 
		ret = sendto(s, SendBuf, iDataLen, 0, (struct sockaddr *) &addr, sizeof(addr)); 
		if(ret == SOCKET_ERROR) 
		{ 
			AfxMessageBox("Error Call to sendto(s, szMessage, iMessageLen, 0, (SOCKADDR_IN *) &addr, sizeof(addr))"); 
			exit(1); 
		} 
		Sleep(20); 
		//向窗口发送消息提示已经发送的数据报个数 
		if(pWnd) pWnd->SendMessage(WM_DATASEND,rtp_sequence_1,rtp_timestamp_1);  
	} 
 
	closesocket(s); 
 
	return 0; 
} 
 
//发送第二个媒体流数据 
HANDLE SendStreamProc_2_normal(LPVOID param) 
{ 
	char SendBuf[80]={0}; 
	int iDataLen; 
	char SendValue[5]; 
	int ret; 
	int i,j; 
	SOCKET s;		// Our TCP socket handle 
	SOCKADDR_IN addr;	// The host's address 
	RTP_HEADER rtp_header; 
 
	// Create a UDP socket 
	s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 
	// Error? 
	if(s == SOCKET_ERROR) 
	{ 
		AfxMessageBox("Error Call to socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)"); 
		exit(1); 
	} 
 
	// Fill in the host information 
	addr.sin_family = AF_INET; 
	addr.sin_port = htons(7778); 
	addr.sin_addr.s_addr = inet_addr("127.0.0.1"); 
	 
	//获取窗口句柄以发送消息 
	CWnd *pWnd=CWnd::FindWindow(NULL,"RTP数据报发送");  
	for(j=0;j<5;j++){SendValue[j]=96;} 
	for(i=0;i<10;i++){ 
		//填充发送缓冲区 
		WriteRtpHeader(&rtp_header, 
			&rtp_sequence_2, 
			&rtp_timestamp_2, 
			&rtp_SSRC_2, 
			&rtp_sampletime_2, 
			STREAM_2_SAMPLE_FREQ); 
//		WriteRtpHeader(&rtp_header,&rtp_sequence_2,&rtp_timestamp_2); 
		PrintRtpHeader(&rtp_header); 
		memcpy(SendBuf,&rtp_header,sizeof(rtp_header)); 
		// Copy the pre-defined message into a buffer 
		for(j=0;j<5;j++){SendValue[j] = SendValue[j] + 1;} 
		memcpy(SendBuf+sizeof(rtp_header),&SendValue,5); 
		iDataLen = sizeof(rtp_header)+5; 
		// Ready to send data 
		ret = sendto(s, SendBuf, iDataLen, 0, (struct sockaddr *) &addr, sizeof(addr)); 
		if(ret == SOCKET_ERROR) 
		{ 
			AfxMessageBox("Error Call to sendto(s, szMessage, iMessageLen, 0, (SOCKADDR_IN *) &addr, sizeof(addr))"); 
			exit(1); 
		} 
		Sleep(10); 
		ret = sendto(s, SendBuf, iDataLen, 0, (struct sockaddr *) &addr, sizeof(addr)); 
		if(ret == SOCKET_ERROR) 
		{ 
			AfxMessageBox("Error Call to sendto(s, szMessage, iMessageLen, 0, (SOCKADDR_IN *) &addr, sizeof(addr))"); 
			exit(1); 
		} 
		Sleep(10); 
		//向窗口发送消息提示已经发送的数据报个数 
		if(pWnd) pWnd->SendMessage(WM_DATASEND,rtp_sequence_2,rtp_timestamp_2);  
	} 
 
	closesocket(s); 
//	::MessageBox((HWND)param, "数据流2发送已经停止!", "注意", MB_OK); 
	return 0; 
} 
 
void CRtp_sendDlg::OnBUTTONSendSingleNormal()  
{ 
	HWND hWnd = GetSafeHwnd(); 
	m_status.ResetContent();	 
	threadController = threadController + 1; 
	IsRandomDelay = false; 
	AfxBeginThread((AFX_THREADPROC)SendStreamProc_1_normal, hWnd, THREAD_PRIORITY_NORMAL); 
//	GetDlgItem(IDC_BUTTON_Send_Single_Normal)->EnableWindow(false);	 
} 
 
void CRtp_sendDlg::OnBUTTONSendMultiNormal()  
{ 
	HWND hWnd; 
	m_status.ResetContent();	 
 
	hWnd = GetSafeHwnd(); 
	threadController = threadController + 1; 
	AfxBeginThread((AFX_THREADPROC)SendStreamProc_1_normal, hWnd, THREAD_PRIORITY_NORMAL); 
 
	hWnd = GetSafeHwnd(); 
	threadController = threadController + 1; 
	AfxBeginThread((AFX_THREADPROC)SendStreamProc_2_normal, hWnd, THREAD_PRIORITY_NORMAL); 
} 
 
LONG CRtp_sendDlg::OnDataSend(WPARAM w,LPARAM l) 
{ 
	char tmpstr[80]; 
	sprintf(tmpstr,"Sequence:%d , TimeStamp:%d",w,l); 
	m_status.AddString(tmpstr); 
	UpdateData(false); 
	return 0; 
} 
 
void CRtp_sendDlg::OnBUTTONSendSingleRandomDelay()  
{ 
	HWND hWnd = GetSafeHwnd(); 
	m_status.ResetContent();	 
	threadController = threadController + 1; 
	IsRandomDelay = true; 
	AfxBeginThread((AFX_THREADPROC)SendStreamProc_1_normal, hWnd, THREAD_PRIORITY_NORMAL);	 
}