使用ortp windows

D:ortp- 0.16.3srctestswin_sender RTPSender.cpp

#include <ortp/ortp.h>

#include <string.h>

#define STREAMS_COUNT 1000

enum

{

EVENT_STOP,

EVENT_RTP,

EVENT_COUNT // Always last

};

RtpSession * m_Session[STREAMS_COUNT];

int m_nPacket_Size = 160;

int m_nTimestamp_Inc = 160;

char * m_pBuffer = NULL;

char * m_SSRC = NULL;

int m_nChannels = 0;

int m_nPort = 0;

HANDLE m_hEvents[EVENT_COUNT];

BOOL m_bExit = FALSE;

static char *help="usage: mrtpsend filename ip port nstreams [--packet-size size] [--ts-inc value]n";

BOOL ctrlHandlerFunction(DWORD fdwCtrlType)

{

switch (fdwCtrlType)

{

// Handle the CTRL+C signal.

// CTRL+CLOSE: confirm that the user wants to exit.

case CTRL_C_EVENT:

case CTRL_CLOSE_EVENT:

case CTRL_BREAK_EVENT:

case CTRL_LOGOFF_EVENT:

case CTRL_SHUTDOWN_EVENT:

m_bExit = TRUE;

SetEvent(m_hEvents[EVENT_STOP]);

return TRUE;

default:

return FALSE;

}

}

int GetCommandArguments(int argc, char *argv[])

{

int nCounter;

// Check the number of arguments

if (argc<5)

{

printf(help);

return -1;

}

m_nChannels = atoi(argv[4]); // 流數目

// Get the number of channels

if (m_nChannels == 0)

{

printf(help);

return -1;

}

for (nCounter=5; nCounter<argc; nCounter++)

{

if (strcmp(argv[nCounter],"--packet-size")==0)

{

if ( nCounter+1 < argc ){

m_nPacket_Size=atoi(argv[nCounter+1]);

}

else {

printf(help);

return -1;

}

if (m_nPacket_Size==0)

{

printf("Packet size can't be %s.n",argv[nCounter+1]);

return -1;

}

nCounter+=1;

}

else if (strcmp(argv[nCounter],"--ts-inc")==0)

{

if ( nCounter+1 < argc )

{

m_nTimestamp_Inc=atoi(argv[nCounter+1]);

}

else {

printf(help);

return -1;

}

if (m_nTimestamp_Inc==0)

{

printf("Timestanp increment can't be %s.n",argv[nCounter+1]);

return -1;

}

nCounter+=1;

}

}

return 0;

}

void ProductVersion()

{

char strBuffer[255];

printf("====================================n");

printf("Author : Simon Morlat =n");

printf("Porting : Yann STEPHAN =n");

printf("====================================n");

 

memset(&strBuffer, 0x0, sizeof(strBuffer));

sprintf((char *) &strBuffer, "= RTPSender V1.0 - Date : %s - %sn", __DATE__, __TIME__);

printf(strBuffer);

printf("====================================n");

}

int __cdecl main(int argc, char *argv[])

