summaryrefslogtreecommitdiffstats
path: root/dom/media/webrtc/common/browser_logging/WebRtcLog.cpp
blob: ae5aac8022e43fdb1908180804a7cbfce649768a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "WebRtcLog.h"

#include "nsThreadUtils.h"
#include "mozilla/Logging.h"
#include "rtc_base/logging.h"

#include "nscore.h"
#include "nsStringFwd.h"
#include "nsXULAppAPI.h"
#include "mozilla/Preferences.h"

#include "nsIFile.h"
#include "nsDirectoryServiceUtils.h"
#include "nsDirectoryServiceDefs.h"

#ifdef XP_WIN
#  include "nsNativeCharsetUtils.h"
#endif

using mozilla::LogLevel;

#define WEBRTC_LOG_MODULE_NAME "webrtc_trace"
#define WEBRTC_LOG_PREF "logging." WEBRTC_LOG_MODULE_NAME
static mozilla::LazyLogModule sWebRtcLog(WEBRTC_LOG_MODULE_NAME);

static rtc::LoggingSeverity LevelToSeverity(mozilla::LogLevel aLevel) {
  switch (aLevel) {
    case mozilla::LogLevel::Verbose:
      return rtc::LoggingSeverity::LS_VERBOSE;
    case mozilla::LogLevel::Debug:
    case mozilla::LogLevel::Info:
      return rtc::LoggingSeverity::LS_INFO;
    case mozilla::LogLevel::Warning:
      return rtc::LoggingSeverity::LS_WARNING;
    case mozilla::LogLevel::Error:
      return rtc::LoggingSeverity::LS_ERROR;
    case mozilla::LogLevel::Disabled:
      return rtc::LoggingSeverity::LS_NONE;
  }
  MOZ_ASSERT_UNREACHABLE("Unexpected log level");
  return rtc::LoggingSeverity::LS_NONE;
}

static LogLevel SeverityToLevel(rtc::LoggingSeverity aSeverity) {
  switch (aSeverity) {
    case rtc::LoggingSeverity::LS_VERBOSE:
      return mozilla::LogLevel::Verbose;
    case rtc::LoggingSeverity::LS_INFO:
      return mozilla::LogLevel::Debug;
    case rtc::LoggingSeverity::LS_WARNING:
      return mozilla::LogLevel::Warning;
    case rtc::LoggingSeverity::LS_ERROR:
      return mozilla::LogLevel::Error;
    case rtc::LoggingSeverity::LS_NONE:
      return mozilla::LogLevel::Disabled;
  }
  MOZ_ASSERT_UNREACHABLE("Unexpected severity");
  return LogLevel::Disabled;
}

/**
 * Implementation of rtc::LogSink that forwards RTC_LOG() to MOZ_LOG().
 */
class LogSinkImpl : public WebrtcLogSinkHandle, public rtc::LogSink {
  NS_INLINE_DECL_REFCOUNTING(LogSinkImpl, override)

 public:
  static already_AddRefed<WebrtcLogSinkHandle> EnsureLogSink() {
    mozilla::AssertIsOnMainThread();
    if (sSingleton) {
      return do_AddRef(sSingleton);
    }
    return mozilla::MakeAndAddRef<LogSinkImpl>();
  }

  static void OnPrefChanged(const char* aPref, void* aData) {
    mozilla::AssertIsOnMainThread();
    MOZ_ASSERT(strcmp(aPref, WEBRTC_LOG_PREF) == 0);
    MOZ_ASSERT(aData == sSingleton);

    // Bounce to main thread again so the LogModule can settle on the new level
    // via its own observer.
    NS_DispatchToMainThread(mozilla::NewRunnableMethod(
        __func__, sSingleton, &LogSinkImpl::UpdateLogLevels));
  }

  LogSinkImpl() {
    mozilla::AssertIsOnMainThread();
    MOZ_RELEASE_ASSERT(!sSingleton);

    rtc::LogMessage::AddLogToStream(this, LevelToSeverity(mLevel));
    sSingleton = this;

    mozilla::Preferences::RegisterCallbackAndCall(&LogSinkImpl::OnPrefChanged,
                                                  WEBRTC_LOG_PREF, this);
  }

 private:
  ~LogSinkImpl() {
    mozilla::AssertIsOnMainThread();
    MOZ_RELEASE_ASSERT(sSingleton == this);

    mozilla::Preferences::UnregisterCallback(&LogSinkImpl::OnPrefChanged,
                                             WEBRTC_LOG_PREF, this);
    rtc::LogMessage::RemoveLogToStream(this);
    sSingleton = nullptr;
  }

  void UpdateLogLevels() {
    mozilla::AssertIsOnMainThread();
    mozilla::LogModule* webrtcModule = sWebRtcLog;
    mozilla::LogLevel webrtcLevel = webrtcModule->Level();

    if (webrtcLevel == mLevel) {
      return;
    }

    mLevel = webrtcLevel;

    rtc::LogMessage::RemoveLogToStream(this);
    rtc::LogMessage::AddLogToStream(this, LevelToSeverity(mLevel));
  }

  void OnLogMessage(const rtc::LogLineRef& aLogLine) override {
    MOZ_LOG(sWebRtcLog, SeverityToLevel(aLogLine.severity()),
            ("%s", aLogLine.DefaultLogLine().data()));
  }

  void OnLogMessage(const std::string&) override {
    MOZ_CRASH(
        "Called overriden OnLogMessage that is inexplicably pure virtual");
  }

  static LogSinkImpl* sSingleton MOZ_GUARDED_BY(mozilla::sMainThreadCapability);
  LogLevel mLevel MOZ_GUARDED_BY(mozilla::sMainThreadCapability) =
      LogLevel::Disabled;
};

LogSinkImpl* LogSinkImpl::sSingleton = nullptr;

already_AddRefed<WebrtcLogSinkHandle> EnsureWebrtcLogging() {
  mozilla::AssertIsOnMainThread();
  return LogSinkImpl::EnsureLogSink();
}

nsCString ConfigAecLog() {
  nsCString aecLogDir;
  if (rtc::LogMessage::aec_debug()) {
    return ""_ns;
  }
#if defined(ANDROID)
  const char* default_tmp_dir = "/dev/null";
  aecLogDir.Assign(default_tmp_dir);
#else
  nsCOMPtr<nsIFile> tempDir;
  nsresult rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(tempDir));
  if (NS_SUCCEEDED(rv)) {
#  ifdef XP_WIN
    // WebRTC wants a path encoded in the native charset, not UTF-8.
    nsAutoString temp;
    tempDir->GetPath(temp);
    NS_CopyUnicodeToNative(temp, aecLogDir);
#  else
    tempDir->GetNativePath(aecLogDir);
#  endif
  }
#endif
  rtc::LogMessage::set_aec_debug_filename(aecLogDir.get());

  return aecLogDir;
}

nsCString StartAecLog() {
  nsCString aecLogDir;
  if (rtc::LogMessage::aec_debug()) {
    return ""_ns;
  }

  aecLogDir = ConfigAecLog();

  rtc::LogMessage::set_aec_debug(true);

  return aecLogDir;
}

void StopAecLog() { rtc::LogMessage::set_aec_debug(false); }