1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 
5 #include "WebRtcLog.h"
6 
7 #include "mozilla/Logging.h"
8 #include "mozilla/StaticPtr.h"
9 #include "prenv.h"
10 #include "common_types.h"
11 #include "rtc_base/logging.h"
12 
13 #include "nscore.h"
14 #include "nsString.h"
15 #include "nsXULAppAPI.h"
16 #include "mozilla/Preferences.h"
17 
18 #include "nsIFile.h"
19 #include "nsDirectoryServiceUtils.h"
20 #include "nsDirectoryServiceDefs.h"
21 #include "nsNativeCharsetUtils.h"
22 
23 using mozilla::LogLevel;
24 
25 #if defined(ANDROID)
26 static const char* default_tmp_dir = "/dev/null";
27 static const char* default_log_name = "nspr";
28 #else  // Assume a POSIX environment
29 constexpr auto default_log_name = "WebRTC.log"_ns;
30 #endif
31 
32 static mozilla::LazyLogModule sWebRtcLog("webrtc_trace");
33 static mozilla::LazyLogModule sLogAEC("AEC");
34 
35 class LogSinkImpl : public rtc::LogSink {
36  public:
LogSinkImpl()37   LogSinkImpl() {}
38 
39  private:
OnLogMessage(const std::string & message)40   void OnLogMessage(const std::string& message) override {
41     MOZ_LOG(sWebRtcLog, LogLevel::Debug, ("%s", message.data()));
42   }
43 };
44 
45 // For RTC_LOG()
46 static mozilla::StaticAutoPtr<LogSinkImpl> sSink;
47 
GetWebRtcLogPrefs()48 void GetWebRtcLogPrefs() {
49   rtc::LogMessage::set_aec_debug_size(
50       mozilla::Preferences::GetUint("media.webrtc.debug.aec_dump_max_size"));
51 }
52 
CheckOverrides()53 mozilla::LogLevel CheckOverrides() {
54   mozilla::LogModule* log_info = sWebRtcLog;
55   mozilla::LogLevel log_level = log_info->Level();
56 
57   log_info = sLogAEC;
58   if (sLogAEC && (log_info->Level() != mozilla::LogLevel::Disabled)) {
59     rtc::LogMessage::set_aec_debug(true);
60   }
61 
62   return log_level;
63 }
64 
ConfigWebRtcLog(mozilla::LogLevel level)65 void ConfigWebRtcLog(mozilla::LogLevel level) {
66   rtc::LoggingSeverity log_level;
67   switch (level) {
68     case mozilla::LogLevel::Verbose:
69       log_level = rtc::LoggingSeverity::LS_VERBOSE;
70       break;
71     case mozilla::LogLevel::Debug:
72     case mozilla::LogLevel::Info:
73       log_level = rtc::LoggingSeverity::LS_INFO;
74       break;
75     case mozilla::LogLevel::Warning:
76       log_level = rtc::LoggingSeverity::LS_WARNING;
77       break;
78     case mozilla::LogLevel::Error:
79       log_level = rtc::LoggingSeverity::LS_ERROR;
80       break;
81     case mozilla::LogLevel::Disabled:
82       log_level = rtc::LoggingSeverity::LS_NONE;
83       break;
84     default:
85       MOZ_ASSERT(false);
86       break;
87   }
88   rtc::LogMessage::LogToDebug(log_level);
89   if (level != mozilla::LogLevel::Disabled) {
90     // always capture LOG(...) << ... logging in webrtc.org code to nspr logs
91     if (!sSink) {
92       sSink = new LogSinkImpl();
93       rtc::LogMessage::AddLogToStream(sSink, log_level);
94       // it's ok if this leaks to program end
95     }
96   } else if (sSink) {
97     rtc::LogMessage::RemoveLogToStream(sSink);
98     sSink = nullptr;
99   }
100 }
101 
StartWebRtcLog(mozilla::LogLevel log_level)102 void StartWebRtcLog(mozilla::LogLevel log_level) {
103   if (log_level == mozilla::LogLevel::Disabled) {
104     return;
105   }
106 
107   GetWebRtcLogPrefs();
108   mozilla::LogLevel level = CheckOverrides();
109 
110   ConfigWebRtcLog(level);
111 }
112 
EnableWebRtcLog()113 void EnableWebRtcLog() {
114   GetWebRtcLogPrefs();
115   mozilla::LogLevel level = CheckOverrides();
116   ConfigWebRtcLog(level);
117 }
118 
119 // Called when we destroy the singletons from PeerConnectionCtx or if the
120 // user changes logging in about:webrtc
StopWebRtcLog()121 void StopWebRtcLog() {
122   if (sSink) {
123     rtc::LogMessage::RemoveLogToStream(sSink);
124     sSink = nullptr;
125   }
126 }
127 
ConfigAecLog()128 nsCString ConfigAecLog() {
129   nsCString aecLogDir;
130   if (rtc::LogMessage::aec_debug()) {
131     return ""_ns;
132   }
133 #if defined(ANDROID)
134   aecLogDir.Assign(default_tmp_dir);
135 #else
136   nsCOMPtr<nsIFile> tempDir;
137   nsresult rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(tempDir));
138   if (NS_SUCCEEDED(rv)) {
139 #  ifdef XP_WIN
140     // WebRTC wants a path encoded in the native charset, not UTF-8.
141     nsAutoString temp;
142     tempDir->GetPath(temp);
143     NS_CopyUnicodeToNative(temp, aecLogDir);
144 #  else
145     tempDir->GetNativePath(aecLogDir);
146 #  endif
147   }
148 #endif
149   rtc::LogMessage::set_aec_debug_filename(aecLogDir.get());
150 
151   return aecLogDir;
152 }
153 
StartAecLog()154 nsCString StartAecLog() {
155   nsCString aecLogDir;
156   if (rtc::LogMessage::aec_debug()) {
157     return ""_ns;
158   }
159 
160   GetWebRtcLogPrefs();
161   CheckOverrides();
162   aecLogDir = ConfigAecLog();
163 
164   rtc::LogMessage::set_aec_debug(true);
165 
166   return aecLogDir;
167 }
168 
StopAecLog()169 void StopAecLog() { rtc::LogMessage::set_aec_debug(false); }
170