Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

phNetClientThread.cpp

Go to the documentation of this file.
00001 /* ---------------------------------------------------------------------------
00002     Phission : 
00003         Realtime Vision Processing System
00004     
00005     Copyright (C) 2003-2006 Philip D.S. Thoren (pthoren@cs.uml.edu)
00006     University of Massachusetts at Lowell,
00007     Laboratory for Artificial Intelligence and Robotics
00008     
00009     This file is part of Phission.
00010 
00011     Phission is free software; you can redistribute it and/or modify
00012     it under the terms of the GNU Lesser General Public License as published by
00013     the Free Software Foundation; either version 2 of the License, or
00014     (at your option) any later version.
00015 
00016     Phission is distributed in the hope that it will be useful,
00017     but WITHOUT ANY WARRANTY; without even the implied warranty of
00018     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019     GNU Lesser General Public License for more details.
00020 
00021     You should have received a copy of the GNU Lesser General Public License
00022     along with Phission; if not, write to the Free Software
00023     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00024 
00025  ---------------------------------------------------------------------------*/
00026 #ifdef HAVE_CONFIG_H
00027     #include <phissionconfig.h>
00028 #endif
00029 
00030 #include <phStandard.h>
00031 #include <phNetClientThread.h>
00032 //#include <errno.h>
00033 
00034 #include <phError.h>
00035 #include <phMemory.h>
00036 #include <phPrint.h>
00037 
00038 #define phNetClientThread_USE_JITTER_SYNC() 0
00039 
00040 /* ------------------------------------------------------------------------- */
00041 phNetClientThread::phNetClientThread( )
00042 {
00043     phFUNCTION("phNetClientThread::phNetClientThread")
00044     int locked = 0;
00045 
00046     phTHIS_LOCK(locked);
00047 
00048     this->setName("phNetClientThread");
00049     
00050     this->m_server_running  = NULL;
00051     this->m_title           = NULL;
00052     this->m_comms           = NULL;
00053     this->m_image           = NULL;
00054     this->m_condVar         = NULL;
00055     this->m_recv_thread     = NULL;
00056     
00057     phTHIS_UNLOCK(locked);
00058     
00059 error:
00060     phTHIS_ERROR_UNLOCK(locked);
00061 }
00062 
00063 /* ------------------------------------------------------------------------- */
00064 phNetClientThread::~phNetClientThread( )
00065 {
00066     phFUNCTION("phNetClientThread::~phNetClientThread")
00067     int locked = 0;
00068 
00069     phTHIS_LOOSE_LOCK(locked);
00070     
00071     this->m_condVar         = NULL;
00072     this->m_server_running  = NULL;
00073     this->m_image           = NULL;
00074     
00075     phFree(this->m_title);
00076     phDelete(this->m_comms);
00077     phDelete(this->m_recv_thread);
00078 
00079     phTHIS_LOOSE_UNLOCK(locked);
00080 }
00081 
00082 /* ------------------------------------------------------------------------- */
00083 int phNetClientThread::set( phConditionCounter *counter,
00084                             phSocket           *comms,
00085                             phImage            *image,
00086                             const char         *title,
00087                             volatile uint32_t  *server_running )
00088 {
00089     phFUNCTION("phNetClientThread::set")
00090     int         locked      = 0;
00091     uint32_t    title_len   = (uint32_t)((title != NULL) ? strlen(title) : 50);
00092 
00093     phTHIS_LOCK(locked);
00094 
00095     this->m_condVar     = counter;
00096     this->m_comms       = comms;
00097     this->m_image       = image;
00098     
00099     if (title != NULL)
00100     {
00101         this->m_title = (char *)phCalloc(title_len+1,sizeof(char));
00102         phCHECK_NULLPTR(this->m_title,"phCalloc","phCalloc failed");
00103         
00104 #if defined(HAVE_SNPRINTF)
00105         snprintf(this->m_title,title_len+1,"%s",title);
00106 #else
00107         sprintf(this->m_title,"%s",title);
00108 #endif
00109     }
00110     else
00111     {
00112         if (this->m_title != NULL)
00113         {
00114             phFree(this->m_title);
00115         }
00116     }
00117 
00118     this->m_server_running = server_running;
00119     
00120     phTHIS_UNLOCK(locked);
00121     
00122     return phSUCCESS;
00123 error:
00124     phTHIS_ERROR_UNLOCK(locked);
00125     
00126     return phFAIL;
00127 }
00128 
00129 /* ------------------------------------------------------------------------- */
00130 int phNetClientThread::setConditionVar( phConditionCounter  *counter )
00131 {
00132     phFUNCTION("phNetClientThread::setConditionVar")
00133     int locked = 0;
00134 
00135     phTHIS_LOCK(locked);
00136 
00137     this->m_condVar = counter;
00138     
00139     phTHIS_UNLOCK(locked);
00140     
00141     return phSUCCESS;
00142 error:
00143     phTHIS_ERROR_UNLOCK(locked);
00144     
00145     return phFAIL;
00146 }
00147 
00148 /* ------------------------------------------------------------------------- */
00149 int phNetClientThread::setComms( phSocket  *comms )
00150 {
00151     phFUNCTION("phNetClientThread::setComms")
00152     int locked = 0;
00153 
00154     phTHIS_LOCK(locked);
00155 
00156     this->m_comms = comms;
00157     
00158     phTHIS_UNLOCK(locked);
00159     
00160     return phSUCCESS;
00161 error:
00162     phTHIS_ERROR_UNLOCK(locked);
00163     
00164     return phFAIL;
00165 }
00166 
00167 /* ------------------------------------------------------------------------- */
00168 int phNetClientThread::setLiveObject( phImage   *image )
00169 {
00170     phFUNCTION("phNetClientThread::setLiveObjec")
00171     int locked = 0;
00172 
00173     phTHIS_LOCK(locked);
00174 
00175     this->m_image = image;
00176     
00177     phTHIS_UNLOCK(locked);
00178     
00179     return phSUCCESS;
00180 error:
00181     phTHIS_ERROR_UNLOCK(locked);
00182     
00183     return phFAIL;
00184 }
00185 
00186 /* ------------------------------------------------------------------------- */
00187 int phNetClientThread::setTitle( const char *title )
00188 {
00189     phFUNCTION("phNetClientThread::setTitle")
00190     int locked = 0;
00191     uint32_t title_len = (uint32_t)((title != NULL) ? strlen(title) : 50);
00192 
00193     phTHIS_LOCK(locked);
00194 
00195     if (title != NULL)
00196     {
00197         this->m_title = (char *)phCalloc(title_len+1,sizeof(char));
00198         phCHECK_NULLPTR(this->m_title,"phCalloc","phCalloc failed");
00199         
00200 #if defined(HAVE_SNPRINTF)
00201         snprintf(this->m_title,title_len+1,"%s",title);
00202 #else
00203         sprintf(this->m_title,"%s",title);
00204 #endif
00205     }
00206     else
00207     {
00208         if (this->m_title != NULL)
00209         {
00210             phFree(this->m_title);
00211         }
00212     }
00213 
00214     phTHIS_UNLOCK(locked);
00215     
00216     return phSUCCESS;
00217 error:
00218     phTHIS_ERROR_UNLOCK(locked);
00219     
00220     return phFAIL;
00221 }
00222 
00223 /* ------------------------------------------------------------------------- */
00224 int phNetClientThread::setRunningVar( volatile uint32_t *server_running )
00225 {
00226     phFUNCTION("phNetClientThread::setRunningVar")
00227     int locked = 0;
00228 
00229     phTHIS_LOCK(locked);
00230 
00231     this->m_server_running = server_running;
00232     
00233     phTHIS_UNLOCK(locked);
00234     
00235     return phSUCCESS;
00236 error:
00237     phTHIS_ERROR_UNLOCK(locked);
00238     
00239     return phFAIL;
00240 }
00241 
00242 /* ----------------------------------------------------------------------------
00243  * -- thread to manage a client connection
00244  * ------------------------------------------------------------------------- */
00245 int phNetClientThread::run()
00246 {
00247     phFUNCTION("phNetClientThread::run")
00248    
00249     int         inited      = 0;
00250     int32_t     titleSize   = 0;
00251     
00252     phTimeStamp timestamp;
00253 
00254     uint32_t jitter_avg  = 0;
00255     uint32_t notify_avg  = 0;
00256     uint32_t sleeptime_us= 0;
00257     
00258     int         client_incremented_int = 0;
00259     volatile uint32_t *server_running = this->m_server_running;
00260 
00261     /* For some reason, this needs to be allocated here 
00262      * instead of on the stack.
00263      * Weird behaviour happens on some systems 
00264      * (specifically Linux 2.6.8.1, 
00265      *               P4 2.8GHz HT-enabled, 
00266      *               1GB RAM, 
00267      *               800MHzFSB, 
00268      * compiled with full optimization/not GDB) 
00269      */       
00270     phImage  *localCopy = new phImage();
00271     
00272     uint32_t connect_flags = phLiveObjectWAIT |
00273                              /* use copy because there are N clients, 
00274                               * not just 1 */
00275                              phLiveObjectCOPY;
00276     
00277     DEBUG_PRINT("Accepted connection from %s\n", comms->getHostname());
00278     
00279     /* Connect the objects */
00280     rc = localCopy->connect(this->m_image, connect_flags);
00281     phPRINT_RC(rc,NULL,"localCopy->connect() failed.");
00282 
00283     DEBUG_PRINT("Established Live Source connection w/image.\n");
00284 
00285     /* Set up the recv thread to set up the jitter values */
00286     this->m_recv_thread = new phNetClientRecvThread();
00287     phCHECK_PTR(this->m_recv_thread,"new","new phNetClientRecvThread");
00288 
00289     rc = this->m_recv_thread->resetData();
00290     phCHECK_RC(rc,NULL,"this->m_recv_thread->resetData()");
00291     
00292     rc = this->m_recv_thread->setRttAvgSamples(100);
00293     phCHECK_RC(rc,NULL,"this->m_recv_thread->setRttAvgSamples");
00294 
00295     rc = this->m_recv_thread->setJitterAvgSamples(100);
00296     phCHECK_RC(rc,NULL,"this->m_recv_thread->setJitterAvgSamples");
00297 
00298     rc = this->m_recv_thread->set(this->m_comms,
00299                                   this->m_server_running );
00300     phCHECK_RC(rc,NULL,"this->m_recv_thread->set()");
00301    
00302     rc = this->m_recv_thread->start();
00303     phCHECK_RC(rc,NULL,"this->m_recv_thread->start()");
00304     
00305     if (this->m_condVar != NULL)
00306     {
00307         rc = this->m_condVar->increment();
00308         phCHECK_RC(rc,NULL,"this->m_condVar->increment()");
00309         client_incremented_int = 1;
00310     }
00311     
00312     rc = this->signal_running();
00313     phCHECK_RC(rc,NULL,"this->signal_running()");
00314 
00315     titleSize = (int32_t)(strlen(this->m_title) * sizeof(char));
00316     rc = this->m_comms->send_uint32(titleSize);
00317     rc = this->m_comms->send(this->m_title, titleSize);
00318 
00319     while ( this->m_comms->isConnected() && 
00320             (*server_running) && 
00321             localCopy->isConnected())
00322     {
00323         /* 1: non-blocking */
00324         rc = localCopy->update();
00325         phPRINT_RC(rc,NULL,"localCopy->update() failed");
00326         
00327         if ((rc == 0) && (localCopy->isNull() == 0))
00328         {
00329             if (inited == 0)
00330             {
00331                 /* send the client the image dimensions */
00332                 rc = this->m_comms->send_uint32(localCopy->getWidth());
00333                 rc = this->m_comms->send_uint32(localCopy->getHeight());
00334                 rc = this->m_comms->send_uint32(localCopy->getFormat());
00335                 inited = 1;
00336             }
00337 
00338             /* send the client the image dimensions */
00339             rc = this->m_comms->send_uint32(localCopy->getWidth());
00340             rc = this->m_comms->send_uint32(localCopy->getHeight());
00341             rc = this->m_comms->send_uint32(localCopy->getFormat());
00342             
00343             timestamp.stamp();
00344             rc = this->m_comms->send_uint32(timestamp.getMicroseconds());
00345 
00346             rc = this->m_comms->send_uint32(localCopy->getSize());
00347             /* send the image */
00348             //phPROGRESS("sending image to client\n");
00349             rc = this->m_comms->send(localCopy->getData(),
00350                                      localCopy->getSize());
00351             //phPROGRESS("sent image to client\n");
00352             if (rc < 0)
00353             {
00354                 /* We could complain here, but printing starts to get really 
00355                  * annoying after a while and alot of printing can
00356                  * harm the performance of the server */
00357                 /*phERR_PRINT("failed to send image, disconnecting\n");*/
00358                 this->m_comms->disconnect();
00359             }
00360 #if phNetClientThread_USE_JITTER_SYNC() 
00361             else
00362             {
00363                 /* Recieve thread jitter is the time between recieving
00364                  * frames on the client side */
00365                 jitter_avg  = this->m_recv_thread->getJitterAvg();
00366                 /* notify jitter average is the time between updates of
00367                  * the local image copy */
00368                 notify_avg  = localCopy->getNotifyJitterAvg();
00369 
00370                 /* if the time it takes to recieve a frame is greater than
00371                  * the notify time, then sleep */
00372                 if ((jitter_avg > notify_avg) && (notify_avg > 0))
00373                 {
00374                     sleeptime_us = (jitter_avg - notify_avg) ;
00375 #if 0
00376                     phPRINT("recvjit:%8u notify:%8u sleep:%8u\n",
00377                             jitter_avg,notify_avg,sleeptime_us);
00378 #endif
00379 
00380                     //phPRINT("sleeptime:%d\n",sleeptime_us);
00381                     phUSleep(sleeptime_us);
00382                 }
00383                 else
00384                 {
00385 #if 0
00386                     phPRINT("recvjit:%8u notify:%8u\n",
00387                             jitter_avg,notify_avg);
00388 #endif
00389                 }
00390             }
00391 #endif
00392         }
00393     }
00394 
00395     rc = this->m_recv_thread->stop();
00396     phPRINT_RC(rc,NULL,"this->m_recv_thread->stop()");
00397     
00398     if ((this->m_condVar != NULL) && (client_incremented_int))
00399     {
00400         rc = this->m_condVar->decrement();
00401         phPRINT_RC(rc,NULL,"this->m_condVar->decrement()");
00402         client_incremented_int = 0;
00403     }
00404     
00405     /* disconnect and free memory stuff */
00406     rc = localCopy->disconnect();
00407     phPRINT_RC(rc,NULL,"localCopy->disconnect()");
00408     
00409     phDelete(localCopy);
00410     phDelete(this->m_comms);
00411     
00412     return phSUCCESS;
00413 error:
00414     rc = this->signal_error();
00415     phPRINT_RC(rc,NULL,"this->signal_error()");
00416 
00417     rc = this->m_recv_thread->stop();
00418     phPRINT_RC(rc,NULL,"this->m_recv_thread->stop()");
00419 
00420     if ((this->m_condVar != NULL) && (client_incremented_int))
00421     {
00422         rc = this->m_condVar->decrement();
00423         phPRINT_RC(rc,NULL,"this->m_condVar->decrement()");
00424         client_incremented_int = 0;
00425     }
00426 
00427     /* disconnect and free memory stuff */
00428     rc = localCopy->disconnect();
00429     phPRINT_RC(rc,NULL,"localCopy->disconnect()");
00430     
00431     phDelete(localCopy);
00432     phDelete(this->m_comms);
00433     
00434     phPROGRESS("Thread returning with error\n");
00435     
00436     return phFAIL;
00437 }
00438 
00439 
00440 
00441 
00442 
00443 
00444 /* ------------------------------------------------------------------------- */
00445 phNetClientRecvThread::phNetClientRecvThread( )
00446 {
00447     phFUNCTION("phNetClientRecvThread::phNetClientRecvThread")
00448     int locked = 0;
00449 
00450     phTHIS_LOCK(locked);
00451     
00452     this->m_server_running  = NULL;
00453     this->m_comms           = NULL;
00454     
00455     this->m_last_host_time[0]   = 0;
00456     this->m_last_host_time[1]   = 0;
00457     this->m_last_client_time[0] = 0;
00458     this->m_last_client_time[1] = 0;
00459     
00460     this->m_client_jitter_us    = 0;
00461     this->m_client_end_jitter_us= 0;
00462     this->m_client_recv_time_us = 0;
00463     
00464     this->m_rtt_us          = 0;
00465     this->m_half_rtt_us     = 0;
00466     this->m_half_rtt_avg_us = 0;
00467     this->m_rtt_samples     = 0;
00468 
00469     this->m_jitter_us       = 0;
00470     this->m_jitter_avg_us   = 0;
00471     this->m_jitter_samples  = 0;
00472     
00473     phTHIS_UNLOCK(locked);
00474     
00475 error:
00476     phTHIS_ERROR_UNLOCK(locked);
00477 }
00478 
00479 /* ------------------------------------------------------------------------- */
00480 phNetClientRecvThread::~phNetClientRecvThread( )
00481 {
00482     phFUNCTION("phNetClientRecvThread::~phNetClientRecvThread")
00483     int locked = 0;
00484 
00485     phTHIS_LOOSE_LOCK(locked);
00486     
00487     this->m_server_running  = NULL;
00488 
00489     phTHIS_LOOSE_UNLOCK(locked);
00490 }
00491 
00492 /* ------------------------------------------------------------------------- */
00493 int phNetClientRecvThread::set( phSocket           *comms,
00494                                 volatile uint32_t  *server_running )
00495 {
00496     phFUNCTION("phNetClientRecvThread::set")
00497     int         locked      = 0;
00498 
00499     phTHIS_LOCK(locked);
00500 
00501     this->m_comms           = comms;
00502     this->m_server_running  = server_running;
00503     
00504     phTHIS_UNLOCK(locked);
00505     
00506     return phSUCCESS;
00507 error:
00508     phTHIS_ERROR_UNLOCK(locked);
00509     
00510     return phFAIL;
00511 }
00512 
00513 /* ------------------------------------------------------------------------- */
00514 int phNetClientRecvThread::setComms( phSocket  *comms )
00515 {
00516     phFUNCTION("phNetClientRecvThread::setComms")
00517     int locked = 0;
00518 
00519     phTHIS_LOCK(locked);
00520 
00521     this->m_comms = comms;
00522     
00523     phTHIS_UNLOCK(locked);
00524     
00525     return phSUCCESS;
00526 error:
00527     phTHIS_ERROR_UNLOCK(locked);
00528     
00529     return phFAIL;
00530 }
00531 
00532 /* ------------------------------------------------------------------------- */
00533 int phNetClientRecvThread::setRunningVar( volatile uint32_t *server_running )
00534 {
00535     phFUNCTION("phNetClientRecvThread::setRunningVar")
00536     int locked = 0;
00537 
00538     phTHIS_LOCK(locked);
00539 
00540     this->m_server_running = server_running;
00541     
00542     phTHIS_UNLOCK(locked);
00543     
00544     return phSUCCESS;
00545 error:
00546     phTHIS_ERROR_UNLOCK(locked);
00547     
00548     return phFAIL;
00549 }
00550 
00551 /* ------------------------------------------------------------------------- */
00552 int phNetClientRecvThread::setData( uint32_t host_time[2],
00553                                     uint32_t client_time[2],
00554                                     uint32_t recv_size )
00555 {
00556     phFUNCTION("phNetClientRecvThread::setData")
00557     int locked = 0;
00558     uint32_t     host_rtt= 0;
00559     uint32_t     half_rtt= 0;
00560     uint32_t     client_start_jitter = 0;
00561     uint32_t     client_end_jitter   = 0;
00562     uint32_t     client_recv_time    = 0;
00563     double      avg     = 0.0;
00564     double      major   = 0.0;
00565     double      minor   = 0.0;
00566     double      samples = 0.0;
00567     int         csj = 0;
00568     int         cej = 0;
00569     int         crt = 0;
00570     int         hrtt = 0;
00571     int         hhrtt = 0;
00572             
00573     /* Lock the read write lock so we can set these at once */
00574     phRWLOCK_WRITELOCK(this->m_jitter_rwlock,locked);
00575 #if 0    
00576     phPRINT("----------------------------------------------------------\n");
00577     phPRINT("ct[0]:%8u ct[1]:%8u\n",client_time[0],client_time[1]);
00578 #endif
00579     /* The interval of time between the last start recv and the most
00580        recent start of recv */
00581     if ((client_time[0] > this->m_last_client_time[0]) && 
00582         (this->m_last_client_time[0] > 0))
00583     {
00584         csj = 1;
00585         client_start_jitter = client_time[0] - this->m_last_client_time[0];
00586 #if 0
00587         phPRINT("%u = %u - %u\n",
00588                 client_start_jitter,
00589                 client_time[0],this->m_last_client_time[0]);;
00590 #endif
00591     }
00592 
00593     /* The interval of time between the last end recv and the most
00594        recent end of recv */
00595     if ((client_time[1] > this->m_last_client_time[1]) && 
00596         (this->m_last_client_time[1] > 0))
00597     {
00598         cej = 1;
00599         client_end_jitter = client_time[1] - this->m_last_client_time[1];
00600     }
00601 
00602     /* The difference between the start of the recv and the end */
00603     if (client_time[1] > client_time[0])
00604     {
00605         crt = 1;
00606         client_recv_time = client_time[1] - client_time[0];
00607     }
00608 
00609     if (host_time[1] > host_time[0])
00610     {
00611         hrtt = 1;
00612         host_rtt  = host_time[1] - host_time[0];
00613     }
00614 
00615     if (host_rtt > 0)
00616     {
00617         hhrtt = 1;
00618         half_rtt   = host_rtt / 2;
00619     }
00620     
00621 
00622     this->m_last_host_time[0]   = host_time[0];
00623     this->m_last_host_time[1]   = host_time[1];
00624     this->m_last_client_time[0] = client_time[0];
00625     this->m_last_client_time[1] = client_time[1];
00626     
00627     this->m_rtt_us              = host_rtt;
00628     this->m_half_rtt_us         = half_rtt;
00629     
00630     this->m_client_jitter_us    = client_start_jitter;
00631     this->m_client_end_jitter_us= client_end_jitter;
00632     this->m_client_recv_time_us = client_recv_time;
00633     
00634     /* rtt moving average */
00635     if (this->m_rtt_samples > 0)
00636     {
00637         avg = this->m_half_rtt_avg_us;
00638         samples = this->m_rtt_samples;
00639         
00640         major = (samples - 1.0) / samples;
00641         minor = 1.0 / samples;
00642         
00643         avg = (avg * major) + (this->m_half_rtt_us * minor);
00644         
00645         this->m_half_rtt_avg_us = (uint32_t)avg;
00646     }
00647     else
00648     {
00649         this->m_half_rtt_avg_us = this->m_half_rtt_us;
00650     }
00651 
00652     /* Calculate the time difference between the client start jitter and the
00653      * average time it takes for a byte to travel to the client. This value is
00654      * the amount of time between frames if there were no network lag. */
00655     if (client_start_jitter > this->m_half_rtt_avg_us)
00656     {
00657         this->m_jitter_us = client_start_jitter - this->m_half_rtt_avg_us;
00658     }
00659     else
00660     {
00661         this->m_jitter_us = 0;
00662     }
00663     
00664     /* jitter moving average */
00665     if (this->m_jitter_samples > 0)
00666     {
00667         avg = this->m_jitter_avg_us;
00668         samples = this->m_jitter_samples;
00669         
00670         major = (samples - 1.0) / samples;
00671         minor = 1.0 / samples;
00672         
00673         avg = (avg * major) + (this->m_jitter_us * minor);
00674         
00675         this->m_jitter_avg_us = (uint32_t)avg;
00676     }
00677     else
00678     {
00679         this->m_jitter_avg_us = this->m_jitter_us;
00680     }
00681 
00682     phRWLOCK_UNLOCK(this->m_jitter_rwlock,locked);
00683 #if 0
00684     phPRINT("[ rtt[%d]:%8u hrt[%d]:%6u ] [ csj[%d]:%11u cej[%d]:%11u crt[%d]:%11u ]\n",
00685             hrtt,
00686             host_rtt,
00687             hhrtt,
00688             half_rtt,
00689             csj,
00690             client_start_jitter,
00691             cej,
00692             client_end_jitter,
00693             crt,
00694             client_recv_time
00695            );
00696 #endif
00697 
00698     return phSUCCESS;
00699 
00700 error:
00701     phRWLOCK_UNLOCK_ERROR(this->m_jitter_rwlock,locked);
00702     
00703     return phFAIL;
00704 }
00705 
00706 /* ------------------------------------------------------------------------- */
00707 int phNetClientRecvThread::resetData()
00708 {
00709     phFUNCTION("phNetClientRecvThread::resetData")
00710     int locked = 0;
00711             
00712     /* Lock the read write lock so we can set these at once */
00713     phRWLOCK_WRITELOCK(this->m_jitter_rwlock,locked);
00714  
00715     this->m_last_host_time[0]   = 0;
00716     this->m_last_host_time[1]   = 0;
00717     this->m_last_client_time[0] = 0;
00718     this->m_last_client_time[1] = 0;
00719     
00720     this->m_client_jitter_us    = 0;
00721     this->m_client_end_jitter_us= 0;
00722     this->m_client_recv_time_us = 0;
00723     
00724     this->m_rtt_us          = 0;
00725     this->m_half_rtt_us     = 0;
00726     this->m_half_rtt_avg_us = 0;
00727     
00728     this->m_jitter_us       = 0;
00729     this->m_jitter_avg_us   = 0;
00730                 
00731     phRWLOCK_UNLOCK(this->m_jitter_rwlock,locked);
00732 
00733     return phSUCCESS;
00734 error:
00735     phRWLOCK_UNLOCK_ERROR(this->m_jitter_rwlock,locked);
00736     
00737     return phFAIL;
00738 }
00739 
00740 
00741 /* ------------------------------------------------------------------------- */
00742 uint32_t phNetClientRecvThread::getClientJitter()
00743 {
00744     phFUNCTION("phNetClientRecvThread::getClientJitter")
00745     int locked = 0;
00746     uint32_t retrc = 0;
00747             
00748     /* Lock the read write lock so we can set these at once */
00749     phRWLOCK_READLOCK(this->m_jitter_rwlock,locked);
00750 
00751     retrc = this->m_client_jitter_us;
00752                 
00753     phRWLOCK_UNLOCK(this->m_jitter_rwlock,locked);
00754 
00755     return retrc;
00756 error:
00757     phRWLOCK_UNLOCK_ERROR(this->m_jitter_rwlock,locked);
00758     
00759     return 0;
00760 }
00761 
00762 /* ------------------------------------------------------------------------- */
00763 uint32_t phNetClientRecvThread::getClientEndJitter()
00764 {
00765     phFUNCTION("phNetClientRecvThread::getClientEndJitter")
00766     int locked = 0;
00767     uint32_t retrc = 0;
00768             
00769     /* Lock the read write lock so we can set these at once */
00770     phRWLOCK_READLOCK(this->m_jitter_rwlock,locked);
00771 
00772     retrc = this->m_client_end_jitter_us;
00773                 
00774     phRWLOCK_UNLOCK(this->m_jitter_rwlock,locked);
00775 
00776     return retrc;
00777 error:
00778     phRWLOCK_UNLOCK_ERROR(this->m_jitter_rwlock,locked);
00779     
00780     return 0;
00781 }
00782 
00783 /* ------------------------------------------------------------------------- */
00784 uint32_t phNetClientRecvThread::getClientRecvTime()
00785 {
00786     phFUNCTION("phNetClientRecvThread::getClientRecvTime")
00787     int locked = 0;
00788     uint32_t retrc = 0;
00789             
00790     /* Lock the read write lock so we can set these at once */
00791     phRWLOCK_READLOCK(this->m_jitter_rwlock,locked);
00792 
00793     retrc = this->m_client_recv_time_us;
00794                 
00795     phRWLOCK_UNLOCK(this->m_jitter_rwlock,locked);
00796 
00797     return retrc;
00798 error:
00799     phRWLOCK_UNLOCK_ERROR(this->m_jitter_rwlock,locked);
00800     
00801     return 0;
00802 }
00803 
00804 /* ------------------------------------------------------------------------- */
00805 uint32_t phNetClientRecvThread::getRoundTrip()
00806 {
00807     phFUNCTION("phNetClientRecvThread::getRoundTrip")
00808     int locked = 0;
00809     uint32_t retrc = 0;
00810             
00811     /* Lock the read write lock so we can set these at once */
00812     phRWLOCK_READLOCK(this->m_jitter_rwlock,locked);
00813 
00814     retrc = this->m_rtt_us;
00815                 
00816     phRWLOCK_UNLOCK(this->m_jitter_rwlock,locked);
00817 
00818     return retrc;
00819 error:
00820     phRWLOCK_UNLOCK_ERROR(this->m_jitter_rwlock,locked);
00821     
00822     return 0;
00823 }
00824 
00825 /* ------------------------------------------------------------------------- */
00826 uint32_t phNetClientRecvThread::getHalfRoundTrip()
00827 {
00828     phFUNCTION("phNetClientRecvThread::getHalfRoundTrip")
00829     int locked = 0;
00830     uint32_t retrc = 0;
00831             
00832     /* Lock the read write lock so we can set these at once */
00833     phRWLOCK_READLOCK(this->m_jitter_rwlock,locked);
00834 
00835     retrc = this->m_half_rtt_us;
00836                 
00837     phRWLOCK_UNLOCK(this->m_jitter_rwlock,locked);
00838 
00839     return retrc;
00840 error:
00841     phRWLOCK_UNLOCK_ERROR(this->m_jitter_rwlock,locked);
00842     
00843     return 0;
00844 }
00845 
00846 /* ------------------------------------------------------------------------- */
00847 /* jitter values in microseconds/us */
00848 uint32_t phNetClientRecvThread::getHalfRoundTripAvg()
00849 {
00850     phFUNCTION("phNetClientRecvThread::getHalfRoundTripAvg")
00851     int locked = 0;
00852     uint32_t retrc = 0;
00853             
00854     /* Lock the read write lock so we can set these at once */
00855     phRWLOCK_WRITELOCK(this->m_jitter_rwlock,locked);
00856 
00857     retrc = this->m_half_rtt_avg_us;
00858                 
00859     phRWLOCK_UNLOCK(this->m_jitter_rwlock,locked);
00860 
00861     return retrc;
00862 error:
00863     phRWLOCK_UNLOCK_ERROR(this->m_jitter_rwlock,locked);
00864     
00865     return 0;
00866 }
00867 
00868 /* ------------------------------------------------------------------------- */
00869 int phNetClientRecvThread::setRttAvgSamples( uint32_t samples )
00870 {
00871     phFUNCTION("phNetClientRecvThread::setRttAvgSamples")
00872     int locked = 0;
00873             
00874     /* Lock the read write lock so we can set these at once */
00875     phRWLOCK_WRITELOCK(this->m_jitter_rwlock,locked);
00876 
00877     this->m_rtt_samples = samples;
00878                 
00879     phRWLOCK_UNLOCK(this->m_jitter_rwlock,locked);
00880 
00881     return phSUCCESS;
00882 error:
00883     phRWLOCK_UNLOCK_ERROR(this->m_jitter_rwlock,locked);
00884     
00885     return phFAIL;
00886 }
00887 
00888 /* ------------------------------------------------------------------------- */
00889 uint32_t phNetClientRecvThread::getRttAvgSamples()
00890 {
00891     phFUNCTION("phNetClientRecvThread::getRttAvgSamples")
00892     int locked = 0;
00893     uint32_t retrc = 0;
00894             
00895     /* Lock the read write lock so we can set these at once */
00896     phRWLOCK_READLOCK(this->m_jitter_rwlock,locked);
00897 
00898     retrc = this->m_rtt_samples;
00899                 
00900     phRWLOCK_UNLOCK(this->m_jitter_rwlock,locked);
00901 
00902     return retrc;
00903 error:
00904     phRWLOCK_UNLOCK_ERROR(this->m_jitter_rwlock,locked);
00905     
00906     return 0;
00907 }
00908 
00909 
00910 /* ------------------------------------------------------------------------- */
00911 /* jitter values in microseconds/us */
00912 uint32_t phNetClientRecvThread::getJitter()
00913 {
00914     phFUNCTION("phNetClientRecvThread::getJitter")
00915     int locked = 0;
00916     uint32_t retrc = 0;
00917             
00918     /* Lock the read write lock so we can set these at once */
00919     phRWLOCK_READLOCK(this->m_jitter_rwlock,locked);
00920 
00921     retrc = this->m_jitter_us;
00922                 
00923     phRWLOCK_UNLOCK(this->m_jitter_rwlock,locked);
00924 
00925     return retrc;
00926 error:
00927     phRWLOCK_UNLOCK_ERROR(this->m_jitter_rwlock,locked);
00928     
00929     return 0;
00930 }
00931 
00932 /* ------------------------------------------------------------------------- */
00933 /* jitter values in microseconds/us */
00934 uint32_t phNetClientRecvThread::getJitterAvg()
00935 {
00936     phFUNCTION("phNetClientRecvThread::getJitterAvg")
00937     int locked = 0;
00938     uint32_t retrc = 0;
00939             
00940     /* Lock the read write lock so we can set these at once */
00941     phRWLOCK_WRITELOCK(this->m_jitter_rwlock,locked);
00942 
00943     retrc = this->m_jitter_avg_us;
00944                 
00945     phRWLOCK_UNLOCK(this->m_jitter_rwlock,locked);
00946 
00947     return retrc;
00948 error:
00949     phRWLOCK_UNLOCK_ERROR(this->m_jitter_rwlock,locked);
00950     
00951     return 0;
00952 }
00953 
00954 /* ------------------------------------------------------------------------- */
00955 int phNetClientRecvThread::setJitterAvgSamples( uint32_t samples )
00956 {
00957     phFUNCTION("phNetClientRecvThread::setJitterAvgSamples")
00958     int locked = 0;
00959             
00960     /* Lock the read write lock so we can set these at once */
00961     phRWLOCK_WRITELOCK(this->m_jitter_rwlock,locked);
00962 
00963     this->m_jitter_samples = samples;
00964                 
00965     phRWLOCK_UNLOCK(this->m_jitter_rwlock,locked);
00966 
00967     return phSUCCESS;
00968 error:
00969     phRWLOCK_UNLOCK_ERROR(this->m_jitter_rwlock,locked);
00970     
00971     return phFAIL;
00972 }
00973 
00974 /* ------------------------------------------------------------------------- */
00975 uint32_t phNetClientRecvThread::getJitterAvgSamples()
00976 {
00977     phFUNCTION("phNetClientRecvThread::getJitterAvgSamples")
00978     int locked = 0;
00979     uint32_t retrc = 0;
00980             
00981     /* Lock the read write lock so we can set these at once */
00982     phRWLOCK_READLOCK(this->m_jitter_rwlock,locked);
00983 
00984     retrc = this->m_jitter_samples;
00985                 
00986     phRWLOCK_UNLOCK(this->m_jitter_rwlock,locked);
00987 
00988     return retrc;
00989 error:
00990     phRWLOCK_UNLOCK_ERROR(this->m_jitter_rwlock,locked);
00991     
00992     return 0;
00993 }
00994 
00995 /* ----------------------------------------------------------------------------
00996  * -- Thread to recv data from the client
00997  *
00998  *  The first type of data it receives is a host_time/client_jitter packet
00999  *      so I can throttle the net display's sending.
01000  * ------------------------------------------------------------------------- */
01001 int phNetClientRecvThread::run()
01002 {
01003     phFUNCTION("phNetClientRecvThread::run")
01004    
01005     phTimeStamp timestamp;
01006     int32_t     packet_id       = 0;
01007     uint32_t    data_size       = 0;
01008     uint32_t    host_time[2]    = {0,0};
01009     uint32_t    client_time[2]  = {0,0};
01010     
01011     volatile uint32_t *server_running = this->m_server_running;
01012     
01013     DEBUG_PRINT("Established Live Source connection w/image.\n");
01014 
01015     rc = this->signal_running();
01016     phCHECK_RC(rc,NULL,"this->signal_running()");
01017 
01018     while ( this->m_comms->isConnected() && 
01019             this->isRunning() &&
01020             (*server_running))
01021     {
01022         packet_id       = 0;
01023         data_size       = 0;
01024         host_time[0]    = 0;
01025         host_time[1]    = 0;
01026         client_time[0]  = 0;
01027         client_time[1]  = 0;
01028 
01029         rc = this->m_comms->recv_int32(&packet_id);
01030         //phSocket_CONT_RC(rc,NULL,"this->m_comms->recv_int32");
01031         timestamp.stamp();
01032         if (packet_id != 0xaaaa)
01033         {
01034             if (packet_id == 0)
01035             {
01036                 continue;
01037             }
01038             phERR_PRINT("Warning: packet id not correct 0x%08x != 0xaaaa\n",
01039                         packet_id );
01040         }
01041 
01042         /* Host times : 
01043            0 - time transmission start
01044            1 - time "tranmission complete" packet recieved */
01045         rc = this->m_comms->recv_uint32(&host_time[0]);
01046         //phSocket_CONT_RC(rc,NULL,"this->m_comms->recv_int32");
01047         host_time[1]    = timestamp.getMicroseconds();
01048 
01049         /* The size of the data recv */
01050         rc = this->m_comms->recv_uint32(&data_size);
01051         //phSocket_CONT_RC(rc,NULL,"this->m_comms->recv_uint32");
01052 
01053         /* Client times :
01054            0 - client time transmission recv began
01055                 This isn't necesarily when the transmission is being received.
01056                 This is when the client goes into the recv loop.
01057                 However, this is useful to tell how long it takes the client
01058                     to loop from the last recv end to the current recv begin.
01059            1 - client time transmission recv end 
01060          */
01061         rc = this->m_comms->recv_uint32(&client_time[0]);
01062         //phSocket_CONT_RC(rc,NULL,"this->m_comms->recv_int32");
01063         
01064         rc = this->m_comms->recv_uint32(&client_time[1]);
01065         //phSocket_CONT_RC(rc,NULL,"this->m_comms->recv_int32");
01066         
01067         rc = this->setData( host_time, client_time, data_size );
01068         phPRINT_RC(rc,NULL,"setData()");
01069     }
01070     
01071     return phSUCCESS;
01072 error:
01073     rc = this->signal_error();
01074     phPRINT_RC(rc,NULL,"this->signal_error()");
01075 
01076     phPROGRESS("Thread returning with error\n");
01077     
01078     return phFAIL;
01079 }
01080 
01081 




Copyright (C) 2002 - 2007 Philip D.S. Thoren ( pthoren@users.sourceforge.net )
University Of Massachusetts at Lowell
Robotics Lab
SourceForge.net Logo

Generated on Sat Jun 16 02:44:03 2007 for phission by  doxygen 1.4.4