|  | /* | 
|  | *  Copyright (c) 2012 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_win.h" | 
|  | #else | 
|  | #include <stdio.h> | 
|  | #include <stdarg.h> | 
|  | #include "trace_posix.h" | 
|  | #endif // _WIN32 | 
|  |  | 
|  | #include "system_wrappers/interface/sleep.h" | 
|  |  | 
|  | #define KEY_LEN_CHARS 31 | 
|  |  | 
|  | #ifdef _WIN32 | 
|  | #pragma warning(disable:4355) | 
|  | #endif // _WIN32 | 
|  |  | 
|  | namespace webrtc { | 
|  | static WebRtc_UWord32 levelFilter = kTraceDefault; | 
|  |  | 
|  | // Construct On First Use idiom. Avoids "static initialization order fiasco". | 
|  | TraceImpl* TraceImpl::StaticInstance(CountOperation count_operation, | 
|  | const TraceLevel level) | 
|  | { | 
|  | // Sanities to avoid taking lock unless absolutely necessary (for | 
|  | // performance reasons). | 
|  | // count_operation == kAddRefNoCreate implies that a message will be | 
|  | // written to file. | 
|  | if((level != kTraceAll) && (count_operation == kAddRefNoCreate)) | 
|  | { | 
|  | if(!(level & levelFilter)) | 
|  | { | 
|  | return NULL; | 
|  | } | 
|  | } | 
|  | TraceImpl* impl = | 
|  | GetStaticInstance<TraceImpl>(count_operation); | 
|  | return impl; | 
|  | } | 
|  |  | 
|  | TraceImpl* TraceImpl::GetTrace(const TraceLevel level) | 
|  | { | 
|  | return StaticInstance(kAddRefNoCreate, level); | 
|  | } | 
|  |  | 
|  | TraceImpl* TraceImpl::CreateInstance() | 
|  | { | 
|  | #if defined(_WIN32) | 
|  | return new TraceWindows(); | 
|  | #else | 
|  | return new TracePosix(); | 
|  | #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 | 
|  | char[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? | 
|  | SleepMs(10); | 
|  |  | 
|  | _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::AddThreadId(char* traceMessage) const { | 
|  | WebRtc_UWord32 threadId = ThreadWrapper::GetThreadId(); | 
|  | // Messages is 12 characters. | 
|  | return sprintf(traceMessage, "%10u; ", threadId); | 
|  | } | 
|  |  | 
|  | 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; | 
|  | const int kMessageLength = 25; | 
|  | if(idl != -1) | 
|  | { | 
|  | const unsigned long int idEngine = id>>16; | 
|  | const unsigned long int idChannel = id & 0xffff; | 
|  |  | 
|  | switch (module) | 
|  | { | 
|  | case kTraceUndefined: | 
|  | // Add the appropriate amount of whitespace. | 
|  | memset(traceMessage, ' ', kMessageLength); | 
|  | break; | 
|  | 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 kTraceAudioProcessing: | 
|  | sprintf(traceMessage, "  AUDIO PROC:%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; | 
|  | } | 
|  | } else { | 
|  | switch (module) | 
|  | { | 
|  | case kTraceUndefined: | 
|  | // Add the appropriate amount of whitespace. | 
|  | memset(traceMessage, ' ', kMessageLength); | 
|  | break; | 
|  | 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 kTraceAudioProcessing: | 
|  | sprintf (traceMessage, "  AUDIO PROC:%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; | 
|  | } | 
|  | } | 
|  | return kMessageLength; | 
|  | } | 
|  |  | 
|  | WebRtc_Word32 TraceImpl::SetTraceFileImpl(const char* fileNameUTF8, | 
|  | const bool addFileCounter) | 
|  | { | 
|  | CriticalSectionScoped lock(_critsectInterface); | 
|  |  | 
|  | _traceFile.Flush(); | 
|  | _traceFile.CloseFile(); | 
|  |  | 
|  | if(fileNameUTF8) | 
|  | { | 
|  | if(addFileCounter) | 
|  | { | 
|  | _fileCountText = 1; | 
|  |  | 
|  | char 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( | 
|  | char 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) { | 
|  | #ifdef WEBRTC_DIRECT_TRACE | 
|  | if (_callback) { | 
|  | _callback->Print(level, traceMessage, length); | 
|  | } | 
|  | return; | 
|  | #endif | 
|  |  | 
|  | 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) | 
|  | { | 
|  | // Logging more messages than can be worked off. Log a warning. | 
|  | const char warning_msg[] = "WARNING MISSING TRACE MESSAGES\n"; | 
|  | _level[_activeQueue][_nextFreeIdx[_activeQueue]] = kTraceWarning; | 
|  | _length[_activeQueue][_nextFreeIdx[_activeQueue]] = strlen(warning_msg); | 
|  | memcpy(_messageQueue[_activeQueue][_nextFreeIdx[_activeQueue]], | 
|  | warning_msg, strlen(warning_msg)); | 
|  | _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 | 
|  | { | 
|  | char oldFileName[FileWrapper::kMaxFileNameSize]; | 
|  | char 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) | 
|  | { | 
|  | char 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* messagePtr = traceMessage; | 
|  |  | 
|  | WebRtc_Word32 len = 0; | 
|  | WebRtc_Word32 ackLen = 0; | 
|  |  | 
|  | len = AddLevel(messagePtr, level); | 
|  | if(len == -1) | 
|  | { | 
|  | return; | 
|  | } | 
|  | messagePtr += len; | 
|  | ackLen += len; | 
|  |  | 
|  | len = AddTime(messagePtr, level); | 
|  | if(len == -1) | 
|  | { | 
|  | return; | 
|  | } | 
|  | messagePtr += len; | 
|  | ackLen += len; | 
|  |  | 
|  | len = AddModuleAndId(messagePtr, module, id); | 
|  | if(len == -1) | 
|  | { | 
|  | return; | 
|  | } | 
|  | messagePtr += len; | 
|  | ackLen += len; | 
|  |  | 
|  | len = AddThreadId(messagePtr); | 
|  | if(len < 0) | 
|  | { | 
|  | return; | 
|  | } | 
|  | messagePtr += len; | 
|  | ackLen += len; | 
|  |  | 
|  | len = AddMessage(messagePtr, 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 char fileNameUTF8[FileWrapper::kMaxFileNameSize], | 
|  | char 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", | 
|  | static_cast<long unsigned int> (newCount), | 
|  | fileNameUTF8+lengthWithoutFileEnding); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool TraceImpl::CreateFileName( | 
|  | const char fileNameUTF8[FileWrapper::kMaxFileNameSize], | 
|  | char 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", | 
|  | static_cast<long unsigned int> (newCount), | 
|  | fileNameUTF8+lengthWithoutFileEnding); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | void Trace::CreateTrace() | 
|  | { | 
|  | TraceImpl::StaticInstance(kAddRef); | 
|  | } | 
|  |  | 
|  | void Trace::ReturnTrace() | 
|  | { | 
|  | TraceImpl::StaticInstance(kRelease); | 
|  | } | 
|  |  | 
|  | 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(char fileName[FileWrapper::kMaxFileNameSize]) | 
|  | { | 
|  | TraceImpl* trace = TraceImpl::GetTrace(); | 
|  | if(trace) | 
|  | { | 
|  | int retVal = trace->TraceFileImpl(fileName); | 
|  | ReturnTrace(); | 
|  | return retVal; | 
|  | } | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | WebRtc_Word32 Trace::SetTraceFile(const char* 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 |