{

FILE * infile = NULL;

SessionSet * pSessionSet = NULL;

int nCounter = 0;

UINT32 m_nUser_Timestamp = 0;

ProductVersion();

if (GetCommandArguments(argc, argv) != 0)

{

printf("==> Sorry dude...n");

Sleep(1000);

return -1;

}

printf("==> Starting the RTP Sender testn");

// =============== INSTALL THE CONTROL HANDLER ===============

if (SetConsoleCtrlHandler( (PHANDLER_ROUTINE) ctrlHandlerFunction, TRUE) == 0)

{

printf("==> Cannot handle the CTRL-C...n");

}

printf("==> Timestamp increment will be %in" , m_nTimestamp_Inc);

printf("==> Packet size will be %in" , m_nPacket_Size);

m_pBuffer = (char *) ortp_malloc(m_nPacket_Size); // 申請內存。與malloc同等

ortp_init(); // 初始化oRTP庫,在使用oRTP API前使用

ortp_scheduler_init(); // 初始化oRTP調度器. 如果在應用程序中使用RtpSession模式,則必須調用。調度器可以管理多個session

printf("==> Scheduler initializedn");

m_SSRC = getenv("SSRC"); // 獲取同步源標識,即SSRC環境變量值

m_nPort = atoi(argv[3]);  //  端口地址

for (nCounter=0; nCounter < m_nChannels; nCounter++)

{

//printf("==> Channel [#%d]n", nCounter);

m_Session[nCounter] = rtp_session_new(RTP_SESSION_SENDONLY);

rtp_session_set_scheduling_mode(m_Session[nCounter],1); // RtpScheduler管理多個session的調度和收發的控制,本函數設置是否使用該session調度管理功能。

rtp_session_set_blocking_mode(m_Session[nCounter],0);

rtp_session_set_remote_addr(m_Session[nCounter],argv[2], m_nPort);

rtp_session_set_send_payload_type(m_Session[nCounter],0);

if (m_SSRC != NULL)

{ // Sets the SSRC for the outgoing stream.

rtp_session_set_ssrc(m_Session[nCounter],atoi(m_SSRC));

}

m_nPort+=2;

}

infile=fopen(argv[1],"rb"); // 打開傳輸的文件

if (infile==NULL)

{

printf("==> Cannot open file !!!!");

Sleep(1000);

return -1;

}

// printf("==> Open filen");

pSessionSet = session_set_new(); // Allocates and initialize a new empty session set.

// printf("==> Session setn");

while( ((nCounter= (int) fread(m_pBuffer,1,m_nPacket_Size,infile))>0) && (m_bExit == FALSE) )

{

int k;

//g_message("Sending packet.");

for (k=0;k<m_nChannels;k++){

session_set_set(pSessionSet,m_Session[k]);  // This macro adds the rtp session to the set.

//printf("==> Session set set %dn", k);

}

session_set_select(NULL,pSessionSet,NULL); // 選擇發送會話集。

//printf("==> Session set selectn");

for (k=0;k<m_nChannels;k++)

{

//printf("---n");

if (session_set_is_set(pSessionSet,m_Session[k]))

{

//printf("==> Session set is set %dn", k);

rtp_session_send_with_ts(m_Session[k],m_pBuffer,nCounter,m_nUser_Timestamp);

//g_message("packet sended !");

}

}

m_nUser_Timestamp+=m_nTimestamp_Inc;

}

fclose(infile);

printf("==> Close filen");

for(nCounter=0;nCounter<m_nChannels;nCounter++)

{

rtp_session_destroy(m_Session[nCounter]);

}

session_set_destroy(pSessionSet);

// Give us some time

Sleep(250);

ortp_exit();

ortp_global_stats_display();

ortp_free(m_pBuffer);

printf("==> Remove the CTRL-C handler...n");

SetConsoleCtrlHandler( (PHANDLER_ROUTINE) ctrlHandlerFunction, FALSE);

// Wait for an input key

printf("Waiting for exit : ");

for (nCounter = 0; nCounter < 4*5; nCounter++)

{

printf(".");

Sleep(250);

}

return 0;

}

小知識

__cdecl

__cdecl 是C DECLaration的縮寫(declaration,聲明),表示C語言默認的函數調用方法:所有參數從右到左依次入棧,這些參數由調用者清除,稱爲手動清棧。被調用函數不需要求調用者傳遞多少參數,調用者傳遞過多或者過少的參數,甚至完全不同的參數都不會產生編譯階段的錯誤。

_stdcall 是StandardCall的縮寫,是C++的標準調用方式:所有參數從右到左依次入棧,如果是調用類成員的話,最後一個入棧的是this指針。這些堆棧中的參數由被調用的函數在返回後清除,使用的指令是 retnX,X表示參數佔用的字節數,CPU在ret之後自動彈出X個字節的堆棧空間。稱爲自動清棧。函數在編譯的時候就必須確定參數個數,並且調用者必須嚴格的控制參數的生成,不能多,不能少,否則返回後會出錯。

