Main page → NatNet SDK → NatNet: Creating a Native (C++) Client Application
This guide covers essential points to developing a native client application using the NatNet SDK. The guideline uses sample codes in the SampleClient.cpp application in the \NatNet SDK\Sample folder, please refer to this project as an additional reference.
\NatNet SDK\Sample
SDK/API Support Disclaimer
NatNet SDK/include
[C++] SampleClient.cpp : Instantiating NatNetClient
<source> int CreateClient(ConnectionType connectionType) {
// release previous server if(g_pClient) { g_pClient -> Disconnect(); delete g_pClient; }
// create NatNet client g_pClient = new NatNetClient(connectionType);
</source>
[C++] SampleClient.cpp : Server Discovery
<source> const unsigned int kDiscoveryWaitTimeMillisec = 5 * 1000; // Wait 5 seconds for responses. const int kMaxDescriptions = 10; // Get info for, at most, the first 10 servers to respond. sNatNetDiscoveredServer servers[kMaxDescriptions]; int actualNumDescriptions = kMaxDescriptions; NatNet_BroadcastServerDiscovery( servers, &actualNumDescriptions );
if ( actualNumDescriptions < kMaxDescriptions ) {
// If this happens, more servers responded than the array was able to store.
} </source>
sNatNetClientConnectParams from NatNetTypes.h <source> typedef struct sNatNetClientConnectParams {
ConnectionType connectionType; uint16_t serverCommandPort; uint16_t serverDataPort; const char* serverAddress; const char* localAddress; const char* multicastAddress;
sNatNetClientConnectParams() : connectionType( ConnectionType_Multicast ) , serverCommandPort( 0 ) , serverDataPort( 0 ) , serverAddress( NULL ) , localAddress( NULL ) , multicastAddress( NULL ) { }
} sNatNetClientConnectParams; </source>
[C++] SampleClient.cpp : Connect to the Server
// release previous server if(g_pClient) { g_pClient->Disconnect(); delete g_pClient; }
// set the frame callback handler g_pClient->SetFrameReceivedCallback( DataHandler, g_pClient ); // this function will receive data from the server
// print version info unsigned char ver[4]; NatNet_GetVersion(ver); printf("NatNet Sample Client (NatNet ver. %d.%d.%d.%d)\n", ver[0], ver[1], ver[2], ver[3]);
// Init Client and connect to NatNet server // to use NatNet default port assignments int retCode = g_pClient->Connect( g_connectParams );
[C++] SampleClient.cpp : Request Server Description
<source> // print server info memset( &g_serverDescription, 0, sizeof( g_serverDescription ) ); ret = g_pClient->GetServerDescription( &g_serverDescription ); if ( ret != ErrorCode_OK || ! g_serverDescription.HostPresent ) {
printf("Unable to connect to server. Host not present. Exiting."); return 1;
} printf("[SampleClient] Server application info:\n");
printf("Application: %s (ver. %d.%d.%d.%d)\n", g_serverDescription.szHostApp, g_serverDescription.HostAppVersion[0],
g_serverDescription.HostAppVersion[1],g_serverDescription.HostAppVersion[2], g_serverDescription.HostAppVersion[3]);
printf("NatNet Version: %d.%d.%d.%d\n", g_serverDescription.NatNetVersion[0], g_serverDescription.NatNetVersion[1],
g_serverDescription.NatNetVersion[2], g_serverDescription.NatNetVersion[3]);
printf( "Client IP:%s\n", g_connectParams.localAddress ); printf( "Server IP:%s\n", g_connectParams.serverAddress ); printf("Server Name:%s\n\n", g_serverDescription.szHostComputerName); </source>
[C++] SampleClient.cpp : Send NatNet Commands
<source> // send/receive test request printf("[SampleClient] Sending Test Request\n"); void* pResult; int ret = 0; int nBytes = 0;
// Querying configured system frame rate from the connected server ret = g_pClient -> SendMessageAndWait("AnalogSamplesPerMocapFrame", &pResult, &nBytes);
if (ret == ErrorCode_OK) {
analogSamplesPerMocapFrame = *((int*)pResult); printf("Analog Samples Per Mocap Frame : %d", analogSamplesPerMocapFrame);
[C++] SampleClient.cpp : Get Data Descriptions
<source> // Retrieve Data Descriptions from server printf("\n\n[SampleClient] Requesting Data Descriptions..."); sDataDescriptions* pDataDefs = NULL; iResult = g_pClient->GetDataDescriptions(&pDataDefs);
if (iResult != ErrorCode_OK || pDataDefs == NULL) {
printf("[SampleClient] Unable to retrieve Data Descriptions.");
[C++] SampleClient.cpp : Parsing Data Descriptions
} else {
printf("[SampleClient] Received %d Data Descriptions:\n", pDataDefs->nDataDescriptions ); for(int i=0; i < pDataDefs->nDataDescriptions; i++) { printf("Data Description # %d (type=%d)\n", i, pDataDefs->arrDataDescriptions[i].type); if(pDataDefs->arrDataDescriptions[i].type == Descriptor_MarkerSet) { // MarkerSet sMarkerSetDescription* pMS = pDataDefs->arrDataDescriptions[i].Data.MarkerSetDescription; } else if(pDataDefs->arrDataDescriptions[i].type == Descriptor_RigidBody) { // RigidBody sRigidBodyDescription* pRB = pDataDefs->arrDataDescriptions[i].Data.RigidBodyDescription; } else if(pDataDefs->arrDataDescriptions[i].type == Descriptor_Skeleton) { // Skeleton sSkeletonDescription* pSK = pDataDefs->arrDataDescriptions[i].Data.SkeletonDescription; } else if(pDataDefs->arrDataDescriptions[i].type == Descriptor_ForcePlate) { // Force Plate sForcePlateDescription* pFP = pDataDefs->arrDataDescriptions[i].Data.ForcePlateDescription; } else { printf("Unknown data type."); // Unknown } }
<source> if ( pDataDefs ) {
NatNet_FreeDescriptions( pDataDefs ); pDataDefs = NULL;
typedef void (NATNET_CALLCONV* NatNetFrameReceivedCallback)(sFrameOfMocapData* pFrameOfData, void* pUserData);
void NATNET_CALLCONV DataHandler(sFrameOfMocapData* data, void* pUserData)
<source> // set the callback handlers // The DataHandler function will receive data from the server g_pClient -> SetFrameReceivedCallback( DataHandler, theClient ); </source>
[C++] SampleClient.cpp : Frame Data Callback Handler
<source> // set the callback handlers // The DataHandler function will receive data from the server g_pClient->SetDataCallback( DataHandler, theClient );
void __cdecl DataHandler(sFrameOfMocapData* data, void* pUserData) {
NatNetClient* pClient = (NatNetClient*) pUserData;
const double softwareLatencyMillisec = (softwareLatencyHostTicks * 1000) / static_cast<double>(g_serverDescription.HighResClockFrequency);
if(fp) _WriteFrame(fp,data);
int i=0;
printf("FrameID : %d\n", data->iFrame); printf("Timestamp : %3.2lf\n", data->fTimestamp); printf("Latency : %3.2lf\n", data->softwareLatencyMillisec);
// FrameOfMocapData params bool bIsRecording = ((data->params & 0x01)!=0); bool bTrackedModelsChanged = ((data->params & 0x02)!=0);
if(bIsRecording) printf("RECORDING\n");
if(bTrackedModelsChanged) printf("Models Changed.\n");
// Printing Rigid Body Data… //…
// Printing Skeleton Data… //…
// labeled markers… //…
// force plates… //…
<source> if (g_pClient) {
g_pClient->Disconnect(); delete g_pClient; g_pClient = NULL;