Home | History | Annotate | Download | only in source
      1 /*
      2  *  Copyright (c) 2012 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 "trace_impl.h"
     12 
     13 #include <cassert>
     14 #include <string.h> // memset
     15 
     16 #ifdef _WIN32
     17 #include "trace_win.h"
     18 #else
     19 #include <stdio.h>
     20 #include <stdarg.h>
     21 #include "trace_posix.h"
     22 #endif // _WIN32
     23 
     24 #include "system_wrappers/interface/sleep.h"
     25 
     26 #define KEY_LEN_CHARS 31
     27 
     28 #ifdef _WIN32
     29 #pragma warning(disable:4355)
     30 #endif // _WIN32
     31 
     32 namespace webrtc {
     33 static WebRtc_UWord32 levelFilter = kTraceDefault;
     34 
     35 // Construct On First Use idiom. Avoids "static initialization order fiasco".
     36 TraceImpl* TraceImpl::StaticInstance(CountOperation count_operation,
     37                                      const TraceLevel level)
     38 {
     39     // Sanities to avoid taking lock unless absolutely necessary (for
     40     // performance reasons).
     41     // count_operation == kAddRefNoCreate implies that a message will be
     42     // written to file.
     43     if((level != kTraceAll) && (count_operation == kAddRefNoCreate))
     44     {
     45         if(!(level & levelFilter))
     46         {
     47             return NULL;
     48         }
     49     }
     50     TraceImpl* impl =
     51         GetStaticInstance<TraceImpl>(count_operation);
     52     return impl;
     53 }
     54 
     55 TraceImpl* TraceImpl::GetTrace(const TraceLevel level)
     56 {
     57     return StaticInstance(kAddRefNoCreate, level);
     58 }
     59 
     60 TraceImpl* TraceImpl::CreateInstance()
     61 {
     62 #if defined(_WIN32)
     63     return new TraceWindows();
     64 #else
     65     return new TracePosix();
     66 #endif
     67 }
     68 
     69 TraceImpl::TraceImpl()
     70     : _critsectInterface(CriticalSectionWrapper::CreateCriticalSection()),
     71       _callback(NULL),
     72       _rowCountText(0),
     73       _fileCountText(0),
     74       _traceFile(*FileWrapper::Create()),
     75       _thread(*ThreadWrapper::CreateThread(TraceImpl::Run, this,
     76                                            kHighestPriority, "Trace")),
     77       _event(*EventWrapper::Create()),
     78       _critsectArray(CriticalSectionWrapper::CreateCriticalSection()),
     79       _nextFreeIdx(),
     80       _level(),
     81       _length(),
     82       _messageQueue(),
     83       _activeQueue(0)
     84 {
     85     _nextFreeIdx[0] = 0;
     86     _nextFreeIdx[1] = 0;
     87 
     88     unsigned int tid = 0;
     89     _thread.Start(tid);
     90 
     91     for(int m = 0; m < WEBRTC_TRACE_NUM_ARRAY; m++)
     92     {
     93         for(int n = 0; n < WEBRTC_TRACE_MAX_QUEUE; n++)
     94         {
     95             _messageQueue[m][n] = new
     96                 char[WEBRTC_TRACE_MAX_MESSAGE_SIZE];
     97         }
     98     }
     99 }
    100 
    101 bool TraceImpl::StopThread()
    102 {
    103     // Release the worker thread so that it can flush any lingering messages.
    104     _event.Set();
    105 
    106     // Allow 10 ms for pending messages to be flushed out.
    107     // TODO (hellner): why not use condition variables to do this? Or let the
    108     //                 worker thread die and let this thread flush remaining
    109     //                 messages?
    110     SleepMs(10);
    111 
    112     _thread.SetNotAlive();
    113     // Make sure the thread finishes as quickly as possible (instead of having
    114     // to wait for the timeout).
    115     _event.Set();
    116     bool stopped = _thread.Stop();
    117 
    118     CriticalSectionScoped lock(_critsectInterface);
    119     _traceFile.Flush();
    120     _traceFile.CloseFile();
    121     return stopped;
    122 }
    123 
    124 TraceImpl::~TraceImpl()
    125 {
    126     StopThread();
    127     delete &_event;
    128     delete &_traceFile;
    129     delete &_thread;
    130     delete _critsectInterface;
    131     delete _critsectArray;
    132 
    133     for(int m = 0; m < WEBRTC_TRACE_NUM_ARRAY; m++)
    134     {
    135         for(int n = 0; n < WEBRTC_TRACE_MAX_QUEUE; n++)
    136         {
    137             delete [] _messageQueue[m][n];
    138         }
    139     }
    140 }
    141 
    142 WebRtc_Word32 TraceImpl::AddThreadId(char* traceMessage) const {
    143   WebRtc_UWord32 threadId = ThreadWrapper::GetThreadId();
    144   // Messages is 12 characters.
    145   return sprintf(traceMessage, "%10u; ", threadId);
    146 }
    147 
    148 WebRtc_Word32 TraceImpl::AddLevel(char* szMessage, const TraceLevel level) const
    149 {
    150     switch (level)
    151     {
    152         case kTraceStateInfo:
    153             sprintf (szMessage, "STATEINFO ; ");
    154             break;
    155         case kTraceWarning:
    156             sprintf (szMessage, "WARNING   ; ");
    157             break;
    158         case kTraceError:
    159             sprintf (szMessage, "ERROR     ; ");
    160             break;
    161         case kTraceCritical:
    162             sprintf (szMessage, "CRITICAL  ; ");
    163             break;
    164         case kTraceInfo:
    165             sprintf (szMessage, "DEBUGINFO ; ");
    166             break;
    167         case kTraceModuleCall:
    168             sprintf (szMessage, "MODULECALL; ");
    169             break;
    170         case kTraceMemory:
    171             sprintf (szMessage, "MEMORY    ; ");
    172             break;
    173         case kTraceTimer:
    174             sprintf (szMessage, "TIMER     ; ");
    175             break;
    176         case kTraceStream:
    177             sprintf (szMessage, "STREAM    ; ");
    178             break;
    179         case kTraceApiCall:
    180             sprintf (szMessage, "APICALL   ; ");
    181             break;
    182         case kTraceDebug:
    183             sprintf (szMessage, "DEBUG     ; ");
    184             break;
    185         default:
    186             assert(false);
    187             return 0;
    188     }
    189     // All messages are 12 characters.
    190     return 12;
    191 }
    192 
    193 WebRtc_Word32 TraceImpl::AddModuleAndId(char* traceMessage,
    194                                         const TraceModule module,
    195                                         const WebRtc_Word32 id) const
    196 {
    197     // Use long int to prevent problems with different definitions of
    198     // WebRtc_Word32.
    199     // TODO (hellner): is this actually a problem? If so, it should be better to
    200     //                 clean up WebRtc_Word32
    201     const long int idl = id;
    202     if(idl != -1)
    203     {
    204         const unsigned long int idEngine = id>>16;
    205         const unsigned long int idChannel = id & 0xffff;
    206 
    207         switch (module)
    208         {
    209             case kTraceVoice:
    210                 sprintf(traceMessage, "       VOICE:%5ld %5ld;", idEngine,
    211                         idChannel);
    212                 break;
    213             case kTraceVideo:
    214                 sprintf(traceMessage, "       VIDEO:%5ld %5ld;", idEngine,
    215                         idChannel);
    216                 break;
    217             case kTraceUtility:
    218                 sprintf(traceMessage, "     UTILITY:%5ld %5ld;", idEngine,
    219                         idChannel);
    220                 break;
    221             case kTraceRtpRtcp:
    222                 sprintf(traceMessage, "    RTP/RTCP:%5ld %5ld;", idEngine,
    223                         idChannel);
    224                 break;
    225             case kTraceTransport:
    226                 sprintf(traceMessage, "   TRANSPORT:%5ld %5ld;", idEngine,
    227                         idChannel);
    228                 break;
    229             case kTraceAudioCoding:
    230                 sprintf(traceMessage, "AUDIO CODING:%5ld %5ld;", idEngine,
    231                         idChannel);
    232                 break;
    233             case kTraceSrtp:
    234                 sprintf(traceMessage, "        SRTP:%5ld %5ld;", idEngine,
    235                         idChannel);
    236                 break;
    237             case kTraceAudioMixerServer:
    238                 sprintf(traceMessage, " AUDIO MIX/S:%5ld %5ld;", idEngine,
    239                         idChannel);
    240                 break;
    241             case kTraceAudioMixerClient:
    242                 sprintf(traceMessage, " AUDIO MIX/C:%5ld %5ld;", idEngine,
    243                         idChannel);
    244                 break;
    245             case kTraceVideoCoding:
    246                 sprintf(traceMessage, "VIDEO CODING:%5ld %5ld;", idEngine,
    247                         idChannel);
    248                 break;
    249             case kTraceVideoMixer:
    250                 // Print sleep time and API call
    251                 sprintf(traceMessage, "   VIDEO MIX:%5ld %5ld;", idEngine,
    252                         idChannel);
    253                 break;
    254             case kTraceFile:
    255                 sprintf(traceMessage, "        FILE:%5ld %5ld;", idEngine,
    256                         idChannel);
    257                 break;
    258             case kTraceAudioProcessing:
    259                 sprintf(traceMessage, "  AUDIO PROC:%5ld %5ld;", idEngine,
    260                         idChannel);
    261                 break;
    262             case kTraceAudioDevice:
    263                 sprintf(traceMessage, "AUDIO DEVICE:%5ld %5ld;", idEngine,
    264                         idChannel);
    265                 break;
    266             case kTraceVideoRenderer:
    267                 sprintf(traceMessage, "VIDEO RENDER:%5ld %5ld;", idEngine,
    268                         idChannel);
    269                 break;
    270             case kTraceVideoCapture:
    271                 sprintf(traceMessage, "VIDEO CAPTUR:%5ld %5ld;", idEngine,
    272                         idChannel);
    273                 break;
    274             case kTraceVideoPreocessing:
    275                 sprintf(traceMessage, "  VIDEO PROC:%5ld %5ld;", idEngine,
    276                         idChannel);
    277                 break;
    278         }
    279     } else {
    280         switch (module)
    281         {
    282             case kTraceVoice:
    283                 sprintf (traceMessage, "       VOICE:%11ld;", idl);
    284                 break;
    285             case kTraceVideo:
    286                 sprintf (traceMessage, "       VIDEO:%11ld;", idl);
    287                 break;
    288             case kTraceUtility:
    289                 sprintf (traceMessage, "     UTILITY:%11ld;", idl);
    290                 break;
    291             case kTraceRtpRtcp:
    292                 sprintf (traceMessage, "    RTP/RTCP:%11ld;", idl);
    293                 break;
    294             case kTraceTransport:
    295                 sprintf (traceMessage, "   TRANSPORT:%11ld;", idl);
    296                 break;
    297             case kTraceAudioCoding:
    298                 sprintf (traceMessage, "AUDIO CODING:%11ld;", idl);
    299                 break;
    300             case kTraceSrtp:
    301                 sprintf (traceMessage, "        SRTP:%11ld;", idl);
    302                 break;
    303             case kTraceAudioMixerServer:
    304                 sprintf (traceMessage, " AUDIO MIX/S:%11ld;", idl);
    305                 break;
    306             case kTraceAudioMixerClient:
    307                 sprintf (traceMessage, " AUDIO MIX/C:%11ld;", idl);
    308                 break;
    309             case kTraceVideoCoding:
    310                 sprintf (traceMessage, "VIDEO CODING:%11ld;", idl);
    311                 break;
    312             case kTraceVideoMixer:
    313                 sprintf (traceMessage, "   VIDEO MIX:%11ld;", idl);
    314                 break;
    315             case kTraceFile:
    316                 sprintf (traceMessage, "        FILE:%11ld;", idl);
    317                 break;
    318             case kTraceAudioProcessing:
    319                 sprintf (traceMessage, "  AUDIO PROC:%11ld;", idl);
    320                 break;
    321             case kTraceAudioDevice:
    322                 sprintf (traceMessage, "AUDIO DEVICE:%11ld;", idl);
    323                 break;
    324             case kTraceVideoRenderer:
    325                 sprintf (traceMessage, "VIDEO RENDER:%11ld;", idl);
    326                 break;
    327             case kTraceVideoCapture:
    328                 sprintf (traceMessage, "VIDEO CAPTUR:%11ld;", idl);
    329                 break;
    330             case kTraceVideoPreocessing:
    331                 sprintf (traceMessage, "  VIDEO PROC:%11ld;", idl);
    332                 break;
    333         }
    334     }
    335     // All messages are 25 characters.
    336     return 25;
    337 }
    338 
    339 WebRtc_Word32 TraceImpl::SetTraceFileImpl(const char* fileNameUTF8,
    340                                           const bool addFileCounter)
    341 {
    342     CriticalSectionScoped lock(_critsectInterface);
    343 
    344     _traceFile.Flush();
    345     _traceFile.CloseFile();
    346 
    347     if(fileNameUTF8)
    348     {
    349         if(addFileCounter)
    350         {
    351             _fileCountText = 1;
    352 
    353             char fileNameWithCounterUTF8[FileWrapper::kMaxFileNameSize];
    354             CreateFileName(fileNameUTF8, fileNameWithCounterUTF8,
    355                            _fileCountText);
    356             if(_traceFile.OpenFile(fileNameWithCounterUTF8, false, false,
    357                                    true) == -1)
    358             {
    359                 return -1;
    360             }
    361         }else {
    362             _fileCountText = 0;
    363             if(_traceFile.OpenFile(fileNameUTF8, false, false, true) == -1)
    364             {
    365                 return -1;
    366             }
    367         }
    368     }
    369     _rowCountText = 0;
    370     return 0;
    371 }
    372 
    373 WebRtc_Word32 TraceImpl::TraceFileImpl(
    374     char fileNameUTF8[FileWrapper::kMaxFileNameSize])
    375 {
    376     CriticalSectionScoped lock(_critsectInterface);
    377     return _traceFile.FileName(fileNameUTF8, FileWrapper::kMaxFileNameSize);
    378 }
    379 
    380 WebRtc_Word32 TraceImpl::SetTraceCallbackImpl(TraceCallback* callback)
    381 {
    382     CriticalSectionScoped lock(_critsectInterface);
    383     _callback = callback;
    384     return 0;
    385 }
    386 
    387 WebRtc_Word32 TraceImpl::AddMessage(
    388     char* traceMessage,
    389     const char msg[WEBRTC_TRACE_MAX_MESSAGE_SIZE],
    390     const WebRtc_UWord16 writtenSoFar) const
    391 
    392 {
    393     int length = 0;
    394     if(writtenSoFar >= WEBRTC_TRACE_MAX_MESSAGE_SIZE)
    395     {
    396         return -1;
    397     }
    398     // - 2 to leave room for newline and NULL termination
    399 #ifdef _WIN32
    400     length = _snprintf(traceMessage,
    401                        WEBRTC_TRACE_MAX_MESSAGE_SIZE - writtenSoFar - 2,
    402                        "%s",msg);
    403     if(length < 0)
    404     {
    405         length = WEBRTC_TRACE_MAX_MESSAGE_SIZE - writtenSoFar - 2;
    406         traceMessage[length] = 0;
    407     }
    408 #else
    409     length = snprintf(traceMessage,
    410                       WEBRTC_TRACE_MAX_MESSAGE_SIZE-writtenSoFar-2, "%s",msg);
    411     if(length < 0 || length > WEBRTC_TRACE_MAX_MESSAGE_SIZE-writtenSoFar - 2)
    412     {
    413         length = WEBRTC_TRACE_MAX_MESSAGE_SIZE - writtenSoFar - 2;
    414         traceMessage[length] = 0;
    415     }
    416 #endif
    417     // Length with NULL termination.
    418     return length+1;
    419 }
    420 
    421 void TraceImpl::AddMessageToList(
    422     const char traceMessage[WEBRTC_TRACE_MAX_MESSAGE_SIZE],
    423     const WebRtc_UWord16 length,
    424     const TraceLevel level) {
    425 #ifdef WEBRTC_DIRECT_TRACE
    426     if (_callback) {
    427       _callback->Print(level, traceMessage, length);
    428     }
    429     return;
    430 #endif
    431 
    432     CriticalSectionScoped lock(_critsectArray);
    433 
    434     if(_nextFreeIdx[_activeQueue] >= WEBRTC_TRACE_MAX_QUEUE)
    435     {
    436         if( ! _traceFile.Open() &&
    437             !_callback)
    438         {
    439             // Keep at least the last 1/4 of old messages when not logging.
    440             // TODO (hellner): isn't this redundant. The user will make it known
    441             //                 when to start logging. Why keep messages before
    442             //                 that?
    443             for(int n = 0; n < WEBRTC_TRACE_MAX_QUEUE/4; n++)
    444             {
    445                 const int lastQuarterOffset = (3*WEBRTC_TRACE_MAX_QUEUE/4);
    446                 memcpy(_messageQueue[_activeQueue][n],
    447                        _messageQueue[_activeQueue][n + lastQuarterOffset],
    448                        WEBRTC_TRACE_MAX_MESSAGE_SIZE);
    449             }
    450             _nextFreeIdx[_activeQueue] = WEBRTC_TRACE_MAX_QUEUE/4;
    451         } else {
    452             // More messages are being written than there is room for in the
    453             // buffer. Drop any new messages.
    454             // TODO (hellner): its probably better to drop old messages instead
    455             //                 of new ones. One step further: if this happens
    456             //                 it's due to writing faster than what can be
    457             //                 processed. Maybe modify the filter at this point.
    458             //                 E.g. turn of STREAM.
    459             return;
    460         }
    461     }
    462 
    463     WebRtc_UWord16 idx = _nextFreeIdx[_activeQueue];
    464     _nextFreeIdx[_activeQueue]++;
    465 
    466     _level[_activeQueue][idx] = level;
    467     _length[_activeQueue][idx] = length;
    468     memcpy(_messageQueue[_activeQueue][idx], traceMessage, length);
    469 
    470     if(_nextFreeIdx[_activeQueue] == WEBRTC_TRACE_MAX_QUEUE-1)
    471     {
    472         // Logging more messages than can be worked off. Log a warning.
    473         const char warning_msg[] = "WARNING MISSING TRACE MESSAGES\n";
    474         _level[_activeQueue][_nextFreeIdx[_activeQueue]] = kTraceWarning;
    475         _length[_activeQueue][_nextFreeIdx[_activeQueue]] = strlen(warning_msg);
    476         memcpy(_messageQueue[_activeQueue][_nextFreeIdx[_activeQueue]],
    477                warning_msg, _length[_activeQueue][idx]);
    478         _nextFreeIdx[_activeQueue]++;
    479     }
    480 }
    481 
    482 bool TraceImpl::Run(void* obj)
    483 {
    484     return static_cast<TraceImpl*>(obj)->Process();
    485 }
    486 
    487 bool TraceImpl::Process()
    488 {
    489     if(_event.Wait(1000) == kEventSignaled)
    490     {
    491         if(_traceFile.Open() || _callback)
    492         {
    493             // File mode (not calback mode).
    494             WriteToFile();
    495         }
    496     } else {
    497         _traceFile.Flush();
    498     }
    499     return true;
    500 }
    501 
    502 void TraceImpl::WriteToFile()
    503 {
    504     WebRtc_UWord8 localQueueActive = 0;
    505     WebRtc_UWord16 localNextFreeIdx = 0;
    506 
    507     // There are two buffer. One for reading (for writing to file) and one for
    508     // writing (for storing new messages). Let new messages be posted to the
    509     // unused buffer so that the current buffer can be flushed safely.
    510     {
    511         CriticalSectionScoped lock(_critsectArray);
    512         localNextFreeIdx = _nextFreeIdx[_activeQueue];
    513         _nextFreeIdx[_activeQueue] = 0;
    514         localQueueActive = _activeQueue;
    515         if(_activeQueue == 0)
    516         {
    517             _activeQueue = 1;
    518         } else
    519         {
    520             _activeQueue = 0;
    521         }
    522     }
    523     if(localNextFreeIdx == 0)
    524     {
    525         return;
    526     }
    527 
    528     CriticalSectionScoped lock(_critsectInterface);
    529 
    530     for(WebRtc_UWord16 idx = 0; idx <localNextFreeIdx; idx++)
    531     {
    532         TraceLevel localLevel = _level[localQueueActive][idx];
    533         if(_callback)
    534         {
    535             _callback->Print(localLevel, _messageQueue[localQueueActive][idx],
    536                              _length[localQueueActive][idx]);
    537         }
    538         if(_traceFile.Open())
    539         {
    540             if(_rowCountText > WEBRTC_TRACE_MAX_FILE_SIZE)
    541             {
    542                 // wrap file
    543                 _rowCountText = 0;
    544                 _traceFile.Flush();
    545 
    546                 if(_fileCountText == 0)
    547                 {
    548                     _traceFile.Rewind();
    549                 } else
    550                 {
    551                     char oldFileName[FileWrapper::kMaxFileNameSize];
    552                     char newFileName[FileWrapper::kMaxFileNameSize];
    553 
    554                     // get current name
    555                     _traceFile.FileName(oldFileName,
    556                                         FileWrapper::kMaxFileNameSize);
    557                     _traceFile.CloseFile();
    558 
    559                     _fileCountText++;
    560 
    561                     UpdateFileName(oldFileName, newFileName, _fileCountText);
    562 
    563                     if(_traceFile.OpenFile(newFileName, false, false,
    564                                            true) == -1)
    565                     {
    566                         return;
    567                     }
    568                 }
    569             }
    570             if(_rowCountText ==  0)
    571             {
    572                 char message[WEBRTC_TRACE_MAX_MESSAGE_SIZE + 1];
    573                 WebRtc_Word32 length = AddDateTimeInfo(message);
    574                 if(length != -1)
    575                 {
    576                     message[length] = 0;
    577                     message[length-1] = '\n';
    578                     _traceFile.Write(message, length);
    579                     _rowCountText++;
    580                 }
    581                 length = AddBuildInfo(message);
    582                 if(length != -1)
    583                 {
    584                     message[length+1] = 0;
    585                     message[length] = '\n';
    586                     message[length-1] = '\n';
    587                     _traceFile.Write(message, length+1);
    588                     _rowCountText++;
    589                     _rowCountText++;
    590                 }
    591             }
    592             WebRtc_UWord16 length = _length[localQueueActive][idx];
    593             _messageQueue[localQueueActive][idx][length] = 0;
    594             _messageQueue[localQueueActive][idx][length-1] = '\n';
    595             _traceFile.Write(_messageQueue[localQueueActive][idx], length);
    596             _rowCountText++;
    597         }
    598     }
    599 }
    600 
    601 void TraceImpl::AddImpl(const TraceLevel level, const TraceModule module,
    602                         const WebRtc_Word32 id,
    603                         const char msg[WEBRTC_TRACE_MAX_MESSAGE_SIZE])
    604 {
    605     if (TraceCheck(level))
    606     {
    607         char traceMessage[WEBRTC_TRACE_MAX_MESSAGE_SIZE];
    608         char* meassagePtr = traceMessage;
    609 
    610         WebRtc_Word32 len = 0;
    611         WebRtc_Word32 ackLen = 0;
    612 
    613         len = AddLevel(meassagePtr, level);
    614         if(len == -1)
    615         {
    616             return;
    617         }
    618         meassagePtr += len;
    619         ackLen += len;
    620 
    621         len = AddTime(meassagePtr, level);
    622         if(len == -1)
    623         {
    624             return;
    625         }
    626         meassagePtr += len;
    627         ackLen += len;
    628 
    629         len = AddModuleAndId(meassagePtr, module, id);
    630         if(len == -1)
    631         {
    632             return;
    633         }
    634         meassagePtr += len;
    635         ackLen += len;
    636 
    637         len = AddThreadId(meassagePtr);
    638         if(len < 0)
    639         {
    640             return;
    641         }
    642         meassagePtr += len;
    643         ackLen += len;
    644 
    645         len = AddMessage(meassagePtr, msg, (WebRtc_UWord16)ackLen);
    646         if(len == -1)
    647         {
    648             return;
    649         }
    650         ackLen += len;
    651         AddMessageToList(traceMessage,(WebRtc_UWord16)ackLen, level);
    652 
    653         // Make sure that messages are written as soon as possible.
    654         _event.Set();
    655     }
    656 }
    657 
    658 bool TraceImpl::TraceCheck(const TraceLevel level) const
    659 {
    660     return (level & levelFilter)? true:false;
    661 }
    662 
    663 bool TraceImpl::UpdateFileName(
    664     const char fileNameUTF8[FileWrapper::kMaxFileNameSize],
    665     char fileNameWithCounterUTF8[FileWrapper::kMaxFileNameSize],
    666     const WebRtc_UWord32 newCount) const
    667 {
    668     WebRtc_Word32 length = (WebRtc_Word32)strlen(fileNameUTF8);
    669     if(length < 0)
    670     {
    671         return false;
    672     }
    673 
    674     WebRtc_Word32 lengthWithoutFileEnding = length-1;
    675     while(lengthWithoutFileEnding > 0)
    676     {
    677         if(fileNameUTF8[lengthWithoutFileEnding] == '.')
    678         {
    679             break;
    680         } else {
    681             lengthWithoutFileEnding--;
    682         }
    683     }
    684     if(lengthWithoutFileEnding == 0)
    685     {
    686         lengthWithoutFileEnding = length;
    687     }
    688     WebRtc_Word32 lengthTo_ = lengthWithoutFileEnding - 1;
    689     while(lengthTo_ > 0)
    690     {
    691         if(fileNameUTF8[lengthTo_] == '_')
    692         {
    693             break;
    694         } else {
    695             lengthTo_--;
    696         }
    697     }
    698 
    699     memcpy(fileNameWithCounterUTF8, fileNameUTF8, lengthTo_);
    700     sprintf(fileNameWithCounterUTF8+lengthTo_, "_%lu%s",
    701             static_cast<long unsigned int> (newCount),
    702             fileNameUTF8+lengthWithoutFileEnding);
    703     return true;
    704 }
    705 
    706 bool TraceImpl::CreateFileName(
    707     const char fileNameUTF8[FileWrapper::kMaxFileNameSize],
    708     char fileNameWithCounterUTF8[FileWrapper::kMaxFileNameSize],
    709     const WebRtc_UWord32 newCount) const
    710 {
    711     WebRtc_Word32 length = (WebRtc_Word32)strlen(fileNameUTF8);
    712     if(length < 0)
    713     {
    714         return false;
    715     }
    716 
    717     WebRtc_Word32 lengthWithoutFileEnding = length-1;
    718     while(lengthWithoutFileEnding > 0)
    719     {
    720         if(fileNameUTF8[lengthWithoutFileEnding] == '.')
    721         {
    722             break;
    723         }else
    724         {
    725             lengthWithoutFileEnding--;
    726         }
    727     }
    728     if(lengthWithoutFileEnding == 0)
    729     {
    730         lengthWithoutFileEnding = length;
    731     }
    732     memcpy(fileNameWithCounterUTF8, fileNameUTF8, lengthWithoutFileEnding);
    733     sprintf(fileNameWithCounterUTF8+lengthWithoutFileEnding, "_%lu%s",
    734             static_cast<long unsigned int> (newCount),
    735             fileNameUTF8+lengthWithoutFileEnding);
    736     return true;
    737 }
    738 
    739 void Trace::CreateTrace()
    740 {
    741     TraceImpl::StaticInstance(kAddRef);
    742 }
    743 
    744 void Trace::ReturnTrace()
    745 {
    746     TraceImpl::StaticInstance(kRelease);
    747 }
    748 
    749 WebRtc_Word32 Trace::SetLevelFilter(WebRtc_UWord32 filter)
    750 {
    751     levelFilter = filter;
    752     return 0;
    753 }
    754 
    755 WebRtc_Word32 Trace::LevelFilter(WebRtc_UWord32& filter)
    756 {
    757     filter = levelFilter;
    758     return 0;
    759 }
    760 
    761 WebRtc_Word32 Trace::TraceFile(char fileName[FileWrapper::kMaxFileNameSize])
    762 {
    763     TraceImpl* trace = TraceImpl::GetTrace();
    764     if(trace)
    765     {
    766         int retVal = trace->TraceFileImpl(fileName);
    767         ReturnTrace();
    768         return retVal;
    769     }
    770     return -1;
    771 }
    772 
    773 WebRtc_Word32 Trace::SetTraceFile(const char* fileName,
    774                                   const bool addFileCounter)
    775 {
    776     TraceImpl* trace = TraceImpl::GetTrace();
    777     if(trace)
    778     {
    779         int retVal = trace->SetTraceFileImpl(fileName, addFileCounter);
    780         ReturnTrace();
    781         return retVal;
    782     }
    783     return -1;
    784 }
    785 
    786 WebRtc_Word32 Trace::SetTraceCallback(TraceCallback* callback)
    787 {
    788     TraceImpl* trace = TraceImpl::GetTrace();
    789     if(trace)
    790     {
    791         int retVal = trace->SetTraceCallbackImpl(callback);
    792         ReturnTrace();
    793         return retVal;
    794     }
    795     return -1;
    796 }
    797 
    798 void Trace::Add(const TraceLevel level, const TraceModule module,
    799                 const WebRtc_Word32 id, const char* msg, ...)
    800 
    801 {
    802     TraceImpl* trace = TraceImpl::GetTrace(level);
    803     if(trace)
    804     {
    805         if(trace->TraceCheck(level))
    806         {
    807             char tempBuff[WEBRTC_TRACE_MAX_MESSAGE_SIZE];
    808             char* buff = 0;
    809             if(msg)
    810             {
    811                 va_list args;
    812                 va_start(args, msg);
    813 #ifdef _WIN32
    814                 _vsnprintf(tempBuff,WEBRTC_TRACE_MAX_MESSAGE_SIZE-1,msg,args);
    815 #else
    816                 vsnprintf(tempBuff,WEBRTC_TRACE_MAX_MESSAGE_SIZE-1,msg,args);
    817 #endif
    818                 va_end(args);
    819                 buff = tempBuff;
    820             }
    821             trace->AddImpl(level, module, id, buff);
    822         }
    823         ReturnTrace();
    824     }
    825 }
    826 
    827 } // namespace webrtc
    828