1 // Copyright 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/browser/media/webrtc_logging_handler_host.h" 6 7 #include <string> 8 9 #include "base/bind.h" 10 #include "base/command_line.h" 11 #include "base/cpu.h" 12 #include "base/file_util.h" 13 #include "base/logging.h" 14 #include "base/prefs/pref_service.h" 15 #include "base/strings/string_number_conversions.h" 16 #include "base/sys_info.h" 17 #include "base/time/time.h" 18 #include "chrome/browser/browser_process.h" 19 #include "chrome/browser/chromeos/settings/cros_settings.h" 20 #include "chrome/browser/media/webrtc_log_list.h" 21 #include "chrome/browser/media/webrtc_log_uploader.h" 22 #include "chrome/browser/media/webrtc_rtp_dump_handler.h" 23 #include "chrome/browser/profiles/profile.h" 24 #include "chrome/common/chrome_switches.h" 25 #include "chrome/common/media/webrtc_logging_messages.h" 26 #include "chrome/common/partial_circular_buffer.h" 27 #include "chrome/common/pref_names.h" 28 #include "chromeos/settings/cros_settings_names.h" 29 #include "content/public/browser/browser_thread.h" 30 #include "content/public/browser/content_browser_client.h" 31 #include "content/public/browser/gpu_data_manager.h" 32 #include "content/public/browser/render_process_host.h" 33 #include "gpu/config/gpu_info.h" 34 #include "net/base/address_family.h" 35 #include "net/url_request/url_request_context_getter.h" 36 37 #if defined(OS_LINUX) 38 #include "base/linux_util.h" 39 #endif 40 41 #if defined(OS_MACOSX) 42 #include "base/mac/mac_util.h" 43 #endif 44 45 #if defined(OS_CHROMEOS) 46 #include "chromeos/system/statistics_provider.h" 47 #endif 48 49 using base::IntToString; 50 using content::BrowserThread; 51 52 namespace { 53 54 #if defined(OS_ANDROID) 55 const size_t kWebRtcLogSize = 1 * 1024 * 1024; // 1 MB 56 #else 57 const size_t kWebRtcLogSize = 6 * 1024 * 1024; // 6 MB 58 #endif 59 60 const char kLogNotStoppedOrNoLogOpen[] = 61 "Logging not stopped or no log open."; 62 63 // For privacy reasons when logging IP addresses. The returned "sensitive 64 // string" is for release builds a string with the end stripped away. Last 65 // octet for IPv4 and last 80 bits (5 groups) for IPv6. String will be 66 // "1.2.3.x" and "1.2.3::" respectively. For debug builds, the string is 67 // not stripped. 68 std::string IPAddressToSensitiveString(const net::IPAddressNumber& address) { 69 #if defined(NDEBUG) 70 std::string sensitive_address; 71 switch (net::GetAddressFamily(address)) { 72 case net::ADDRESS_FAMILY_IPV4: { 73 sensitive_address = net::IPAddressToString(address); 74 size_t find_pos = sensitive_address.rfind('.'); 75 if (find_pos == std::string::npos) 76 return std::string(); 77 sensitive_address.resize(find_pos); 78 sensitive_address += ".x"; 79 break; 80 } 81 case net::ADDRESS_FAMILY_IPV6: { 82 // TODO(grunell): Create a string of format "1:2:3:x:x:x:x:x" to clarify 83 // that the end has been stripped out. 84 net::IPAddressNumber sensitive_address_number = address; 85 sensitive_address_number.resize(net::kIPv6AddressSize - 10); 86 sensitive_address_number.resize(net::kIPv6AddressSize, 0); 87 sensitive_address = net::IPAddressToString(sensitive_address_number); 88 break; 89 } 90 case net::ADDRESS_FAMILY_UNSPECIFIED: { 91 break; 92 } 93 } 94 return sensitive_address; 95 #else 96 return net::IPAddressToString(address); 97 #endif 98 } 99 100 void FormatMetaDataAsLogMessage( 101 const MetaDataMap& meta_data, 102 std::string* message) { 103 for (MetaDataMap::const_iterator it = meta_data.begin(); 104 it != meta_data.end(); ++it) { 105 *message += it->first + ": " + it->second + '\n'; 106 } 107 // Remove last '\n'. 108 message->resize(message->size() - 1); 109 } 110 111 } // namespace 112 113 WebRtcLoggingHandlerHost::WebRtcLoggingHandlerHost(Profile* profile) 114 : BrowserMessageFilter(WebRtcLoggingMsgStart), 115 profile_(profile), 116 logging_state_(CLOSED), 117 upload_log_on_render_close_(false) { 118 DCHECK(profile_); 119 } 120 121 WebRtcLoggingHandlerHost::~WebRtcLoggingHandlerHost() {} 122 123 void WebRtcLoggingHandlerHost::SetMetaData( 124 const MetaDataMap& meta_data, 125 const GenericDoneCallback& callback) { 126 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 127 DCHECK(!callback.is_null()); 128 129 std::string error_message; 130 if (logging_state_ == CLOSED) { 131 meta_data_ = meta_data; 132 } else if (logging_state_ == STARTED) { 133 meta_data_ = meta_data; 134 std::string meta_data_message; 135 FormatMetaDataAsLogMessage(meta_data_, &meta_data_message); 136 LogToCircularBuffer(meta_data_message); 137 } else { 138 error_message = "Meta data must be set before stop or upload."; 139 } 140 bool success = error_message.empty(); 141 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, 142 base::Bind(callback, success, 143 error_message)); 144 } 145 146 void WebRtcLoggingHandlerHost::StartLogging( 147 const GenericDoneCallback& callback) { 148 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 149 DCHECK(!callback.is_null()); 150 151 start_callback_ = callback; 152 if (logging_state_ != CLOSED) { 153 FireGenericDoneCallback(&start_callback_, false, "A log is already open"); 154 return; 155 } 156 logging_state_ = STARTING; 157 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind( 158 &WebRtcLoggingHandlerHost::StartLoggingIfAllowed, this)); 159 } 160 161 void WebRtcLoggingHandlerHost::StopLogging( 162 const GenericDoneCallback& callback) { 163 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 164 DCHECK(!callback.is_null()); 165 166 stop_callback_ = callback; 167 if (logging_state_ != STARTED) { 168 FireGenericDoneCallback(&stop_callback_, false, "Logging not started"); 169 return; 170 } 171 logging_state_ = STOPPING; 172 Send(new WebRtcLoggingMsg_StopLogging()); 173 } 174 175 void WebRtcLoggingHandlerHost::UploadLog(const UploadDoneCallback& callback) { 176 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 177 DCHECK(!callback.is_null()); 178 179 if (logging_state_ != STOPPED) { 180 if (!callback.is_null()) { 181 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, 182 base::Bind(callback, false, "", kLogNotStoppedOrNoLogOpen)); 183 } 184 return; 185 } 186 187 upload_callback_ = callback; 188 logging_state_ = UPLOADING; 189 content::BrowserThread::PostTaskAndReplyWithResult( 190 content::BrowserThread::FILE, 191 FROM_HERE, 192 base::Bind(&WebRtcLoggingHandlerHost::GetLogDirectoryAndEnsureExists, 193 this), 194 base::Bind(&WebRtcLoggingHandlerHost::TriggerUpload, this)); 195 } 196 197 void WebRtcLoggingHandlerHost::UploadLogDone() { 198 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 199 logging_state_ = CLOSED; 200 } 201 202 void WebRtcLoggingHandlerHost::DiscardLog(const GenericDoneCallback& callback) { 203 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 204 DCHECK(!callback.is_null()); 205 206 GenericDoneCallback discard_callback = callback; 207 if (logging_state_ != STOPPED) { 208 FireGenericDoneCallback(&discard_callback, false, 209 kLogNotStoppedOrNoLogOpen); 210 return; 211 } 212 g_browser_process->webrtc_log_uploader()->LoggingStoppedDontUpload(); 213 circular_buffer_.reset(); 214 log_buffer_.reset(); 215 logging_state_ = CLOSED; 216 rtp_dump_handler_.reset(); 217 stop_rtp_dump_callback_.Reset(); 218 FireGenericDoneCallback(&discard_callback, true, ""); 219 } 220 221 void WebRtcLoggingHandlerHost::LogMessage(const std::string& message) { 222 BrowserThread::PostTask( 223 BrowserThread::IO, 224 FROM_HERE, 225 base::Bind( 226 &WebRtcLoggingHandlerHost::AddLogMessageFromBrowser, 227 this, 228 WebRtcLoggingMessageData(base::Time::Now(), message))); 229 } 230 231 void WebRtcLoggingHandlerHost::StartRtpDump( 232 RtpDumpType type, 233 const GenericDoneCallback& callback, 234 const content::RenderProcessHost::WebRtcStopRtpDumpCallback& 235 stop_callback) { 236 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 237 DCHECK(stop_rtp_dump_callback_.is_null() || 238 stop_rtp_dump_callback_.Equals(stop_callback)); 239 240 stop_rtp_dump_callback_ = stop_callback; 241 242 if (!rtp_dump_handler_) { 243 content::BrowserThread::PostTaskAndReplyWithResult( 244 content::BrowserThread::FILE, 245 FROM_HERE, 246 base::Bind(&WebRtcLoggingHandlerHost::GetLogDirectoryAndEnsureExists, 247 this), 248 base::Bind(&WebRtcLoggingHandlerHost::CreateRtpDumpHandlerAndStart, 249 this, 250 type, 251 callback)); 252 return; 253 } 254 255 GenericDoneCallback start_callback = callback; 256 DoStartRtpDump(type, &start_callback); 257 } 258 259 void WebRtcLoggingHandlerHost::StopRtpDump( 260 RtpDumpType type, 261 const GenericDoneCallback& callback) { 262 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 263 DCHECK(!callback.is_null()); 264 265 if (!rtp_dump_handler_) { 266 GenericDoneCallback stop_callback = callback; 267 FireGenericDoneCallback( 268 &stop_callback, false, "RTP dump has not been started."); 269 return; 270 } 271 272 if (!stop_rtp_dump_callback_.is_null()) { 273 BrowserThread::PostTask( 274 BrowserThread::UI, 275 FROM_HERE, 276 base::Bind(stop_rtp_dump_callback_, 277 type == RTP_DUMP_INCOMING || type == RTP_DUMP_BOTH, 278 type == RTP_DUMP_OUTGOING || type == RTP_DUMP_BOTH)); 279 } 280 281 rtp_dump_handler_->StopDump(type, callback); 282 } 283 284 void WebRtcLoggingHandlerHost::OnRtpPacket(scoped_ptr<uint8[]> packet_header, 285 size_t header_length, 286 size_t packet_length, 287 bool incoming) { 288 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 289 290 BrowserThread::PostTask( 291 BrowserThread::IO, 292 FROM_HERE, 293 base::Bind(&WebRtcLoggingHandlerHost::DumpRtpPacketOnIOThread, 294 this, 295 base::Passed(&packet_header), 296 header_length, 297 packet_length, 298 incoming)); 299 } 300 301 void WebRtcLoggingHandlerHost::DumpRtpPacketOnIOThread( 302 scoped_ptr<uint8[]> packet_header, 303 size_t header_length, 304 size_t packet_length, 305 bool incoming) { 306 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 307 308 // |rtp_dump_handler_| could be NULL if we are waiting for the FILE thread to 309 // create/ensure the log directory. 310 if (rtp_dump_handler_) { 311 rtp_dump_handler_->OnRtpPacket( 312 packet_header.get(), header_length, packet_length, incoming); 313 } 314 } 315 316 void WebRtcLoggingHandlerHost::OnChannelClosing() { 317 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 318 if (logging_state_ == STARTED || logging_state_ == STOPPED) { 319 if (upload_log_on_render_close_) { 320 logging_state_ = UPLOADING; 321 logging_started_time_ = base::Time(); 322 323 content::BrowserThread::PostTaskAndReplyWithResult( 324 content::BrowserThread::FILE, 325 FROM_HERE, 326 base::Bind(&WebRtcLoggingHandlerHost::GetLogDirectoryAndEnsureExists, 327 this), 328 base::Bind(&WebRtcLoggingHandlerHost::TriggerUpload, this)); 329 } else { 330 g_browser_process->webrtc_log_uploader()->LoggingStoppedDontUpload(); 331 } 332 } 333 content::BrowserMessageFilter::OnChannelClosing(); 334 } 335 336 void WebRtcLoggingHandlerHost::OnDestruct() const { 337 BrowserThread::DeleteOnIOThread::Destruct(this); 338 } 339 340 bool WebRtcLoggingHandlerHost::OnMessageReceived(const IPC::Message& message) { 341 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 342 bool handled = true; 343 IPC_BEGIN_MESSAGE_MAP(WebRtcLoggingHandlerHost, message) 344 IPC_MESSAGE_HANDLER(WebRtcLoggingMsg_AddLogMessages, OnAddLogMessages) 345 IPC_MESSAGE_HANDLER(WebRtcLoggingMsg_LoggingStopped, 346 OnLoggingStoppedInRenderer) 347 IPC_MESSAGE_UNHANDLED(handled = false) 348 IPC_END_MESSAGE_MAP() 349 350 return handled; 351 } 352 353 void WebRtcLoggingHandlerHost::AddLogMessageFromBrowser( 354 const WebRtcLoggingMessageData& message) { 355 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 356 if (logging_state_ == STARTED) 357 LogToCircularBuffer(message.Format(logging_started_time_)); 358 } 359 360 void WebRtcLoggingHandlerHost::OnAddLogMessages( 361 const std::vector<WebRtcLoggingMessageData>& messages) { 362 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 363 if (logging_state_ == STARTED || logging_state_ == STOPPING) { 364 for (size_t i = 0; i < messages.size(); ++i) { 365 LogToCircularBuffer(messages[i].Format(logging_started_time_)); 366 } 367 } 368 } 369 370 void WebRtcLoggingHandlerHost::OnLoggingStoppedInRenderer() { 371 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 372 if (logging_state_ != STOPPING) { 373 // If an out-of-order response is received, stop_callback_ may be invalid, 374 // and must not be invoked. 375 DLOG(ERROR) << "OnLoggingStoppedInRenderer invoked in state " 376 << logging_state_; 377 BadMessageReceived(); 378 return; 379 } 380 logging_started_time_ = base::Time(); 381 logging_state_ = STOPPED; 382 FireGenericDoneCallback(&stop_callback_, true, ""); 383 } 384 385 void WebRtcLoggingHandlerHost::StartLoggingIfAllowed() { 386 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 387 if (!g_browser_process->webrtc_log_uploader()->ApplyForStartLogging()) { 388 logging_state_ = CLOSED; 389 FireGenericDoneCallback( 390 &start_callback_, false, "Cannot start, maybe the maximum number of " 391 "simultaneuos logs has been reached."); 392 return; 393 } 394 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, base::Bind( 395 &WebRtcLoggingHandlerHost::DoStartLogging, this)); 396 } 397 398 void WebRtcLoggingHandlerHost::DoStartLogging() { 399 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 400 401 log_buffer_.reset(new unsigned char[kWebRtcLogSize]); 402 circular_buffer_.reset( 403 new PartialCircularBuffer(log_buffer_.get(), 404 kWebRtcLogSize, 405 kWebRtcLogSize / 2, 406 false)); 407 408 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, base::Bind( 409 &WebRtcLoggingHandlerHost::LogInitialInfoOnFileThread, this)); 410 } 411 412 void WebRtcLoggingHandlerHost::LogInitialInfoOnFileThread() { 413 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 414 415 net::NetworkInterfaceList network_list; 416 net::GetNetworkList(&network_list, 417 net::EXCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES); 418 419 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, base::Bind( 420 &WebRtcLoggingHandlerHost::LogInitialInfoOnIOThread, this, network_list)); 421 } 422 423 void WebRtcLoggingHandlerHost::LogInitialInfoOnIOThread( 424 const net::NetworkInterfaceList& network_list) { 425 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 426 427 // Log start time (current time). We don't use base/i18n/time_formatting.h 428 // here because we don't want the format of the current locale. 429 base::Time::Exploded now = {0}; 430 base::Time::Now().LocalExplode(&now); 431 LogToCircularBuffer(base::StringPrintf( 432 "Start %d-%02d-%02d %02d:%02d:%02d", now.year, now.month, 433 now.day_of_month, now.hour, now.minute, now.second)); 434 435 // Write metadata if received before logging started. 436 if (!meta_data_.empty()) { 437 std::string info; 438 FormatMetaDataAsLogMessage(meta_data_, &info); 439 LogToCircularBuffer(info); 440 } 441 442 // OS 443 LogToCircularBuffer(base::SysInfo::OperatingSystemName() + " " + 444 base::SysInfo::OperatingSystemVersion() + " " + 445 base::SysInfo::OperatingSystemArchitecture()); 446 #if defined(OS_LINUX) 447 LogToCircularBuffer("Linux distribution: " + base::GetLinuxDistro()); 448 #endif 449 450 // CPU 451 base::CPU cpu; 452 LogToCircularBuffer( 453 "Cpu: " + IntToString(cpu.family()) + "." + IntToString(cpu.model()) + 454 "." + IntToString(cpu.stepping()) + ", x" + 455 IntToString(base::SysInfo::NumberOfProcessors()) + ", " + 456 IntToString(base::SysInfo::AmountOfPhysicalMemoryMB()) + "MB"); 457 std::string cpu_brand = cpu.cpu_brand(); 458 // Workaround for crbug.com/249713. 459 // TODO(grunell): Remove workaround when bug is fixed. 460 size_t null_pos = cpu_brand.find('\0'); 461 if (null_pos != std::string::npos) 462 cpu_brand.erase(null_pos); 463 LogToCircularBuffer("Cpu brand: " + cpu_brand); 464 465 // Computer model 466 std::string computer_model = "Not available"; 467 #if defined(OS_MACOSX) 468 computer_model = base::mac::GetModelIdentifier(); 469 #elif defined(OS_CHROMEOS) 470 chromeos::system::StatisticsProvider::GetInstance()-> 471 GetMachineStatistic(chromeos::system::kHardwareClassKey, &computer_model); 472 #endif 473 LogToCircularBuffer("Computer model: " + computer_model); 474 475 // GPU 476 gpu::GPUInfo gpu_info = content::GpuDataManager::GetInstance()->GetGPUInfo(); 477 LogToCircularBuffer( 478 "Gpu: machine-model-name=" + gpu_info.machine_model_name + 479 ", machine-model-version=" + gpu_info.machine_model_version + 480 ", vendor-id=" + IntToString(gpu_info.gpu.vendor_id) + 481 ", device-id=" + IntToString(gpu_info.gpu.device_id) + 482 ", driver-vendor=" + gpu_info.driver_vendor + 483 ", driver-version=" + gpu_info.driver_version); 484 LogToCircularBuffer( 485 "OpenGL: gl-vendor=" + gpu_info.gl_vendor + 486 ", gl-renderer=" + gpu_info.gl_renderer + 487 ", gl-version=" + gpu_info.gl_version); 488 489 // Network interfaces 490 LogToCircularBuffer("Discovered " + IntToString(network_list.size()) + 491 " network interfaces:"); 492 for (net::NetworkInterfaceList::const_iterator it = network_list.begin(); 493 it != network_list.end(); ++it) { 494 LogToCircularBuffer("Name: " + it->friendly_name + ", Address: " + 495 IPAddressToSensitiveString(it->address)); 496 } 497 498 NotifyLoggingStarted(); 499 } 500 501 void WebRtcLoggingHandlerHost::NotifyLoggingStarted() { 502 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 503 Send(new WebRtcLoggingMsg_StartLogging()); 504 logging_started_time_ = base::Time::Now(); 505 logging_state_ = STARTED; 506 FireGenericDoneCallback(&start_callback_, true, ""); 507 } 508 509 void WebRtcLoggingHandlerHost::LogToCircularBuffer(const std::string& message) { 510 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 511 DCHECK(circular_buffer_.get()); 512 circular_buffer_->Write(message.c_str(), message.length()); 513 const char eol = '\n'; 514 circular_buffer_->Write(&eol, 1); 515 } 516 517 base::FilePath WebRtcLoggingHandlerHost::GetLogDirectoryAndEnsureExists() { 518 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 519 base::FilePath log_dir_path = 520 WebRtcLogList::GetWebRtcLogDirectoryForProfile(profile_->GetPath()); 521 base::File::Error error; 522 if (!base::CreateDirectoryAndGetError(log_dir_path, &error)) { 523 DLOG(ERROR) << "Could not create WebRTC log directory, error: " << error; 524 return base::FilePath(); 525 } 526 return log_dir_path; 527 } 528 529 void WebRtcLoggingHandlerHost::TriggerUpload( 530 const base::FilePath& log_directory) { 531 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 532 DCHECK_EQ(logging_state_, UPLOADING); 533 534 if (rtp_dump_handler_) { 535 BrowserThread::PostTask( 536 BrowserThread::UI, 537 FROM_HERE, 538 base::Bind(stop_rtp_dump_callback_, true, true)); 539 540 rtp_dump_handler_->StopOngoingDumps( 541 base::Bind(&WebRtcLoggingHandlerHost::DoUploadLogAndRtpDumps, 542 this, 543 log_directory)); 544 return; 545 } 546 547 DoUploadLogAndRtpDumps(log_directory); 548 } 549 550 void WebRtcLoggingHandlerHost::DoUploadLogAndRtpDumps( 551 const base::FilePath& log_directory) { 552 WebRtcLogUploadDoneData upload_done_data; 553 upload_done_data.log_path = log_directory; 554 555 if (rtp_dump_handler_) { 556 WebRtcRtpDumpHandler::ReleasedDumps rtp_dumps( 557 rtp_dump_handler_->ReleaseDumps()); 558 upload_done_data.incoming_rtp_dump = rtp_dumps.incoming_dump_path; 559 upload_done_data.outgoing_rtp_dump = rtp_dumps.outgoing_dump_path; 560 561 rtp_dump_handler_.reset(); 562 stop_rtp_dump_callback_.Reset(); 563 } 564 565 upload_done_data.callback = upload_callback_; 566 upload_done_data.host = this; 567 upload_callback_.Reset(); 568 569 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, base::Bind( 570 &WebRtcLogUploader::LoggingStoppedDoUpload, 571 base::Unretained(g_browser_process->webrtc_log_uploader()), 572 Passed(&log_buffer_), 573 kWebRtcLogSize, 574 meta_data_, 575 upload_done_data)); 576 577 meta_data_.clear(); 578 circular_buffer_.reset(); 579 } 580 581 void WebRtcLoggingHandlerHost::FireGenericDoneCallback( 582 GenericDoneCallback* callback, 583 bool success, 584 const std::string& error_message) { 585 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 586 DCHECK(!(*callback).is_null()); 587 content::BrowserThread::PostTask( 588 content::BrowserThread::UI, 589 FROM_HERE, 590 base::Bind(*callback, success, error_message)); 591 (*callback).Reset(); 592 } 593 594 void WebRtcLoggingHandlerHost::CreateRtpDumpHandlerAndStart( 595 RtpDumpType type, 596 GenericDoneCallback callback, 597 const base::FilePath& dump_dir) { 598 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 599 600 // |rtp_dump_handler_| may be non-NULL if StartRtpDump is called again before 601 // GetLogDirectoryAndEnsureExists returns on the FILE thread for a previous 602 // StartRtpDump. 603 if (!rtp_dump_handler_) 604 rtp_dump_handler_.reset(new WebRtcRtpDumpHandler(dump_dir)); 605 606 DoStartRtpDump(type, &callback); 607 } 608 609 void WebRtcLoggingHandlerHost::DoStartRtpDump(RtpDumpType type, 610 GenericDoneCallback* callback) { 611 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 612 DCHECK(rtp_dump_handler_); 613 614 std::string error; 615 616 bool result = rtp_dump_handler_->StartDump(type, &error); 617 FireGenericDoneCallback(callback, result, error); 618 } 619