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
32namespace webrtc {
33static WebRtc_UWord32 levelFilter = kTraceDefault;
34
35// Construct On First Use idiom. Avoids "static initialization order fiasco".
36TraceImpl* 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
55TraceImpl* TraceImpl::GetTrace(const TraceLevel level)
56{
57    return StaticInstance(kAddRefNoCreate, level);
58}
59
60TraceImpl* TraceImpl::CreateInstance()
61{
62#if defined(_WIN32)
63    return new TraceWindows();
64#else
65    return new TracePosix();
66#endif
67}
68
69TraceImpl::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
101bool 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
124TraceImpl::~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
142WebRtc_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
148WebRtc_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
193WebRtc_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
339WebRtc_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
373WebRtc_Word32 TraceImpl::TraceFileImpl(
374    char fileNameUTF8[FileWrapper::kMaxFileNameSize])
375{
376    CriticalSectionScoped lock(_critsectInterface);
377    return _traceFile.FileName(fileNameUTF8, FileWrapper::kMaxFileNameSize);
378}
379
380WebRtc_Word32 TraceImpl::SetTraceCallbackImpl(TraceCallback* callback)
381{
382    CriticalSectionScoped lock(_critsectInterface);
383    _callback = callback;
384    return 0;
385}
386
387WebRtc_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
421void 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
482bool TraceImpl::Run(void* obj)
483{
484    return static_cast<TraceImpl*>(obj)->Process();
485}
486
487bool 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
502void 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
601void 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
658bool TraceImpl::TraceCheck(const TraceLevel level) const
659{
660    return (level & levelFilter)? true:false;
661}
662
663bool 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
706bool 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
739void Trace::CreateTrace()
740{
741    TraceImpl::StaticInstance(kAddRef);
742}
743
744void Trace::ReturnTrace()
745{
746    TraceImpl::StaticInstance(kRelease);
747}
748
749WebRtc_Word32 Trace::SetLevelFilter(WebRtc_UWord32 filter)
750{
751    levelFilter = filter;
752    return 0;
753}
754
755WebRtc_Word32 Trace::LevelFilter(WebRtc_UWord32& filter)
756{
757    filter = levelFilter;
758    return 0;
759}
760
761WebRtc_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
773WebRtc_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
786WebRtc_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
798void 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