PASCAL 是Pascal語言的函數調用方式,也可以在C/C++中使用,參數壓棧順序與前兩者相反。返回時的清棧方式忘記了……

_fastcall是編譯器指定的快速調用方式。由於大多數的函數參數個數很少,使用堆棧傳遞比較費時。因此_fastcall通常規定將前兩個(或若干個)參數由寄存器傳遞,其餘參數還是通過堆棧傳遞。不同編譯器編譯的程序規定的寄存器不同。返回方式和_stdcall相當。

_thiscall 是爲了解決類成員調用中this指針傳遞而規定的。_thiscall要求把this指針放在特定寄存器中,該寄存器由編譯器決定。VC使用ecx,Borland的C++編譯器使用eax。返回方式和_stdcall相當。

_fastcall 和 _thiscall涉及的寄存器由編譯器決定,因此不能用作跨編譯器的接口。所以Windows上的COM對象接口都定義爲_stdcall調用方式。

C中不加說明默認函數爲_cdecl方式(C中也只能用這種方式),C++也一樣,但是默認的調用方式可以在IDE環境中設置。

帶有可變參數的函數必須且只能使用_cdecl方式,例如下面的函數:

int printf(char * fmtStr, ...);

int scanf(char * fmtStr, ...);

SetConsoleCtrlHandler 處理控制檯消息

來源:http://andylin02.javaeye.com/blog/661431

SetConsoleCtrlHandler 處理控制檯消息

一、如何處理所有的控制檯消息。

第一步,首先要安裝一個事件鉤子,也就是說要建立一個回調函數。調用Win32 API,原型如下:

BOOL SetConsoleCtrlHandler(

PHANDLER_ROUTINE HandlerRoutine, // 回調函數

BOOL Add // 表示添加還是刪除

);

參數HandlerRoutine是一個指向函數的指針,原型如下:

BOOL WINAPI HandlerRoutine(

DWORD dwCtrlType // 控制事件類型

);

所有的HandlerRoutine函數只有一個參數dwCtrlType,他表示控制檯發出了什麼消息。參數有下列值:

CTRL_C_EVENT - 當用戶按下了CTRL+C,或者由GenerateConsoleCtrlEvent API發出.

CTRL_BREAK_EVENT - 用戶按下CTRL+BREAK, 或者由GenerateConsoleCtrlEvent API發出.

CTRL_CLOSE_EVENT - 當試圖關閉控制檯程序,系統發送關閉消息。

CTRL_LOGOFF_EVENT - 用戶退出時,但是不能決定是哪個用戶.

CTRL_SHUTDOWN_EVENT - 當系統被關閉時.

當收到事件的時候,HandlerRoutine可以選擇處理,或者簡單的忽略。如果回調函數選擇忽略,函數返回FALSE,系統將處理下一個鉤子程序。如果處理消息,程序在處理完消息後應該返回TRUE。

CTRL_CLOSE_EVENT, CTRL_LOGOFF_EVENT和CTRL_SHUTDOWN_EVENT通常被用來處理一些程序的清理工作,然後調用ExitProcess API。另外,這三個事件有超時機制,CTRL_CLOSE_EVENT是5秒,另外兩個是20秒。如果程序超時候,系統將會彈出結束進程的對話框。如果用戶選擇了結束進程,任何清理工作都不會做,所以應該在超時時間內完成工作。下面是一個回調函數的例子:

BOOL WINAPI ConsoleHandler(DWORD CEvent)

{

char mesg[128];

switch(CEvent)

{

case CTRL_C_EVENT:

MessageBox(NULL, "CTRL+C received!","CEvent",MB_OK);

break;

case CTRL_BREAK_EVENT:

MessageBox(NULL, "CTRL+BREAK received!","CEvent",MB_OK);

break;

case CTRL_CLOSE_EVENT:

MessageBox(NULL, "Program being closed!","CEvent",MB_OK);

break;

case CTRL_LOGOFF_EVENT:

MessageBox(NULL, "User is logging off!","CEvent",MB_OK);

break;

case CTRL_SHUTDOWN_EVENT:

MessageBox(NULL, "User is logging off!","CEvent",MB_OK);

break;

}

return TRUE;

}

