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