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);
}