好,現在已經有了回調函數,再來看看怎麼安裝鉤子:

if (SetConsoleCtrlHandler((PHANDLER_ROUTINE)ConsoleHandler,TRUE)==FALSE)

{

// unable to install handler...

// display message to the user

printf("Unable to install handler!n");

return -1;

}

第一個參數是函數指針,就是上面的那個函數。第二個參數是標誌,如果爲TRUE那麼就安裝鉤子,如果爲FALSE那麼刪除鉤子。

好了,在安裝了鉤子後,我們就能收到控制檯消息了,在程序退出前,要刪除鉤子。很簡單吧。

getenv()讀取環境變量的當前值的函數

原形:char *getenv(const char *name)

用法:s=getenv("環境變量名");

   需先定義char *s;

功能:返回一給定的環境變量值,環境變量名可大寫或小寫。如果指定的變量在環境中未定義,則返回一空串。

頭文件:stdlib.h

eg:

String strEnv ="";

strEnv = getenv( "TMP_DIR");

if( ( NULL == strEnv ) || ( 0 == strlen(strEnv ) ) )

{

//error

}

oRTP函數

rtp_session_new

RtpSession * rtp_session_new (int mode) 
Creates a new rtp session. 
If the session is able to send data (RTP_SESSION_SENDONLY or  RTP_SESSION_SENDRECV), then a random SSRC number is choosed for the outgoing stream. 
@param mode One of the RtpSessionMode flags.  
@return the newly created rtp session. 
 

rtp_session_set_blocking_mode

函數原型:void rtp_session_set_blocking_mode (RtpSession * session, int yesno)

函數功能:設置是否使用阻塞模式,

參數含義:

session: rtp會話結構體

yesno: 是否使用阻塞模式

說明:

阻塞模式只有在scheduling mode被開啓的情況下才能使用,本函數決定了rtp_session_recv_with_ts() 和 rtp_session_send_with_ts()兩個函數的行爲,如果啓用了阻塞模式,則rtp_session_recv_with_ts()會一直阻塞直到接收RTP包的時間點到達(這個時間點由該函數參數中所定義的時間戳來決定),當接收完RTP數據包後,該函數纔會返回。同樣,rtp_session_send_with_ts()也會一直阻塞直到需要被髮送的RTP包的時間點到達,發送結束後,函數才返回。

This function implicitely enables the scheduling mode if yesno is TRUE.

rtp_session_set_blocking_mode() defines the behaviour of the rtp_session_recv_with_ts() and rtp_session_send_with_ts() functions. If @yesno is TRUE, rtp_session_recv_with_ts() will block until it is time for the packet to be received, according to the timestamp passed to the function. After this time, the function returns.

For rtp_session_send_with_ts(), it will block until it is time for the packet to be sent.

If @yesno is FALSE, then the two functions will return immediately.

@param session a rtp session

@param yesno a boolean

rtp_session_set_remote_addr

函數原型:int rtp_session_set_remote_addr (RtpSession * session, const char * addr, int port)

函數功能:設置RTP發送的目的地址

參數含義:

session: rtp會話結構體

addr: 目的IP地址

port: 目的地址的監聽端口號

返回值: 0表示成功

rtp_session_set_scheduling_mode

函數原型:void rtp_session_set_scheduling_mode (RtpSession * session, int yesno)

函數功能: RtpScheduler管理多個session的調度和收發的控制,本函數設置是否使用該session調度管理功能。

參數含義:

session:rtp會話結構體

yesno: 是否使用rtp session的系統調度功能

說明:

如果yesno爲1,則表明使用系統的session調度管理功能,意味着可以使用以下功能:

1. 可以使用session_set_select在多個rtp會話之間進行選擇,根據時間戳判定某個會話是否到達了收發的時間。

2. 可以使用rtp_session_set_blocking_mode()設置是否使用阻塞模式來進行rtp包的發送和接收。

如果yesno爲0,則表明該會話不受系統管理和調度。

