Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "content/browser/renderer_host/media/audio_input_renderer_host.h" | 5 #include "content/browser/renderer_host/media/audio_input_renderer_host.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/files/file.h" | |
| 9 #include "base/memory/ref_counted.h" | |
| 8 #include "base/memory/shared_memory.h" | 10 #include "base/memory/shared_memory.h" |
| 9 #include "base/metrics/histogram.h" | 11 #include "base/metrics/histogram.h" |
| 10 #include "base/numerics/safe_math.h" | 12 #include "base/numerics/safe_math.h" |
| 11 #include "base/process/process.h" | 13 #include "base/process/process.h" |
| 14 #include "base/strings/string_number_conversions.h" | |
| 12 #include "base/strings/stringprintf.h" | 15 #include "base/strings/stringprintf.h" |
| 13 #include "content/browser/media/capture/web_contents_audio_input_stream.h" | 16 #include "content/browser/media/capture/web_contents_audio_input_stream.h" |
| 14 #include "content/browser/media/capture/web_contents_capture_util.h" | 17 #include "content/browser/media/capture/web_contents_capture_util.h" |
| 15 #include "content/browser/media/media_internals.h" | 18 #include "content/browser/media/media_internals.h" |
| 19 #include "content/browser/media/webrtc_internals.h" | |
| 20 #include "content/browser/renderer_host/media/audio_input_debug_writer.h" | |
| 16 #include "content/browser/renderer_host/media/audio_input_device_manager.h" | 21 #include "content/browser/renderer_host/media/audio_input_device_manager.h" |
| 17 #include "content/browser/renderer_host/media/audio_input_sync_writer.h" | 22 #include "content/browser/renderer_host/media/audio_input_sync_writer.h" |
| 18 #include "content/browser/renderer_host/media/media_stream_manager.h" | 23 #include "content/browser/renderer_host/media/media_stream_manager.h" |
| 24 #include "content/public/browser/render_process_host.h" | |
| 19 #include "media/audio/audio_manager_base.h" | 25 #include "media/audio/audio_manager_base.h" |
| 20 #include "media/base/audio_bus.h" | 26 #include "media/base/audio_bus.h" |
| 21 | 27 |
| 28 namespace content { | |
| 29 | |
| 22 namespace { | 30 namespace { |
| 23 | 31 |
| 32 const char kDebugRecordingFileNameAddition[] = "source_input"; | |
| 33 const char kDebugRecordingFileNameExtension[] = "pcm"; | |
| 34 | |
| 24 void LogMessage(int stream_id, const std::string& msg, bool add_prefix) { | 35 void LogMessage(int stream_id, const std::string& msg, bool add_prefix) { |
| 25 std::ostringstream oss; | 36 std::ostringstream oss; |
| 26 oss << "[stream_id=" << stream_id << "] "; | 37 oss << "[stream_id=" << stream_id << "] "; |
| 27 if (add_prefix) | 38 if (add_prefix) |
| 28 oss << "AIRH::"; | 39 oss << "AIRH::"; |
| 29 oss << msg; | 40 oss << msg; |
| 30 content::MediaStreamManager::SendMessageToNativeLog(oss.str()); | 41 content::MediaStreamManager::SendMessageToNativeLog(oss.str()); |
| 31 DVLOG(1) << oss.str(); | 42 DVLOG(1) << oss.str(); |
| 32 } | 43 } |
| 33 | 44 |
| 45 base::File CreateDebugRecordingFile(base::FilePath file_path) { | |
| 46 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | |
| 47 base::File recording_file( | |
| 48 file_path, | |
|
tommi (sloooow) - chröme
2015/08/07 12:09:51
not sure about the indent here... 4 spaces from th
Henrik Grunell
2015/08/17 15:05:17
Indeed. Creative indenting. :) Fixed.
| |
| 49 base::File::FLAG_OPEN_ALWAYS | base::File::FLAG_APPEND); | |
| 50 if (!recording_file.IsValid()) { | |
| 51 VLOG(1) << "Could not open debug recording file, error=" << | |
|
tommi (sloooow) - chröme
2015/08/07 12:09:51
nit: could use [P]LOG_IF(ERROR, !recording_file.Is
Henrik Grunell
2015/08/17 15:05:16
Done.
| |
| 52 recording_file.error_details(); | |
| 53 } | |
| 54 return recording_file.Pass(); | |
| 55 } | |
| 56 | |
| 57 void CloseFile(base::File* file) { | |
|
tommi (sloooow) - chröme
2015/08/07 12:09:51
just wondering - could ownership be passed via mov
Henrik Grunell
2015/08/17 15:05:17
Done.
| |
| 58 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | |
| 59 // |file| must be closed and destroyed on FILE thread. | |
| 60 delete file; | |
| 61 } | |
| 62 | |
| 63 void DeleteInputDebugWriterOnFileThread(AudioInputDebugWriter* writer) { | |
|
tommi (sloooow) - chröme
2015/08/07 12:09:51
same here... wondering if we could use scoped_ptr<
Henrik Grunell
2015/08/17 15:05:17
Done.
| |
| 64 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | |
| 65 delete writer; | |
| 66 } | |
| 67 | |
| 34 } // namespace | 68 } // namespace |
| 35 | 69 |
| 36 namespace content { | |
| 37 | |
| 38 struct AudioInputRendererHost::AudioEntry { | 70 struct AudioInputRendererHost::AudioEntry { |
| 39 AudioEntry(); | 71 AudioEntry(); |
| 40 ~AudioEntry(); | 72 ~AudioEntry(); |
| 41 | 73 |
| 42 // The AudioInputController that manages the audio input stream. | 74 // The AudioInputController that manages the audio input stream. |
| 43 scoped_refptr<media::AudioInputController> controller; | 75 scoped_refptr<media::AudioInputController> controller; |
| 44 | 76 |
| 45 // The audio input stream ID in the render view. | 77 // The audio input stream ID in the render view. |
| 46 int stream_id; | 78 int stream_id; |
| 47 | 79 |
| 48 // Shared memory for transmission of the audio data. It has | 80 // Shared memory for transmission of the audio data. It has |
| 49 // |shared_memory_segment_count| equal lengthed segments. | 81 // |shared_memory_segment_count| equal lengthed segments. |
| 50 base::SharedMemory shared_memory; | 82 base::SharedMemory shared_memory; |
| 51 int shared_memory_segment_count; | 83 int shared_memory_segment_count; |
| 52 | 84 |
| 53 // The synchronous writer to be used by the controller. We have the | 85 // The synchronous writer to be used by the controller. We have the |
| 54 // ownership of the writer. | 86 // ownership of the writer. |
| 55 scoped_ptr<media::AudioInputController::SyncWriter> writer; | 87 scoped_ptr<media::AudioInputController::SyncWriter> writer; |
| 56 | 88 |
| 89 // Keep a raw pointer since it must be deleted on the file thread. Must be | |
| 90 // posted for deletion and nulled before the AudioEntry is deleted. | |
| 91 AudioInputDebugWriter* input_debug_writer; | |
|
tommi (sloooow) - chröme
2015/08/07 12:09:51
I think you could still use a scoped_ptr even thou
Henrik Grunell
2015/08/17 15:05:17
I think that would signal that it's OK if it's del
tommi (sloooow) - chröme
2015/08/19 11:32:21
By that logic, it sounds like not deleting it shou
Henrik Grunell
2015/08/19 19:57:15
Hm, well, not sure I agree. :) But maybe "scoped_p
| |
| 92 | |
| 57 // Set to true after we called Close() for the controller. | 93 // Set to true after we called Close() for the controller. |
| 58 bool pending_close; | 94 bool pending_close; |
| 59 | 95 |
| 60 // If this entry's layout has a keyboard mic channel. | 96 // If this entry's layout has a keyboard mic channel. |
| 61 bool has_keyboard_mic_; | 97 bool has_keyboard_mic; |
| 62 }; | 98 }; |
| 63 | 99 |
| 64 AudioInputRendererHost::AudioEntry::AudioEntry() | 100 AudioInputRendererHost::AudioEntry::AudioEntry() |
| 65 : stream_id(0), | 101 : stream_id(0), |
| 66 shared_memory_segment_count(0), | 102 shared_memory_segment_count(0), |
| 103 input_debug_writer(nullptr), | |
| 67 pending_close(false), | 104 pending_close(false), |
| 68 has_keyboard_mic_(false) { | 105 has_keyboard_mic(false) { |
| 69 } | 106 } |
| 70 | 107 |
| 71 AudioInputRendererHost::AudioEntry::~AudioEntry() {} | 108 AudioInputRendererHost::AudioEntry::~AudioEntry() { |
| 109 DCHECK(!input_debug_writer); | |
| 110 } | |
| 72 | 111 |
| 73 AudioInputRendererHost::AudioInputRendererHost( | 112 AudioInputRendererHost::AudioInputRendererHost( |
| 74 int render_process_id, | 113 int render_process_id, |
| 114 RenderProcessHost* render_process_host, | |
| 75 media::AudioManager* audio_manager, | 115 media::AudioManager* audio_manager, |
| 76 MediaStreamManager* media_stream_manager, | 116 MediaStreamManager* media_stream_manager, |
| 77 AudioMirroringManager* audio_mirroring_manager, | 117 AudioMirroringManager* audio_mirroring_manager, |
| 78 media::UserInputMonitor* user_input_monitor) | 118 media::UserInputMonitor* user_input_monitor) |
| 79 : BrowserMessageFilter(AudioMsgStart), | 119 : BrowserMessageFilter(AudioMsgStart), |
| 80 render_process_id_(render_process_id), | 120 render_process_id_(render_process_id), |
| 121 render_process_host_(render_process_host), | |
| 81 audio_manager_(audio_manager), | 122 audio_manager_(audio_manager), |
| 82 media_stream_manager_(media_stream_manager), | 123 media_stream_manager_(media_stream_manager), |
| 83 audio_mirroring_manager_(audio_mirroring_manager), | 124 audio_mirroring_manager_(audio_mirroring_manager), |
| 84 user_input_monitor_(user_input_monitor), | 125 user_input_monitor_(user_input_monitor), |
| 85 audio_log_(MediaInternals::GetInstance()->CreateAudioLog( | 126 audio_log_(MediaInternals::GetInstance()->CreateAudioLog( |
| 86 media::AudioLogFactory::AUDIO_INPUT_CONTROLLER)) {} | 127 media::AudioLogFactory::AUDIO_INPUT_CONTROLLER)), |
| 128 weak_factory_(this) {} | |
| 87 | 129 |
| 88 AudioInputRendererHost::~AudioInputRendererHost() { | 130 AudioInputRendererHost::~AudioInputRendererHost() { |
| 89 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 131 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 90 DCHECK(audio_entries_.empty()); | 132 DCHECK(audio_entries_.empty()); |
| 91 } | 133 } |
| 92 | 134 |
| 135 void AudioInputRendererHost::EnableDebugRecording(const base::FilePath& file) { | |
| 136 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
| 137 base::FilePath file_with_extensions = | |
| 138 GetDebugRecordingFilePathWithExtensions(file); | |
| 139 for (AudioEntryMap::iterator i = audio_entries_.begin(); | |
|
tommi (sloooow) - chröme
2015/08/07 12:09:51
for (const auto& entry : audio_entries_)
Enabled
Henrik Grunell
2015/08/17 15:05:17
Done.
| |
| 140 i != audio_entries_.end(); ++i) { | |
| 141 EnabledDebugRecordingForId(file_with_extensions, i->first); | |
| 142 } | |
| 143 } | |
| 144 | |
| 145 void AudioInputRendererHost::DisableDebugRecording() { | |
| 146 for (AudioEntryMap::iterator it = audio_entries_.begin(); | |
|
tommi (sloooow) - chröme
2015/08/07 12:09:51
could use a range based loop here as well
Henrik Grunell
2015/08/17 15:05:17
Done.
| |
| 147 it != audio_entries_.end(); ++it) { | |
| 148 it->second->controller->DisableDebugRecording( | |
| 149 base::Bind(&AudioInputRendererHost::DeleteDebugWriter, | |
| 150 this, | |
| 151 it->first)); | |
| 152 } | |
| 153 } | |
| 154 | |
| 93 void AudioInputRendererHost::OnChannelClosing() { | 155 void AudioInputRendererHost::OnChannelClosing() { |
| 94 // Since the IPC sender is gone, close all requested audio streams. | 156 // Since the IPC sender is gone, close all requested audio streams. |
| 95 DeleteEntries(); | 157 DeleteEntries(); |
| 96 } | 158 } |
| 97 | 159 |
| 98 void AudioInputRendererHost::OnDestruct() const { | 160 void AudioInputRendererHost::OnDestruct() const { |
| 99 BrowserThread::DeleteOnIOThread::Destruct(this); | 161 BrowserThread::DeleteOnIOThread::Destruct(this); |
| 100 } | 162 } |
| 101 | 163 |
| 102 void AudioInputRendererHost::OnCreated( | 164 void AudioInputRendererHost::OnCreated( |
| (...skipping 299 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 402 | 464 |
| 403 if (!entry->controller.get()) { | 465 if (!entry->controller.get()) { |
| 404 SendErrorMessage(stream_id, STREAM_CREATE_ERROR); | 466 SendErrorMessage(stream_id, STREAM_CREATE_ERROR); |
| 405 MaybeUnregisterKeyboardMicStream(config); | 467 MaybeUnregisterKeyboardMicStream(config); |
| 406 return; | 468 return; |
| 407 } | 469 } |
| 408 | 470 |
| 409 #if defined(OS_CHROMEOS) | 471 #if defined(OS_CHROMEOS) |
| 410 if (config.params.channel_layout() == | 472 if (config.params.channel_layout() == |
| 411 media::CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC) { | 473 media::CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC) { |
| 412 entry->has_keyboard_mic_ = true; | 474 entry->has_keyboard_mic = true; |
| 413 } | 475 } |
| 414 #endif | 476 #endif |
| 415 | 477 |
| 416 MediaStreamManager::SendMessageToNativeLog(oss.str()); | 478 MediaStreamManager::SendMessageToNativeLog(oss.str()); |
| 417 DVLOG(1) << oss.str(); | 479 DVLOG(1) << oss.str(); |
| 418 | 480 |
| 419 // Since the controller was created successfully, create an entry and add it | 481 // Since the controller was created successfully, create an entry and add it |
| 420 // to the map. | 482 // to the map. |
| 421 entry->stream_id = stream_id; | 483 entry->stream_id = stream_id; |
| 422 audio_entries_.insert(std::make_pair(stream_id, entry.release())); | 484 audio_entries_.insert(std::make_pair(stream_id, entry.release())); |
| 423 audio_log_->OnCreated(stream_id, audio_params, device_id); | 485 audio_log_->OnCreated(stream_id, audio_params, device_id); |
| 424 MediaInternals::GetInstance()->SetWebContentsTitleForAudioLogEntry( | 486 MediaInternals::GetInstance()->SetWebContentsTitleForAudioLogEntry( |
| 425 stream_id, render_process_id_, render_frame_id, audio_log_.get()); | 487 stream_id, render_process_id_, render_frame_id, audio_log_.get()); |
| 488 | |
| 489 if (WebRTCInternals::GetInstance()->audio_debug_recordings_enabled()) { | |
| 490 AudioInputRendererHost::EnabledDebugRecordingForId( | |
| 491 GetDebugRecordingFilePathWithExtensions( | |
| 492 WebRTCInternals::GetInstance()->audio_debug_recordings_file_path()), | |
| 493 stream_id); | |
| 494 } | |
| 426 } | 495 } |
| 427 | 496 |
| 428 void AudioInputRendererHost::OnRecordStream(int stream_id) { | 497 void AudioInputRendererHost::OnRecordStream(int stream_id) { |
| 429 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 498 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 430 LogMessage(stream_id, "OnRecordStream", true); | 499 LogMessage(stream_id, "OnRecordStream", true); |
| 431 | 500 |
| 432 AudioEntry* entry = LookupById(stream_id); | 501 AudioEntry* entry = LookupById(stream_id); |
| 433 if (!entry) { | 502 if (!entry) { |
| 434 SendErrorMessage(stream_id, INVALID_AUDIO_ENTRY); | 503 SendErrorMessage(stream_id, INVALID_AUDIO_ENTRY); |
| 435 return; | 504 return; |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 491 entry->pending_close = true; | 560 entry->pending_close = true; |
| 492 audio_log_->OnClosed(entry->stream_id); | 561 audio_log_->OnClosed(entry->stream_id); |
| 493 } | 562 } |
| 494 } | 563 } |
| 495 | 564 |
| 496 void AudioInputRendererHost::DeleteEntry(AudioEntry* entry) { | 565 void AudioInputRendererHost::DeleteEntry(AudioEntry* entry) { |
| 497 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 566 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 498 LogMessage(entry->stream_id, "DeleteEntry: stream is now closed", true); | 567 LogMessage(entry->stream_id, "DeleteEntry: stream is now closed", true); |
| 499 | 568 |
| 500 #if defined(OS_CHROMEOS) | 569 #if defined(OS_CHROMEOS) |
| 501 if (entry->has_keyboard_mic_) { | 570 if (entry->has_keyboard_mic) { |
| 502 media_stream_manager_->audio_input_device_manager() | 571 media_stream_manager_->audio_input_device_manager() |
| 503 ->UnregisterKeyboardMicStream(); | 572 ->UnregisterKeyboardMicStream(); |
| 504 } | 573 } |
| 505 #endif | 574 #endif |
| 506 | 575 |
| 576 if (entry->input_debug_writer) { | |
| 577 BrowserThread::PostTask( | |
| 578 BrowserThread::FILE, | |
| 579 FROM_HERE, | |
| 580 base::Bind( | |
| 581 &DeleteInputDebugWriterOnFileThread, | |
| 582 entry->input_debug_writer)); | |
|
tommi (sloooow) - chröme
2015/08/07 12:09:51
would be nice to do input_debug_writer.Pass() :)
Henrik Grunell
2015/08/17 15:05:17
Why not? Made it move-only. :)
EDIT: Argh, can't
| |
| 583 entry->input_debug_writer = nullptr; | |
| 584 } | |
| 585 | |
| 507 // Delete the entry when this method goes out of scope. | 586 // Delete the entry when this method goes out of scope. |
| 508 scoped_ptr<AudioEntry> entry_deleter(entry); | 587 scoped_ptr<AudioEntry> entry_deleter(entry); |
| 509 | 588 |
| 510 // Erase the entry from the map. | 589 // Erase the entry from the map. |
| 511 audio_entries_.erase(entry->stream_id); | 590 audio_entries_.erase(entry->stream_id); |
| 512 } | 591 } |
| 513 | 592 |
| 514 void AudioInputRendererHost::DeleteEntryOnError(AudioEntry* entry, | 593 void AudioInputRendererHost::DeleteEntryOnError(AudioEntry* entry, |
| 515 ErrorCode error_code) { | 594 ErrorCode error_code) { |
| 516 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 595 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 549 const AudioInputHostMsg_CreateStream_Config& config) { | 628 const AudioInputHostMsg_CreateStream_Config& config) { |
| 550 #if defined(OS_CHROMEOS) | 629 #if defined(OS_CHROMEOS) |
| 551 if (config.params.channel_layout() == | 630 if (config.params.channel_layout() == |
| 552 media::CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC) { | 631 media::CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC) { |
| 553 media_stream_manager_->audio_input_device_manager() | 632 media_stream_manager_->audio_input_device_manager() |
| 554 ->UnregisterKeyboardMicStream(); | 633 ->UnregisterKeyboardMicStream(); |
| 555 } | 634 } |
| 556 #endif | 635 #endif |
| 557 } | 636 } |
| 558 | 637 |
| 638 #if defined(OS_WIN) | |
| 639 #define IntToStringType base::IntToString16 | |
| 640 #else | |
| 641 #define IntToStringType base::IntToString | |
| 642 #endif | |
| 643 | |
| 644 base::FilePath AudioInputRendererHost::GetDebugRecordingFilePathWithExtensions( | |
| 645 const base::FilePath& file) { | |
| 646 return file.AddExtension(kDebugRecordingFileNameAddition).AddExtension( | |
| 647 IntToStringType(base::GetProcId(render_process_host_->GetHandle()))); | |
| 648 } | |
| 649 | |
| 650 void AudioInputRendererHost::EnabledDebugRecordingForId( | |
| 651 const base::FilePath& file, | |
| 652 int stream_id) { | |
| 653 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
| 654 BrowserThread::PostTaskAndReplyWithResult( | |
| 655 BrowserThread::FILE, | |
| 656 FROM_HERE, | |
| 657 base::Bind( | |
| 658 &CreateDebugRecordingFile, | |
| 659 file.AddExtension(IntToStringType(stream_id)) | |
| 660 .AddExtension( | |
| 661 FILE_PATH_LITERAL(kDebugRecordingFileNameExtension))), | |
| 662 base::Bind( | |
| 663 &AudioInputRendererHost::DoEnableDebugRecording, | |
| 664 weak_factory_.GetWeakPtr(), | |
| 665 stream_id)); | |
| 666 } | |
| 667 | |
| 668 #undef IntToStringType | |
| 669 | |
| 670 void AudioInputRendererHost::DoEnableDebugRecording( | |
| 671 int stream_id, | |
| 672 base::File file) { | |
| 673 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
| 674 if (!file.IsValid()) | |
| 675 return; | |
|
tommi (sloooow) - chröme
2015/08/07 12:09:51
should we dcheck here or is this an expected case?
Henrik Grunell
2015/08/17 15:05:17
It could happen if the user selects a folder witho
| |
| 676 AudioEntry* entry = LookupById(stream_id); | |
| 677 if (!entry) { | |
| 678 BrowserThread::PostTask( | |
| 679 BrowserThread::FILE, | |
| 680 FROM_HERE, | |
| 681 base::Bind( | |
| 682 &CloseFile, | |
| 683 base::Unretained(new base::File(file.Pass())))); | |
|
tommi (sloooow) - chröme
2015/08/07 12:09:51
is there no way we could just do
file.Pass() here?
Henrik Grunell
2015/08/17 15:05:17
Done.
| |
| 684 return; | |
| 685 } | |
| 686 entry->input_debug_writer = new AudioInputDebugWriter(file.Pass()); | |
| 687 entry->controller->EnableDebugRecording(entry->input_debug_writer); | |
| 688 } | |
| 689 | |
| 690 void AudioInputRendererHost::DeleteDebugWriter(int stream_id) { | |
| 691 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
| 692 AudioEntry* entry = LookupById(stream_id); | |
| 693 if (!entry) { | |
| 694 // This happens if DisableDebugRecording is called right after | |
| 695 // DeleteEntries. | |
| 696 return; | |
| 697 } | |
| 698 | |
| 699 if (entry->input_debug_writer) { | |
| 700 BrowserThread::PostTask( | |
| 701 BrowserThread::FILE, | |
| 702 FROM_HERE, | |
| 703 base::Bind( | |
| 704 &DeleteInputDebugWriterOnFileThread, | |
| 705 entry->input_debug_writer)); | |
| 706 entry->input_debug_writer = nullptr; | |
| 707 } | |
| 708 } | |
| 709 | |
| 559 } // namespace content | 710 } // namespace content |
| OLD | NEW |