Line data Source code
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 file,
3 : * You can obtain one at http://mozilla.org/MPL/2.0/. */
4 :
5 : #include "WebrtcGlobalInformation.h"
6 : #include "mozilla/media/webrtc/WebrtcGlobal.h"
7 : #include "WebrtcGlobalChild.h"
8 : #include "WebrtcGlobalParent.h"
9 :
10 : #include <deque>
11 : #include <string>
12 : #include <algorithm>
13 : #include <vector>
14 : #include <map>
15 : #include <queue>
16 :
17 : #include "CSFLog.h"
18 : #include "WebRtcLog.h"
19 : #include "mozilla/dom/WebrtcGlobalInformationBinding.h"
20 : #include "mozilla/dom/ContentChild.h"
21 :
22 : #include "nsAutoPtr.h"
23 : #include "nsNetCID.h" // NS_SOCKETTRANSPORTSERVICE_CONTRACTID
24 : #include "nsServiceManagerUtils.h" // do_GetService
25 : #include "mozilla/ErrorResult.h"
26 : #include "mozilla/Vector.h"
27 : #include "nsProxyRelease.h"
28 : #include "mozilla/Telemetry.h"
29 : #include "mozilla/Unused.h"
30 : #include "mozilla/StaticMutex.h"
31 : #include "mozilla/RefPtr.h"
32 :
33 : #include "rlogconnector.h"
34 : #include "runnable_utils.h"
35 : #include "PeerConnectionCtx.h"
36 : #include "PeerConnectionImpl.h"
37 : #include "webrtc/system_wrappers/include/trace.h"
38 :
39 : static const char* logTag = "WebrtcGlobalInformation";
40 :
41 : namespace mozilla {
42 : namespace dom {
43 :
44 : typedef Vector<nsAutoPtr<RTCStatsQuery>> RTCStatsQueries;
45 : typedef nsTArray<RTCStatsReportInternal> Stats;
46 :
47 : template<class Request, typename Callback,
48 : typename Result, typename QueryParam>
49 0 : class RequestManager
50 : {
51 : public:
52 :
53 0 : static Request* Create(Callback& aCallback, QueryParam& aParam)
54 : {
55 0 : mozilla::StaticMutexAutoLock lock(sMutex);
56 :
57 0 : int id = ++sLastRequestId;
58 : auto result = sRequests.insert(
59 0 : std::make_pair(id, Request(id, aCallback, aParam)));
60 :
61 0 : if (!result.second) {
62 0 : return nullptr;
63 : }
64 :
65 0 : return &result.first->second;
66 : }
67 :
68 0 : static void Delete(int aId)
69 : {
70 0 : mozilla::StaticMutexAutoLock lock(sMutex);
71 0 : sRequests.erase(aId);
72 0 : }
73 :
74 0 : static Request* Get(int aId)
75 : {
76 0 : mozilla::StaticMutexAutoLock lock(sMutex);
77 0 : auto r = sRequests.find(aId);
78 :
79 0 : if (r == sRequests.end()) {
80 0 : return nullptr;
81 : }
82 :
83 0 : return &r->second;
84 : }
85 :
86 : Result mResult;
87 : std::queue<RefPtr<WebrtcGlobalParent>> mContactList;
88 : const int mRequestId;
89 :
90 0 : RefPtr<WebrtcGlobalParent> GetNextParent()
91 : {
92 0 : while (!mContactList.empty()) {
93 0 : RefPtr<WebrtcGlobalParent> next = mContactList.front();
94 0 : mContactList.pop();
95 0 : if (next->IsActive()) {
96 0 : return next;
97 : }
98 : }
99 :
100 0 : return nullptr;
101 : }
102 :
103 0 : void Complete()
104 : {
105 0 : ErrorResult rv;
106 0 : mCallback.get()->Call(mResult, rv);
107 :
108 0 : if (rv.Failed()) {
109 0 : CSFLogError(logTag, "Error firing stats observer callback");
110 : }
111 0 : }
112 :
113 : protected:
114 : // The mutex is used to protect two related operations involving the sRequest map
115 : // and the sLastRequestId. For the map, it prevents more than one thread from
116 : // adding or deleting map entries at the same time. For id generation,
117 : // it creates an atomic allocation and increment.
118 : static mozilla::StaticMutex sMutex;
119 : static std::map<int, Request> sRequests;
120 : static int sLastRequestId;
121 :
122 : Callback mCallback;
123 :
124 0 : explicit RequestManager(int aId, Callback& aCallback)
125 : : mRequestId(aId)
126 0 : , mCallback(aCallback)
127 0 : {}
128 0 : ~RequestManager() {}
129 : private:
130 :
131 : RequestManager() = delete;
132 : RequestManager& operator=(const RequestManager&) = delete;
133 : };
134 :
135 : template<class Request, typename Callback,
136 : typename Result, typename QueryParam>
137 6 : mozilla::StaticMutex RequestManager<Request, Callback, Result, QueryParam>::sMutex;
138 : template<class Request, typename Callback,
139 : typename Result, typename QueryParam>
140 6 : std::map<int, Request> RequestManager<Request, Callback, Result, QueryParam>::sRequests;
141 : template<class Request, typename Callback,
142 : typename Result, typename QueryParam>
143 : int RequestManager<Request, Callback, Result, QueryParam>::sLastRequestId;
144 :
145 : typedef nsMainThreadPtrHandle<WebrtcGlobalStatisticsCallback> StatsRequestCallback;
146 :
147 0 : class StatsRequest
148 : : public RequestManager<StatsRequest,
149 : StatsRequestCallback,
150 : WebrtcGlobalStatisticsReport,
151 : nsAString>
152 : {
153 : public:
154 : const nsString mPcIdFilter;
155 0 : explicit StatsRequest(int aId, StatsRequestCallback& aCallback, nsAString& aFilter)
156 0 : : RequestManager(aId, aCallback)
157 0 : , mPcIdFilter(aFilter)
158 : {
159 0 : mResult.mReports.Construct();
160 0 : }
161 :
162 : private:
163 : StatsRequest() = delete;
164 : StatsRequest& operator=(const StatsRequest&) = delete;
165 : };
166 :
167 : typedef nsMainThreadPtrHandle<WebrtcGlobalLoggingCallback> LogRequestCallback;
168 :
169 0 : class LogRequest
170 : : public RequestManager<LogRequest,
171 : LogRequestCallback,
172 : Sequence<nsString>,
173 : const nsACString>
174 : {
175 : public:
176 : const nsCString mPattern;
177 0 : explicit LogRequest(int aId, LogRequestCallback& aCallback, const nsACString& aPattern)
178 0 : : RequestManager(aId, aCallback)
179 0 : , mPattern(aPattern)
180 0 : {}
181 :
182 : private:
183 : LogRequest() = delete;
184 : LogRequest& operator=(const LogRequest&) = delete;
185 : };
186 :
187 : class WebrtcContentParents
188 : {
189 : public:
190 : static WebrtcGlobalParent* Alloc();
191 : static void Dealloc(WebrtcGlobalParent* aParent);
192 0 : static bool Empty()
193 : {
194 0 : return sContentParents.empty();
195 : }
196 0 : static const std::vector<RefPtr<WebrtcGlobalParent>>& GetAll()
197 : {
198 0 : return sContentParents;
199 : }
200 : private:
201 : static std::vector<RefPtr<WebrtcGlobalParent>> sContentParents;
202 : WebrtcContentParents() = delete;
203 : WebrtcContentParents(const WebrtcContentParents&) = delete;
204 : WebrtcContentParents& operator=(const WebrtcContentParents&) = delete;
205 : };
206 :
207 3 : std::vector<RefPtr<WebrtcGlobalParent>> WebrtcContentParents::sContentParents;
208 :
209 0 : WebrtcGlobalParent* WebrtcContentParents::Alloc()
210 : {
211 0 : RefPtr<WebrtcGlobalParent> cp = new WebrtcGlobalParent;
212 0 : sContentParents.push_back(cp);
213 0 : return cp.get();
214 : }
215 :
216 0 : void WebrtcContentParents::Dealloc(WebrtcGlobalParent* aParent)
217 : {
218 0 : if (aParent) {
219 0 : aParent->mShutdown = true;
220 0 : auto cp = std::find(sContentParents.begin(), sContentParents.end(), aParent);
221 0 : if (cp != sContentParents.end()) {
222 0 : sContentParents.erase(cp);
223 : }
224 : }
225 0 : }
226 :
227 0 : static PeerConnectionCtx* GetPeerConnectionCtx()
228 : {
229 0 : if(PeerConnectionCtx::isActive()) {
230 0 : MOZ_ASSERT(PeerConnectionCtx::GetInstance());
231 0 : return PeerConnectionCtx::GetInstance();
232 : }
233 0 : return nullptr;
234 : }
235 :
236 : static void
237 0 : OnStatsReport_m(WebrtcGlobalChild* aThisChild,
238 : const int aRequestId,
239 : nsAutoPtr<RTCStatsQueries> aQueryList)
240 : {
241 0 : MOZ_ASSERT(NS_IsMainThread());
242 0 : MOZ_ASSERT(aQueryList);
243 :
244 0 : if (aThisChild) {
245 0 : Stats stats;
246 :
247 : // Copy stats generated for the currently active PeerConnections
248 0 : for (auto&& query : *aQueryList) {
249 0 : stats.AppendElement(*(query->report));
250 : }
251 : // Reports saved for closed/destroyed PeerConnections
252 0 : auto ctx = PeerConnectionCtx::GetInstance();
253 0 : if (ctx) {
254 0 : for (auto&& pc : ctx->mStatsForClosedPeerConnections) {
255 0 : stats.AppendElement(pc);
256 : }
257 : }
258 :
259 0 : Unused << aThisChild->SendGetStatsResult(aRequestId, stats);
260 0 : return;
261 : }
262 :
263 : // This is the last stats report to be collected. (Must be the gecko process).
264 0 : MOZ_ASSERT(XRE_IsParentProcess());
265 :
266 0 : StatsRequest* request = StatsRequest::Get(aRequestId);
267 :
268 0 : if (!request) {
269 0 : CSFLogError(logTag, "Bad RequestId");
270 0 : return;
271 : }
272 :
273 0 : for (auto&& query : *aQueryList) {
274 0 : request->mResult.mReports.Value().AppendElement(*(query->report), fallible);
275 : }
276 :
277 : // Reports saved for closed/destroyed PeerConnections
278 0 : auto ctx = PeerConnectionCtx::GetInstance();
279 0 : if (ctx) {
280 0 : for (auto&& pc : ctx->mStatsForClosedPeerConnections) {
281 0 : request->mResult.mReports.Value().AppendElement(pc, fallible);
282 : }
283 : }
284 :
285 0 : request->Complete();
286 0 : StatsRequest::Delete(aRequestId);
287 : }
288 :
289 : static void
290 0 : GetAllStats_s(WebrtcGlobalChild* aThisChild,
291 : const int aRequestId,
292 : nsAutoPtr<RTCStatsQueries> aQueryList)
293 : {
294 0 : MOZ_ASSERT(aQueryList);
295 : // The call to PeerConnetionImpl must happen from a runnable
296 : // dispatched on the STS thread.
297 :
298 : // Get stats from active connections.
299 0 : for (auto&& query : *aQueryList) {
300 0 : PeerConnectionImpl::ExecuteStatsQuery_s(query);
301 : }
302 :
303 : // After the RTCStatsQueries have been filled in, control must return
304 : // to the main thread before their eventual destruction.
305 0 : NS_DispatchToMainThread(WrapRunnableNM(&OnStatsReport_m,
306 : aThisChild,
307 : aRequestId,
308 : aQueryList),
309 0 : NS_DISPATCH_NORMAL);
310 0 : }
311 :
312 0 : static void OnGetLogging_m(WebrtcGlobalChild* aThisChild,
313 : const int aRequestId,
314 : nsAutoPtr<std::deque<std::string>> aLogList)
315 : {
316 0 : MOZ_ASSERT(NS_IsMainThread());
317 :
318 0 : if (aThisChild) {
319 : // Add this log to the collection of logs and call into
320 : // the next content process.
321 0 : Sequence<nsString> nsLogs;
322 :
323 0 : if (!aLogList->empty()) {
324 0 : for (auto& line : *aLogList) {
325 0 : nsLogs.AppendElement(NS_ConvertUTF8toUTF16(line.c_str()), fallible);
326 : }
327 0 : nsLogs.AppendElement(NS_LITERAL_STRING("+++++++ END ++++++++"), fallible);
328 : }
329 :
330 0 : Unused << aThisChild->SendGetLogResult(aRequestId, nsLogs);
331 0 : return;
332 : }
333 :
334 : // This is the last log to be collected. (Must be the gecko process).
335 0 : MOZ_ASSERT(XRE_IsParentProcess());
336 :
337 0 : LogRequest* request = LogRequest::Get(aRequestId);
338 :
339 0 : if (!request) {
340 0 : CSFLogError(logTag, "Bad RequestId");
341 0 : return;
342 : }
343 :
344 0 : if (!aLogList->empty()) {
345 0 : for (auto& line : *aLogList) {
346 0 : request->mResult.AppendElement(NS_ConvertUTF8toUTF16(line.c_str()),
347 0 : fallible);
348 : }
349 0 : request->mResult.AppendElement(NS_LITERAL_STRING("+++++++ END ++++++++"),
350 0 : fallible);
351 : }
352 :
353 0 : request->Complete();
354 0 : LogRequest::Delete(aRequestId);
355 : }
356 :
357 0 : static void GetLogging_s(WebrtcGlobalChild* aThisChild,
358 : const int aRequestId,
359 : const std::string& aPattern)
360 : {
361 : // Request log while not on the main thread.
362 0 : RLogConnector* logs = RLogConnector::GetInstance();
363 0 : nsAutoPtr<std::deque<std::string>> result(new std::deque<std::string>);
364 : // Might not exist yet.
365 0 : if (logs) {
366 0 : logs->Filter(aPattern, 0, result);
367 : }
368 : // Return to main thread to complete processing.
369 0 : NS_DispatchToMainThread(WrapRunnableNM(&OnGetLogging_m,
370 : aThisChild,
371 : aRequestId,
372 : result),
373 0 : NS_DISPATCH_NORMAL);
374 0 : }
375 :
376 : static nsresult
377 0 : BuildStatsQueryList(
378 : const std::map<const std::string, PeerConnectionImpl *>& aPeerConnections,
379 : const nsAString& aPcIdFilter,
380 : RTCStatsQueries* queries)
381 : {
382 : nsresult rv;
383 :
384 0 : for (auto&& pc : aPeerConnections) {
385 0 : MOZ_ASSERT(pc.second);
386 0 : if (aPcIdFilter.IsEmpty() ||
387 0 : aPcIdFilter.EqualsASCII(pc.second->GetIdAsAscii().c_str())) {
388 0 : if (pc.second->HasMedia()) {
389 0 : if (!queries->append(nsAutoPtr<RTCStatsQuery>(new RTCStatsQuery(true)))) {
390 0 : return NS_ERROR_OUT_OF_MEMORY;
391 : }
392 0 : rv = pc.second->BuildStatsQuery_m(nullptr, queries->back()); // all tracks
393 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
394 0 : return rv;
395 : }
396 0 : MOZ_ASSERT(queries->back()->report);
397 : }
398 : }
399 : }
400 :
401 0 : return NS_OK;
402 : }
403 :
404 : static nsresult
405 0 : RunStatsQuery(
406 : const std::map<const std::string, PeerConnectionImpl *>& aPeerConnections,
407 : const nsAString& aPcIdFilter,
408 : WebrtcGlobalChild* aThisChild,
409 : const int aRequestId)
410 : {
411 0 : nsAutoPtr<RTCStatsQueries> queries(new RTCStatsQueries);
412 0 : nsresult rv = BuildStatsQueryList(aPeerConnections, aPcIdFilter, queries);
413 :
414 0 : if (NS_FAILED(rv)) {
415 0 : return rv;
416 : }
417 :
418 : nsCOMPtr<nsIEventTarget> stsThread =
419 0 : do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
420 :
421 0 : if (NS_FAILED(rv)) {
422 0 : return rv;
423 : }
424 0 : if (!stsThread) {
425 0 : return NS_ERROR_FAILURE;
426 : }
427 :
428 0 : rv = RUN_ON_THREAD(stsThread,
429 0 : WrapRunnableNM(&GetAllStats_s,
430 : aThisChild,
431 : aRequestId,
432 : queries),
433 : NS_DISPATCH_NORMAL);
434 0 : return rv;
435 : }
436 :
437 0 : void ClearClosedStats()
438 : {
439 0 : PeerConnectionCtx* ctx = GetPeerConnectionCtx();
440 :
441 0 : if (ctx) {
442 0 : ctx->mStatsForClosedPeerConnections.Clear();
443 : }
444 0 : }
445 :
446 : void
447 0 : WebrtcGlobalInformation::ClearAllStats(
448 : const GlobalObject& aGlobal)
449 : {
450 0 : if (!NS_IsMainThread()) {
451 0 : return;
452 : }
453 :
454 : // Chrome-only API
455 0 : MOZ_ASSERT(XRE_IsParentProcess());
456 :
457 0 : if (!WebrtcContentParents::Empty()) {
458 : // Pass on the request to any content process based PeerConnections.
459 0 : for (auto& cp : WebrtcContentParents::GetAll()) {
460 0 : Unused << cp->SendClearStatsRequest();
461 : }
462 : }
463 :
464 : // Flush the history for the chrome process
465 0 : ClearClosedStats();
466 : }
467 :
468 : void
469 0 : WebrtcGlobalInformation::GetAllStats(
470 : const GlobalObject& aGlobal,
471 : WebrtcGlobalStatisticsCallback& aStatsCallback,
472 : const Optional<nsAString>& pcIdFilter,
473 : ErrorResult& aRv)
474 : {
475 0 : if (!NS_IsMainThread()) {
476 0 : aRv.Throw(NS_ERROR_NOT_SAME_THREAD);
477 0 : return;
478 : }
479 :
480 0 : MOZ_ASSERT(XRE_IsParentProcess());
481 :
482 : // CallbackObject does not support threadsafe refcounting, and must be
483 : // used and destroyed on main.
484 : StatsRequestCallback callbackHandle(
485 : new nsMainThreadPtrHolder<WebrtcGlobalStatisticsCallback>(
486 0 : "WebrtcGlobalStatisticsCallback", &aStatsCallback));
487 :
488 0 : nsString filter;
489 0 : if (pcIdFilter.WasPassed()) {
490 0 : filter = pcIdFilter.Value();
491 : }
492 :
493 0 : auto* request = StatsRequest::Create(callbackHandle, filter);
494 :
495 0 : if (!request) {
496 0 : aRv.Throw(NS_ERROR_FAILURE);
497 0 : return;
498 : }
499 :
500 0 : if (!WebrtcContentParents::Empty()) {
501 : // Pass on the request to any content based PeerConnections.
502 0 : for (auto& cp : WebrtcContentParents::GetAll()) {
503 0 : request->mContactList.push(cp);
504 : }
505 :
506 0 : auto next = request->GetNextParent();
507 0 : if (next) {
508 0 : aRv = next->SendGetStatsRequest(request->mRequestId, request->mPcIdFilter) ?
509 0 : NS_OK : NS_ERROR_FAILURE;
510 0 : return;
511 : }
512 : }
513 : // No content resident PeerConnectionCtx instances.
514 : // Check this process.
515 0 : PeerConnectionCtx* ctx = GetPeerConnectionCtx();
516 : nsresult rv;
517 :
518 0 : if (ctx) {
519 0 : rv = RunStatsQuery(ctx->mGetPeerConnections(),
520 0 : filter, nullptr, request->mRequestId);
521 :
522 0 : if (NS_FAILED(rv)) {
523 0 : StatsRequest::Delete(request->mRequestId);
524 : }
525 : } else {
526 : // Just send back an empty report.
527 0 : rv = NS_OK;
528 0 : request->Complete();
529 0 : StatsRequest::Delete(request->mRequestId);
530 : }
531 :
532 0 : aRv = rv;
533 0 : return;
534 : }
535 :
536 : static nsresult
537 0 : RunLogQuery(const nsCString& aPattern,
538 : WebrtcGlobalChild* aThisChild,
539 : const int aRequestId)
540 : {
541 : nsresult rv;
542 : nsCOMPtr<nsIEventTarget> stsThread =
543 0 : do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
544 :
545 0 : if (NS_FAILED(rv)) {
546 0 : return rv;
547 : }
548 0 : if (!stsThread) {
549 0 : return NS_ERROR_FAILURE;
550 : }
551 :
552 0 : rv = RUN_ON_THREAD(stsThread,
553 0 : WrapRunnableNM(&GetLogging_s,
554 : aThisChild,
555 : aRequestId,
556 0 : aPattern.get()),
557 : NS_DISPATCH_NORMAL);
558 0 : return rv;
559 : }
560 :
561 0 : static void ClearLogs_s()
562 : {
563 : // Make call off main thread.
564 0 : RLogConnector* logs = RLogConnector::GetInstance();
565 0 : if (logs) {
566 0 : logs->Clear();
567 : }
568 0 : }
569 :
570 : static nsresult
571 0 : RunLogClear()
572 : {
573 : nsresult rv;
574 : nsCOMPtr<nsIEventTarget> stsThread =
575 0 : do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
576 :
577 0 : if (NS_FAILED(rv)) {
578 0 : return rv;
579 : }
580 0 : if (!stsThread) {
581 0 : return NS_ERROR_FAILURE;
582 : }
583 :
584 0 : return RUN_ON_THREAD(stsThread,
585 0 : WrapRunnableNM(&ClearLogs_s),
586 0 : NS_DISPATCH_NORMAL);
587 : }
588 :
589 : void
590 0 : WebrtcGlobalInformation::ClearLogging(
591 : const GlobalObject& aGlobal)
592 : {
593 0 : if (!NS_IsMainThread()) {
594 0 : return;
595 : }
596 :
597 : // Chrome-only API
598 0 : MOZ_ASSERT(XRE_IsParentProcess());
599 :
600 0 : if (!WebrtcContentParents::Empty()) {
601 : // Clear content process signaling logs
602 0 : for (auto& cp : WebrtcContentParents::GetAll()) {
603 0 : Unused << cp->SendClearLogRequest();
604 : }
605 : }
606 :
607 : // Clear chrome process signaling logs
608 0 : Unused << RunLogClear();
609 : }
610 :
611 : void
612 0 : WebrtcGlobalInformation::GetLogging(
613 : const GlobalObject& aGlobal,
614 : const nsAString& aPattern,
615 : WebrtcGlobalLoggingCallback& aLoggingCallback,
616 : ErrorResult& aRv)
617 : {
618 0 : if (!NS_IsMainThread()) {
619 0 : aRv.Throw(NS_ERROR_NOT_SAME_THREAD);
620 0 : return;
621 : }
622 :
623 0 : MOZ_ASSERT(XRE_IsParentProcess());
624 :
625 : // CallbackObject does not support threadsafe refcounting, and must be
626 : // destroyed on main.
627 : LogRequestCallback callbackHandle(
628 : new nsMainThreadPtrHolder<WebrtcGlobalLoggingCallback>(
629 0 : "WebrtcGlobalLoggingCallback", &aLoggingCallback));
630 :
631 0 : nsAutoCString pattern;
632 0 : CopyUTF16toUTF8(aPattern, pattern);
633 :
634 0 : LogRequest* request = LogRequest::Create(callbackHandle, pattern);
635 :
636 0 : if (!request) {
637 0 : aRv.Throw(NS_ERROR_FAILURE);
638 0 : return;
639 : }
640 :
641 0 : if (!WebrtcContentParents::Empty()) {
642 : // Pass on the request to any content based PeerConnections.
643 0 : for (auto& cp : WebrtcContentParents::GetAll()) {
644 0 : request->mContactList.push(cp);
645 : }
646 :
647 0 : auto next = request->GetNextParent();
648 0 : if (next) {
649 0 : aRv = next->SendGetLogRequest(request->mRequestId, request->mPattern) ?
650 0 : NS_OK : NS_ERROR_FAILURE;
651 0 : return;
652 : }
653 : }
654 :
655 0 : nsresult rv = RunLogQuery(request->mPattern, nullptr, request->mRequestId);
656 :
657 0 : if (NS_FAILED(rv)) {
658 0 : LogRequest::Delete(request->mRequestId);
659 : }
660 :
661 0 : aRv = rv;
662 0 : return;
663 : }
664 :
665 : static int32_t sLastSetLevel = 0;
666 : static bool sLastAECDebug = false;
667 :
668 : void
669 0 : WebrtcGlobalInformation::SetDebugLevel(const GlobalObject& aGlobal, int32_t aLevel)
670 : {
671 0 : if (aLevel) {
672 0 : StartWebRtcLog(webrtc::TraceLevel(aLevel));
673 : } else {
674 0 : StopWebRtcLog();
675 : }
676 0 : sLastSetLevel = aLevel;
677 :
678 0 : for (auto& cp : WebrtcContentParents::GetAll()){
679 0 : Unused << cp->SendSetDebugMode(aLevel);
680 : }
681 0 : }
682 :
683 : int32_t
684 0 : WebrtcGlobalInformation::DebugLevel(const GlobalObject& aGlobal)
685 : {
686 0 : return sLastSetLevel;
687 : }
688 :
689 : void
690 0 : WebrtcGlobalInformation::SetAecDebug(const GlobalObject& aGlobal, bool aEnable)
691 : {
692 0 : if (aEnable) {
693 0 : StartAecLog();
694 : } else {
695 0 : StopAecLog();
696 : }
697 :
698 0 : sLastAECDebug = aEnable;
699 :
700 0 : for (auto& cp : WebrtcContentParents::GetAll()){
701 0 : Unused << cp->SendSetAecLogging(aEnable);
702 : }
703 0 : }
704 :
705 : bool
706 0 : WebrtcGlobalInformation::AecDebug(const GlobalObject& aGlobal)
707 : {
708 0 : return sLastAECDebug;
709 : }
710 :
711 : mozilla::ipc::IPCResult
712 0 : WebrtcGlobalParent::RecvGetStatsResult(const int& aRequestId,
713 : nsTArray<RTCStatsReportInternal>&& Stats)
714 : {
715 0 : MOZ_ASSERT(NS_IsMainThread());
716 0 : nsresult rv = NS_OK;
717 :
718 0 : StatsRequest* request = StatsRequest::Get(aRequestId);
719 :
720 0 : if (!request) {
721 0 : CSFLogError(logTag, "Bad RequestId");
722 0 : return IPC_FAIL_NO_REASON(this);
723 : }
724 :
725 0 : for (auto&& s : Stats) {
726 0 : request->mResult.mReports.Value().AppendElement(s, fallible);
727 : }
728 :
729 0 : auto next = request->GetNextParent();
730 0 : if (next) {
731 : // There are more content instances to query.
732 0 : if (!next->SendGetStatsRequest(request->mRequestId, request->mPcIdFilter)) {
733 0 : return IPC_FAIL_NO_REASON(this);
734 : }
735 0 : return IPC_OK();
736 : }
737 :
738 : // Content queries complete, run chrome instance query if applicable
739 0 : PeerConnectionCtx* ctx = GetPeerConnectionCtx();
740 :
741 0 : if (ctx) {
742 0 : rv = RunStatsQuery(ctx->mGetPeerConnections(),
743 0 : request->mPcIdFilter, nullptr, aRequestId);
744 : } else {
745 : // No instance in the process, return the collections as is
746 0 : request->Complete();
747 0 : StatsRequest::Delete(aRequestId);
748 : }
749 :
750 0 : if (NS_FAILED(rv)) {
751 0 : return IPC_FAIL_NO_REASON(this);
752 : }
753 0 : return IPC_OK();
754 : }
755 :
756 : mozilla::ipc::IPCResult
757 0 : WebrtcGlobalParent::RecvGetLogResult(const int& aRequestId,
758 : const WebrtcGlobalLog& aLog)
759 : {
760 0 : MOZ_ASSERT(NS_IsMainThread());
761 :
762 0 : LogRequest* request = LogRequest::Get(aRequestId);
763 :
764 0 : if (!request) {
765 0 : CSFLogError(logTag, "Bad RequestId");
766 0 : return IPC_FAIL_NO_REASON(this);
767 : }
768 0 : request->mResult.AppendElements(aLog, fallible);
769 :
770 0 : auto next = request->GetNextParent();
771 0 : if (next) {
772 : // There are more content instances to query.
773 0 : if (!next->SendGetLogRequest(request->mRequestId, request->mPattern)) {
774 0 : return IPC_FAIL_NO_REASON(this);
775 : }
776 0 : return IPC_OK();
777 : }
778 :
779 : // Content queries complete, run chrome instance query if applicable
780 0 : nsresult rv = RunLogQuery(request->mPattern, nullptr, aRequestId);
781 :
782 0 : if (NS_FAILED(rv)) {
783 : //Unable to get gecko process log. Return what has been collected.
784 0 : CSFLogError(logTag, "Unable to extract chrome process log");
785 0 : request->Complete();
786 0 : LogRequest::Delete(aRequestId);
787 : }
788 :
789 0 : return IPC_OK();
790 : }
791 :
792 : WebrtcGlobalParent*
793 0 : WebrtcGlobalParent::Alloc()
794 : {
795 0 : return WebrtcContentParents::Alloc();
796 : }
797 :
798 : bool
799 0 : WebrtcGlobalParent::Dealloc(WebrtcGlobalParent * aActor)
800 : {
801 0 : WebrtcContentParents::Dealloc(aActor);
802 0 : return true;
803 : }
804 :
805 : void
806 0 : WebrtcGlobalParent::ActorDestroy(ActorDestroyReason aWhy)
807 : {
808 0 : mShutdown = true;
809 0 : return;
810 : }
811 :
812 : mozilla::ipc::IPCResult
813 0 : WebrtcGlobalParent::Recv__delete__()
814 : {
815 0 : return IPC_OK();
816 : }
817 :
818 0 : MOZ_IMPLICIT WebrtcGlobalParent::WebrtcGlobalParent()
819 0 : : mShutdown(false)
820 : {
821 0 : MOZ_COUNT_CTOR(WebrtcGlobalParent);
822 0 : }
823 :
824 0 : MOZ_IMPLICIT WebrtcGlobalParent::~WebrtcGlobalParent()
825 : {
826 0 : MOZ_COUNT_DTOR(WebrtcGlobalParent);
827 0 : }
828 :
829 : mozilla::ipc::IPCResult
830 0 : WebrtcGlobalChild::RecvGetStatsRequest(const int& aRequestId,
831 : const nsString& aPcIdFilter)
832 : {
833 0 : if (mShutdown) {
834 0 : return IPC_OK();
835 : }
836 :
837 0 : PeerConnectionCtx* ctx = GetPeerConnectionCtx();
838 :
839 0 : if (ctx) {
840 0 : nsresult rv = RunStatsQuery(ctx->mGetPeerConnections(),
841 0 : aPcIdFilter, this, aRequestId);
842 0 : if (NS_FAILED(rv)) {
843 0 : return IPC_FAIL_NO_REASON(this);
844 : }
845 0 : return IPC_OK();
846 : }
847 :
848 0 : nsTArray<RTCStatsReportInternal> empty_stats;
849 0 : SendGetStatsResult(aRequestId, empty_stats);
850 :
851 0 : return IPC_OK();
852 : }
853 :
854 : mozilla::ipc::IPCResult
855 0 : WebrtcGlobalChild::RecvClearStatsRequest()
856 : {
857 0 : if (mShutdown) {
858 0 : return IPC_OK();
859 : }
860 :
861 0 : ClearClosedStats();
862 0 : return IPC_OK();
863 : }
864 :
865 : mozilla::ipc::IPCResult
866 0 : WebrtcGlobalChild::RecvGetLogRequest(const int& aRequestId,
867 : const nsCString& aPattern)
868 : {
869 0 : if (mShutdown) {
870 0 : return IPC_OK();
871 : }
872 :
873 : nsresult rv;
874 : nsCOMPtr<nsIEventTarget> stsThread =
875 0 : do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
876 :
877 0 : if (NS_SUCCEEDED(rv) && stsThread) {
878 : // this is a singleton, so we shouldn't need to hold a ref for the
879 : // request (and can't just add a ref here anyways)
880 0 : rv = RUN_ON_THREAD(stsThread,
881 0 : WrapRunnableNM(&GetLogging_s, this, aRequestId, aPattern.get()),
882 : NS_DISPATCH_NORMAL);
883 :
884 0 : if (NS_SUCCEEDED(rv)) {
885 0 : return IPC_OK();
886 : }
887 : }
888 :
889 0 : Sequence<nsString> empty_log;
890 0 : SendGetLogResult(aRequestId, empty_log);
891 :
892 0 : return IPC_OK();
893 : }
894 :
895 : mozilla::ipc::IPCResult
896 0 : WebrtcGlobalChild::RecvClearLogRequest()
897 : {
898 0 : if (mShutdown) {
899 0 : return IPC_OK();
900 : }
901 :
902 0 : RunLogClear();
903 0 : return IPC_OK();
904 : }
905 :
906 : mozilla::ipc::IPCResult
907 0 : WebrtcGlobalChild::RecvSetAecLogging(const bool& aEnable)
908 : {
909 0 : if (!mShutdown) {
910 0 : if (aEnable) {
911 0 : StartAecLog();
912 : } else {
913 0 : StopAecLog();
914 : }
915 : }
916 0 : return IPC_OK();
917 : }
918 :
919 : mozilla::ipc::IPCResult
920 0 : WebrtcGlobalChild::RecvSetDebugMode(const int& aLevel)
921 : {
922 0 : if (!mShutdown) {
923 0 : if (aLevel) {
924 0 : StartWebRtcLog(webrtc::TraceLevel(aLevel));
925 : } else {
926 0 : StopWebRtcLog();
927 : }
928 : }
929 0 : return IPC_OK();
930 : }
931 :
932 : WebrtcGlobalChild*
933 0 : WebrtcGlobalChild::Create()
934 : {
935 : WebrtcGlobalChild* child =
936 : static_cast<WebrtcGlobalChild*>(
937 0 : ContentChild::GetSingleton()->SendPWebrtcGlobalConstructor());
938 0 : return child;
939 : }
940 :
941 : void
942 0 : WebrtcGlobalChild::ActorDestroy(ActorDestroyReason aWhy)
943 : {
944 0 : mShutdown = true;
945 0 : }
946 :
947 0 : MOZ_IMPLICIT WebrtcGlobalChild::WebrtcGlobalChild()
948 0 : : mShutdown(false)
949 : {
950 0 : MOZ_COUNT_CTOR(WebrtcGlobalChild);
951 0 : }
952 :
953 0 : MOZ_IMPLICIT WebrtcGlobalChild::~WebrtcGlobalChild()
954 : {
955 0 : MOZ_COUNT_DTOR(WebrtcGlobalChild);
956 0 : }
957 :
958 : struct StreamResult {
959 0 : StreamResult() : candidateTypeBitpattern(0), streamSucceeded(false) {}
960 : uint32_t candidateTypeBitpattern;
961 : bool streamSucceeded;
962 : };
963 :
964 0 : static uint32_t GetCandidateIpAndTransportMask(const RTCIceCandidateStats *cand) {
965 :
966 : enum {
967 : CANDIDATE_BITMASK_UDP = 1,
968 : CANDIDATE_BITMASK_TCP = 1 << 1,
969 : CANDIDATE_BITMASK_IPV6 = 1 << 2,
970 : };
971 :
972 0 : uint32_t res = 0;
973 :
974 0 : nsAutoCString transport;
975 : // prefer local transport for local relay candidates
976 0 : if (cand->mMozLocalTransport.WasPassed()) {
977 0 : transport.Assign(NS_ConvertUTF16toUTF8(cand->mMozLocalTransport.Value()));
978 : } else {
979 0 : transport.Assign(NS_ConvertUTF16toUTF8(cand->mTransport.Value()));
980 : }
981 0 : if (transport == kNrIceTransportUdp) {
982 0 : res |= CANDIDATE_BITMASK_UDP;
983 0 : } else if (transport == kNrIceTransportTcp) {
984 0 : res |= CANDIDATE_BITMASK_TCP;
985 : }
986 :
987 0 : if (cand->mIpAddress.Value().FindChar(':') != -1) {
988 0 : res |= CANDIDATE_BITMASK_IPV6;
989 : }
990 :
991 0 : return res;
992 : };
993 :
994 0 : static void StoreLongTermICEStatisticsImpl_m(
995 : nsresult result,
996 : nsAutoPtr<RTCStatsQuery> query) {
997 :
998 : using namespace Telemetry;
999 :
1000 0 : if (NS_FAILED(result) ||
1001 0 : !query->error.empty() ||
1002 0 : !query->report->mIceCandidateStats.WasPassed()) {
1003 0 : return;
1004 : }
1005 :
1006 0 : query->report->mClosed.Construct(true);
1007 :
1008 : // TODO(bcampen@mozilla.com): Do we need to watch out for cases where the
1009 : // components within a stream didn't have the same types of relayed
1010 : // candidates? I have a feeling that late trickle could cause this, but right
1011 : // now we don't have enough information to detect it (we would need to know
1012 : // the ICE component id for each candidate pair and candidate)
1013 :
1014 0 : std::map<std::string, StreamResult> streamResults;
1015 :
1016 : // Build list of streams, and whether or not they failed.
1017 0 : for (size_t i = 0;
1018 0 : i < query->report->mIceCandidatePairStats.Value().Length();
1019 : ++i) {
1020 : const RTCIceCandidatePairStats &pair =
1021 0 : query->report->mIceCandidatePairStats.Value()[i];
1022 :
1023 0 : if (!pair.mState.WasPassed() || !pair.mTransportId.WasPassed()) {
1024 0 : MOZ_CRASH();
1025 : continue;
1026 : }
1027 :
1028 : // Note: we use NrIceMediaStream's name for the
1029 : // RTCIceCandidatePairStats tranportId
1030 : std::string streamId(
1031 0 : NS_ConvertUTF16toUTF8(pair.mTransportId.Value()).get());
1032 :
1033 0 : streamResults[streamId].streamSucceeded |=
1034 0 : pair.mState.Value() == RTCStatsIceCandidatePairState::Succeeded;
1035 : }
1036 :
1037 0 : for (size_t i = 0;
1038 0 : i < query->report->mIceCandidateStats.Value().Length();
1039 : ++i) {
1040 : const RTCIceCandidateStats &cand =
1041 0 : query->report->mIceCandidateStats.Value()[i];
1042 :
1043 0 : if (!cand.mType.WasPassed() ||
1044 0 : !cand.mCandidateType.WasPassed() ||
1045 0 : !cand.mTransport.WasPassed() ||
1046 0 : !cand.mIpAddress.WasPassed() ||
1047 0 : !cand.mComponentId.WasPassed()) {
1048 : // Crash on debug, ignore this candidate otherwise.
1049 0 : MOZ_CRASH();
1050 : continue;
1051 : }
1052 :
1053 : /* The bitmask after examaning a candidate should look like this:
1054 : * REMOTE_GATHERED_HOST_UDP = 1,
1055 : * REMOTE_GATHERED_HOST_TCP = 1 << 1,
1056 : * REMOTE_GATHERED_HOST_IPV6 = 1 << 2,
1057 : * REMOTE_GATHERED_SERVER_REFLEXIVE_UDP = 1 << 3,
1058 : * REMOTE_GATHERED_SERVER_REFLEXIVE_TCP = 1 << 4,
1059 : * REMOTE_GATHERED_SERVER_REFLEXIVE_IPV6 = 1 << 5,
1060 : * REMOTE_GATHERED_TURN_UDP = 1 << 6,
1061 : * REMOTE_GATHERED_TURN_TCP = 1 << 7, // dummy place holder
1062 : * REMOTE_GATHERED_TURN_IPV6 = 1 << 8,
1063 : * REMOTE_GATHERED_PEER_REFLEXIVE_UDP = 1 << 9,
1064 : * REMOTE_GATHERED_PEER_REFLEXIVE_TCP = 1 << 10,
1065 : * REMOTE_GATHERED_PEER_REFLEXIVE_IPV6 = 1 << 11,
1066 : * LOCAL_GATHERED_HOST_UDP = 1 << 16,
1067 : * LOCAL_GATHERED_HOST_TCP = 1 << 17,
1068 : * LOCAL_GATHERED_HOST_IPV6 = 1 << 18,
1069 : * LOCAL_GATHERED_SERVER_REFLEXIVE_UDP = 1 << 19,
1070 : * LOCAL_GATHERED_SERVER_REFLEXIVE_TCP = 1 << 20,
1071 : * LOCAL_GATHERED_SERVER_REFLEXIVE_IPV6 = 1 << 21,
1072 : * LOCAL_GATHERED_TURN_UDP = 1 << 22,
1073 : * LOCAL_GATHERED_TURN_TCP = 1 << 23,
1074 : * LOCAL_GATHERED_TURN_IPV6 = 1 << 24,
1075 : * LOCAL_GATHERED_PEERREFLEXIVE_UDP = 1 << 25,
1076 : * LOCAL_GATHERED_PEERREFLEXIVE_TCP = 1 << 26,
1077 : * LOCAL_GATHERED_PEERREFLEXIVE_IPV6 = 1 << 27,
1078 : *
1079 : * This results in following shift values
1080 : */
1081 : static const uint32_t kLocalShift = 16;
1082 : static const uint32_t kSrflxShift = 3;
1083 : static const uint32_t kRelayShift = 6;
1084 : static const uint32_t kPrflxShift = 9;
1085 :
1086 0 : uint32_t candBitmask = GetCandidateIpAndTransportMask(&cand);
1087 :
1088 : // Note: shift values need to result in the above enum table
1089 0 : if (cand.mType.Value() == RTCStatsType::Local_candidate) {
1090 0 : candBitmask <<= kLocalShift;
1091 : }
1092 :
1093 0 : if (cand.mCandidateType.Value() == RTCStatsIceCandidateType::Serverreflexive) {
1094 0 : candBitmask <<= kSrflxShift;
1095 0 : } else if (cand.mCandidateType.Value() == RTCStatsIceCandidateType::Relayed) {
1096 0 : candBitmask <<= kRelayShift;
1097 0 : } else if (cand.mCandidateType.Value() == RTCStatsIceCandidateType::Peerreflexive) {
1098 0 : candBitmask <<= kPrflxShift;
1099 : }
1100 :
1101 : // Note: this is not a "component" in the ICE definition, this is really a
1102 : // stream ID. This is just the way the stats API is standardized right now.
1103 : // Very confusing.
1104 : std::string streamId(
1105 0 : NS_ConvertUTF16toUTF8(cand.mComponentId.Value()).get());
1106 :
1107 0 : streamResults[streamId].candidateTypeBitpattern |= candBitmask;
1108 : }
1109 :
1110 0 : for (auto& streamResult : streamResults) {
1111 0 : Telemetry::RecordWebrtcIceCandidates(streamResult.second.candidateTypeBitpattern,
1112 0 : streamResult.second.streamSucceeded);
1113 : }
1114 :
1115 : // Beyond ICE, accumulate telemetry for various PER_CALL settings here.
1116 :
1117 0 : if (query->report->mOutboundRTPStreamStats.WasPassed()) {
1118 0 : auto& array = query->report->mOutboundRTPStreamStats.Value();
1119 0 : for (decltype(array.Length()) i = 0; i < array.Length(); i++) {
1120 0 : auto& s = array[i];
1121 0 : bool isVideo = (s.mId.Value().Find("video") != -1);
1122 0 : if (!isVideo || s.mIsRemote) {
1123 0 : continue;
1124 : }
1125 0 : if (s.mBitrateMean.WasPassed()) {
1126 0 : Accumulate(WEBRTC_VIDEO_ENCODER_BITRATE_AVG_PER_CALL_KBPS,
1127 0 : uint32_t(s.mBitrateMean.Value() / 1000));
1128 : }
1129 0 : if (s.mBitrateStdDev.WasPassed()) {
1130 0 : Accumulate(WEBRTC_VIDEO_ENCODER_BITRATE_STD_DEV_PER_CALL_KBPS,
1131 0 : uint32_t(s.mBitrateStdDev.Value() / 1000));
1132 : }
1133 0 : if (s.mFramerateMean.WasPassed()) {
1134 0 : Accumulate(WEBRTC_VIDEO_ENCODER_FRAMERATE_AVG_PER_CALL,
1135 0 : uint32_t(s.mFramerateMean.Value()));
1136 : }
1137 0 : if (s.mFramerateStdDev.WasPassed()) {
1138 0 : Accumulate(WEBRTC_VIDEO_ENCODER_FRAMERATE_10X_STD_DEV_PER_CALL,
1139 0 : uint32_t(s.mFramerateStdDev.Value() * 10));
1140 : }
1141 0 : if (s.mDroppedFrames.WasPassed() && !query->iceStartTime.IsNull()) {
1142 0 : double mins = (TimeStamp::Now() - query->iceStartTime).ToSeconds() / 60;
1143 0 : if (mins > 0) {
1144 0 : Accumulate(WEBRTC_VIDEO_ENCODER_DROPPED_FRAMES_PER_CALL_FPM,
1145 0 : uint32_t(double(s.mDroppedFrames.Value()) / mins));
1146 : }
1147 : }
1148 : }
1149 : }
1150 :
1151 0 : if (query->report->mInboundRTPStreamStats.WasPassed()) {
1152 0 : auto& array = query->report->mInboundRTPStreamStats.Value();
1153 0 : for (decltype(array.Length()) i = 0; i < array.Length(); i++) {
1154 0 : auto& s = array[i];
1155 0 : bool isVideo = (s.mId.Value().Find("video") != -1);
1156 0 : if (!isVideo || s.mIsRemote) {
1157 0 : continue;
1158 : }
1159 0 : if (s.mBitrateMean.WasPassed()) {
1160 0 : Accumulate(WEBRTC_VIDEO_DECODER_BITRATE_AVG_PER_CALL_KBPS,
1161 0 : uint32_t(s.mBitrateMean.Value() / 1000));
1162 : }
1163 0 : if (s.mBitrateStdDev.WasPassed()) {
1164 0 : Accumulate(WEBRTC_VIDEO_DECODER_BITRATE_STD_DEV_PER_CALL_KBPS,
1165 0 : uint32_t(s.mBitrateStdDev.Value() / 1000));
1166 : }
1167 0 : if (s.mFramerateMean.WasPassed()) {
1168 0 : Accumulate(WEBRTC_VIDEO_DECODER_FRAMERATE_AVG_PER_CALL,
1169 0 : uint32_t(s.mFramerateMean.Value()));
1170 : }
1171 0 : if (s.mFramerateStdDev.WasPassed()) {
1172 0 : Accumulate(WEBRTC_VIDEO_DECODER_FRAMERATE_10X_STD_DEV_PER_CALL,
1173 0 : uint32_t(s.mFramerateStdDev.Value() * 10));
1174 : }
1175 0 : if (s.mDiscardedPackets.WasPassed() && !query->iceStartTime.IsNull()) {
1176 0 : double mins = (TimeStamp::Now() - query->iceStartTime).ToSeconds() / 60;
1177 0 : if (mins > 0) {
1178 0 : Accumulate(WEBRTC_VIDEO_DECODER_DISCARDED_PACKETS_PER_CALL_PPM,
1179 0 : uint32_t(double(s.mDiscardedPackets.Value()) / mins));
1180 : }
1181 : }
1182 : }
1183 : }
1184 :
1185 : // Finally, store the stats
1186 :
1187 0 : PeerConnectionCtx *ctx = GetPeerConnectionCtx();
1188 0 : if (ctx) {
1189 0 : ctx->mStatsForClosedPeerConnections.AppendElement(*query->report, fallible);
1190 : }
1191 : }
1192 :
1193 0 : static void GetStatsForLongTermStorage_s(
1194 : nsAutoPtr<RTCStatsQuery> query) {
1195 :
1196 0 : MOZ_ASSERT(query);
1197 :
1198 0 : nsresult rv = PeerConnectionImpl::ExecuteStatsQuery_s(query.get());
1199 :
1200 : // Check whether packets were dropped due to rate limiting during
1201 : // this call. (These calls must be made on STS)
1202 0 : unsigned char rate_limit_bit_pattern = 0;
1203 0 : if (!mozilla::nr_socket_short_term_violation_time().IsNull() &&
1204 0 : !query->iceStartTime.IsNull() &&
1205 0 : mozilla::nr_socket_short_term_violation_time() >= query->iceStartTime) {
1206 0 : rate_limit_bit_pattern |= 1;
1207 : }
1208 0 : if (!mozilla::nr_socket_long_term_violation_time().IsNull() &&
1209 0 : !query->iceStartTime.IsNull() &&
1210 0 : mozilla::nr_socket_long_term_violation_time() >= query->iceStartTime) {
1211 0 : rate_limit_bit_pattern |= 2;
1212 : }
1213 :
1214 0 : if (query->failed) {
1215 0 : Telemetry::Accumulate(
1216 : Telemetry::WEBRTC_STUN_RATE_LIMIT_EXCEEDED_BY_TYPE_GIVEN_FAILURE,
1217 0 : rate_limit_bit_pattern);
1218 : } else {
1219 0 : Telemetry::Accumulate(
1220 : Telemetry::WEBRTC_STUN_RATE_LIMIT_EXCEEDED_BY_TYPE_GIVEN_SUCCESS,
1221 0 : rate_limit_bit_pattern);
1222 : }
1223 :
1224 : // Even if Telemetry::Accumulate is threadsafe, we still need to send the
1225 : // query back to main, since that is where it must be destroyed.
1226 : NS_DispatchToMainThread(
1227 0 : WrapRunnableNM(
1228 : &StoreLongTermICEStatisticsImpl_m,
1229 : rv,
1230 : query),
1231 0 : NS_DISPATCH_NORMAL);
1232 0 : }
1233 :
1234 0 : void WebrtcGlobalInformation::StoreLongTermICEStatistics(
1235 : PeerConnectionImpl& aPc) {
1236 0 : Telemetry::Accumulate(Telemetry::WEBRTC_ICE_FINAL_CONNECTION_STATE,
1237 0 : static_cast<uint32_t>(aPc.IceConnectionState()));
1238 :
1239 0 : if (aPc.IceConnectionState() == PCImplIceConnectionState::New) {
1240 : // ICE has not started; we won't have any remote candidates, so recording
1241 : // statistics on gathered candidates is pointless.
1242 0 : return;
1243 : }
1244 :
1245 0 : nsAutoPtr<RTCStatsQuery> query(new RTCStatsQuery(true));
1246 :
1247 0 : nsresult rv = aPc.BuildStatsQuery_m(nullptr, query.get());
1248 :
1249 0 : NS_ENSURE_SUCCESS_VOID(rv);
1250 :
1251 0 : RUN_ON_THREAD(aPc.GetSTSThread(),
1252 0 : WrapRunnableNM(&GetStatsForLongTermStorage_s,
1253 : query),
1254 0 : NS_DISPATCH_NORMAL);
1255 : }
1256 :
1257 : } // namespace dom
1258 9 : } // namespace mozilla
|