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.
5 #include "content/browser/renderer_host/media/device_request_message_filter.h"
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"
13 // Clears the MediaStreamDevice.name from all devices in |device_list|.
14 static void ClearDeviceLabels(content::StreamDeviceInfoArray* devices) {
15 for (content::StreamDeviceInfoArray::iterator device_itr = devices->begin();
16 device_itr != devices->end();
18 device_itr->device.name.clear();
24 DeviceRequestMessageFilter::DeviceRequestMessageFilter(
25 ResourceContext* resource_context,
26 MediaStreamManager* media_stream_manager,
27 int render_process_id)
28 : BrowserMessageFilter(MediaStreamMsgStart),
29 resource_context_(resource_context),
30 media_stream_manager_(media_stream_manager),
31 render_process_id_(render_process_id) {
32 DCHECK(resource_context);
33 DCHECK(media_stream_manager);
36 DeviceRequestMessageFilter::~DeviceRequestMessageFilter() {
37 // CHECK rather than DCHECK to make sure this never happens in the
38 // wild. We want to be sure due to http://crbug.com/341211
39 CHECK(requests_.empty());
42 struct DeviceRequestMessageFilter::DeviceRequest {
43 DeviceRequest(int request_id,
45 const std::string& audio_devices_label,
46 const std::string& video_devices_label)
47 : request_id(request_id),
49 has_audio_returned(false),
50 has_video_returned(false),
51 audio_devices_label(audio_devices_label),
52 video_devices_label(video_devices_label) {}
56 bool has_audio_returned;
57 bool has_video_returned;
58 std::string audio_devices_label;
59 std::string video_devices_label;
60 StreamDeviceInfoArray audio_devices;
61 StreamDeviceInfoArray video_devices;
64 void DeviceRequestMessageFilter::DevicesEnumerated(
67 const std::string& label,
68 const StreamDeviceInfoArray& new_devices) {
69 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
71 // Look up the DeviceRequest by id.
72 DeviceRequestList::iterator request_it = requests_.begin();
73 for (; request_it != requests_.end(); ++request_it) {
74 if (label == request_it->audio_devices_label ||
75 label == request_it->video_devices_label) {
79 DCHECK(request_it != requests_.end());
81 StreamDeviceInfoArray* audio_devices = &request_it->audio_devices;
82 StreamDeviceInfoArray* video_devices = &request_it->video_devices;
84 // Store hmac'd device ids instead of raw device ids.
85 if (label == request_it->audio_devices_label) {
86 request_it->has_audio_returned = true;
87 DCHECK(audio_devices->empty());
88 *audio_devices = new_devices;
90 DCHECK(label == request_it->video_devices_label);
91 request_it->has_video_returned = true;
92 DCHECK(video_devices->empty());
93 *video_devices = new_devices;
96 if (!request_it->has_audio_returned || !request_it->has_video_returned) {
97 // Wait for the rest of the devices to complete.
101 // Query for mic and camera permissions.
102 if (!resource_context_->AllowMicAccess(request_it->origin))
103 ClearDeviceLabels(audio_devices);
104 if (!resource_context_->AllowCameraAccess(request_it->origin))
105 ClearDeviceLabels(video_devices);
107 // Both audio and video devices are ready for copying.
108 StreamDeviceInfoArray all_devices = *audio_devices;
110 all_devices.end(), video_devices->begin(), video_devices->end());
112 Send(new MediaStreamMsg_GetSourcesACK(request_it->request_id, all_devices));
114 media_stream_manager_->CancelRequest(request_it->audio_devices_label);
115 media_stream_manager_->CancelRequest(request_it->video_devices_label);
116 requests_.erase(request_it);
119 bool DeviceRequestMessageFilter::OnMessageReceived(const IPC::Message& message,
120 bool* message_was_ok) {
122 IPC_BEGIN_MESSAGE_MAP_EX(DeviceRequestMessageFilter, message, *message_was_ok)
123 IPC_MESSAGE_HANDLER(MediaStreamHostMsg_GetSources, OnGetSources)
124 IPC_MESSAGE_UNHANDLED(handled = false)
125 IPC_END_MESSAGE_MAP_EX()
129 void DeviceRequestMessageFilter::OnChannelClosing() {
130 // Since the IPC channel is gone, cancel outstanding device requests.
131 for (DeviceRequestList::iterator request_it = requests_.begin();
132 request_it != requests_.end(); ++request_it) {
133 media_stream_manager_->CancelRequest(request_it->audio_devices_label);
134 media_stream_manager_->CancelRequest(request_it->video_devices_label);
139 void DeviceRequestMessageFilter::OnGetSources(int request_id,
140 const GURL& security_origin) {
141 if (!ChildProcessSecurityPolicyImpl::GetInstance()->CanRequestURL(
142 render_process_id_, security_origin)) {
143 LOG(ERROR) << "Disallowed URL in DRMF::OnGetSources: " << security_origin;
147 // Make request to get audio devices.
148 const std::string& audio_label = media_stream_manager_->EnumerateDevices(
149 this, -1, -1, resource_context_->GetMediaDeviceIDSalt(), -1,
150 MEDIA_DEVICE_AUDIO_CAPTURE, security_origin);
151 DCHECK(!audio_label.empty());
153 // Make request for video devices.
154 const std::string& video_label = media_stream_manager_->EnumerateDevices(
155 this, -1, -1, resource_context_->GetMediaDeviceIDSalt(), -1,
156 MEDIA_DEVICE_VIDEO_CAPTURE, security_origin);
157 DCHECK(!video_label.empty());
159 requests_.push_back(DeviceRequest(
160 request_id, security_origin, audio_label, video_label));
163 } // namespace content