關於rtp session的管理和調度,由全局的變量RtpScheduler *__ortp_scheduler來負責,該變量必須通過ortp_scheduler_init() 來進行初始化操作。

Sets the scheduling mode of the rtp session. If @yesno is TRUE, the rtp session is in the scheduled mode, that means that you can use session_set_select() to block until it's time to receive or send on this session according to the timestamp passed to the respective functions.

You can also use blocking mode (see rtp_session_set_blocking_mode() ), to simply block within the receive and send functions.

If @yesno is FALSE, the ortp scheduler will not manage those sessions, meaning that blocking mode and the use of session_set_select() for this session are disabled.

@param session a rtp session.

@param yesno a boolean to indicate the scheduling mode.

rtp_session_set_send_payload_type

rtp_session_set_send_payload_type

函數原型:int rtp_session_set_send_payload_type (RtpSession * session, int paytype)

函數功能:設置RTP發送數據的負載類型

參數含義:

session: rtp會話結構體

paytype:負載類型

返回值: 0表示成功,-1表示負載未定義

說明:

負載類型在payloadtype.h文件中有詳細的定義,RTP接收端有着類似的負載類型設置函數,int rtp_session_set_recv_payload_type ( RtpSession * session, int paytype ) ,注意,發送的負載類型必須與接收的負載類型一致才能正常完成收發。

rtp_session_set_ssrc

void rtp_session_set_ssrc (RtpSession * session, uint32_t ssrc)

Sets the SSRC for the outgoing stream.

If not done, a random ssrc is used.

@param session a rtp session.

@param ssrc an unsigned 32bit integer representing the synchronisation source identifier (SSRC).

session_set_new

SessionSet* session_set_new ( void )

Allocates and initialize a new empty session set.

Returns: the empty session set.

session_set_select

int session_set_select ( SessionSet * recvs,

SessionSet * sends,

SessionSet * errors

)

This function performs similarly as libc select() function, but performs on RtpSession instead of file descriptors. session_set_select() suspends the calling process until some events arrive on one of the three sets passed in argument. Two of the sets can be NULL. The first set is interpreted as a set of RtpSession waiting for receive events: a new buffer (perhaps empty) is availlable on one or more sessions of the set, or the last receive operation with rtp_session_recv_with_ts() would have finished if it were in blocking mode. The second set is interpreted as a set of RtpSession waiting for send events, i.e. the last rtp_session_send_with_ts() call on a session would have finished if it were in blocking mode.

When some events arrived on some of sets, then the function returns and sets are changed to indicate the sessions where events happened. Sessions can be added to sets using session_set_set(), a session has to be tested to be part of a set using session_set_is_set().

Parameters:

recvs a set of rtp sessions to be watched for read events

sends a set of rtp sessions to be watched for write events

errors a set of rtp sessions to be watched for errors

Returns:

: the number of sessions on which the selected events happened.

Definition at line 98 of file sessionset.c.

References session_set_select().

Referenced by session_set_select().

session_set_set

#define session_set_set ( ss, rtpsession)  ORTP_FD_SET((rtpsession)->mask_pos,&(ss)->rtpset)

This macro adds the rtp session to the set.

Parameters:

ss a set (SessionSet object)

rtpsession a RtpSession

Definition at line 104 of file sessionset.h.

Referenced by rtp_session_recvm_with_ts().

session_set_is_set

#define session_set_is_set (ss, rtpsession) ORTP_FD_ISSET((rtpsession)->mask_pos,&(ss)->rtpset)

This macro tests if the session is part of the set. 1 is returned if true, 0 else.

Parameters:

ss a set (SessionSet object)

rtpsession a rtp session

Definition at line 112 of file sessionset.h.

rtp_session_send_with_ts

函數原型:int rtp_session_send_with_ts (RtpSession * session, const char * buffer, int len,uint32_t userts)

函數功能:發送RTP數據包

參數含義:

session: rtp會話結構體

buffer: 需要發送的RTP數據的緩衝區

len: 需要發送的RTP數據的長度

