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 "content/browser/renderer_host/media/device_request_message_filter.h" 6 7 #include "content/browser/browser_main_loop.h" 8 #include "content/browser/child_process_security_policy_impl.h" 9 #include "content/browser/renderer_host/media/media_stream_manager.h" 10 #include "content/common/media/media_stream_messages.h" 11 #include "content/public/browser/resource_context.h" 12 13 namespace content { 14 15 DeviceRequestMessageFilter::DeviceRequestMessageFilter( 16 ResourceContext* resource_context, 17 MediaStreamManager* media_stream_manager, 18 int render_process_id) 19 : BrowserMessageFilter(MediaStreamMsgStart), 20 resource_context_(resource_context), 21 media_stream_manager_(media_stream_manager), 22 render_process_id_(render_process_id) { 23 DCHECK(resource_context); 24 DCHECK(media_stream_manager); 25 } 26 27 DeviceRequestMessageFilter::~DeviceRequestMessageFilter() { 28 // CHECK rather than DCHECK to make sure this never happens in the 29 // wild. We want to be sure due to http://crbug.com/341211 30 CHECK(requests_.empty()); 31 } 32 33 struct DeviceRequestMessageFilter::DeviceRequest { 34 DeviceRequest(int request_id, 35 const GURL& origin, 36 const std::string& audio_devices_label, 37 const std::string& video_devices_label) 38 : request_id(request_id), 39 origin(origin), 40 has_audio_returned(false), 41 has_video_returned(false), 42 audio_devices_label(audio_devices_label), 43 video_devices_label(video_devices_label) {} 44 45 int request_id; 46 GURL origin; 47 bool has_audio_returned; 48 bool has_video_returned; 49 std::string audio_devices_label; 50 std::string video_devices_label; 51 StreamDeviceInfoArray audio_devices; 52 StreamDeviceInfoArray video_devices; 53 }; 54 55 void DeviceRequestMessageFilter::DevicesEnumerated( 56 int render_view_id, 57 int page_request_id, 58 const std::string& label, 59 const StreamDeviceInfoArray& new_devices) { 60 DCHECK_CURRENTLY_ON(BrowserThread::IO); 61 62 // Look up the DeviceRequest by id. 63 DeviceRequestList::iterator request_it = requests_.begin(); 64 for (; request_it != requests_.end(); ++request_it) { 65 if (label == request_it->audio_devices_label || 66 label == request_it->video_devices_label) { 67 break; 68 } 69 } 70 DCHECK(request_it != requests_.end()); 71 72 StreamDeviceInfoArray* audio_devices = &request_it->audio_devices; 73 StreamDeviceInfoArray* video_devices = &request_it->video_devices; 74 75 // Store hmac'd device ids instead of raw device ids. 76 if (label == request_it->audio_devices_label) { 77 request_it->has_audio_returned = true; 78 DCHECK(audio_devices->empty()); 79 *audio_devices = new_devices; 80 } else { 81 DCHECK(label == request_it->video_devices_label); 82 request_it->has_video_returned = true; 83 DCHECK(video_devices->empty()); 84 *video_devices = new_devices; 85 } 86 87 if (!request_it->has_audio_returned || !request_it->has_video_returned) { 88 // Wait for the rest of the devices to complete. 89 return; 90 } 91 92 // Both audio and video devices are ready for copying. 93 StreamDeviceInfoArray all_devices = *audio_devices; 94 all_devices.insert( 95 all_devices.end(), video_devices->begin(), video_devices->end()); 96 97 Send(new MediaStreamMsg_GetSourcesACK(request_it->request_id, all_devices)); 98 99 media_stream_manager_->CancelRequest(request_it->audio_devices_label); 100 media_stream_manager_->CancelRequest(request_it->video_devices_label); 101 requests_.erase(request_it); 102 } 103 104 bool DeviceRequestMessageFilter::OnMessageReceived( 105 const IPC::Message& message) { 106 bool handled = true; 107 IPC_BEGIN_MESSAGE_MAP(DeviceRequestMessageFilter, message) 108 IPC_MESSAGE_HANDLER(MediaStreamHostMsg_GetSources, OnGetSources) 109 IPC_MESSAGE_UNHANDLED(handled = false) 110 IPC_END_MESSAGE_MAP() 111 return handled; 112 } 113 114 void DeviceRequestMessageFilter::OnChannelClosing() { 115 // Since the IPC channel is gone, cancel outstanding device requests. 116 for (DeviceRequestList::iterator request_it = requests_.begin(); 117 request_it != requests_.end(); ++request_it) { 118 media_stream_manager_->CancelRequest(request_it->audio_devices_label); 119 media_stream_manager_->CancelRequest(request_it->video_devices_label); 120 } 121 requests_.clear(); 122 } 123 124 void DeviceRequestMessageFilter::OnGetSources(int request_id, 125 const GURL& security_origin) { 126 if (!ChildProcessSecurityPolicyImpl::GetInstance()->CanRequestURL( 127 render_process_id_, security_origin)) { 128 LOG(ERROR) << "Disallowed URL in DRMF::OnGetSources: " << security_origin; 129 return; 130 } 131 132 // Make request to get audio devices. 133 const std::string& audio_label = media_stream_manager_->EnumerateDevices( 134 this, -1, -1, resource_context_->GetMediaDeviceIDSalt(), -1, 135 MEDIA_DEVICE_AUDIO_CAPTURE, security_origin, 136 resource_context_->AllowMicAccess(security_origin)); 137 DCHECK(!audio_label.empty()); 138 139 // Make request for video devices. 140 const std::string& video_label = media_stream_manager_->EnumerateDevices( 141 this, -1, -1, resource_context_->GetMediaDeviceIDSalt(), -1, 142 MEDIA_DEVICE_VIDEO_CAPTURE, security_origin, 143 resource_context_->AllowCameraAccess(security_origin)); 144 DCHECK(!video_label.empty()); 145 146 requests_.push_back(DeviceRequest( 147 request_id, security_origin, audio_label, video_label)); 148 } 149 150 } // namespace content 151