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".
StaticInstance(CountOperation count_operation,const TraceLevel level)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 
GetTrace(const TraceLevel level)55 TraceImpl* TraceImpl::GetTrace(const TraceLevel level)
56 {
57     return StaticInstance(kAddRefNoCreate, level);
58 }
59 
CreateInstance()60 TraceImpl* TraceImpl::CreateInstance()
61 {
62 #if defined(_WIN32)
63     return new TraceWindows();
64 #else
65     return new TracePosix();
66 #endif
67 }
68 
TraceImpl()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 
StopThread()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 
~TraceImpl()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 
AddThreadId(char * traceMessage) const142 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 
AddLevel(char * szMessage,const TraceLevel level) const148 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 
AddModuleAndId(char * traceMessage,const TraceModule module,const WebRtc_Word32 id) const193 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 
SetTraceFileImpl(const char * fileNameUTF8,const bool addFileCounter)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 
TraceFileImpl(char fileNameUTF8[FileWrapper::kMaxFileNameSize])373 WebRtc_Word32 TraceImpl::TraceFileImpl(
374     char fileNameUTF8[FileWrapper::kMaxFileNameSize])
375 {
376     CriticalSectionScoped lock(_critsectInterface);
377     return _traceFile.FileName(fileNameUTF8, FileWrapper::kMaxFileNameSize);
378 }
379 
SetTraceCallbackImpl(TraceCallback * callback)380 WebRtc_Word32 TraceImpl::SetTraceCallbackImpl(TraceCallback* callback)
381 {
382     CriticalSectionScoped lock(_critsectInterface);
383     _callback = callback;
384     return 0;
385 }
386 
AddMessage(char * traceMessage,const char msg[WEBRTC_TRACE_MAX_MESSAGE_SIZE],const WebRtc_UWord16 writtenSoFar) const387 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 
AddMessageToList(const char traceMessage[WEBRTC_TRACE_MAX_MESSAGE_SIZE],const WebRtc_UWord16 length,const TraceLevel level)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 
Run(void * obj)482 bool TraceImpl::Run(void* obj)
483 {
484     return static_cast<TraceImpl*>(obj)->Process();
485 }
486 
Process()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 
WriteToFile()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 
AddImpl(const TraceLevel level,const TraceModule module,const WebRtc_Word32 id,const char msg[WEBRTC_TRACE_MAX_MESSAGE_SIZE])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 
TraceCheck(const TraceLevel level) const658 bool TraceImpl::TraceCheck(const TraceLevel level) const
659 {
660     return (level & levelFilter)? true:false;
661 }
662 
UpdateFileName(const char fileNameUTF8[FileWrapper::kMaxFileNameSize],char fileNameWithCounterUTF8[FileWrapper::kMaxFileNameSize],const WebRtc_UWord32 newCount) const663 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 
CreateFileName(const char fileNameUTF8[FileWrapper::kMaxFileNameSize],char fileNameWithCounterUTF8[FileWrapper::kMaxFileNameSize],const WebRtc_UWord32 newCount) const706 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 
CreateTrace()739 void Trace::CreateTrace()
740 {
741     TraceImpl::StaticInstance(kAddRef);
742 }
743 
ReturnTrace()744 void Trace::ReturnTrace()
745 {
746     TraceImpl::StaticInstance(kRelease);
747 }
748 
SetLevelFilter(WebRtc_UWord32 filter)749 WebRtc_Word32 Trace::SetLevelFilter(WebRtc_UWord32 filter)
750 {
751     levelFilter = filter;
752     return 0;
753 }
754 
LevelFilter(WebRtc_UWord32 & filter)755 WebRtc_Word32 Trace::LevelFilter(WebRtc_UWord32& filter)
756 {
757     filter = levelFilter;
758     return 0;
759 }
760 
TraceFile(char fileName[FileWrapper::kMaxFileNameSize])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 
SetTraceFile(const char * fileName,const bool addFileCounter)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 
SetTraceCallback(TraceCallback * callback)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 
Add(const TraceLevel level,const TraceModule module,const WebRtc_Word32 id,const char * msg,...)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