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