Clean up check for dependency_info.
[chromium-blink-merge.git] / content / browser / renderer_host / media / audio_input_renderer_host.cc
blob74330b9f23d1a97feeccbd04b4b7b78039ab007c
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
3 // found in the LICENSE file.
5 #include "content/browser/renderer_host/media/audio_input_renderer_host.h"
7 #include "base/bind.h"
8 #include "base/files/file.h"
9 #include "base/memory/ref_counted.h"
10 #include "base/memory/shared_memory.h"
11 #include "base/metrics/histogram.h"
12 #include "base/numerics/safe_math.h"
13 #include "base/process/process.h"
14 #include "base/strings/string_number_conversions.h"
15 #include "base/strings/stringprintf.h"
16 #include "content/browser/media/capture/web_contents_audio_input_stream.h"
17 #include "content/browser/media/capture/web_contents_capture_util.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"
21 #include "content/browser/renderer_host/media/audio_input_device_manager.h"
22 #include "content/browser/renderer_host/media/audio_input_sync_writer.h"
23 #include "content/browser/renderer_host/media/media_stream_manager.h"
24 #include "media/audio/audio_manager_base.h"
25 #include "media/base/audio_bus.h"
27 namespace content {
29 namespace {
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
38 void LogMessage(int stream_id, const std::string& msg, bool add_prefix) {
39 std::ostringstream oss;
40 oss << "[stream_id=" << stream_id << "] ";
41 if (add_prefix)
42 oss << "AIRH::";
43 oss << msg;
44 content::MediaStreamManager::SendMessageToNativeLog(oss.str());
45 DVLOG(1) << oss.str();
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();
59 void CloseFile(base::File file) {
60 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
61 // |file| must be closed and destroyed on FILE thread.
64 void DeleteInputDebugWriterOnFileThread(
65 scoped_ptr<AudioInputDebugWriter> writer) {
66 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
67 // |writer| must be closed and destroyed on FILE thread.
69 #endif // ENABLE_WEBRTC
71 } // namespace
73 struct AudioInputRendererHost::AudioEntry {
74 AudioEntry();
75 ~AudioEntry();
77 // The AudioInputController that manages the audio input stream.
78 scoped_refptr<media::AudioInputController> controller;
80 // The audio input stream ID in the render view.
81 int stream_id;
83 // Shared memory for transmission of the audio data. It has
84 // |shared_memory_segment_count| equal lengthed segments.
85 base::SharedMemory shared_memory;
86 int shared_memory_segment_count;
88 // The synchronous writer to be used by the controller. We have the
89 // ownership of the writer.
90 scoped_ptr<media::AudioInputController::SyncWriter> writer;
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;
96 // Set to true after we called Close() for the controller.
97 bool pending_close;
99 // If this entry's layout has a keyboard mic channel.
100 bool has_keyboard_mic;
103 AudioInputRendererHost::AudioEntry::AudioEntry()
104 : stream_id(0),
105 shared_memory_segment_count(0),
106 pending_close(false),
107 has_keyboard_mic(false) {
110 AudioInputRendererHost::AudioEntry::~AudioEntry() {
111 DCHECK(!input_debug_writer.get());
114 AudioInputRendererHost::AudioInputRendererHost(
115 int render_process_id,
116 int32 renderer_pid,
117 media::AudioManager* audio_manager,
118 MediaStreamManager* media_stream_manager,
119 AudioMirroringManager* audio_mirroring_manager,
120 media::UserInputMonitor* user_input_monitor)
121 : BrowserMessageFilter(AudioMsgStart),
122 render_process_id_(render_process_id),
123 renderer_pid_(renderer_pid),
124 audio_manager_(audio_manager),
125 media_stream_manager_(media_stream_manager),
126 audio_mirroring_manager_(audio_mirroring_manager),
127 user_input_monitor_(user_input_monitor),
128 audio_log_(MediaInternals::GetInstance()->CreateAudioLog(
129 media::AudioLogFactory::AUDIO_INPUT_CONTROLLER)),
130 weak_factory_(this) {}
132 AudioInputRendererHost::~AudioInputRendererHost() {
133 DCHECK_CURRENTLY_ON(BrowserThread::IO);
134 DCHECK(audio_entries_.empty());
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);
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));
154 #endif // ENABLE_WEBRTC
156 void AudioInputRendererHost::OnChannelClosing() {
157 // Since the IPC sender is gone, close all requested audio streams.
158 DeleteEntries();
161 void AudioInputRendererHost::OnDestruct() const {
162 BrowserThread::DeleteOnIOThread::Destruct(this);
165 void AudioInputRendererHost::OnCreated(
166 media::AudioInputController* controller) {
167 BrowserThread::PostTask(
168 BrowserThread::IO,
169 FROM_HERE,
170 base::Bind(
171 &AudioInputRendererHost::DoCompleteCreation,
172 this,
173 make_scoped_refptr(controller)));
176 void AudioInputRendererHost::OnRecording(
177 media::AudioInputController* controller) {
178 BrowserThread::PostTask(
179 BrowserThread::IO,
180 FROM_HERE,
181 base::Bind(
182 &AudioInputRendererHost::DoSendRecordingMessage,
183 this,
184 make_scoped_refptr(controller)));
187 void AudioInputRendererHost::OnError(media::AudioInputController* controller,
188 media::AudioInputController::ErrorCode error_code) {
189 BrowserThread::PostTask(
190 BrowserThread::IO,
191 FROM_HERE,
192 base::Bind(
193 &AudioInputRendererHost::DoHandleError,
194 this,
195 make_scoped_refptr(controller),
196 error_code));
199 void AudioInputRendererHost::OnData(media::AudioInputController* controller,
200 const media::AudioBus* data) {
201 NOTREACHED() << "Only low-latency mode is supported.";
204 void AudioInputRendererHost::OnLog(media::AudioInputController* controller,
205 const std::string& message) {
206 BrowserThread::PostTask(BrowserThread::IO,
207 FROM_HERE,
208 base::Bind(&AudioInputRendererHost::DoLog,
209 this,
210 make_scoped_refptr(controller),
211 message));
214 void AudioInputRendererHost::set_renderer_pid(int32 renderer_pid) {
215 DCHECK_CURRENTLY_ON(BrowserThread::IO);
216 renderer_pid_ = renderer_pid;
219 void AudioInputRendererHost::DoCompleteCreation(
220 media::AudioInputController* controller) {
221 DCHECK_CURRENTLY_ON(BrowserThread::IO);
223 AudioEntry* entry = LookupByController(controller);
224 if (!entry) {
225 NOTREACHED() << "AudioInputController is invalid.";
226 return;
229 if (!PeerHandle()) {
230 NOTREACHED() << "Renderer process handle is invalid.";
231 DeleteEntryOnError(entry, INVALID_PEER_HANDLE);
232 return;
235 if (!entry->controller->SharedMemoryAndSyncSocketMode()) {
236 NOTREACHED() << "Only shared-memory/sync-socket mode is supported.";
237 DeleteEntryOnError(entry, INVALID_LATENCY_MODE);
238 return;
241 // Once the audio stream is created then complete the creation process by
242 // mapping shared memory and sharing with the renderer process.
243 base::SharedMemoryHandle foreign_memory_handle;
244 if (!entry->shared_memory.ShareToProcess(PeerHandle(),
245 &foreign_memory_handle)) {
246 // If we failed to map and share the shared memory then close the audio
247 // stream and send an error message.
248 DeleteEntryOnError(entry, MEMORY_SHARING_FAILED);
249 return;
252 AudioInputSyncWriter* writer =
253 static_cast<AudioInputSyncWriter*>(entry->writer.get());
255 base::SyncSocket::TransitDescriptor socket_transit_descriptor;
257 // If we failed to prepare the sync socket for the renderer then we fail
258 // the construction of audio input stream.
259 if (!writer->PrepareForeignSocket(PeerHandle(), &socket_transit_descriptor)) {
260 DeleteEntryOnError(entry, SYNC_SOCKET_ERROR);
261 return;
264 LogMessage(entry->stream_id,
265 "DoCompleteCreation: IPC channel and stream are now open",
266 true);
268 Send(new AudioInputMsg_NotifyStreamCreated(
269 entry->stream_id, foreign_memory_handle, socket_transit_descriptor,
270 entry->shared_memory.requested_size(),
271 entry->shared_memory_segment_count));
274 void AudioInputRendererHost::DoSendRecordingMessage(
275 media::AudioInputController* controller) {
276 DCHECK_CURRENTLY_ON(BrowserThread::IO);
277 // TODO(henrika): See crbug.com/115262 for details on why this method
278 // should be implemented.
279 AudioEntry* entry = LookupByController(controller);
280 if (!entry) {
281 NOTREACHED() << "AudioInputController is invalid.";
282 return;
284 LogMessage(
285 entry->stream_id, "DoSendRecordingMessage: stream is now started", true);
288 void AudioInputRendererHost::DoHandleError(
289 media::AudioInputController* controller,
290 media::AudioInputController::ErrorCode error_code) {
291 DCHECK_CURRENTLY_ON(BrowserThread::IO);
292 AudioEntry* entry = LookupByController(controller);
293 if (!entry) {
294 NOTREACHED() << "AudioInputController is invalid.";
295 return;
298 // This is a fix for crbug.com/357501. The error can be triggered when closing
299 // the lid on Macs, which causes more problems than it fixes.
300 // Also, in crbug.com/357569, the goal is to remove usage of the error since
301 // it was added to solve a crash on Windows that no longer can be reproduced.
302 if (error_code == media::AudioInputController::NO_DATA_ERROR) {
303 // TODO(henrika): it might be possible to do something other than just
304 // logging when we detect many NO_DATA_ERROR calls for a stream.
305 LogMessage(entry->stream_id, "AIC::DoCheckForNoData: NO_DATA_ERROR", false);
306 return;
309 std::ostringstream oss;
310 oss << "AIC reports error_code=" << error_code;
311 LogMessage(entry->stream_id, oss.str(), false);
313 audio_log_->OnError(entry->stream_id);
314 DeleteEntryOnError(entry, AUDIO_INPUT_CONTROLLER_ERROR);
317 void AudioInputRendererHost::DoLog(media::AudioInputController* controller,
318 const std::string& message) {
319 DCHECK_CURRENTLY_ON(BrowserThread::IO);
320 AudioEntry* entry = LookupByController(controller);
321 if (!entry) {
322 NOTREACHED() << "AudioInputController is invalid.";
323 return;
326 // Add stream ID and current audio level reported by AIC to native log.
327 LogMessage(entry->stream_id, message, false);
330 bool AudioInputRendererHost::OnMessageReceived(const IPC::Message& message) {
331 bool handled = true;
332 IPC_BEGIN_MESSAGE_MAP(AudioInputRendererHost, message)
333 IPC_MESSAGE_HANDLER(AudioInputHostMsg_CreateStream, OnCreateStream)
334 IPC_MESSAGE_HANDLER(AudioInputHostMsg_RecordStream, OnRecordStream)
335 IPC_MESSAGE_HANDLER(AudioInputHostMsg_CloseStream, OnCloseStream)
336 IPC_MESSAGE_HANDLER(AudioInputHostMsg_SetVolume, OnSetVolume)
337 IPC_MESSAGE_UNHANDLED(handled = false)
338 IPC_END_MESSAGE_MAP()
340 return handled;
343 void AudioInputRendererHost::OnCreateStream(
344 int stream_id,
345 int render_frame_id,
346 int session_id,
347 const AudioInputHostMsg_CreateStream_Config& config) {
348 DCHECK_CURRENTLY_ON(BrowserThread::IO);
350 #if defined(OS_CHROMEOS)
351 if (config.params.channel_layout() ==
352 media::CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC) {
353 media_stream_manager_->audio_input_device_manager()
354 ->RegisterKeyboardMicStream(
355 base::Bind(&AudioInputRendererHost::DoCreateStream, this, stream_id,
356 render_frame_id, session_id, config));
357 } else {
358 DoCreateStream(stream_id, render_frame_id, session_id, config);
360 #else
361 DoCreateStream(stream_id, render_frame_id, session_id, config);
362 #endif
365 void AudioInputRendererHost::DoCreateStream(
366 int stream_id,
367 int render_frame_id,
368 int session_id,
369 const AudioInputHostMsg_CreateStream_Config& config) {
370 DCHECK_CURRENTLY_ON(BrowserThread::IO);
372 std::ostringstream oss;
373 oss << "[stream_id=" << stream_id << "] "
374 << "AIRH::OnCreateStream(render_frame_id=" << render_frame_id
375 << ", session_id=" << session_id << ")";
376 DCHECK_GT(render_frame_id, 0);
378 // media::AudioParameters is validated in the deserializer.
379 if (LookupById(stream_id) != NULL) {
380 SendErrorMessage(stream_id, STREAM_ALREADY_EXISTS);
381 MaybeUnregisterKeyboardMicStream(config);
382 return;
385 media::AudioParameters audio_params(config.params);
386 if (media_stream_manager_->audio_input_device_manager()
387 ->ShouldUseFakeDevice())
388 audio_params.set_format(media::AudioParameters::AUDIO_FAKE);
390 // Check if we have the permission to open the device and which device to use.
391 std::string device_name;
392 std::string device_id = media::AudioManagerBase::kDefaultDeviceId;
393 if (audio_params.format() != media::AudioParameters::AUDIO_FAKE) {
394 const StreamDeviceInfo* info = media_stream_manager_->
395 audio_input_device_manager()->GetOpenedDeviceInfoById(session_id);
396 if (!info) {
397 SendErrorMessage(stream_id, PERMISSION_DENIED);
398 DLOG(WARNING) << "No permission has been granted to input stream with "
399 << "session_id=" << session_id;
400 MaybeUnregisterKeyboardMicStream(config);
401 return;
404 device_id = info->device.id;
405 device_name = info->device.name;
406 oss << ": device_name=" << device_name;
409 // Create a new AudioEntry structure.
410 scoped_ptr<AudioEntry> entry(new AudioEntry());
412 const uint32 segment_size =
413 (sizeof(media::AudioInputBufferParameters) +
414 media::AudioBus::CalculateMemorySize(audio_params));
415 entry->shared_memory_segment_count = config.shared_memory_count;
417 // Create the shared memory and share it with the renderer process
418 // using a new SyncWriter object.
419 base::CheckedNumeric<uint32> size = segment_size;
420 size *= entry->shared_memory_segment_count;
421 if (!size.IsValid() ||
422 !entry->shared_memory.CreateAndMapAnonymous(size.ValueOrDie())) {
423 // If creation of shared memory failed then send an error message.
424 SendErrorMessage(stream_id, SHARED_MEMORY_CREATE_FAILED);
425 MaybeUnregisterKeyboardMicStream(config);
426 return;
429 scoped_ptr<AudioInputSyncWriter> writer(new AudioInputSyncWriter(
430 entry->shared_memory.memory(), entry->shared_memory.requested_size(),
431 entry->shared_memory_segment_count, audio_params));
433 if (!writer->Init()) {
434 SendErrorMessage(stream_id, SYNC_WRITER_INIT_FAILED);
435 MaybeUnregisterKeyboardMicStream(config);
436 return;
439 // If we have successfully created the SyncWriter then assign it to the
440 // entry and construct an AudioInputController.
441 entry->writer.reset(writer.release());
442 if (WebContentsCaptureUtil::IsWebContentsDeviceId(device_id)) {
443 entry->controller = media::AudioInputController::CreateForStream(
444 audio_manager_->GetTaskRunner(),
445 this,
446 WebContentsAudioInputStream::Create(
447 device_id,
448 audio_params,
449 audio_manager_->GetWorkerTaskRunner(),
450 audio_mirroring_manager_),
451 entry->writer.get(),
452 user_input_monitor_);
453 } else {
454 DCHECK_EQ(config.params.format(),
455 media::AudioParameters::AUDIO_PCM_LOW_LATENCY);
456 entry->controller = media::AudioInputController::CreateLowLatency(
457 audio_manager_,
458 this,
459 audio_params,
460 device_id,
461 entry->writer.get(),
462 user_input_monitor_,
463 config.automatic_gain_control);
464 oss << ", AGC=" << config.automatic_gain_control;
467 if (!entry->controller.get()) {
468 SendErrorMessage(stream_id, STREAM_CREATE_ERROR);
469 MaybeUnregisterKeyboardMicStream(config);
470 return;
473 #if defined(OS_CHROMEOS)
474 if (config.params.channel_layout() ==
475 media::CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC) {
476 entry->has_keyboard_mic = true;
478 #endif
480 MediaStreamManager::SendMessageToNativeLog(oss.str());
481 DVLOG(1) << oss.str();
483 // Since the controller was created successfully, create an entry and add it
484 // to the map.
485 entry->stream_id = stream_id;
486 audio_entries_.insert(std::make_pair(stream_id, entry.release()));
487 audio_log_->OnCreated(stream_id, audio_params, device_id);
488 MediaInternals::GetInstance()->SetWebContentsTitleForAudioLogEntry(
489 stream_id, render_process_id_, render_frame_id, audio_log_.get());
491 #if defined(ENABLE_WEBRTC)
492 BrowserThread::PostTask(
493 BrowserThread::UI,
494 FROM_HERE,
495 base::Bind(
496 &AudioInputRendererHost::MaybeEnableDebugRecordingForId,
497 this,
498 stream_id));
499 #endif
502 void AudioInputRendererHost::OnRecordStream(int stream_id) {
503 DCHECK_CURRENTLY_ON(BrowserThread::IO);
504 LogMessage(stream_id, "OnRecordStream", true);
506 AudioEntry* entry = LookupById(stream_id);
507 if (!entry) {
508 SendErrorMessage(stream_id, INVALID_AUDIO_ENTRY);
509 return;
512 entry->controller->Record();
513 audio_log_->OnStarted(stream_id);
516 void AudioInputRendererHost::OnCloseStream(int stream_id) {
517 DCHECK_CURRENTLY_ON(BrowserThread::IO);
518 LogMessage(stream_id, "OnCloseStream", true);
520 AudioEntry* entry = LookupById(stream_id);
522 if (entry)
523 CloseAndDeleteStream(entry);
526 void AudioInputRendererHost::OnSetVolume(int stream_id, double volume) {
527 DCHECK_CURRENTLY_ON(BrowserThread::IO);
529 AudioEntry* entry = LookupById(stream_id);
530 if (!entry) {
531 SendErrorMessage(stream_id, INVALID_AUDIO_ENTRY);
532 return;
535 entry->controller->SetVolume(volume);
536 audio_log_->OnSetVolume(stream_id, volume);
539 void AudioInputRendererHost::SendErrorMessage(
540 int stream_id, ErrorCode error_code) {
541 std::string err_msg =
542 base::StringPrintf("SendErrorMessage(error_code=%d)", error_code);
543 LogMessage(stream_id, err_msg, true);
545 Send(new AudioInputMsg_NotifyStreamStateChanged(
546 stream_id, media::AUDIO_INPUT_IPC_DELEGATE_STATE_ERROR));
549 void AudioInputRendererHost::DeleteEntries() {
550 DCHECK_CURRENTLY_ON(BrowserThread::IO);
552 for (AudioEntryMap::iterator i = audio_entries_.begin();
553 i != audio_entries_.end(); ++i) {
554 CloseAndDeleteStream(i->second);
558 void AudioInputRendererHost::CloseAndDeleteStream(AudioEntry* entry) {
559 DCHECK_CURRENTLY_ON(BrowserThread::IO);
561 if (!entry->pending_close) {
562 LogMessage(entry->stream_id, "CloseAndDeleteStream", true);
563 entry->controller->Close(base::Bind(&AudioInputRendererHost::DeleteEntry,
564 this, entry));
565 entry->pending_close = true;
566 audio_log_->OnClosed(entry->stream_id);
570 void AudioInputRendererHost::DeleteEntry(AudioEntry* entry) {
571 DCHECK_CURRENTLY_ON(BrowserThread::IO);
572 LogMessage(entry->stream_id, "DeleteEntry: stream is now closed", true);
574 #if defined(OS_CHROMEOS)
575 if (entry->has_keyboard_mic) {
576 media_stream_manager_->audio_input_device_manager()
577 ->UnregisterKeyboardMicStream();
579 #endif
581 #if defined(ENABLE_WEBRTC)
582 if (entry->input_debug_writer.get()) {
583 BrowserThread::PostTask(
584 BrowserThread::FILE,
585 FROM_HERE,
586 base::Bind(&DeleteInputDebugWriterOnFileThread,
587 base::Passed(entry->input_debug_writer.Pass())));
589 #endif
591 // Delete the entry when this method goes out of scope.
592 scoped_ptr<AudioEntry> entry_deleter(entry);
594 // Erase the entry from the map.
595 audio_entries_.erase(entry->stream_id);
598 void AudioInputRendererHost::DeleteEntryOnError(AudioEntry* entry,
599 ErrorCode error_code) {
600 DCHECK_CURRENTLY_ON(BrowserThread::IO);
602 // Sends the error message first before we close the stream because
603 // |entry| is destroyed in DeleteEntry().
604 SendErrorMessage(entry->stream_id, error_code);
605 CloseAndDeleteStream(entry);
608 AudioInputRendererHost::AudioEntry* AudioInputRendererHost::LookupById(
609 int stream_id) {
610 DCHECK_CURRENTLY_ON(BrowserThread::IO);
612 AudioEntryMap::iterator i = audio_entries_.find(stream_id);
613 if (i != audio_entries_.end())
614 return i->second;
615 return NULL;
618 AudioInputRendererHost::AudioEntry* AudioInputRendererHost::LookupByController(
619 media::AudioInputController* controller) {
620 DCHECK_CURRENTLY_ON(BrowserThread::IO);
622 // Iterate the map of entries.
623 // TODO(hclam): Implement a faster look up method.
624 for (AudioEntryMap::iterator i = audio_entries_.begin();
625 i != audio_entries_.end(); ++i) {
626 if (controller == i->second->controller.get())
627 return i->second;
629 return NULL;
632 void AudioInputRendererHost::MaybeUnregisterKeyboardMicStream(
633 const AudioInputHostMsg_CreateStream_Config& config) {
634 #if defined(OS_CHROMEOS)
635 if (config.params.channel_layout() ==
636 media::CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC) {
637 media_stream_manager_->audio_input_device_manager()
638 ->UnregisterKeyboardMicStream();
640 #endif
643 #if defined(ENABLE_WEBRTC)
644 void AudioInputRendererHost::MaybeEnableDebugRecordingForId(int stream_id) {
645 DCHECK_CURRENTLY_ON(BrowserThread::UI);
646 if (WebRTCInternals::GetInstance()->IsAudioDebugRecordingsEnabled()) {
647 BrowserThread::PostTask(
648 BrowserThread::IO,
649 FROM_HERE,
650 base::Bind(
651 &AudioInputRendererHost::EnableDebugRecordingForId,
652 this,
653 GetDebugRecordingFilePathWithExtensions(
654 WebRTCInternals::GetInstance()->
655 GetAudioDebugRecordingsFilePath()),
656 stream_id));
660 #if defined(OS_WIN)
661 #define IntToStringType base::IntToString16
662 #else
663 #define IntToStringType base::IntToString
664 #endif
666 base::FilePath AudioInputRendererHost::GetDebugRecordingFilePathWithExtensions(
667 const base::FilePath& file) {
668 return file.AddExtension(IntToStringType(renderer_pid_))
669 .AddExtension(kDebugRecordingFileNameAddition);
672 void AudioInputRendererHost::EnableDebugRecordingForId(
673 const base::FilePath& file,
674 int stream_id) {
675 DCHECK_CURRENTLY_ON(BrowserThread::IO);
676 BrowserThread::PostTaskAndReplyWithResult(
677 BrowserThread::FILE,
678 FROM_HERE,
679 base::Bind(
680 &CreateDebugRecordingFile,
681 file.AddExtension(IntToStringType(stream_id))
682 .AddExtension(kDebugRecordingFileNameExtension)),
683 base::Bind(
684 &AudioInputRendererHost::DoEnableDebugRecording,
685 weak_factory_.GetWeakPtr(),
686 stream_id));
689 #undef IntToStringType
691 void AudioInputRendererHost::DoEnableDebugRecording(
692 int stream_id,
693 base::File file) {
694 DCHECK_CURRENTLY_ON(BrowserThread::IO);
695 if (!file.IsValid())
696 return;
697 AudioEntry* entry = LookupById(stream_id);
698 if (!entry) {
699 BrowserThread::PostTask(
700 BrowserThread::FILE,
701 FROM_HERE,
702 base::Bind(
703 &CloseFile,
704 Passed(file.Pass())));
705 return;
707 entry->input_debug_writer.reset(new AudioInputDebugWriter(file.Pass()));
708 entry->controller->EnableDebugRecording(entry->input_debug_writer.get());
711 void AudioInputRendererHost::DeleteDebugWriter(int stream_id) {
712 DCHECK_CURRENTLY_ON(BrowserThread::IO);
713 AudioEntry* entry = LookupById(stream_id);
714 if (!entry) {
715 // This happens if DisableDebugRecording is called right after
716 // DeleteEntries.
717 return;
720 if (entry->input_debug_writer.get()) {
721 BrowserThread::PostTask(
722 BrowserThread::FILE,
723 FROM_HERE,
724 base::Bind(&DeleteInputDebugWriterOnFileThread,
725 base::Passed(entry->input_debug_writer.Pass())));
728 #endif // defined(ENABLE_WEBRTC)
730 } // namespace content