media/webrtc/signaling/src/peerconnection/WebrtcGlobalInformation.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
michael@0 3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 #include "WebrtcGlobalInformation.h"
michael@0 6
michael@0 7 #include <deque>
michael@0 8 #include <string>
michael@0 9
michael@0 10 #include "CSFLog.h"
michael@0 11
michael@0 12 #include "mozilla/dom/WebrtcGlobalInformationBinding.h"
michael@0 13
michael@0 14 #include "nsAutoPtr.h"
michael@0 15 #include "nsNetCID.h" // NS_SOCKETTRANSPORTSERVICE_CONTRACTID
michael@0 16 #include "nsServiceManagerUtils.h" // do_GetService
michael@0 17 #include "mozilla/ErrorResult.h"
michael@0 18 #include "mozilla/Vector.h"
michael@0 19 #include "nsProxyRelease.h"
michael@0 20 #include "mozilla/Telemetry.h"
michael@0 21
michael@0 22 #include "rlogringbuffer.h"
michael@0 23 #include "runnable_utils.h"
michael@0 24 #include "PeerConnectionCtx.h"
michael@0 25 #include "PeerConnectionImpl.h"
michael@0 26
michael@0 27 using sipcc::PeerConnectionImpl;
michael@0 28 using sipcc::PeerConnectionCtx;
michael@0 29 using sipcc::RTCStatsQuery;
michael@0 30
michael@0 31 static const char* logTag = "WebrtcGlobalInformation";
michael@0 32
michael@0 33 namespace mozilla {
michael@0 34 namespace dom {
michael@0 35
michael@0 36 typedef Vector<nsAutoPtr<RTCStatsQuery>> RTCStatsQueries;
michael@0 37
michael@0 38 static void OnStatsReport_m(
michael@0 39 nsMainThreadPtrHandle<WebrtcGlobalStatisticsCallback> aStatsCallback,
michael@0 40 nsAutoPtr<RTCStatsQueries> aQueryList)
michael@0 41 {
michael@0 42 MOZ_ASSERT(NS_IsMainThread());
michael@0 43 MOZ_ASSERT(aQueryList);
michael@0 44
michael@0 45 WebrtcGlobalStatisticsReport report;
michael@0 46 report.mReports.Construct();
michael@0 47 for (auto q = aQueryList->begin(); q != aQueryList->end(); ++q) {
michael@0 48 MOZ_ASSERT(*q);
michael@0 49 report.mReports.Value().AppendElement((*q)->report);
michael@0 50 }
michael@0 51
michael@0 52 ErrorResult rv;
michael@0 53 aStatsCallback.get()->Call(report, rv);
michael@0 54
michael@0 55 if (rv.Failed()) {
michael@0 56 CSFLogError(logTag, "Error firing stats observer callback");
michael@0 57 }
michael@0 58 }
michael@0 59
michael@0 60 static void GetAllStats_s(
michael@0 61 nsMainThreadPtrHandle<WebrtcGlobalStatisticsCallback> aStatsCallback,
michael@0 62 nsAutoPtr<RTCStatsQueries> aQueryList)
michael@0 63 {
michael@0 64 MOZ_ASSERT(aQueryList);
michael@0 65
michael@0 66 for (auto q = aQueryList->begin(); q != aQueryList->end(); ++q) {
michael@0 67 MOZ_ASSERT(*q);
michael@0 68 PeerConnectionImpl::ExecuteStatsQuery_s(*q);
michael@0 69 }
michael@0 70
michael@0 71 NS_DispatchToMainThread(WrapRunnableNM(&OnStatsReport_m,
michael@0 72 aStatsCallback,
michael@0 73 aQueryList),
michael@0 74 NS_DISPATCH_NORMAL);
michael@0 75 }
michael@0 76
michael@0 77 static void OnGetLogging_m(
michael@0 78 nsMainThreadPtrHandle<WebrtcGlobalLoggingCallback> aLoggingCallback,
michael@0 79 const std::string& aPattern,
michael@0 80 nsAutoPtr<std::deque<std::string>> aLogList)
michael@0 81 {
michael@0 82 ErrorResult rv;
michael@0 83 if (!aLogList->empty()) {
michael@0 84 Sequence<nsString> nsLogs;
michael@0 85 for (auto l = aLogList->begin(); l != aLogList->end(); ++l) {
michael@0 86 nsLogs.AppendElement(NS_ConvertUTF8toUTF16(l->c_str()));
michael@0 87 }
michael@0 88 aLoggingCallback.get()->Call(nsLogs, rv);
michael@0 89 }
michael@0 90
michael@0 91 if (rv.Failed()) {
michael@0 92 CSFLogError(logTag, "Error firing logging observer callback");
michael@0 93 }
michael@0 94 }
michael@0 95
michael@0 96 static void GetLogging_s(
michael@0 97 nsMainThreadPtrHandle<WebrtcGlobalLoggingCallback> aLoggingCallback,
michael@0 98 const std::string& aPattern)
michael@0 99 {
michael@0 100 RLogRingBuffer* logs = RLogRingBuffer::GetInstance();
michael@0 101 nsAutoPtr<std::deque<std::string>> result(new std::deque<std::string>);
michael@0 102 // Might not exist yet.
michael@0 103 if (logs) {
michael@0 104 logs->Filter(aPattern, 0, result);
michael@0 105 }
michael@0 106 NS_DispatchToMainThread(WrapRunnableNM(&OnGetLogging_m,
michael@0 107 aLoggingCallback,
michael@0 108 aPattern,
michael@0 109 result),
michael@0 110 NS_DISPATCH_NORMAL);
michael@0 111 }
michael@0 112
michael@0 113
michael@0 114 void
michael@0 115 WebrtcGlobalInformation::GetAllStats(
michael@0 116 const GlobalObject& aGlobal,
michael@0 117 WebrtcGlobalStatisticsCallback& aStatsCallback,
michael@0 118 ErrorResult& aRv)
michael@0 119 {
michael@0 120 if (!NS_IsMainThread()) {
michael@0 121 aRv.Throw(NS_ERROR_NOT_SAME_THREAD);
michael@0 122 return;
michael@0 123 }
michael@0 124
michael@0 125 nsresult rv;
michael@0 126 nsCOMPtr<nsIEventTarget> stsThread =
michael@0 127 do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
michael@0 128
michael@0 129 if (NS_FAILED(rv)) {
michael@0 130 aRv.Throw(rv);
michael@0 131 return;
michael@0 132 }
michael@0 133
michael@0 134 if (!stsThread) {
michael@0 135 aRv.Throw(NS_ERROR_UNEXPECTED);
michael@0 136 return;
michael@0 137 }
michael@0 138
michael@0 139 nsAutoPtr<RTCStatsQueries> queries(new RTCStatsQueries);
michael@0 140
michael@0 141 // If there is no PeerConnectionCtx, go through the same motions, since
michael@0 142 // the API consumer doesn't care why there are no PeerConnectionImpl.
michael@0 143 if (PeerConnectionCtx::isActive()) {
michael@0 144 PeerConnectionCtx *ctx = PeerConnectionCtx::GetInstance();
michael@0 145 MOZ_ASSERT(ctx);
michael@0 146 for (auto p = ctx->mPeerConnections.begin();
michael@0 147 p != ctx->mPeerConnections.end();
michael@0 148 ++p) {
michael@0 149 MOZ_ASSERT(p->second);
michael@0 150
michael@0 151 if (p->second->HasMedia()) {
michael@0 152 queries->append(nsAutoPtr<RTCStatsQuery>(new RTCStatsQuery(true)));
michael@0 153 p->second->BuildStatsQuery_m(nullptr, // all tracks
michael@0 154 queries->back());
michael@0 155 }
michael@0 156 }
michael@0 157 }
michael@0 158
michael@0 159 // CallbackObject does not support threadsafe refcounting, and must be
michael@0 160 // destroyed on main.
michael@0 161 nsMainThreadPtrHandle<WebrtcGlobalStatisticsCallback> callbackHandle(
michael@0 162 new nsMainThreadPtrHolder<WebrtcGlobalStatisticsCallback>(&aStatsCallback));
michael@0 163
michael@0 164 rv = RUN_ON_THREAD(stsThread,
michael@0 165 WrapRunnableNM(&GetAllStats_s, callbackHandle, queries),
michael@0 166 NS_DISPATCH_NORMAL);
michael@0 167
michael@0 168 aRv = rv;
michael@0 169 }
michael@0 170
michael@0 171 void
michael@0 172 WebrtcGlobalInformation::GetLogging(
michael@0 173 const GlobalObject& aGlobal,
michael@0 174 const nsAString& aPattern,
michael@0 175 WebrtcGlobalLoggingCallback& aLoggingCallback,
michael@0 176 ErrorResult& aRv)
michael@0 177 {
michael@0 178 if (!NS_IsMainThread()) {
michael@0 179 aRv.Throw(NS_ERROR_NOT_SAME_THREAD);
michael@0 180 return;
michael@0 181 }
michael@0 182
michael@0 183 nsresult rv;
michael@0 184 nsCOMPtr<nsIEventTarget> stsThread =
michael@0 185 do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
michael@0 186
michael@0 187 if (NS_FAILED(rv)) {
michael@0 188 aRv.Throw(rv);
michael@0 189 return;
michael@0 190 }
michael@0 191
michael@0 192 if (!stsThread) {
michael@0 193 aRv.Throw(NS_ERROR_UNEXPECTED);
michael@0 194 return;
michael@0 195 }
michael@0 196
michael@0 197 std::string pattern(NS_ConvertUTF16toUTF8(aPattern).get());
michael@0 198
michael@0 199 // CallbackObject does not support threadsafe refcounting, and must be
michael@0 200 // destroyed on main.
michael@0 201 nsMainThreadPtrHandle<WebrtcGlobalLoggingCallback> callbackHandle(
michael@0 202 new nsMainThreadPtrHolder<WebrtcGlobalLoggingCallback>(&aLoggingCallback));
michael@0 203
michael@0 204 rv = RUN_ON_THREAD(stsThread,
michael@0 205 WrapRunnableNM(&GetLogging_s, callbackHandle, pattern),
michael@0 206 NS_DISPATCH_NORMAL);
michael@0 207
michael@0 208 if (NS_FAILED(rv)) {
michael@0 209 aLoggingCallback.Release();
michael@0 210 }
michael@0 211
michael@0 212 aRv = rv;
michael@0 213 }
michael@0 214
michael@0 215 struct StreamResult {
michael@0 216 StreamResult() : candidateTypeBitpattern(0), streamSucceeded(false) {}
michael@0 217 uint8_t candidateTypeBitpattern;
michael@0 218 bool streamSucceeded;
michael@0 219 };
michael@0 220
michael@0 221 static void StoreLongTermICEStatisticsImpl_m(
michael@0 222 nsresult result,
michael@0 223 nsAutoPtr<RTCStatsQuery> query) {
michael@0 224
michael@0 225 if (NS_FAILED(result) ||
michael@0 226 !query->error.empty() ||
michael@0 227 !query->report.mIceCandidateStats.WasPassed()) {
michael@0 228 return;
michael@0 229 }
michael@0 230
michael@0 231 // First, store stuff in telemetry
michael@0 232 enum {
michael@0 233 REMOTE_GATHERED_SERVER_REFLEXIVE = 1,
michael@0 234 REMOTE_GATHERED_TURN = 1 << 1,
michael@0 235 LOCAL_GATHERED_SERVER_REFLEXIVE = 1 << 2,
michael@0 236 LOCAL_GATHERED_TURN_UDP = 1 << 3,
michael@0 237 LOCAL_GATHERED_TURN_TCP = 1 << 4,
michael@0 238 LOCAL_GATHERED_TURN_TLS = 1 << 5,
michael@0 239 LOCAL_GATHERED_TURN_HTTPS = 1 << 6,
michael@0 240 };
michael@0 241
michael@0 242 // TODO(bcampen@mozilla.com): Do we need to watch out for cases where the
michael@0 243 // components within a stream didn't have the same types of relayed
michael@0 244 // candidates? I have a feeling that late trickle could cause this, but right
michael@0 245 // now we don't have enough information to detect it (we would need to know
michael@0 246 // the ICE component id for each candidate pair and candidate)
michael@0 247
michael@0 248 std::map<std::string, StreamResult> streamResults;
michael@0 249
michael@0 250 // Build list of streams, and whether or not they failed.
michael@0 251 for (size_t i = 0;
michael@0 252 i < query->report.mIceCandidatePairStats.Value().Length();
michael@0 253 ++i) {
michael@0 254 const RTCIceCandidatePairStats &pair =
michael@0 255 query->report.mIceCandidatePairStats.Value()[i];
michael@0 256
michael@0 257 if (!pair.mState.WasPassed() || !pair.mComponentId.WasPassed()) {
michael@0 258 MOZ_CRASH();
michael@0 259 continue;
michael@0 260 }
michael@0 261
michael@0 262 // Note: this is not a "component" in the ICE definition, this is really a
michael@0 263 // stream ID. This is just the way the stats API is standardized right now.
michael@0 264 // Very confusing.
michael@0 265 std::string streamId(
michael@0 266 NS_ConvertUTF16toUTF8(pair.mComponentId.Value()).get());
michael@0 267
michael@0 268 streamResults[streamId].streamSucceeded |=
michael@0 269 pair.mState.Value() == RTCStatsIceCandidatePairState::Succeeded;
michael@0 270 }
michael@0 271
michael@0 272 for (size_t i = 0;
michael@0 273 i < query->report.mIceCandidateStats.Value().Length();
michael@0 274 ++i) {
michael@0 275 const RTCIceCandidateStats &cand =
michael@0 276 query->report.mIceCandidateStats.Value()[i];
michael@0 277
michael@0 278 if (!cand.mType.WasPassed() ||
michael@0 279 !cand.mCandidateType.WasPassed() ||
michael@0 280 !cand.mComponentId.WasPassed()) {
michael@0 281 // Crash on debug, ignore this candidate otherwise.
michael@0 282 MOZ_CRASH();
michael@0 283 continue;
michael@0 284 }
michael@0 285
michael@0 286 // Note: this is not a "component" in the ICE definition, this is really a
michael@0 287 // stream ID. This is just the way the stats API is standardized right now
michael@0 288 // Very confusing.
michael@0 289 std::string streamId(
michael@0 290 NS_ConvertUTF16toUTF8(cand.mComponentId.Value()).get());
michael@0 291
michael@0 292 if (cand.mCandidateType.Value() == RTCStatsIceCandidateType::Relayed) {
michael@0 293 if (cand.mType.Value() == RTCStatsType::Localcandidate) {
michael@0 294 NS_ConvertUTF16toUTF8 transport(cand.mMozLocalTransport.Value());
michael@0 295 if (transport == kNrIceTransportUdp) {
michael@0 296 streamResults[streamId].candidateTypeBitpattern |=
michael@0 297 LOCAL_GATHERED_TURN_UDP;
michael@0 298 } else if (transport == kNrIceTransportTcp) {
michael@0 299 streamResults[streamId].candidateTypeBitpattern |=
michael@0 300 LOCAL_GATHERED_TURN_TCP;
michael@0 301 }
michael@0 302 } else {
michael@0 303 streamResults[streamId].candidateTypeBitpattern |= REMOTE_GATHERED_TURN;
michael@0 304 }
michael@0 305 } else if (cand.mCandidateType.Value() ==
michael@0 306 RTCStatsIceCandidateType::Serverreflexive) {
michael@0 307 if (cand.mType.Value() == RTCStatsType::Localcandidate) {
michael@0 308 streamResults[streamId].candidateTypeBitpattern |=
michael@0 309 LOCAL_GATHERED_SERVER_REFLEXIVE;
michael@0 310 } else {
michael@0 311 streamResults[streamId].candidateTypeBitpattern |=
michael@0 312 REMOTE_GATHERED_SERVER_REFLEXIVE;
michael@0 313 }
michael@0 314 }
michael@0 315 }
michael@0 316
michael@0 317 for (auto i = streamResults.begin(); i != streamResults.end(); ++i) {
michael@0 318 if (i->second.streamSucceeded) {
michael@0 319 Telemetry::Accumulate(Telemetry::WEBRTC_CANDIDATE_TYPES_GIVEN_SUCCESS,
michael@0 320 i->second.candidateTypeBitpattern);
michael@0 321 } else {
michael@0 322 Telemetry::Accumulate(Telemetry::WEBRTC_CANDIDATE_TYPES_GIVEN_FAILURE,
michael@0 323 i->second.candidateTypeBitpattern);
michael@0 324 }
michael@0 325 }
michael@0 326 }
michael@0 327
michael@0 328 static void GetStatsForLongTermStorage_s(
michael@0 329 nsAutoPtr<RTCStatsQuery> query) {
michael@0 330
michael@0 331 MOZ_ASSERT(query);
michael@0 332
michael@0 333 nsresult rv = PeerConnectionImpl::ExecuteStatsQuery_s(query.get());
michael@0 334
michael@0 335 // Even if Telemetry::Accumulate is threadsafe, we still need to send the
michael@0 336 // query back to main, since that is where it must be destroyed.
michael@0 337 NS_DispatchToMainThread(
michael@0 338 WrapRunnableNM(
michael@0 339 &StoreLongTermICEStatisticsImpl_m,
michael@0 340 rv,
michael@0 341 query),
michael@0 342 NS_DISPATCH_NORMAL);
michael@0 343 }
michael@0 344
michael@0 345 void WebrtcGlobalInformation::StoreLongTermICEStatistics(
michael@0 346 sipcc::PeerConnectionImpl& aPc) {
michael@0 347 Telemetry::Accumulate(Telemetry::WEBRTC_ICE_FINAL_CONNECTION_STATE,
michael@0 348 static_cast<uint32_t>(aPc.IceConnectionState()));
michael@0 349
michael@0 350 if (aPc.IceConnectionState() == PCImplIceConnectionState::New) {
michael@0 351 // ICE has not started; we won't have any remote candidates, so recording
michael@0 352 // statistics on gathered candidates is pointless.
michael@0 353 return;
michael@0 354 }
michael@0 355
michael@0 356 nsAutoPtr<RTCStatsQuery> query(new RTCStatsQuery(true));
michael@0 357
michael@0 358 nsresult rv = aPc.BuildStatsQuery_m(nullptr, query.get());
michael@0 359
michael@0 360 NS_ENSURE_SUCCESS_VOID(rv);
michael@0 361
michael@0 362 RUN_ON_THREAD(aPc.GetSTSThread(),
michael@0 363 WrapRunnableNM(&GetStatsForLongTermStorage_s,
michael@0 364 query),
michael@0 365 NS_DISPATCH_NORMAL);
michael@0 366 }
michael@0 367
michael@0 368
michael@0 369 } // namespace dom
michael@0 370 } // namespace mozilla
michael@0 371

mercurial