userts: 本RTP數據包的時間戳

返回值: 成功發送到網絡中的字節數

說明:

發送RTP數據需要自己管理時間戳的遞增,每調用一次本函數,請根據實際情況對userts進行遞增,具體遞增的規則見RTP協議中的說明。

例如:如果發送的是採樣率爲90000Hz的視頻數據包,每秒25幀,則時間戳的增量爲:90000/25 = 3600

時間戳的起始值爲隨機值,建議設置爲0 。

int rtp_session_send_with_ts ( RtpSession * session,

  const uint8_t * buffer,

  int len,

  uint32_t userts

)

Send a rtp datagram to the destination set by rtp_session_set_remote_addr() containing the data from with timestamp . This is a high level function that uses rtp_session_create_packet() and rtp_session_sendm_with_ts() to send the data.

Parameters:

session a rtp session.

buffer a buffer containing the data to be sent in a rtp packet.

len the length of the data buffer, in bytes.

userts the timestamp of the data to be sent. Refer to the rfc to know what it is.

return the number of bytes sent over the network.

Definition at line 892 of file rtpsession.c.

References rtp_session_create_packet(), rtp_session_create_packet_with_data(), rtp_session_send_with_ts(), and rtp_session_sendm_with_ts().

Referenced by rtp_session_send_with_ts().

rtp_session_destroy

rtp_session_destroy

【原型】: void rtp_session_destroy(RtpSession *session)

【功能】:摧毀rtp會話對象,釋放資源

【參數】:session已經創建的RTP會話對象

Destroys a rtp session. All memory allocated for the RtpSession is freed.

Parameters:

session a rtp session.

Definition at line 1481 of file rtpsession.c.

References rtp_session_destroy().

rtp_session_recv_with_ts

函數原型:int rtp_session_recv_with_ts (RtpSession * session, char * buffer,int len, uint32_t time, int * have_more)

函數功能:接收RTP數據包

參數含義:

session: rtp會話結構體

buffer: 存放接收的RTP數據的緩衝區

len: 期望接收的RTP數據的長度

time: 期望接收的RTP數據的時間戳

have_more:標識接收緩衝區是否還有數據沒有傳遞完。當用戶給出的緩衝區不夠大時,爲了標識緩衝區數據未取完,則have_more指向的數據爲1,期望用戶以同樣的時間戳再次調用本函數;否則爲0,標識取完。

rtp_session_destroy

【原型】: void rtp_session_destroy(RtpSession *session)

【功能】:摧毀rtp會話對象,釋放資源

【參數】:session已經創建的RTP會話對象

session_set_destroy

void session_set_destroy ( SessionSet * set )

Frees a SessionSet.

Destroys a session set.

Definition at line 43 of file sessionset.c.

References session_set_destroy().

Referenced by session_set_destroy().

ortp_exit

void ortp_exit ( void )

Gracefully uninitialize the library, including shutdowning the scheduler if it was started.

Definition at line 116 of file ortp.c.

References ortp_exit().

Referenced by ortp_exit().

ortp_global_stats_display

void ortp_global_stats_display ( void)

Display global statistics (cumulative for all RtpSession)

Definition at line 273 of file ortp.c.

References ortp_global_stats_display(), and rtp_stats_display().

Referenced by ortp_global_stats_display().

命令格式

mrtpsend filename ip port nstreams [--packet-size size] [--ts-inc value]

mrtpsend ------- 命令

filename ------- 發送的文件名

ip ------- ip 地址,發送目的地地址

port ------- 端口地址,發送目的地端口地址

nstreams ------- 流數

--packet-size size  ------ 數據報大小,默認值爲160字節

--ts-inc value ------ 郵戳增量,默認值爲160

參考:

http://ticktick.blog.51cto.com/823160/345642

http://blog.csdn.net/ren911/archive/2010/07/09/5724509.aspx

http://linphone.sourcearchive.com/lines/3.2.1-1ubuntu4/mrtpsend_8c-source.html

發佈了29 篇原創文章 · 獲贊 19 · 訪問量 10萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章