git-svn-id: http://webrtc.googlecode.com/svn/trunk@6 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/system_wrappers/source/trace_impl.cc b/system_wrappers/source/trace_impl.cc
new file mode 100644
index 0000000..5d269ff
--- /dev/null
+++ b/system_wrappers/source/trace_impl.cc
@@ -0,0 +1,949 @@
+/*
+ *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "trace_impl.h"
+
+#include <cassert>
+#include <string.h> // memset
+
+#ifdef _WIN32
+#include "trace_windows.h"
+#include "fix_interlocked_exchange_pointer_windows.h"
+#else
+#include <stdio.h>
+#include <time.h>
+#include <stdarg.h>
+#include "trace_linux.h"
+#endif // _WIN32
+
+#define KEY_LEN_CHARS 31
+
+#ifdef _WIN32
+    #pragma warning(disable:4355)
+// VS 2005: Disable warnings for default initialized arrays.
+    #pragma warning(disable:4351)
+#endif // _WIN32
+
+namespace webrtc {
+static WebRtc_UWord32 levelFilter = kTraceDefault;
+
+// Construct On First Use idiom. Avoids "static initialization order fiasco".
+Trace* TraceImpl::StaticInstance(TraceCount inc, const TraceLevel level)
+{
+    // TODO (hellner): use atomic wrapper instead.
+    static volatile long theTraceCount = 0;
+    static Trace* volatile theTrace = NULL;
+
+    TraceCreate state = WEBRTC_TRACE_EXIST;
+
+    // Sanitys to avoid taking lock unless absolutely necessary (for
+    // performance reasons). inc == WEBRTC_TRACE_INC_NO_CREATE) implies that
+    // a message will be written to file.
+    if(level != kTraceAll && inc == WEBRTC_TRACE_INC_NO_CREATE)
+    {
+        if(!(level & levelFilter))
+        {
+            return NULL;
+        }
+    }
+
+#ifndef _WIN32
+    // TODO (pwestin): crtiSect is never reclaimed. Fix memory leak.
+    static CriticalSectionWrapper* crtiSect(
+        CriticalSectionWrapper::CreateCriticalSection());
+    CriticalSectionScoped lock(*crtiSect);
+
+    if(inc == WEBRTC_TRACE_INC_NO_CREATE && theTraceCount == 0)
+    {
+        return NULL;
+    }
+
+    if(inc == WEBRTC_TRACE_INC || inc == WEBRTC_TRACE_INC_NO_CREATE)
+    {
+        theTraceCount++;
+        if(theTraceCount == 1)
+        {
+            state = WEBRTC_TRACE_CREATE;
+        }
+    } else {
+        theTraceCount--;
+        if(theTraceCount == 0)
+        {
+            state = WEBRTC_TRACE_DESTROY;
+        }
+    }
+    if(state == WEBRTC_TRACE_CREATE)
+    {
+        theTrace = TraceImpl::CreateTrace();
+
+    } else if(state == WEBRTC_TRACE_DESTROY) {
+        Trace* oldValue = theTrace;
+        theTrace = NULL;
+        // The lock is held by the scoped critical section. Release the lock
+        // temporarily so that the trace can be safely deleted. If the lock
+        // was kept during the delete, e.g. creating and destroying the trace
+        // too quickly may lead to a deadlock.
+        // This is due to the fact that starting and stopping a ThreadWrapper
+        // thread will trigger writing of trace messages.
+        // TODO (hellner): remove the tight coupling with the thread
+        //                 implementation.
+        crtiSect->Leave();
+        if(oldValue)
+        {
+            delete static_cast<TraceImpl*>(oldValue);
+        }
+        // Re-aqcuire the lock.
+        crtiSect->Enter();
+        return NULL;
+    }
+#else  // _WIN32
+    if(inc == WEBRTC_TRACE_INC_NO_CREATE && theTraceCount == 0)
+    {
+        return NULL;
+    }
+    if(inc == WEBRTC_TRACE_INC_NO_CREATE)
+    {
+        if(1 == InterlockedIncrement(&theTraceCount))
+        {
+            // The trace has been destroyed by some other thread. Rollback.
+            InterlockedDecrement(&theTraceCount);
+            assert(false);
+            return NULL;
+        }
+        // Sanity to catch corrupt state.
+        if(theTrace == NULL)
+        {
+            assert(false);
+            InterlockedDecrement(&theTraceCount);
+            return NULL;
+        }
+    } else if(inc == WEBRTC_TRACE_INC) {
+        if(theTraceCount == 0)
+        {
+            state = WEBRTC_TRACE_CREATE;
+        } else {
+            if(1 == InterlockedIncrement(&theTraceCount))
+            {
+                // InterlockedDecrement because reference count should not be
+                // updated just yet (that's done when the trace is created).
+                InterlockedDecrement(&theTraceCount);
+                state = WEBRTC_TRACE_CREATE;
+            }
+        }
+    } else {
+        int newValue = InterlockedDecrement(&theTraceCount);
+        if(newValue == 0)
+        {
+            state = WEBRTC_TRACE_DESTROY;
+        }
+    }
+
+    if(state == WEBRTC_TRACE_CREATE)
+    {
+        // Create trace and let whichever thread finishes first assign its local
+        // copy to the global instance. All other threads reclaim their local
+        // copy.
+        Trace* newTrace = TraceImpl::CreateTrace();
+        if(1 == InterlockedIncrement(&theTraceCount))
+        {
+            Trace* oldValue = (Trace*)InterlockedExchangePointer(
+                reinterpret_cast<void* volatile*>(&theTrace), newTrace);
+            assert(oldValue == NULL);
+            assert(theTrace);
+        } else {
+            InterlockedDecrement(&theTraceCount);
+            if(newTrace)
+            {
+                delete static_cast<TraceImpl*>(newTrace);
+            }
+        }
+        return NULL;
+    } else if(state == WEBRTC_TRACE_DESTROY)
+    {
+        Trace* oldValue = (Trace*)InterlockedExchangePointer(
+            reinterpret_cast<void* volatile*>(&theTrace), NULL);
+        if(oldValue)
+        {
+            delete static_cast<TraceImpl*>(oldValue);
+        }
+        return NULL;
+    }
+#endif // #ifndef _WIN32
+    return theTrace;
+}
+
+void Trace::CreateTrace()
+{
+    TraceImpl::StaticInstance(WEBRTC_TRACE_INC);
+}
+
+void Trace::ReturnTrace()
+{
+    TraceImpl::StaticInstance(WEBRTC_TRACE_DEC);
+}
+
+TraceImpl* TraceImpl::GetTrace(const TraceLevel level)
+{
+    return (TraceImpl*)StaticInstance(WEBRTC_TRACE_INC_NO_CREATE, level);
+}
+
+Trace* TraceImpl::CreateTrace()
+{
+#if defined(_WIN32)
+    return new TraceWindows();
+#else
+    return new TraceLinux();
+#endif
+}
+
+TraceImpl::TraceImpl()
+    : _critsectInterface(*CriticalSectionWrapper::CreateCriticalSection()),
+      _callback(NULL),
+      _rowCountText(0),
+      _fileCountText(0),
+      _traceFile(*FileWrapper::Create()),
+      _thread(*ThreadWrapper::CreateThread(TraceImpl::Run, this,
+                                           kHighestPriority, "Trace")),
+      _event(*EventWrapper::Create()),
+      _critsectArray(*CriticalSectionWrapper::CreateCriticalSection()),
+      _nextFreeIdx(),
+      _level(),
+      _length(),
+      _messageQueue(),
+      _activeQueue(0)
+{
+    _nextFreeIdx[0] = 0;
+    _nextFreeIdx[1] = 0;
+
+    unsigned int tid = 0;
+    _thread.Start(tid);
+
+    for(int m = 0; m < WEBRTC_TRACE_NUM_ARRAY; m++)
+    {
+        for(int n = 0; n < WEBRTC_TRACE_MAX_QUEUE; n++)
+        {
+            _messageQueue[m][n] = new
+                WebRtc_Word8[WEBRTC_TRACE_MAX_MESSAGE_SIZE];
+        }
+    }
+}
+
+bool TraceImpl::StopThread()
+{
+    // Release the worker thread so that it can flush any lingering messages.
+    _event.Set();
+
+    // Allow 10 ms for pending messages to be flushed out.
+    // TODO (hellner): why not use condition variables to do this? Or let the
+    //                 worker thread die and let this thread flush remaining
+    //                 messages?
+#ifdef _WIN32
+    Sleep(10);
+#else
+    timespec t;
+    t.tv_sec = 0;
+    t.tv_nsec = 10*1000000;
+    nanosleep(&t,NULL);
+#endif
+
+    _thread.SetNotAlive();
+    // Make sure the thread finishes as quickly as possible (instead of having
+    // to wait for the timeout).
+    _event.Set();
+    bool stopped = _thread.Stop();
+
+    CriticalSectionScoped lock(_critsectInterface);
+    _traceFile.Flush();
+    _traceFile.CloseFile();
+    return stopped;
+}
+
+TraceImpl::~TraceImpl()
+{
+    StopThread();
+    delete &_event;
+    delete &_traceFile;
+    delete &_thread;
+    delete &_critsectInterface;
+    delete &_critsectArray;
+
+    for(int m = 0; m < WEBRTC_TRACE_NUM_ARRAY; m++)
+    {
+        for(int n = 0; n < WEBRTC_TRACE_MAX_QUEUE; n++)
+        {
+            delete [] _messageQueue[m][n];
+        }
+    }
+}
+
+WebRtc_Word32 TraceImpl::AddLevel(char* szMessage, const TraceLevel level) const
+{
+    switch (level)
+    {
+        case kTraceStateInfo:
+            sprintf (szMessage, "STATEINFO ; ");
+            break;
+        case kTraceWarning:
+            sprintf (szMessage, "WARNING   ; ");
+            break;
+        case kTraceError:
+            sprintf (szMessage, "ERROR     ; ");
+            break;
+        case kTraceCritical:
+            sprintf (szMessage, "CRITICAL  ; ");
+            break;
+        case kTraceInfo:
+            sprintf (szMessage, "DEBUGINFO ; ");
+            break;
+        case kTraceModuleCall:
+            sprintf (szMessage, "MODULECALL; ");
+            break;
+        case kTraceMemory:
+            sprintf (szMessage, "MEMORY    ; ");
+            break;
+        case kTraceTimer:
+            sprintf (szMessage, "TIMER     ; ");
+            break;
+        case kTraceStream:
+            sprintf (szMessage, "STREAM    ; ");
+            break;
+        case kTraceApiCall:
+            sprintf (szMessage, "APICALL   ; ");
+            break;
+        case kTraceDebug:
+            sprintf (szMessage, "DEBUG     ; ");
+            break;
+        default:
+            assert(false);
+            return 0;
+    }
+    // All messages are 12 characters.
+    return 12;
+}
+
+WebRtc_Word32 TraceImpl::AddModuleAndId(char* traceMessage,
+                                        const TraceModule module,
+                                        const WebRtc_Word32 id) const
+{
+    // Use long int to prevent problems with different definitions of
+    // WebRtc_Word32.
+    // TODO (hellner): is this actually a problem? If so, it should be better to
+    //                 clean up WebRtc_Word32
+    const long int idl = id;
+    if(idl != -1)
+    {
+        const unsigned long int idEngine = id>>16;
+        const unsigned long int idChannel = id & 0xffff;
+
+        switch (module)
+        {
+            case kTraceVoice:
+                sprintf(traceMessage, "       VOICE:%5ld %5ld;", idEngine,
+                        idChannel);
+                break;
+            case kTraceVideo:
+                sprintf(traceMessage, "       VIDEO:%5ld %5ld;", idEngine,
+                        idChannel);
+                break;
+            case kTraceUtility:
+                sprintf(traceMessage, "     UTILITY:%5ld %5ld;", idEngine,
+                        idChannel);
+                break;
+            case kTraceRtpRtcp:
+                sprintf(traceMessage, "    RTP/RTCP:%5ld %5ld;", idEngine,
+                        idChannel);
+                break;
+            case kTraceTransport:
+                sprintf(traceMessage, "   TRANSPORT:%5ld %5ld;", idEngine,
+                        idChannel);
+                break;
+            case kTraceAudioCoding:
+                sprintf(traceMessage, "AUDIO CODING:%5ld %5ld;", idEngine,
+                        idChannel);
+                break;
+            case kTraceSrtp:
+                sprintf(traceMessage, "        SRTP:%5ld %5ld;", idEngine,
+                        idChannel);
+                break;
+            case kTraceAudioMixerServer:
+                sprintf(traceMessage, " AUDIO MIX/S:%5ld %5ld;", idEngine,
+                        idChannel);
+                break;
+            case kTraceAudioMixerClient:
+                sprintf(traceMessage, " AUDIO MIX/C:%5ld %5ld;", idEngine,
+                        idChannel);
+                break;
+            case kTraceVideoCoding:
+                sprintf(traceMessage, "VIDEO CODING:%5ld %5ld;", idEngine,
+                        idChannel);
+                break;
+            case kTraceVideoMixer:
+                // Print sleep time and API call
+                sprintf(traceMessage, "   VIDEO MIX:%5ld %5ld;", idEngine,
+                        idChannel);
+                break;
+            case kTraceFile:
+                sprintf(traceMessage, "        FILE:%5ld %5ld;", idEngine,
+                        idChannel);
+                break;
+            case kTraceVqe:
+                sprintf(traceMessage, "         VQE:%5ld %5ld;", idEngine,
+                        idChannel);
+                break;
+            case kTraceAudioDevice:
+                sprintf(traceMessage, "AUDIO DEVICE:%5ld %5ld;", idEngine,
+                        idChannel);
+                break;
+            case kTraceVideoRenderer:
+                sprintf(traceMessage, "VIDEO RENDER:%5ld %5ld;", idEngine,
+                        idChannel);
+                break;
+            case kTraceVideoCapture:
+                sprintf(traceMessage, "VIDEO CAPTUR:%5ld %5ld;", idEngine,
+                        idChannel);
+                break;
+            case kTraceVideoPreocessing:
+                sprintf(traceMessage, "  VIDEO PROC:%5ld %5ld;", idEngine,
+                        idChannel);
+                break;
+            default:
+                assert(false);
+                return 0;
+        }
+    } else {
+        switch (module)
+        {
+            case kTraceVoice:
+                sprintf (traceMessage, "       VOICE:%11ld;", idl);
+                break;
+            case kTraceVideo:
+                sprintf (traceMessage, "       VIDEO:%11ld;", idl);
+                break;
+            case kTraceUtility:
+                sprintf (traceMessage, "     UTILITY:%11ld;", idl);
+                break;
+            case kTraceRtpRtcp:
+                sprintf (traceMessage, "    RTP/RTCP:%11ld;", idl);
+                break;
+            case kTraceTransport:
+                sprintf (traceMessage, "   TRANSPORT:%11ld;", idl);
+                break;
+            case kTraceAudioCoding:
+                sprintf (traceMessage, "AUDIO CODING:%11ld;", idl);
+                break;
+            case kTraceSrtp:
+                sprintf (traceMessage, "        SRTP:%11ld;", idl);
+                break;
+            case kTraceAudioMixerServer:
+                sprintf (traceMessage, " AUDIO MIX/S:%11ld;", idl);
+                break;
+            case kTraceAudioMixerClient:
+                sprintf (traceMessage, " AUDIO MIX/C:%11ld;", idl);
+                break;
+            case kTraceVideoCoding:
+                sprintf (traceMessage, "VIDEO CODING:%11ld;", idl);
+                break;
+            case kTraceVideoMixer:
+                sprintf (traceMessage, "   VIDEO MIX:%11ld;", idl);
+                break;
+            case kTraceFile:
+                sprintf (traceMessage, "        FILE:%11ld;", idl);
+                break;
+            case kTraceVqe:
+                sprintf (traceMessage, "         VQE:%11ld;", idl);
+                break;
+            case kTraceAudioDevice:
+                sprintf (traceMessage, "AUDIO DEVICE:%11ld;", idl);
+                break;
+            case kTraceVideoRenderer:
+                sprintf (traceMessage, "VIDEO RENDER:%11ld;", idl);
+                break;
+            case kTraceVideoCapture:
+                sprintf (traceMessage, "VIDEO CAPTUR:%11ld;", idl);
+                break;
+            case kTraceVideoPreocessing:
+                sprintf (traceMessage, "  VIDEO PROC:%11ld;", idl);
+                break;
+            default:
+                assert(false);
+                return 0;
+        }
+    }
+    // All messages are 25 characters.
+    return 25;
+}
+
+WebRtc_Word32 TraceImpl::SetTraceFileImpl(const WebRtc_Word8* fileNameUTF8,
+                                          const bool addFileCounter)
+{
+    CriticalSectionScoped lock(_critsectInterface);
+
+    _traceFile.Flush();
+    _traceFile.CloseFile();
+
+    if(fileNameUTF8)
+    {
+        if(addFileCounter)
+        {
+            _fileCountText = 1;
+
+            WebRtc_Word8 fileNameWithCounterUTF8[FileWrapper::kMaxFileNameSize];
+            CreateFileName(fileNameUTF8, fileNameWithCounterUTF8,
+                           _fileCountText);
+            if(_traceFile.OpenFile(fileNameWithCounterUTF8, false, false,
+                                   true) == -1)
+            {
+                return -1;
+            }
+        }else {
+            _fileCountText = 0;
+            if(_traceFile.OpenFile(fileNameUTF8, false, false, true) == -1)
+            {
+                return -1;
+            }
+        }
+    }
+    _rowCountText = 0;
+    return 0;
+}
+
+WebRtc_Word32 TraceImpl::TraceFileImpl(
+    WebRtc_Word8 fileNameUTF8[FileWrapper::kMaxFileNameSize])
+{
+    CriticalSectionScoped lock(_critsectInterface);
+    return _traceFile.FileName(fileNameUTF8, FileWrapper::kMaxFileNameSize);
+}
+
+WebRtc_Word32 TraceImpl::SetTraceCallbackImpl(TraceCallback* callback)
+{
+    CriticalSectionScoped lock(_critsectInterface);
+    _callback = callback;
+    return 0;
+}
+
+WebRtc_Word32 TraceImpl::AddMessage(
+    char* traceMessage,
+    const char msg[WEBRTC_TRACE_MAX_MESSAGE_SIZE],
+    const WebRtc_UWord16 writtenSoFar) const
+
+{
+    int length = 0;
+    if(writtenSoFar >= WEBRTC_TRACE_MAX_MESSAGE_SIZE)
+    {
+        return -1;
+    }
+    // - 2 to leave room for newline and NULL termination
+#ifdef _WIN32
+    length = _snprintf(traceMessage,
+                       WEBRTC_TRACE_MAX_MESSAGE_SIZE - writtenSoFar - 2,
+                       "%s",msg);
+    if(length < 0)
+    {
+        length = WEBRTC_TRACE_MAX_MESSAGE_SIZE - writtenSoFar - 2;
+        traceMessage[length] = 0;
+    }
+#else
+    length = snprintf(traceMessage,
+                      WEBRTC_TRACE_MAX_MESSAGE_SIZE-writtenSoFar-2, "%s",msg);
+    if(length < 0 || length > WEBRTC_TRACE_MAX_MESSAGE_SIZE-writtenSoFar - 2)
+    {
+        length = WEBRTC_TRACE_MAX_MESSAGE_SIZE - writtenSoFar - 2;
+        traceMessage[length] = 0;
+    }
+#endif
+    // Length with NULL termination.
+    return length+1;
+}
+
+void TraceImpl::AddMessageToList(
+    const char traceMessage[WEBRTC_TRACE_MAX_MESSAGE_SIZE],
+    const WebRtc_UWord16 length,
+    const TraceLevel level)
+{
+    CriticalSectionScoped lock(_critsectArray);
+
+    if(_nextFreeIdx[_activeQueue] >= WEBRTC_TRACE_MAX_QUEUE)
+    {
+        if( ! _traceFile.Open() &&
+            !_callback)
+        {
+            // Keep at least the last 1/4 of old messages when not logging.
+            // TODO (hellner): isn't this redundant. The user will make it known
+            //                 when to start logging. Why keep messages before
+            //                 that?
+            for(int n = 0; n < WEBRTC_TRACE_MAX_QUEUE/4; n++)
+            {
+                const int lastQuarterOffset = (3*WEBRTC_TRACE_MAX_QUEUE/4);
+                memcpy(_messageQueue[_activeQueue][n],
+                       _messageQueue[_activeQueue][n + lastQuarterOffset],
+                       WEBRTC_TRACE_MAX_MESSAGE_SIZE);
+            }
+            _nextFreeIdx[_activeQueue] = WEBRTC_TRACE_MAX_QUEUE/4;
+        } else {
+            // More messages are being written than there is room for in the
+            // buffer. Drop any new messages.
+            // TODO (hellner): its probably better to drop old messages instead
+            //                 of new ones. One step further: if this happens
+            //                 it's due to writing faster than what can be
+            //                 processed. Maybe modify the filter at this point.
+            //                 E.g. turn of STREAM.
+            return;
+        }
+    }
+
+    WebRtc_UWord16 idx = _nextFreeIdx[_activeQueue];
+    _nextFreeIdx[_activeQueue]++;
+
+    _level[_activeQueue][idx] = level;
+    _length[_activeQueue][idx] = length;
+    memcpy(_messageQueue[_activeQueue][idx], traceMessage, length);
+
+    if(_nextFreeIdx[_activeQueue] == WEBRTC_TRACE_MAX_QUEUE-1)
+    {
+        // Loggin more messages than can be worked off. Log a warning.
+        memcpy(_messageQueue[_activeQueue][_nextFreeIdx[_activeQueue]],
+               "WARNING MISSING TRACE MESSAGES\n", 32);
+        _nextFreeIdx[_activeQueue]++;
+    }
+}
+
+bool TraceImpl::Run(void* obj)
+{
+    return static_cast<TraceImpl*>(obj)->Process();
+}
+
+bool TraceImpl::Process()
+{
+    if(_event.Wait(1000) == kEventSignaled)
+    {
+        if(_traceFile.Open() || _callback)
+        {
+            // File mode (not calback mode).
+            WriteToFile();
+        }
+    } else {
+        _traceFile.Flush();
+    }
+    return true;
+}
+
+void TraceImpl::WriteToFile()
+{
+    WebRtc_UWord8 localQueueActive = 0;
+    WebRtc_UWord16 localNextFreeIdx = 0;
+
+    // There are two buffer. One for reading (for writing to file) and one for
+    // writing (for storing new messages). Let new messages be posted to the
+    // unused buffer so that the current buffer can be flushed safely.
+    {
+        CriticalSectionScoped lock(_critsectArray);
+        localNextFreeIdx = _nextFreeIdx[_activeQueue];
+        _nextFreeIdx[_activeQueue] = 0;
+        localQueueActive = _activeQueue;
+        if(_activeQueue == 0)
+        {
+            _activeQueue = 1;
+        } else
+        {
+            _activeQueue = 0;
+        }
+    }
+    if(localNextFreeIdx == 0)
+    {
+        return;
+    }
+
+    CriticalSectionScoped lock(_critsectInterface);
+
+    for(WebRtc_UWord16 idx = 0; idx <localNextFreeIdx; idx++)
+    {
+        TraceLevel localLevel = _level[localQueueActive][idx];
+        if(_callback)
+        {
+            _callback->Print(localLevel, _messageQueue[localQueueActive][idx],
+                             _length[localQueueActive][idx]);
+        }
+        if(_traceFile.Open())
+        {
+            if(_rowCountText > WEBRTC_TRACE_MAX_FILE_SIZE)
+            {
+                // wrap file
+                _rowCountText = 0;
+                _traceFile.Flush();
+
+                if(_fileCountText == 0)
+                {
+                    _traceFile.Rewind();
+                } else
+                {
+                    WebRtc_Word8 oldFileName[FileWrapper::kMaxFileNameSize];
+                    WebRtc_Word8 newFileName[FileWrapper::kMaxFileNameSize];
+
+                    // get current name
+                    _traceFile.FileName(oldFileName,
+                                        FileWrapper::kMaxFileNameSize);
+                    _traceFile.CloseFile();
+
+                    _fileCountText++;
+
+                    UpdateFileName(oldFileName, newFileName, _fileCountText);
+
+                    if(_traceFile.OpenFile(newFileName, false, false,
+                                           true) == -1)
+                    {
+                        return;
+                    }
+                }
+            }
+            if(_rowCountText ==  0)
+            {
+                WebRtc_Word8 message[WEBRTC_TRACE_MAX_MESSAGE_SIZE + 1];
+                WebRtc_Word32 length = AddDateTimeInfo(message);
+                if(length != -1)
+                {
+                    message[length] = 0;
+                    message[length-1] = '\n';
+                    _traceFile.Write(message, length);
+                    _rowCountText++;
+                }
+                length = AddBuildInfo(message);
+                if(length != -1)
+                {
+                    message[length+1] = 0;
+                    message[length] = '\n';
+                    message[length-1] = '\n';
+                    _traceFile.Write(message, length+1);
+                    _rowCountText++;
+                    _rowCountText++;
+                }
+            }
+            WebRtc_UWord16 length = _length[localQueueActive][idx];
+            _messageQueue[localQueueActive][idx][length] = 0;
+            _messageQueue[localQueueActive][idx][length-1] = '\n';
+            _traceFile.Write(_messageQueue[localQueueActive][idx], length);
+            _rowCountText++;
+        }
+    }
+}
+
+void TraceImpl::AddImpl(const TraceLevel level, const TraceModule module,
+                        const WebRtc_Word32 id,
+                        const char msg[WEBRTC_TRACE_MAX_MESSAGE_SIZE])
+{
+    if (TraceCheck(level))
+    {
+        char traceMessage[WEBRTC_TRACE_MAX_MESSAGE_SIZE];
+        char* meassagePtr = traceMessage;
+
+        WebRtc_Word32 len = 0;
+        WebRtc_Word32 ackLen = 0;
+
+        len = AddLevel(meassagePtr, level);
+        if(len == -1)
+        {
+            return;
+        }
+        meassagePtr += len;
+        ackLen += len;
+
+        len = AddTime(meassagePtr, level);
+        if(len == -1)
+        {
+            return;
+        }
+        meassagePtr += len;
+        ackLen += len;
+
+        len = AddModuleAndId(meassagePtr, module, id);
+        if(len == -1)
+        {
+            return;
+        }
+        meassagePtr += len;
+        ackLen += len;
+
+        len = AddThreadId(meassagePtr);
+        if(len == -1)
+        {
+            return;
+        }
+        meassagePtr += len;
+        ackLen += len;
+
+        len = AddMessage(meassagePtr, msg, (WebRtc_UWord16)ackLen);
+        if(len == -1)
+        {
+            return;
+        }
+        ackLen += len;
+        AddMessageToList(traceMessage,(WebRtc_UWord16)ackLen, level);
+
+        // Make sure that messages are written as soon as possible.
+        _event.Set();
+    }
+}
+
+bool TraceImpl::TraceCheck(const TraceLevel level) const
+{
+    return (level & levelFilter)? true:false;
+}
+
+bool TraceImpl::UpdateFileName(
+    const WebRtc_Word8 fileNameUTF8[FileWrapper::kMaxFileNameSize],
+    WebRtc_Word8 fileNameWithCounterUTF8[FileWrapper::kMaxFileNameSize],
+    const WebRtc_UWord32 newCount) const
+{
+    WebRtc_Word32 length = (WebRtc_Word32)strlen(fileNameUTF8);
+    if(length < 0)
+    {
+        return false;
+    }
+
+    WebRtc_Word32 lengthWithoutFileEnding = length-1;
+    while(lengthWithoutFileEnding > 0)
+    {
+        if(fileNameUTF8[lengthWithoutFileEnding] == '.')
+        {
+            break;
+        } else {
+            lengthWithoutFileEnding--;
+        }
+    }
+    if(lengthWithoutFileEnding == 0)
+    {
+        lengthWithoutFileEnding = length;
+    }
+    WebRtc_Word32 lengthTo_ = lengthWithoutFileEnding - 1;
+    while(lengthTo_ > 0)
+    {
+        if(fileNameUTF8[lengthTo_] == '_')
+        {
+            break;
+        } else {
+            lengthTo_--;
+        }
+    }
+
+    memcpy(fileNameWithCounterUTF8, fileNameUTF8, lengthTo_);
+    sprintf(fileNameWithCounterUTF8+lengthTo_, "_%lu%s", newCount,
+            fileNameUTF8+lengthWithoutFileEnding);
+    return true;
+}
+
+bool TraceImpl::CreateFileName(
+    const WebRtc_Word8 fileNameUTF8[FileWrapper::kMaxFileNameSize],
+    WebRtc_Word8 fileNameWithCounterUTF8[FileWrapper::kMaxFileNameSize],
+    const WebRtc_UWord32 newCount) const
+{
+    WebRtc_Word32 length = (WebRtc_Word32)strlen(fileNameUTF8);
+    if(length < 0)
+    {
+        return false;
+    }
+
+    WebRtc_Word32 lengthWithoutFileEnding = length-1;
+    while(lengthWithoutFileEnding > 0)
+    {
+        if(fileNameUTF8[lengthWithoutFileEnding] == '.')
+        {
+            break;
+        }else
+        {
+            lengthWithoutFileEnding--;
+        }
+    }
+    if(lengthWithoutFileEnding == 0)
+    {
+        lengthWithoutFileEnding = length;
+    }
+    memcpy(fileNameWithCounterUTF8, fileNameUTF8, lengthWithoutFileEnding);
+    sprintf(fileNameWithCounterUTF8+lengthWithoutFileEnding, "_%lu%s",
+            newCount, fileNameUTF8+lengthWithoutFileEnding);
+    return true;
+}
+
+WebRtc_Word32 Trace::SetLevelFilter(WebRtc_UWord32 filter)
+{
+    levelFilter = filter;
+    return 0;
+};
+
+WebRtc_Word32 Trace::LevelFilter(WebRtc_UWord32& filter)
+{
+    filter = levelFilter;
+    return 0;
+};
+
+WebRtc_Word32 Trace::TraceFile(WebRtc_Word8 fileName[FileWrapper::kMaxFileNameSize])
+{
+    TraceImpl* trace = TraceImpl::GetTrace();
+    if(trace)
+    {
+        int retVal = trace->TraceFileImpl(fileName);
+        ReturnTrace();
+        return retVal;
+    }
+    return -1;
+}
+
+WebRtc_Word32 Trace::SetTraceFile(const WebRtc_Word8* fileName,
+                                  const bool addFileCounter)
+{
+    TraceImpl* trace = TraceImpl::GetTrace();
+    if(trace)
+    {
+        int retVal = trace->SetTraceFileImpl(fileName, addFileCounter);
+        ReturnTrace();
+        return retVal;
+    }
+    return -1;
+}
+
+WebRtc_Word32 Trace::SetTraceCallback(TraceCallback* callback)
+{
+    TraceImpl* trace = TraceImpl::GetTrace();
+    if(trace)
+    {
+        int retVal = trace->SetTraceCallbackImpl(callback);
+        ReturnTrace();
+        return retVal;
+    }
+    return -1;
+}
+
+void Trace::Add(const TraceLevel level, const TraceModule module,
+                const WebRtc_Word32 id, const char* msg, ...)
+
+{
+    TraceImpl* trace = TraceImpl::GetTrace(level);
+    if(trace)
+    {
+        if(trace->TraceCheck(level))
+        {
+            char tempBuff[WEBRTC_TRACE_MAX_MESSAGE_SIZE];
+            char* buff = 0;
+            if(msg)
+            {
+                va_list args;
+                va_start(args, msg);
+#ifdef _WIN32
+                _vsnprintf(tempBuff,WEBRTC_TRACE_MAX_MESSAGE_SIZE-1,msg,args);
+#else
+                vsnprintf(tempBuff,WEBRTC_TRACE_MAX_MESSAGE_SIZE-1,msg,args);
+#endif
+                va_end(args);
+                buff = tempBuff;
+            }
+            trace->AddImpl(level, module, id, buff);
+        }
+        ReturnTrace();
+    }
+}
+} // namespace webrtc