Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(73)

Side by Side Diff: content/browser/renderer_host/media/audio_input_renderer_host.cc

Issue 1272223003: Implement writing mic audio input data to file for debugging purposes. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase. Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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"
19 #include "media/audio/audio_manager_base.h" 24 #include "media/audio/audio_manager_base.h"
20 #include "media/base/audio_bus.h" 25 #include "media/base/audio_bus.h"
21 26
27 namespace content {
28
22 namespace { 29 namespace {
23 30
31 #ifdef ENABLE_WEBRTC
32 const base::FilePath::CharType kDebugRecordingFileNameAddition[] =
33 FILE_PATH_LITERAL("source_input");
34 const base::FilePath::CharType kDebugRecordingFileNameExtension[] =
35 FILE_PATH_LITERAL("pcm");
36 #endif
37
24 void LogMessage(int stream_id, const std::string& msg, bool add_prefix) { 38 void LogMessage(int stream_id, const std::string& msg, bool add_prefix) {
25 std::ostringstream oss; 39 std::ostringstream oss;
26 oss << "[stream_id=" << stream_id << "] "; 40 oss << "[stream_id=" << stream_id << "] ";
27 if (add_prefix) 41 if (add_prefix)
28 oss << "AIRH::"; 42 oss << "AIRH::";
29 oss << msg; 43 oss << msg;
30 content::MediaStreamManager::SendMessageToNativeLog(oss.str()); 44 content::MediaStreamManager::SendMessageToNativeLog(oss.str());
31 DVLOG(1) << oss.str(); 45 DVLOG(1) << oss.str();
32 } 46 }
33 47
48 #ifdef ENABLE_WEBRTC
49 base::File CreateDebugRecordingFile(base::FilePath file_path) {
50 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
51 base::File recording_file(
52 file_path, base::File::FLAG_OPEN_ALWAYS | base::File::FLAG_APPEND);
53 PLOG_IF(ERROR, !recording_file.IsValid())
54 << "Could not open debug recording file, error="
55 << recording_file.error_details();
56 return recording_file.Pass();
57 }
58
59 void CloseFile(base::File file) {
60 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
61 // |file| must be closed and destroyed on FILE thread.
62 }
63
64 void DeleteInputDebugWriterOnFileThread(
65 scoped_ptr<AudioInputDebugWriter> writer) {
66 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
67 // |writer| must be closed and destroyed on FILE thread.
68 }
69 #endif // ENABLE_WEBRTC
70
34 } // namespace 71 } // namespace
35 72
36 namespace content {
37
38 struct AudioInputRendererHost::AudioEntry { 73 struct AudioInputRendererHost::AudioEntry {
39 AudioEntry(); 74 AudioEntry();
40 ~AudioEntry(); 75 ~AudioEntry();
41 76
42 // The AudioInputController that manages the audio input stream. 77 // The AudioInputController that manages the audio input stream.
43 scoped_refptr<media::AudioInputController> controller; 78 scoped_refptr<media::AudioInputController> controller;
44 79
45 // The audio input stream ID in the render view. 80 // The audio input stream ID in the render view.
46 int stream_id; 81 int stream_id;
47 82
48 // Shared memory for transmission of the audio data. It has 83 // Shared memory for transmission of the audio data. It has
49 // |shared_memory_segment_count| equal lengthed segments. 84 // |shared_memory_segment_count| equal lengthed segments.
50 base::SharedMemory shared_memory; 85 base::SharedMemory shared_memory;
51 int shared_memory_segment_count; 86 int shared_memory_segment_count;
52 87
53 // The synchronous writer to be used by the controller. We have the 88 // The synchronous writer to be used by the controller. We have the
54 // ownership of the writer. 89 // ownership of the writer.
55 scoped_ptr<media::AudioInputController::SyncWriter> writer; 90 scoped_ptr<media::AudioInputController::SyncWriter> writer;
56 91
92 // Must be deleted on the file thread. Must be posted for deletion and nulled
93 // before the AudioEntry is deleted.
94 scoped_ptr<AudioInputDebugWriter> input_debug_writer;
95
57 // Set to true after we called Close() for the controller. 96 // Set to true after we called Close() for the controller.
58 bool pending_close; 97 bool pending_close;
59 98
60 // If this entry's layout has a keyboard mic channel. 99 // If this entry's layout has a keyboard mic channel.
61 bool has_keyboard_mic_; 100 bool has_keyboard_mic;
62 }; 101 };
63 102
64 AudioInputRendererHost::AudioEntry::AudioEntry() 103 AudioInputRendererHost::AudioEntry::AudioEntry()
65 : stream_id(0), 104 : stream_id(0),
66 shared_memory_segment_count(0), 105 shared_memory_segment_count(0),
67 pending_close(false), 106 pending_close(false),
68 has_keyboard_mic_(false) { 107 has_keyboard_mic(false) {
69 } 108 }
70 109
71 AudioInputRendererHost::AudioEntry::~AudioEntry() {} 110 AudioInputRendererHost::AudioEntry::~AudioEntry() {
111 DCHECK(!input_debug_writer.get());
112 }
72 113
73 AudioInputRendererHost::AudioInputRendererHost( 114 AudioInputRendererHost::AudioInputRendererHost(
74 int render_process_id, 115 int render_process_id,
116 int32 renderer_pid,
75 media::AudioManager* audio_manager, 117 media::AudioManager* audio_manager,
76 MediaStreamManager* media_stream_manager, 118 MediaStreamManager* media_stream_manager,
77 AudioMirroringManager* audio_mirroring_manager, 119 AudioMirroringManager* audio_mirroring_manager,
78 media::UserInputMonitor* user_input_monitor) 120 media::UserInputMonitor* user_input_monitor)
79 : BrowserMessageFilter(AudioMsgStart), 121 : BrowserMessageFilter(AudioMsgStart),
80 render_process_id_(render_process_id), 122 render_process_id_(render_process_id),
123 renderer_pid_(renderer_pid),
81 audio_manager_(audio_manager), 124 audio_manager_(audio_manager),
82 media_stream_manager_(media_stream_manager), 125 media_stream_manager_(media_stream_manager),
83 audio_mirroring_manager_(audio_mirroring_manager), 126 audio_mirroring_manager_(audio_mirroring_manager),
84 user_input_monitor_(user_input_monitor), 127 user_input_monitor_(user_input_monitor),
85 audio_log_(MediaInternals::GetInstance()->CreateAudioLog( 128 audio_log_(MediaInternals::GetInstance()->CreateAudioLog(
86 media::AudioLogFactory::AUDIO_INPUT_CONTROLLER)) {} 129 media::AudioLogFactory::AUDIO_INPUT_CONTROLLER)),
130 weak_factory_(this) {}
87 131
88 AudioInputRendererHost::~AudioInputRendererHost() { 132 AudioInputRendererHost::~AudioInputRendererHost() {
89 DCHECK_CURRENTLY_ON(BrowserThread::IO); 133 DCHECK_CURRENTLY_ON(BrowserThread::IO);
90 DCHECK(audio_entries_.empty()); 134 DCHECK(audio_entries_.empty());
91 } 135 }
92 136
137 #ifdef ENABLE_WEBRTC
138 void AudioInputRendererHost::EnableDebugRecording(const base::FilePath& file) {
139 DCHECK_CURRENTLY_ON(BrowserThread::IO);
140 base::FilePath file_with_extensions =
141 GetDebugRecordingFilePathWithExtensions(file);
142 for (const auto& entry : audio_entries_)
143 EnableDebugRecordingForId(file_with_extensions, entry.first);
144 }
145
146 void AudioInputRendererHost::DisableDebugRecording() {
147 for (const auto& entry : audio_entries_) {
148 entry.second->controller->DisableDebugRecording(
149 base::Bind(&AudioInputRendererHost::DeleteDebugWriter,
150 this,
151 entry.first));
152 }
153 }
154 #endif // ENABLE_WEBRTC
155
93 void AudioInputRendererHost::OnChannelClosing() { 156 void AudioInputRendererHost::OnChannelClosing() {
94 // Since the IPC sender is gone, close all requested audio streams. 157 // Since the IPC sender is gone, close all requested audio streams.
95 DeleteEntries(); 158 DeleteEntries();
96 } 159 }
97 160
98 void AudioInputRendererHost::OnDestruct() const { 161 void AudioInputRendererHost::OnDestruct() const {
99 BrowserThread::DeleteOnIOThread::Destruct(this); 162 BrowserThread::DeleteOnIOThread::Destruct(this);
100 } 163 }
101 164
102 void AudioInputRendererHost::OnCreated( 165 void AudioInputRendererHost::OnCreated(
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
141 void AudioInputRendererHost::OnLog(media::AudioInputController* controller, 204 void AudioInputRendererHost::OnLog(media::AudioInputController* controller,
142 const std::string& message) { 205 const std::string& message) {
143 BrowserThread::PostTask(BrowserThread::IO, 206 BrowserThread::PostTask(BrowserThread::IO,
144 FROM_HERE, 207 FROM_HERE,
145 base::Bind(&AudioInputRendererHost::DoLog, 208 base::Bind(&AudioInputRendererHost::DoLog,
146 this, 209 this,
147 make_scoped_refptr(controller), 210 make_scoped_refptr(controller),
148 message)); 211 message));
149 } 212 }
150 213
214 void AudioInputRendererHost::set_renderer_pid(int32 renderer_pid) {
215 DCHECK_CURRENTLY_ON(BrowserThread::IO);
216 renderer_pid_ = renderer_pid;
217 }
218
151 void AudioInputRendererHost::DoCompleteCreation( 219 void AudioInputRendererHost::DoCompleteCreation(
152 media::AudioInputController* controller) { 220 media::AudioInputController* controller) {
153 DCHECK_CURRENTLY_ON(BrowserThread::IO); 221 DCHECK_CURRENTLY_ON(BrowserThread::IO);
154 222
155 AudioEntry* entry = LookupByController(controller); 223 AudioEntry* entry = LookupByController(controller);
156 if (!entry) { 224 if (!entry) {
157 NOTREACHED() << "AudioInputController is invalid."; 225 NOTREACHED() << "AudioInputController is invalid.";
158 return; 226 return;
159 } 227 }
160 228
(...skipping 241 matching lines...) Expand 10 before | Expand all | Expand 10 after
402 470
403 if (!entry->controller.get()) { 471 if (!entry->controller.get()) {
404 SendErrorMessage(stream_id, STREAM_CREATE_ERROR); 472 SendErrorMessage(stream_id, STREAM_CREATE_ERROR);
405 MaybeUnregisterKeyboardMicStream(config); 473 MaybeUnregisterKeyboardMicStream(config);
406 return; 474 return;
407 } 475 }
408 476
409 #if defined(OS_CHROMEOS) 477 #if defined(OS_CHROMEOS)
410 if (config.params.channel_layout() == 478 if (config.params.channel_layout() ==
411 media::CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC) { 479 media::CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC) {
412 entry->has_keyboard_mic_ = true; 480 entry->has_keyboard_mic = true;
413 } 481 }
414 #endif 482 #endif
415 483
416 MediaStreamManager::SendMessageToNativeLog(oss.str()); 484 MediaStreamManager::SendMessageToNativeLog(oss.str());
417 DVLOG(1) << oss.str(); 485 DVLOG(1) << oss.str();
418 486
419 // Since the controller was created successfully, create an entry and add it 487 // Since the controller was created successfully, create an entry and add it
420 // to the map. 488 // to the map.
421 entry->stream_id = stream_id; 489 entry->stream_id = stream_id;
422 audio_entries_.insert(std::make_pair(stream_id, entry.release())); 490 audio_entries_.insert(std::make_pair(stream_id, entry.release()));
423 audio_log_->OnCreated(stream_id, audio_params, device_id); 491 audio_log_->OnCreated(stream_id, audio_params, device_id);
424 MediaInternals::GetInstance()->SetWebContentsTitleForAudioLogEntry( 492 MediaInternals::GetInstance()->SetWebContentsTitleForAudioLogEntry(
425 stream_id, render_process_id_, render_frame_id, audio_log_.get()); 493 stream_id, render_process_id_, render_frame_id, audio_log_.get());
494
495 #if defined(ENABLE_WEBRTC)
496 BrowserThread::PostTask(
497 BrowserThread::UI,
498 FROM_HERE,
499 base::Bind(
500 &AudioInputRendererHost::MaybeEnableDebugRecordingForId,
501 this,
502 stream_id));
503 #endif
426 } 504 }
427 505
428 void AudioInputRendererHost::OnRecordStream(int stream_id) { 506 void AudioInputRendererHost::OnRecordStream(int stream_id) {
429 DCHECK_CURRENTLY_ON(BrowserThread::IO); 507 DCHECK_CURRENTLY_ON(BrowserThread::IO);
430 LogMessage(stream_id, "OnRecordStream", true); 508 LogMessage(stream_id, "OnRecordStream", true);
431 509
432 AudioEntry* entry = LookupById(stream_id); 510 AudioEntry* entry = LookupById(stream_id);
433 if (!entry) { 511 if (!entry) {
434 SendErrorMessage(stream_id, INVALID_AUDIO_ENTRY); 512 SendErrorMessage(stream_id, INVALID_AUDIO_ENTRY);
435 return; 513 return;
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
491 entry->pending_close = true; 569 entry->pending_close = true;
492 audio_log_->OnClosed(entry->stream_id); 570 audio_log_->OnClosed(entry->stream_id);
493 } 571 }
494 } 572 }
495 573
496 void AudioInputRendererHost::DeleteEntry(AudioEntry* entry) { 574 void AudioInputRendererHost::DeleteEntry(AudioEntry* entry) {
497 DCHECK_CURRENTLY_ON(BrowserThread::IO); 575 DCHECK_CURRENTLY_ON(BrowserThread::IO);
498 LogMessage(entry->stream_id, "DeleteEntry: stream is now closed", true); 576 LogMessage(entry->stream_id, "DeleteEntry: stream is now closed", true);
499 577
500 #if defined(OS_CHROMEOS) 578 #if defined(OS_CHROMEOS)
501 if (entry->has_keyboard_mic_) { 579 if (entry->has_keyboard_mic) {
502 media_stream_manager_->audio_input_device_manager() 580 media_stream_manager_->audio_input_device_manager()
503 ->UnregisterKeyboardMicStream(); 581 ->UnregisterKeyboardMicStream();
504 } 582 }
505 #endif 583 #endif
506 584
585 #if defined(ENABLE_WEBRTC)
586 if (entry->input_debug_writer.get()) {
587 BrowserThread::PostTask(
588 BrowserThread::FILE,
589 FROM_HERE,
590 base::Bind(&DeleteInputDebugWriterOnFileThread,
591 base::Passed(entry->input_debug_writer.Pass())));
592 }
593 #endif
594
507 // Delete the entry when this method goes out of scope. 595 // Delete the entry when this method goes out of scope.
508 scoped_ptr<AudioEntry> entry_deleter(entry); 596 scoped_ptr<AudioEntry> entry_deleter(entry);
509 597
510 // Erase the entry from the map. 598 // Erase the entry from the map.
511 audio_entries_.erase(entry->stream_id); 599 audio_entries_.erase(entry->stream_id);
512 } 600 }
513 601
514 void AudioInputRendererHost::DeleteEntryOnError(AudioEntry* entry, 602 void AudioInputRendererHost::DeleteEntryOnError(AudioEntry* entry,
515 ErrorCode error_code) { 603 ErrorCode error_code) {
516 DCHECK_CURRENTLY_ON(BrowserThread::IO); 604 DCHECK_CURRENTLY_ON(BrowserThread::IO);
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
549 const AudioInputHostMsg_CreateStream_Config& config) { 637 const AudioInputHostMsg_CreateStream_Config& config) {
550 #if defined(OS_CHROMEOS) 638 #if defined(OS_CHROMEOS)
551 if (config.params.channel_layout() == 639 if (config.params.channel_layout() ==
552 media::CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC) { 640 media::CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC) {
553 media_stream_manager_->audio_input_device_manager() 641 media_stream_manager_->audio_input_device_manager()
554 ->UnregisterKeyboardMicStream(); 642 ->UnregisterKeyboardMicStream();
555 } 643 }
556 #endif 644 #endif
557 } 645 }
558 646
647 #if defined(ENABLE_WEBRTC)
648 void AudioInputRendererHost::MaybeEnableDebugRecordingForId(int stream_id) {
649 DCHECK_CURRENTLY_ON(BrowserThread::UI);
650 if (WebRTCInternals::GetInstance()->IsAudioDebugRecordingsEnabled()) {
651 BrowserThread::PostTask(
652 BrowserThread::IO,
653 FROM_HERE,
654 base::Bind(
655 &AudioInputRendererHost::EnableDebugRecordingForId,
656 this,
657 GetDebugRecordingFilePathWithExtensions(
658 WebRTCInternals::GetInstance()->
659 GetAudioDebugRecordingsFilePath()),
660 stream_id));
661 }
662 }
663
664 #if defined(OS_WIN)
665 #define IntToStringType base::IntToString16
666 #else
667 #define IntToStringType base::IntToString
668 #endif
669
670 base::FilePath AudioInputRendererHost::GetDebugRecordingFilePathWithExtensions(
671 const base::FilePath& file) {
672 return file.AddExtension(IntToStringType(renderer_pid_))
673 .AddExtension(kDebugRecordingFileNameAddition);
674 }
675
676 void AudioInputRendererHost::EnableDebugRecordingForId(
677 const base::FilePath& file,
678 int stream_id) {
679 DCHECK_CURRENTLY_ON(BrowserThread::IO);
680 BrowserThread::PostTaskAndReplyWithResult(
681 BrowserThread::FILE,
682 FROM_HERE,
683 base::Bind(
684 &CreateDebugRecordingFile,
685 file.AddExtension(IntToStringType(stream_id))
686 .AddExtension(kDebugRecordingFileNameExtension)),
687 base::Bind(
688 &AudioInputRendererHost::DoEnableDebugRecording,
689 weak_factory_.GetWeakPtr(),
690 stream_id));
691 }
692
693 #undef IntToStringType
694
695 void AudioInputRendererHost::DoEnableDebugRecording(
696 int stream_id,
697 base::File file) {
698 DCHECK_CURRENTLY_ON(BrowserThread::IO);
699 if (!file.IsValid())
700 return;
701 AudioEntry* entry = LookupById(stream_id);
702 if (!entry) {
703 BrowserThread::PostTask(
704 BrowserThread::FILE,
705 FROM_HERE,
706 base::Bind(
707 &CloseFile,
708 Passed(file.Pass())));
709 return;
710 }
711 entry->input_debug_writer.reset(new AudioInputDebugWriter(file.Pass()));
712 entry->controller->EnableDebugRecording(entry->input_debug_writer.get());
713 }
714
715 void AudioInputRendererHost::DeleteDebugWriter(int stream_id) {
716 DCHECK_CURRENTLY_ON(BrowserThread::IO);
717 AudioEntry* entry = LookupById(stream_id);
718 if (!entry) {
719 // This happens if DisableDebugRecording is called right after
720 // DeleteEntries.
721 return;
722 }
723
724 if (entry->input_debug_writer.get()) {
725 BrowserThread::PostTask(
726 BrowserThread::FILE,
727 FROM_HERE,
728 base::Bind(&DeleteInputDebugWriterOnFileThread,
729 base::Passed(entry->input_debug_writer.Pass())));
730 }
731 }
732 #endif // defined(ENABLE_WEBRTC)
733
559 } // namespace content 734 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698