Home | History | Annotate | Download | only in BWEStandAlone
      1 /*
      2  *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
      3  *
      4  *  Use of this source code is governed by a BSD-style license
      5  *  that can be found in the LICENSE file in the root of the source
      6  *  tree. An additional intellectual property rights grant can be found
      7  *  in the file PATENTS.  All contributing project authors may
      8  *  be found in the AUTHORS file in the root of the source tree.
      9  */
     10 
     11 #include "webrtc/modules/rtp_rtcp/test/BWEStandAlone/MatlabPlot.h"
     12 
     13 #include <math.h>
     14 #include <stdio.h>
     15 
     16 #include <algorithm>
     17 #include <sstream>
     18 
     19 #ifdef MATLAB
     20 #include "engine.h"
     21 #endif
     22 
     23 #include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
     24 #include "webrtc/system_wrappers/interface/event_wrapper.h"
     25 #include "webrtc/system_wrappers/interface/thread_wrapper.h"
     26 #include "webrtc/system_wrappers/interface/tick_util.h"
     27 
     28 using namespace webrtc;
     29 
     30 #ifdef MATLAB
     31 MatlabEngine eng;
     32 
     33 MatlabLine::MatlabLine(int maxLen /*= -1*/, const char *plotAttrib /*= NULL*/, const char *name /*= NULL*/)
     34 :
     35 _xArray(NULL),
     36 _yArray(NULL),
     37 _maxLen(maxLen),
     38 _plotAttribute(),
     39 _name()
     40 {
     41     if (_maxLen > 0)
     42     {
     43         _xArray = mxCreateDoubleMatrix(1, _maxLen, mxREAL);
     44         _yArray = mxCreateDoubleMatrix(1, _maxLen, mxREAL);
     45     }
     46 
     47     if (plotAttrib)
     48     {
     49         _plotAttribute = plotAttrib;
     50     }
     51 
     52     if (name)
     53     {
     54         _name = name;
     55     }
     56 }
     57 
     58 MatlabLine::~MatlabLine()
     59 {
     60     if (_xArray != NULL)
     61     {
     62         mxDestroyArray(_xArray);
     63     }
     64     if (_yArray != NULL)
     65     {
     66         mxDestroyArray(_yArray);
     67     }
     68 }
     69 
     70 void MatlabLine::Append(double x, double y)
     71 {
     72     if (_maxLen > 0 && _xData.size() > static_cast<uint32_t>(_maxLen))
     73     {
     74         _xData.resize(_maxLen);
     75         _yData.resize(_maxLen);
     76     }
     77 
     78     _xData.push_front(x);
     79     _yData.push_front(y);
     80 }
     81 
     82 
     83 // append y-data with running integer index as x-data
     84 void MatlabLine::Append(double y)
     85 {
     86     if (_xData.empty())
     87     {
     88         // first element is index 0
     89         Append(0, y);
     90     }
     91     else
     92     {
     93         // take last x-value and increment
     94         double temp = _xData.back(); // last x-value
     95         Append(temp + 1, y);
     96     }
     97 }
     98 
     99 
    100 void MatlabLine::SetMaxLen(int maxLen)
    101 {
    102     if (maxLen <= 0)
    103     {
    104         // means no maxLen
    105         _maxLen = -1;
    106     }
    107     else
    108     {
    109         _maxLen = maxLen;
    110 
    111         if (_xArray != NULL)
    112         {
    113             mxDestroyArray(_xArray);
    114             mxDestroyArray(_yArray);
    115         }
    116         _xArray = mxCreateDoubleMatrix(1, _maxLen, mxREAL);
    117         _yArray = mxCreateDoubleMatrix(1, _maxLen, mxREAL);
    118 
    119         maxLen = ((unsigned int)maxLen <= _xData.size()) ? maxLen : (int)_xData.size();
    120         _xData.resize(maxLen);
    121         _yData.resize(maxLen);
    122 
    123         //// reserve the right amount of memory
    124         //_xData.reserve(_maxLen);
    125         //_yData.reserve(_maxLen);
    126     }
    127 }
    128 
    129 void MatlabLine::SetAttribute(char *plotAttrib)
    130 {
    131     _plotAttribute = plotAttrib;
    132 }
    133 
    134 void MatlabLine::SetName(char *name)
    135 {
    136     _name = name;
    137 }
    138 
    139 void MatlabLine::GetPlotData(mxArray** xData, mxArray** yData)
    140 {
    141     // Make sure we have enough Matlab allocated memory.
    142     // Assuming both arrays (x and y) are of the same size.
    143     if (_xData.empty())
    144     {
    145         return; // No data
    146     }
    147     unsigned int size = 0;
    148     if (_xArray != NULL)
    149     {
    150         size = (unsigned int)mxGetNumberOfElements(_xArray);
    151     }
    152     if (size < _xData.size())
    153     {
    154         if (_xArray != NULL)
    155         {
    156             mxDestroyArray(_xArray);
    157             mxDestroyArray(_yArray);
    158         }
    159         _xArray = mxCreateDoubleMatrix(1, _xData.size(), mxREAL);
    160         _yArray = mxCreateDoubleMatrix(1, _yData.size(), mxREAL);
    161     }
    162 
    163     if (!_xData.empty())
    164     {
    165         double* x = mxGetPr(_xArray);
    166 
    167         std::list<double>::iterator it = _xData.begin();
    168 
    169         for (int i = 0; it != _xData.end(); it++, i++)
    170         {
    171             x[i] = *it;
    172         }
    173     }
    174 
    175     if (!_yData.empty())
    176     {
    177         double* y = mxGetPr(_yArray);
    178 
    179         std::list<double>::iterator it = _yData.begin();
    180 
    181         for (int i = 0; it != _yData.end(); it++, i++)
    182         {
    183             y[i] = *it;
    184         }
    185     }
    186     *xData = _xArray;
    187     *yData = _yArray;
    188 }
    189 
    190 std::string MatlabLine::GetXName()
    191 {
    192     std::ostringstream xString;
    193     xString << "x_" << _name;
    194     return xString.str();
    195 }
    196 
    197 std::string MatlabLine::GetYName()
    198 {
    199     std::ostringstream yString;
    200     yString << "y_" << _name;
    201     return yString.str();
    202 }
    203 
    204 std::string MatlabLine::GetPlotString()
    205 {
    206 
    207     std::ostringstream s;
    208 
    209     if (_xData.size() == 0)
    210     {
    211         s << "[0 1], [0 1]"; // To get an empty plot
    212     }
    213     else
    214     {
    215         s << GetXName() << "(1:" << _xData.size() << "),";
    216         s << GetYName() << "(1:" << _yData.size() << ")";
    217     }
    218 
    219     s << ", '";
    220     s << _plotAttribute;
    221     s << "'";
    222 
    223     return s.str();
    224 }
    225 
    226 std::string MatlabLine::GetRefreshString()
    227 {
    228     std::ostringstream s;
    229 
    230     if (_xData.size() > 0)
    231     {
    232         s << "set(h,'xdata',"<< GetXName() <<"(1:" << _xData.size() << "),'ydata',"<< GetYName() << "(1:" << _yData.size() << "));";
    233     }
    234     else
    235     {
    236         s << "set(h,'xdata',[NaN],'ydata',[NaN]);";
    237     }
    238     return s.str();
    239 }
    240 
    241 std::string MatlabLine::GetLegendString()
    242 {
    243     return ("'" + _name + "'");
    244 }
    245 
    246 bool MatlabLine::hasLegend()
    247 {
    248     return (!_name.empty());
    249 }
    250 
    251 
    252 // remove data points, but keep attributes
    253 void MatlabLine::Reset()
    254 {
    255     _xData.clear();
    256     _yData.clear();
    257 }
    258 
    259 
    260 void MatlabLine::UpdateTrendLine(MatlabLine * sourceData, double slope, double offset)
    261 {
    262     Reset(); // reset data, not attributes and name
    263 
    264     double thexMin = sourceData->xMin();
    265     double thexMax = sourceData->xMax();
    266     Append(thexMin, thexMin * slope + offset);
    267     Append(thexMax, thexMax * slope + offset);
    268 }
    269 
    270 double MatlabLine::xMin()
    271 {
    272     if (!_xData.empty())
    273     {
    274         std::list<double>::iterator theStart = _xData.begin();
    275         std::list<double>::iterator theEnd = _xData.end();
    276         return(*min_element(theStart, theEnd));
    277     }
    278     return (0.0);
    279 }
    280 
    281 double MatlabLine::xMax()
    282 {
    283     if (!_xData.empty())
    284     {
    285         std::list<double>::iterator theStart = _xData.begin();
    286         std::list<double>::iterator theEnd = _xData.end();
    287         return(*max_element(theStart, theEnd));
    288     }
    289     return (0.0);
    290 }
    291 
    292 double MatlabLine::yMin()
    293 {
    294     if (!_yData.empty())
    295     {
    296         std::list<double>::iterator theStart = _yData.begin();
    297         std::list<double>::iterator theEnd = _yData.end();
    298         return(*min_element(theStart, theEnd));
    299     }
    300     return (0.0);
    301 }
    302 
    303 double MatlabLine::yMax()
    304 {
    305     if (!_yData.empty())
    306     {
    307         std::list<double>::iterator theStart = _yData.begin();
    308         std::list<double>::iterator theEnd = _yData.end();
    309         return(*max_element(theStart, theEnd));
    310     }
    311     return (0.0);
    312 }
    313 
    314 
    315 
    316 MatlabTimeLine::MatlabTimeLine(int horizonSeconds /*= -1*/, const char *plotAttrib /*= NULL*/,
    317                                const char *name /*= NULL*/,
    318                                int64_t refTimeMs /* = -1*/)
    319                                :
    320 _timeHorizon(horizonSeconds),
    321 MatlabLine(-1, plotAttrib, name) // infinite number of elements
    322 {
    323     if (refTimeMs < 0)
    324         _refTimeMs = TickTime::MillisecondTimestamp();
    325     else
    326         _refTimeMs = refTimeMs;
    327 }
    328 
    329 void MatlabTimeLine::Append(double y)
    330 {
    331     MatlabLine::Append(static_cast<double>(TickTime::MillisecondTimestamp() - _refTimeMs) / 1000.0, y);
    332 
    333     PurgeOldData();
    334 }
    335 
    336 
    337 void MatlabTimeLine::PurgeOldData()
    338 {
    339     if (_timeHorizon > 0)
    340     {
    341         // remove old data
    342         double historyLimit = static_cast<double>(TickTime::MillisecondTimestamp() - _refTimeMs) / 1000.0
    343             - _timeHorizon; // remove data points older than this
    344 
    345         std::list<double>::reverse_iterator ritx = _xData.rbegin();
    346         uint32_t removeCount = 0;
    347         while (ritx != _xData.rend())
    348         {
    349             if (*ritx >= historyLimit)
    350             {
    351                 break;
    352             }
    353             ritx++;
    354             removeCount++;
    355         }
    356         if (removeCount == 0)
    357         {
    358             return;
    359         }
    360 
    361         // remove the range [begin, it).
    362         //if (removeCount > 10)
    363         //{
    364         //    printf("Removing %lu elements\n", removeCount);
    365         //}
    366         _xData.resize(_xData.size() - removeCount);
    367         _yData.resize(_yData.size() - removeCount);
    368     }
    369 }
    370 
    371 
    372 int64_t MatlabTimeLine::GetRefTime()
    373 {
    374     return(_refTimeMs);
    375 }
    376 
    377 
    378 
    379 
    380 MatlabPlot::MatlabPlot()
    381 :
    382 _figHandle(-1),
    383 _smartAxis(false),
    384 _critSect(CriticalSectionWrapper::CreateCriticalSection()),
    385 _timeToPlot(false),
    386 _plotting(false),
    387 _enabled(true),
    388 _firstPlot(true),
    389 _legendEnabled(true),
    390 _donePlottingEvent(EventWrapper::Create())
    391 {
    392     CriticalSectionScoped cs(_critSect);
    393 
    394     _xlim[0] = 0;
    395     _xlim[1] = 0;
    396     _ylim[0] = 0;
    397     _ylim[1] = 0;
    398 
    399 #ifdef PLOT_TESTING
    400     _plotStartTime = -1;
    401     _plotDelay = 0;
    402 #endif
    403 
    404 }
    405 
    406 
    407 MatlabPlot::~MatlabPlot()
    408 {
    409     _critSect->Enter();
    410 
    411     // delete all line objects
    412     while (!_line.empty())
    413     {
    414         delete *(_line.end() - 1);
    415         _line.pop_back();
    416     }
    417 
    418     delete _critSect;
    419     delete _donePlottingEvent;
    420 }
    421 
    422 
    423 int MatlabPlot::AddLine(int maxLen /*= -1*/, const char *plotAttrib /*= NULL*/, const char *name /*= NULL*/)
    424 {
    425     CriticalSectionScoped cs(_critSect);
    426     if (!_enabled)
    427     {
    428         return -1;
    429     }
    430 
    431     MatlabLine *newLine = new MatlabLine(maxLen, plotAttrib, name);
    432     _line.push_back(newLine);
    433 
    434     return (static_cast<int>(_line.size() - 1)); // index of newly inserted line
    435 }
    436 
    437 
    438 int MatlabPlot::AddTimeLine(int maxLen /*= -1*/, const char *plotAttrib /*= NULL*/, const char *name /*= NULL*/,
    439                             int64_t refTimeMs /*= -1*/)
    440 {
    441     CriticalSectionScoped cs(_critSect);
    442 
    443     if (!_enabled)
    444     {
    445         return -1;
    446     }
    447 
    448     MatlabTimeLine *newLine = new MatlabTimeLine(maxLen, plotAttrib, name, refTimeMs);
    449     _line.push_back(newLine);
    450 
    451     return (static_cast<int>(_line.size() - 1)); // index of newly inserted line
    452 }
    453 
    454 
    455 int MatlabPlot::GetLineIx(const char *name)
    456 {
    457     CriticalSectionScoped cs(_critSect);
    458 
    459     if (!_enabled)
    460     {
    461         return -1;
    462     }
    463 
    464     // search the list for a matching line name
    465     std::vector<MatlabLine*>::iterator it = _line.begin();
    466     bool matchFound = false;
    467     int lineIx = 0;
    468 
    469     for (; it != _line.end(); it++, lineIx++)
    470     {
    471         if ((*it)->_name == name)
    472         {
    473             matchFound = true;
    474             break;
    475         }
    476     }
    477 
    478     if (matchFound)
    479     {
    480         return (lineIx);
    481     }
    482     else
    483     {
    484         return (-1);
    485     }
    486 }
    487 
    488 
    489 void MatlabPlot::Append(int lineIndex, double x, double y)
    490 {
    491     CriticalSectionScoped cs(_critSect);
    492 
    493     if (!_enabled)
    494     {
    495         return;
    496     }
    497 
    498     // sanity for index
    499     if (lineIndex < 0 || lineIndex >= static_cast<int>(_line.size()))
    500     {
    501         throw "Line index out of range";
    502         exit(1);
    503     }
    504 
    505     return (_line[lineIndex]->Append(x, y));
    506 }
    507 
    508 
    509 void MatlabPlot::Append(int lineIndex, double y)
    510 {
    511     CriticalSectionScoped cs(_critSect);
    512 
    513     if (!_enabled)
    514     {
    515         return;
    516     }
    517 
    518     // sanity for index
    519     if (lineIndex < 0 || lineIndex >= static_cast<int>(_line.size()))
    520     {
    521         throw "Line index out of range";
    522         exit(1);
    523     }
    524 
    525     return (_line[lineIndex]->Append(y));
    526 }
    527 
    528 
    529 int MatlabPlot::Append(const char *name, double x, double y)
    530 {
    531     CriticalSectionScoped cs(_critSect);
    532 
    533     if (!_enabled)
    534     {
    535         return -1;
    536     }
    537 
    538     // search the list for a matching line name
    539     int lineIx = GetLineIx(name);
    540 
    541     if (lineIx < 0) //(!matchFound)
    542     {
    543         // no match; append new line
    544         lineIx = AddLine(-1, NULL, name);
    545     }
    546 
    547     // append data to line
    548     Append(lineIx, x, y);
    549     return (lineIx);
    550 }
    551 
    552 int MatlabPlot::Append(const char *name, double y)
    553 {
    554     CriticalSectionScoped cs(_critSect);
    555 
    556     if (!_enabled)
    557     {
    558         return -1;
    559     }
    560 
    561     // search the list for a matching line name
    562     int lineIx = GetLineIx(name);
    563 
    564     if (lineIx < 0) //(!matchFound)
    565     {
    566         // no match; append new line
    567         lineIx = AddLine(-1, NULL, name);
    568     }
    569 
    570     // append data to line
    571     Append(lineIx, y);
    572     return (lineIx);
    573 }
    574 
    575 int MatlabPlot::Length(char *name)
    576 {
    577     CriticalSectionScoped cs(_critSect);
    578 
    579     if (!_enabled)
    580     {
    581         return -1;
    582     }
    583 
    584     int ix = GetLineIx(name);
    585     if (ix >= 0)
    586     {
    587         return (static_cast<int>(_line[ix]->_xData.size()));
    588     }
    589     else
    590     {
    591         return (-1);
    592     }
    593 }
    594 
    595 
    596 void MatlabPlot::SetPlotAttribute(char *name, char *plotAttrib)
    597 {
    598     CriticalSectionScoped cs(_critSect);
    599 
    600     if (!_enabled)
    601     {
    602         return;
    603     }
    604 
    605     int lineIx = GetLineIx(name);
    606 
    607     if (lineIx >= 0)
    608     {
    609         _line[lineIx]->SetAttribute(plotAttrib);
    610     }
    611 }
    612 
    613 // Must be called under critical section _critSect
    614 void MatlabPlot::UpdateData(Engine* ep)
    615 {
    616     if (!_enabled)
    617     {
    618         return;
    619     }
    620 
    621     for (std::vector<MatlabLine*>::iterator it = _line.begin(); it != _line.end(); it++)
    622     {
    623         mxArray* xData = NULL;
    624         mxArray* yData = NULL;
    625         (*it)->GetPlotData(&xData, &yData);
    626         if (xData != NULL)
    627         {
    628             std::string xName = (*it)->GetXName();
    629             std::string yName = (*it)->GetYName();
    630             _critSect->Leave();
    631 #ifdef MATLAB6
    632             mxSetName(xData, xName.c_str());
    633             mxSetName(yData, yName.c_str());
    634             engPutArray(ep, xData);
    635             engPutArray(ep, yData);
    636 #else
    637             int ret = engPutVariable(ep, xName.c_str(), xData);
    638             assert(ret == 0);
    639             ret = engPutVariable(ep, yName.c_str(), yData);
    640             assert(ret == 0);
    641 #endif
    642             _critSect->Enter();
    643         }
    644     }
    645 }
    646 
    647 bool MatlabPlot::GetPlotCmd(std::ostringstream & cmd, Engine* ep)
    648 {
    649     _critSect->Enter();
    650 
    651     if (!DataAvailable())
    652     {
    653         return false;
    654     }
    655 
    656     if (_firstPlot)
    657     {
    658         GetPlotCmd(cmd);
    659         _firstPlot = false;
    660     }
    661     else
    662     {
    663         GetRefreshCmd(cmd);
    664     }
    665 
    666     UpdateData(ep);
    667 
    668     _critSect->Leave();
    669 
    670     return true;
    671 }
    672 
    673 // Call inside critsect
    674 void MatlabPlot::GetPlotCmd(std::ostringstream & cmd)
    675 {
    676     // we have something to plot
    677     // empty the stream
    678     cmd.str(""); // (this seems to be the only way)
    679 
    680     cmd << "figure; h" << _figHandle << "= plot(";
    681 
    682     // first line
    683     std::vector<MatlabLine*>::iterator it = _line.begin();
    684     cmd << (*it)->GetPlotString();
    685 
    686     it++;
    687 
    688     // remaining lines
    689     for (; it != _line.end(); it++)
    690     {
    691         cmd << ", ";
    692         cmd << (*it)->GetPlotString();
    693     }
    694 
    695     cmd << "); ";
    696 
    697     if (_legendEnabled)
    698     {
    699         GetLegendCmd(cmd);
    700     }
    701 
    702     if (_smartAxis)
    703     {
    704         double xMin = _xlim[0];
    705         double xMax = _xlim[1];
    706         double yMax = _ylim[1];
    707         for (std::vector<MatlabLine*>::iterator it = _line.begin(); it != _line.end(); it++)
    708         {
    709             xMax = std::max(xMax, (*it)->xMax());
    710             xMin = std::min(xMin, (*it)->xMin());
    711 
    712             yMax = std::max(yMax, (*it)->yMax());
    713             yMax = std::max(yMax, fabs((*it)->yMin()));
    714         }
    715         _xlim[0] = xMin;
    716         _xlim[1] = xMax;
    717         _ylim[0] = -yMax;
    718         _ylim[1] = yMax;
    719 
    720         cmd << "axis([" << _xlim[0] << ", " << _xlim[1] << ", " << _ylim[0] << ", " << _ylim[1] << "]);";
    721     }
    722 
    723     int i=1;
    724     for (it = _line.begin(); it != _line.end(); i++, it++)
    725     {
    726         cmd << "set(h" << _figHandle << "(" << i << "), 'Tag', " << (*it)->GetLegendString() << ");";
    727     }
    728 }
    729 
    730 // Call inside critsect
    731 void MatlabPlot::GetRefreshCmd(std::ostringstream & cmd)
    732 {
    733     cmd.str(""); // (this seems to be the only way)
    734     std::vector<MatlabLine*>::iterator it = _line.begin();
    735     for (it = _line.begin(); it != _line.end(); it++)
    736     {
    737         cmd << "h = findobj(0, 'Tag', " << (*it)->GetLegendString() << ");";
    738         cmd << (*it)->GetRefreshString();
    739     }
    740     //if (_legendEnabled)
    741     //{
    742     //    GetLegendCmd(cmd);
    743     //}
    744 }
    745 
    746 void MatlabPlot::GetLegendCmd(std::ostringstream & cmd)
    747 {
    748     std::vector<MatlabLine*>::iterator it = _line.begin();
    749     bool anyLegend = false;
    750     for (; it != _line.end(); it++)
    751     {
    752         anyLegend = anyLegend || (*it)->hasLegend();
    753     }
    754     if (anyLegend)
    755     {
    756         // create the legend
    757 
    758         cmd << "legend(h" << _figHandle << ",{";
    759 
    760 
    761         // iterate lines
    762         int i = 0;
    763         for (std::vector<MatlabLine*>::iterator it = _line.begin(); it != _line.end(); it++)
    764         {
    765             if (i > 0)
    766             {
    767                 cmd << ", ";
    768             }
    769             cmd << (*it)->GetLegendString();
    770             i++;
    771         }
    772 
    773         cmd << "}, 2); "; // place legend in upper-left corner
    774     }
    775 }
    776 
    777 // Call inside critsect
    778 bool MatlabPlot::DataAvailable()
    779 {
    780     if (!_enabled)
    781     {
    782         return false;
    783     }
    784 
    785     for (std::vector<MatlabLine*>::iterator it = _line.begin(); it != _line.end(); it++)
    786     {
    787         (*it)->PurgeOldData();
    788     }
    789 
    790     return true;
    791 }
    792 
    793 void MatlabPlot::Plot()
    794 {
    795     CriticalSectionScoped cs(_critSect);
    796 
    797     _timeToPlot = true;
    798 
    799 #ifdef PLOT_TESTING
    800     _plotStartTime = TickTime::MillisecondTimestamp();
    801 #endif
    802 }
    803 
    804 
    805 void MatlabPlot::Reset()
    806 {
    807     CriticalSectionScoped cs(_critSect);
    808 
    809     _enabled = true;
    810 
    811     for (std::vector<MatlabLine*>::iterator it = _line.begin(); it != _line.end(); it++)
    812     {
    813         (*it)->Reset();
    814     }
    815 
    816 }
    817 
    818 void MatlabPlot::SetFigHandle(int handle)
    819 {
    820     CriticalSectionScoped cs(_critSect);
    821 
    822     if (handle > 0)
    823         _figHandle = handle;
    824 }
    825 
    826 bool
    827 MatlabPlot::TimeToPlot()
    828 {
    829     CriticalSectionScoped cs(_critSect);
    830     return _enabled && _timeToPlot;
    831 }
    832 
    833 void
    834 MatlabPlot::Plotting()
    835 {
    836     CriticalSectionScoped cs(_critSect);
    837     _plotting = true;
    838 }
    839 
    840 void
    841 MatlabPlot::DonePlotting()
    842 {
    843     CriticalSectionScoped cs(_critSect);
    844     _timeToPlot = false;
    845     _plotting = false;
    846     _donePlottingEvent->Set();
    847 }
    848 
    849 void
    850 MatlabPlot::DisablePlot()
    851 {
    852     _critSect->Enter();
    853     while (_plotting)
    854     {
    855         _critSect->Leave();
    856         _donePlottingEvent->Wait(WEBRTC_EVENT_INFINITE);
    857         _critSect->Enter();
    858     }
    859     _enabled = false;
    860 }
    861 
    862 int MatlabPlot::MakeTrend(const char *sourceName, const char *trendName, double slope, double offset, const char *plotAttrib)
    863 {
    864     CriticalSectionScoped cs(_critSect);
    865 
    866     int sourceIx;
    867     int trendIx;
    868 
    869     sourceIx = GetLineIx(sourceName);
    870     if (sourceIx < 0)
    871     {
    872         // could not find source
    873         return (-1);
    874     }
    875 
    876     trendIx = GetLineIx(trendName);
    877     if (trendIx < 0)
    878     {
    879         // no trend found; add new line
    880         trendIx = AddLine(2 /*maxLen*/, plotAttrib, trendName);
    881     }
    882 
    883     _line[trendIx]->UpdateTrendLine(_line[sourceIx], slope, offset);
    884 
    885     return (trendIx);
    886 
    887 }
    888 
    889 
    890 MatlabEngine::MatlabEngine()
    891 :
    892 _critSect(CriticalSectionWrapper::CreateCriticalSection()),
    893 _eventPtr(NULL),
    894 _plotThread(NULL),
    895 _running(false),
    896 _numPlots(0)
    897 {
    898     _eventPtr = EventWrapper::Create();
    899 
    900     _plotThread = ThreadWrapper::CreateThread(MatlabEngine::PlotThread, this, kLowPriority, "MatlabPlot");
    901 
    902     if (_plotThread == NULL)
    903     {
    904         throw "Unable to start MatlabEngine thread";
    905         exit(1);
    906     }
    907 
    908     _running = true;
    909 
    910     unsigned int tid;
    911     _plotThread->Start(tid);
    912 
    913 }
    914 
    915 MatlabEngine::~MatlabEngine()
    916 {
    917     _critSect->Enter();
    918 
    919     if (_plotThread)
    920     {
    921         _plotThread->SetNotAlive();
    922         _running = false;
    923         _eventPtr->Set();
    924 
    925         while (!_plotThread->Stop())
    926         {
    927             ;
    928         }
    929 
    930         delete _plotThread;
    931     }
    932 
    933     _plots.clear();
    934 
    935     _plotThread = NULL;
    936 
    937     delete _eventPtr;
    938     _eventPtr = NULL;
    939 
    940     _critSect->Leave();
    941     delete _critSect;
    942 
    943 }
    944 
    945 MatlabPlot * MatlabEngine::NewPlot(MatlabPlot *newPlot)
    946 {
    947     CriticalSectionScoped cs(_critSect);
    948 
    949     //MatlabPlot *newPlot = new MatlabPlot();
    950 
    951     if (newPlot)
    952     {
    953         newPlot->SetFigHandle(++_numPlots); // first plot is number 1
    954         _plots.push_back(newPlot);
    955     }
    956 
    957     return (newPlot);
    958 
    959 }
    960 
    961 
    962 void MatlabEngine::DeletePlot(MatlabPlot *plot)
    963 {
    964     CriticalSectionScoped cs(_critSect);
    965 
    966     if (plot == NULL)
    967     {
    968         return;
    969     }
    970 
    971     std::vector<MatlabPlot *>::iterator it;
    972     for (it = _plots.begin(); it < _plots.end(); it++)
    973     {
    974         if (plot == *it)
    975         {
    976             break;
    977         }
    978     }
    979 
    980     assert (plot == *it);
    981 
    982     (*it)->DisablePlot();
    983 
    984     _plots.erase(it);
    985     --_numPlots;
    986 
    987     delete plot;
    988 }
    989 
    990 
    991 bool MatlabEngine::PlotThread(void *obj)
    992 {
    993     if (!obj)
    994     {
    995         return (false);
    996     }
    997 
    998     MatlabEngine *eng = (MatlabEngine *) obj;
    999 
   1000     Engine *ep = engOpen(NULL);
   1001     if (!ep)
   1002     {
   1003         throw "Cannot open Matlab engine";
   1004         return (false);
   1005     }
   1006 
   1007     engSetVisible(ep, true);
   1008     engEvalString(ep, "close all;");
   1009 
   1010     while (eng->_running)
   1011     {
   1012         eng->_critSect->Enter();
   1013 
   1014         // iterate through all plots
   1015         for (unsigned int ix = 0; ix < eng->_plots.size(); ix++)
   1016         {
   1017             MatlabPlot *plot = eng->_plots[ix];
   1018             if (plot->TimeToPlot())
   1019             {
   1020                 plot->Plotting();
   1021                 eng->_critSect->Leave();
   1022                 std::ostringstream cmd;
   1023 
   1024                 if (engEvalString(ep, cmd.str().c_str()))
   1025                 {
   1026                     // engine dead
   1027                     return (false);
   1028                 }
   1029 
   1030                 // empty the stream
   1031                 cmd.str(""); // (this seems to be the only way)
   1032                 if (plot->GetPlotCmd(cmd, ep))
   1033                 {
   1034                     // things to plot, we have already accessed what we need in the plot
   1035                     plot->DonePlotting();
   1036 
   1037                     int64_t start = TickTime::MillisecondTimestamp();
   1038                     // plot it
   1039                     int ret = engEvalString(ep, cmd.str().c_str());
   1040                     printf("time=%I64i\n", TickTime::MillisecondTimestamp() - start);
   1041                     if (ret)
   1042                     {
   1043                         // engine dead
   1044                         return (false);
   1045                     }
   1046 
   1047 #ifdef PLOT_TESTING
   1048                     if(plot->_plotStartTime >= 0)
   1049                     {
   1050                         plot->_plotDelay = TickTime::MillisecondTimestamp() - plot->_plotStartTime;
   1051                         plot->_plotStartTime = -1;
   1052                     }
   1053 #endif
   1054                 }
   1055                 eng->_critSect->Enter();
   1056             }
   1057         }
   1058 
   1059         eng->_critSect->Leave();
   1060         // wait a while
   1061         eng->_eventPtr->Wait(66); // 33 ms
   1062     }
   1063 
   1064     if (ep)
   1065     {
   1066         engClose(ep);
   1067         ep = NULL;
   1068     }
   1069 
   1070     return (true);
   1071 
   1072 }
   1073 
   1074 #endif // MATLAB
   1075