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 "chrome/browser/extensions/api/tab_capture/tab_capture_registry.h" | 5 #include "chrome/browser/extensions/api/tab_capture/tab_capture_registry.h" |
6 | 6 |
7 #include "base/lazy_instance.h" | 7 #include "base/lazy_instance.h" |
8 #include "chrome/browser/chrome_notification_types.h" | 8 #include "base/values.h" |
9 #include "chrome/browser/ui/fullscreen/fullscreen_controller.h" | 9 #include "chrome/browser/sessions/session_id.h" |
10 #include "components/keyed_service/content/browser_context_dependency_manager.h" | 10 #include "components/keyed_service/content/browser_context_dependency_manager.h" |
11 #include "content/public/browser/browser_thread.h" | 11 #include "content/public/browser/browser_thread.h" |
12 #include "content/public/browser/notification_details.h" | 12 #include "content/public/browser/render_frame_host.h" |
13 #include "content/public/browser/notification_service.h" | |
14 #include "content/public/browser/notification_source.h" | |
15 #include "content/public/browser/render_view_host.h" | |
16 #include "content/public/browser/web_contents.h" | 13 #include "content/public/browser/web_contents.h" |
17 #include "content/public/browser/web_contents_observer.h" | 14 #include "content/public/browser/web_contents_observer.h" |
18 #include "extensions/browser/event_router.h" | 15 #include "extensions/browser/event_router.h" |
19 #include "extensions/browser/extension_registry.h" | 16 #include "extensions/browser/extension_registry.h" |
20 #include "extensions/common/extension.h" | 17 #include "extensions/common/extension.h" |
21 | 18 |
22 using content::BrowserThread; | 19 using content::BrowserThread; |
23 using extensions::tab_capture::TabCaptureState; | 20 using extensions::tab_capture::TabCaptureState; |
24 | 21 |
25 namespace extensions { | 22 namespace extensions { |
26 | 23 |
27 namespace tab_capture = api::tab_capture; | 24 namespace tab_capture = api::tab_capture; |
28 | 25 |
29 class FullscreenObserver : public content::WebContentsObserver { | 26 // Stores values associated with a tab capture request, maintains lifecycle |
| 27 // state, and monitors WebContents for fullscreen transition events and |
| 28 // destruction. |
| 29 class TabCaptureRegistry::LiveRequest : public content::WebContentsObserver { |
30 public: | 30 public: |
31 FullscreenObserver(TabCaptureRequest* request, | 31 LiveRequest(content::WebContents* target_contents, |
32 const TabCaptureRegistry* registry); | 32 const std::string& extension_id, |
33 virtual ~FullscreenObserver() {} | 33 TabCaptureRegistry* registry) |
| 34 : content::WebContentsObserver(target_contents), |
| 35 extension_id_(extension_id), |
| 36 registry_(registry), |
| 37 capture_state_(tab_capture::TAB_CAPTURE_STATE_NONE), |
| 38 is_verified_(false), |
| 39 // TODO(miu): This initial value for |is_fullscreened_| is a faulty |
| 40 // assumption. http://crbug.com/350491 |
| 41 is_fullscreened_(false), |
| 42 render_process_id_(-1), |
| 43 render_frame_id_(-1) { |
| 44 DCHECK(web_contents()); |
| 45 DCHECK(registry_); |
| 46 } |
| 47 |
| 48 virtual ~LiveRequest() {} |
| 49 |
| 50 // Accessors. |
| 51 const content::WebContents* target_contents() const { |
| 52 return content::WebContentsObserver::web_contents(); |
| 53 } |
| 54 const std::string& extension_id() const { |
| 55 return extension_id_; |
| 56 } |
| 57 TabCaptureState capture_state() const { |
| 58 return capture_state_; |
| 59 } |
| 60 bool is_verified() const { |
| 61 return is_verified_; |
| 62 } |
| 63 |
| 64 void SetIsVerified() { |
| 65 DCHECK(!is_verified_); |
| 66 is_verified_ = true; |
| 67 } |
| 68 |
| 69 // TODO(miu): See TODO(miu) in VerifyRequest() below. |
| 70 void SetOriginallyTargettedRenderFrameID(int render_process_id, |
| 71 int render_frame_id) { |
| 72 DCHECK_GT(render_frame_id, 0); |
| 73 DCHECK_EQ(render_frame_id_, -1); // Setting ID only once. |
| 74 render_process_id_ = render_process_id; |
| 75 render_frame_id_ = render_frame_id; |
| 76 } |
| 77 |
| 78 bool WasOriginallyTargettingRenderFrameID(int render_process_id, |
| 79 int render_frame_id) const { |
| 80 return render_process_id_ == render_process_id && |
| 81 render_frame_id_ == render_frame_id; |
| 82 } |
| 83 |
| 84 void UpdateCaptureState(TabCaptureState next_capture_state) { |
| 85 // This method can get duplicate calls if both audio and video were |
| 86 // requested, so return early to avoid duplicate dispatching of status |
| 87 // change events. |
| 88 if (capture_state_ == next_capture_state) |
| 89 return; |
| 90 |
| 91 capture_state_ = next_capture_state; |
| 92 registry_->DispatchStatusChangeEvent(this); |
| 93 } |
| 94 |
| 95 void GetCaptureInfo(tab_capture::CaptureInfo* info) const { |
| 96 info->tab_id = SessionID::IdForTab(web_contents()); |
| 97 info->status = capture_state_; |
| 98 info->fullscreen = is_fullscreened_; |
| 99 } |
| 100 |
| 101 protected: |
| 102 virtual void DidShowFullscreenWidget(int routing_id) OVERRIDE { |
| 103 is_fullscreened_ = true; |
| 104 if (capture_state_ == tab_capture::TAB_CAPTURE_STATE_ACTIVE) |
| 105 registry_->DispatchStatusChangeEvent(this); |
| 106 } |
| 107 |
| 108 virtual void DidDestroyFullscreenWidget(int routing_id) OVERRIDE { |
| 109 is_fullscreened_ = false; |
| 110 if (capture_state_ == tab_capture::TAB_CAPTURE_STATE_ACTIVE) |
| 111 registry_->DispatchStatusChangeEvent(this); |
| 112 } |
| 113 |
| 114 virtual void DidToggleFullscreenModeForTab(bool entered_fullscreen) OVERRIDE { |
| 115 is_fullscreened_ = entered_fullscreen; |
| 116 if (capture_state_ == tab_capture::TAB_CAPTURE_STATE_ACTIVE) |
| 117 registry_->DispatchStatusChangeEvent(this); |
| 118 } |
| 119 |
| 120 virtual void WebContentsDestroyed() OVERRIDE { |
| 121 registry_->KillRequest(this); // Deletes |this|. |
| 122 } |
34 | 123 |
35 private: | 124 private: |
36 // content::WebContentsObserver implementation. | 125 const std::string extension_id_; |
37 virtual void DidShowFullscreenWidget(int routing_id) OVERRIDE; | 126 TabCaptureRegistry* const registry_; |
38 virtual void DidDestroyFullscreenWidget(int routing_id) OVERRIDE; | 127 TabCaptureState capture_state_; |
| 128 bool is_verified_; |
| 129 bool is_fullscreened_; |
39 | 130 |
40 TabCaptureRequest* request_; | 131 // These reference the originally targetted RenderFrameHost by its ID. The |
41 const TabCaptureRegistry* registry_; | 132 // RenderFrameHost may have gone away long before a LiveRequest closes, but |
| 133 // calls to OnRequestUpdate() will always refer to this request by this ID. |
| 134 int render_process_id_; |
| 135 int render_frame_id_; |
42 | 136 |
43 DISALLOW_COPY_AND_ASSIGN(FullscreenObserver); | 137 DISALLOW_COPY_AND_ASSIGN(LiveRequest); |
44 }; | 138 }; |
45 | 139 |
46 // Holds all the state related to a tab capture stream. | |
47 struct TabCaptureRequest { | |
48 TabCaptureRequest(int render_process_id, | |
49 int render_view_id, | |
50 const std::string& extension_id, | |
51 int tab_id, | |
52 TabCaptureState status); | |
53 ~TabCaptureRequest(); | |
54 | |
55 const int render_process_id; | |
56 const int render_view_id; | |
57 const std::string extension_id; | |
58 const int tab_id; | |
59 TabCaptureState status; | |
60 TabCaptureState last_status; | |
61 bool fullscreen; | |
62 scoped_ptr<FullscreenObserver> fullscreen_observer; | |
63 }; | |
64 | |
65 FullscreenObserver::FullscreenObserver( | |
66 TabCaptureRequest* request, | |
67 const TabCaptureRegistry* registry) | |
68 : request_(request), | |
69 registry_(registry) { | |
70 content::RenderViewHost* const rvh = | |
71 content::RenderViewHost::FromID(request->render_process_id, | |
72 request->render_view_id); | |
73 Observe(rvh ? content::WebContents::FromRenderViewHost(rvh) : NULL); | |
74 } | |
75 | |
76 void FullscreenObserver::DidShowFullscreenWidget( | |
77 int routing_id) { | |
78 request_->fullscreen = true; | |
79 registry_->DispatchStatusChangeEvent(request_); | |
80 } | |
81 | |
82 void FullscreenObserver::DidDestroyFullscreenWidget( | |
83 int routing_id) { | |
84 request_->fullscreen = false; | |
85 registry_->DispatchStatusChangeEvent(request_); | |
86 } | |
87 | |
88 TabCaptureRequest::TabCaptureRequest( | |
89 int render_process_id, | |
90 int render_view_id, | |
91 const std::string& extension_id, | |
92 const int tab_id, | |
93 TabCaptureState status) | |
94 : render_process_id(render_process_id), | |
95 render_view_id(render_view_id), | |
96 extension_id(extension_id), | |
97 tab_id(tab_id), | |
98 status(status), | |
99 last_status(status), | |
100 fullscreen(false) { | |
101 } | |
102 | |
103 TabCaptureRequest::~TabCaptureRequest() { | |
104 } | |
105 | |
106 TabCaptureRegistry::TabCaptureRegistry(content::BrowserContext* context) | 140 TabCaptureRegistry::TabCaptureRegistry(content::BrowserContext* context) |
107 : browser_context_(context), extension_registry_observer_(this) { | 141 : browser_context_(context), extension_registry_observer_(this) { |
108 MediaCaptureDevicesDispatcher::GetInstance()->AddObserver(this); | 142 MediaCaptureDevicesDispatcher::GetInstance()->AddObserver(this); |
109 registrar_.Add(this, | |
110 chrome::NOTIFICATION_FULLSCREEN_CHANGED, | |
111 content::NotificationService::AllSources()); | |
112 extension_registry_observer_.Add(ExtensionRegistry::Get(browser_context_)); | 143 extension_registry_observer_.Add(ExtensionRegistry::Get(browser_context_)); |
113 } | 144 } |
114 | 145 |
115 TabCaptureRegistry::~TabCaptureRegistry() { | 146 TabCaptureRegistry::~TabCaptureRegistry() { |
116 MediaCaptureDevicesDispatcher::GetInstance()->RemoveObserver(this); | 147 MediaCaptureDevicesDispatcher::GetInstance()->RemoveObserver(this); |
117 } | 148 } |
118 | 149 |
119 // static | 150 // static |
120 TabCaptureRegistry* TabCaptureRegistry::Get(content::BrowserContext* context) { | 151 TabCaptureRegistry* TabCaptureRegistry::Get(content::BrowserContext* context) { |
121 return BrowserContextKeyedAPIFactory<TabCaptureRegistry>::Get(context); | 152 return BrowserContextKeyedAPIFactory<TabCaptureRegistry>::Get(context); |
122 } | 153 } |
123 | 154 |
124 static base::LazyInstance<BrowserContextKeyedAPIFactory<TabCaptureRegistry> > | 155 static base::LazyInstance<BrowserContextKeyedAPIFactory<TabCaptureRegistry> > |
125 g_factory = LAZY_INSTANCE_INITIALIZER; | 156 g_factory = LAZY_INSTANCE_INITIALIZER; |
126 | 157 |
127 // static | 158 // static |
128 BrowserContextKeyedAPIFactory<TabCaptureRegistry>* | 159 BrowserContextKeyedAPIFactory<TabCaptureRegistry>* |
129 TabCaptureRegistry::GetFactoryInstance() { | 160 TabCaptureRegistry::GetFactoryInstance() { |
130 return g_factory.Pointer(); | 161 return g_factory.Pointer(); |
131 } | 162 } |
132 | 163 |
133 const TabCaptureRegistry::RegistryCaptureInfo | 164 void TabCaptureRegistry::GetCapturedTabs( |
134 TabCaptureRegistry::GetCapturedTabs(const std::string& extension_id) const { | 165 const std::string& extension_id, |
| 166 base::ListValue* list_of_capture_info) const { |
135 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 167 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
136 RegistryCaptureInfo list; | 168 DCHECK(list_of_capture_info); |
137 for (ScopedVector<TabCaptureRequest>::const_iterator it = requests_.begin(); | 169 list_of_capture_info->Clear(); |
| 170 for (ScopedVector<LiveRequest>::const_iterator it = requests_.begin(); |
138 it != requests_.end(); ++it) { | 171 it != requests_.end(); ++it) { |
139 if ((*it)->extension_id == extension_id) { | 172 if ((*it)->is_verified() && (*it)->extension_id() == extension_id) { |
140 list.push_back(std::make_pair((*it)->tab_id, (*it)->status)); | 173 tab_capture::CaptureInfo info; |
141 } | 174 (*it)->GetCaptureInfo(&info); |
142 } | 175 list_of_capture_info->Append(info.ToValue().release()); |
143 return list; | |
144 } | |
145 | |
146 void TabCaptureRegistry::Observe(int type, | |
147 const content::NotificationSource& source, | |
148 const content::NotificationDetails& details) { | |
149 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
150 DCHECK_EQ(chrome::NOTIFICATION_FULLSCREEN_CHANGED, type); | |
151 FullscreenController* fullscreen_controller = | |
152 content::Source<FullscreenController>(source).ptr(); | |
153 const bool is_fullscreen = *content::Details<bool>(details).ptr(); | |
154 for (ScopedVector<TabCaptureRequest>::iterator it = requests_.begin(); | |
155 it != requests_.end(); | |
156 ++it) { | |
157 // If we are exiting fullscreen mode, we only need to check if any of | |
158 // the requests had the fullscreen flag toggled previously. The | |
159 // fullscreen controller no longer has the reference to the fullscreen | |
160 // web_contents here. | |
161 if (!is_fullscreen) { | |
162 if ((*it)->fullscreen) { | |
163 (*it)->fullscreen = false; | |
164 DispatchStatusChangeEvent(*it); | |
165 break; | |
166 } | |
167 continue; | |
168 } | |
169 | |
170 // If we are entering fullscreen mode, find whether the web_contents we | |
171 // are capturing entered fullscreen mode. | |
172 content::RenderViewHost* const rvh = content::RenderViewHost::FromID( | |
173 (*it)->render_process_id, (*it)->render_view_id); | |
174 if (rvh && | |
175 fullscreen_controller->IsFullscreenForTabOrPending( | |
176 content::WebContents::FromRenderViewHost(rvh))) { | |
177 (*it)->fullscreen = true; | |
178 DispatchStatusChangeEvent(*it); | |
179 break; | |
180 } | 176 } |
181 } | 177 } |
182 } | 178 } |
183 | 179 |
184 void TabCaptureRegistry::OnExtensionUnloaded( | 180 void TabCaptureRegistry::OnExtensionUnloaded( |
185 content::BrowserContext* browser_context, | 181 content::BrowserContext* browser_context, |
186 const Extension* extension, | 182 const Extension* extension, |
187 UnloadedExtensionInfo::Reason reason) { | 183 UnloadedExtensionInfo::Reason reason) { |
188 // Cleanup all the requested media streams for this extension. | 184 // Cleanup all the requested media streams for this extension. |
189 for (ScopedVector<TabCaptureRequest>::iterator it = requests_.begin(); | 185 for (ScopedVector<LiveRequest>::iterator it = requests_.begin(); |
190 it != requests_.end();) { | 186 it != requests_.end();) { |
191 if ((*it)->extension_id == extension->id()) { | 187 if ((*it)->extension_id() == extension->id()) { |
192 it = requests_.erase(it); | 188 it = requests_.erase(it); |
193 } else { | 189 } else { |
194 ++it; | 190 ++it; |
195 } | 191 } |
196 } | 192 } |
197 } | 193 } |
198 | 194 |
199 bool TabCaptureRegistry::AddRequest(int render_process_id, | 195 bool TabCaptureRegistry::AddRequest(content::WebContents* target_contents, |
200 int render_view_id, | 196 const std::string& extension_id) { |
201 const std::string& extension_id, | 197 LiveRequest* const request = FindRequest(target_contents); |
202 int tab_id, | 198 |
203 TabCaptureState status) { | |
204 TabCaptureRequest* request = FindCaptureRequest(render_process_id, | |
205 render_view_id); | |
206 // Currently, we do not allow multiple active captures for same tab. | 199 // Currently, we do not allow multiple active captures for same tab. |
207 if (request != NULL) { | 200 if (request != NULL) { |
208 if (request->status != tab_capture::TAB_CAPTURE_STATE_STOPPED && | 201 if (request->capture_state() != tab_capture::TAB_CAPTURE_STATE_STOPPED && |
209 request->status != tab_capture::TAB_CAPTURE_STATE_ERROR) { | 202 request->capture_state() != tab_capture::TAB_CAPTURE_STATE_ERROR) { |
210 return false; | 203 return false; |
211 } else { | 204 } else { |
212 DeleteCaptureRequest(render_process_id, render_view_id); | 205 // Delete the request before creating its replacement (below). |
| 206 KillRequest(request); |
213 } | 207 } |
214 } | 208 } |
215 | 209 |
216 requests_.push_back(new TabCaptureRequest(render_process_id, | 210 requests_.push_back(new LiveRequest(target_contents, extension_id, this)); |
217 render_view_id, | |
218 extension_id, | |
219 tab_id, | |
220 status)); | |
221 return true; | 211 return true; |
222 } | 212 } |
223 | 213 |
224 bool TabCaptureRegistry::VerifyRequest(int render_process_id, | 214 bool TabCaptureRegistry::VerifyRequest( |
225 int render_view_id) { | 215 int render_process_id, |
| 216 int render_frame_id, |
| 217 const std::string& extension_id) { |
226 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 218 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
227 DVLOG(1) << "Verifying tabCapture request for " | 219 |
228 << render_process_id << ":" << render_view_id; | 220 LiveRequest* const request = FindRequest( |
229 // TODO(justinlin): Verify extension too. | 221 content::WebContents::FromRenderFrameHost( |
230 return (FindCaptureRequest(render_process_id, render_view_id) != NULL); | 222 content::RenderFrameHost::FromID( |
| 223 render_process_id, render_frame_id))); |
| 224 if (!request) |
| 225 return false; // Unknown RenderFrameHost ID, or frame has gone away. |
| 226 |
| 227 // TODO(miu): We should probably also verify the origin URL, like the desktop |
| 228 // capture API. http://crbug.com/163100 |
| 229 if (request->is_verified() || |
| 230 request->extension_id() != extension_id || |
| 231 (request->capture_state() != tab_capture::TAB_CAPTURE_STATE_NONE && |
| 232 request->capture_state() != tab_capture::TAB_CAPTURE_STATE_PENDING)) |
| 233 return false; |
| 234 |
| 235 // TODO(miu): The RenderFrameHost IDs should be set when LiveRequest is |
| 236 // constructed, but ExtensionFunction does not yet support use of |
| 237 // render_frame_host() to determine the exact RenderFrameHost for the call to |
| 238 // AddRequest() above. Fix tab_capture_api.cc, and then fix this ugly hack. |
| 239 // http://crbug.com/304341 |
| 240 request->SetOriginallyTargettedRenderFrameID( |
| 241 render_process_id, render_frame_id); |
| 242 |
| 243 request->SetIsVerified(); |
| 244 return true; |
231 } | 245 } |
232 | 246 |
233 void TabCaptureRegistry::OnRequestUpdate( | 247 void TabCaptureRegistry::OnRequestUpdate( |
234 int render_process_id, | 248 int original_target_render_process_id, |
235 int render_view_id, | 249 int original_target_render_frame_id, |
236 const content::MediaStreamDevice& device, | 250 content::MediaStreamType stream_type, |
237 const content::MediaRequestState new_state) { | 251 const content::MediaRequestState new_state) { |
238 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 252 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
239 if (device.type != content::MEDIA_TAB_VIDEO_CAPTURE && | 253 if (stream_type != content::MEDIA_TAB_VIDEO_CAPTURE && |
240 device.type != content::MEDIA_TAB_AUDIO_CAPTURE) { | 254 stream_type != content::MEDIA_TAB_AUDIO_CAPTURE) { |
241 return; | 255 return; |
242 } | 256 } |
243 | 257 |
244 TabCaptureRequest* request = FindCaptureRequest(render_process_id, | 258 LiveRequest* request = FindRequest(original_target_render_process_id, |
245 render_view_id); | 259 original_target_render_frame_id); |
246 if (request == NULL) { | 260 if (!request) { |
247 // TODO(justinlin): This can happen because the extension's renderer does | 261 // Fall-back: Search again using WebContents since this method may have been |
248 // not seem to always cleanup streams correctly. | 262 // called before VerifyRequest() set the RenderFrameHost ID. If the |
249 LOG(ERROR) << "Receiving updates for deleted capture request."; | 263 // RenderFrameHost has gone away, that's okay since the upcoming call to |
250 return; | 264 // VerifyRequest() will fail, and that means the tracking of request updates |
| 265 // doesn't matter anymore. |
| 266 request = FindRequest(content::WebContents::FromRenderFrameHost( |
| 267 content::RenderFrameHost::FromID(original_target_render_process_id, |
| 268 original_target_render_frame_id))); |
| 269 if (!request) |
| 270 return; // Stale or invalid request update. |
251 } | 271 } |
252 | 272 |
253 bool opening_stream = false; | |
254 bool stopping_stream = false; | |
255 | |
256 TabCaptureState next_state = tab_capture::TAB_CAPTURE_STATE_NONE; | 273 TabCaptureState next_state = tab_capture::TAB_CAPTURE_STATE_NONE; |
257 switch (new_state) { | 274 switch (new_state) { |
258 case content::MEDIA_REQUEST_STATE_PENDING_APPROVAL: | 275 case content::MEDIA_REQUEST_STATE_PENDING_APPROVAL: |
259 next_state = tab_capture::TAB_CAPTURE_STATE_PENDING; | 276 next_state = tab_capture::TAB_CAPTURE_STATE_PENDING; |
260 break; | 277 break; |
261 case content::MEDIA_REQUEST_STATE_DONE: | 278 case content::MEDIA_REQUEST_STATE_DONE: |
262 opening_stream = true; | |
263 next_state = tab_capture::TAB_CAPTURE_STATE_ACTIVE; | 279 next_state = tab_capture::TAB_CAPTURE_STATE_ACTIVE; |
264 break; | 280 break; |
265 case content::MEDIA_REQUEST_STATE_CLOSING: | 281 case content::MEDIA_REQUEST_STATE_CLOSING: |
266 stopping_stream = true; | |
267 next_state = tab_capture::TAB_CAPTURE_STATE_STOPPED; | 282 next_state = tab_capture::TAB_CAPTURE_STATE_STOPPED; |
268 break; | 283 break; |
269 case content::MEDIA_REQUEST_STATE_ERROR: | 284 case content::MEDIA_REQUEST_STATE_ERROR: |
270 stopping_stream = true; | |
271 next_state = tab_capture::TAB_CAPTURE_STATE_ERROR; | 285 next_state = tab_capture::TAB_CAPTURE_STATE_ERROR; |
272 break; | 286 break; |
273 case content::MEDIA_REQUEST_STATE_OPENING: | 287 case content::MEDIA_REQUEST_STATE_OPENING: |
274 return; | 288 return; |
275 case content::MEDIA_REQUEST_STATE_REQUESTED: | 289 case content::MEDIA_REQUEST_STATE_REQUESTED: |
276 case content::MEDIA_REQUEST_STATE_NOT_REQUESTED: | 290 case content::MEDIA_REQUEST_STATE_NOT_REQUESTED: |
277 NOTREACHED(); | 291 NOTREACHED(); |
278 return; | 292 return; |
279 } | 293 } |
280 | 294 |
281 if (next_state == tab_capture::TAB_CAPTURE_STATE_PENDING && | 295 if (next_state == tab_capture::TAB_CAPTURE_STATE_PENDING && |
282 request->status != tab_capture::TAB_CAPTURE_STATE_PENDING && | 296 request->capture_state() != tab_capture::TAB_CAPTURE_STATE_PENDING && |
283 request->status != tab_capture::TAB_CAPTURE_STATE_NONE && | 297 request->capture_state() != tab_capture::TAB_CAPTURE_STATE_NONE && |
284 request->status != tab_capture::TAB_CAPTURE_STATE_STOPPED && | 298 request->capture_state() != tab_capture::TAB_CAPTURE_STATE_STOPPED && |
285 request->status != tab_capture::TAB_CAPTURE_STATE_ERROR) { | 299 request->capture_state() != tab_capture::TAB_CAPTURE_STATE_ERROR) { |
286 // If we end up trying to grab a new stream while the previous one was never | 300 // If we end up trying to grab a new stream while the previous one was never |
287 // terminated, then something fishy is going on. | 301 // terminated, then something fishy is going on. |
288 NOTREACHED() << "Trying to capture tab with existing stream."; | 302 NOTREACHED() << "Trying to capture tab with existing stream."; |
289 return; | 303 return; |
290 } | 304 } |
291 | 305 |
292 if (opening_stream) { | 306 request->UpdateCaptureState(next_state); |
293 request->fullscreen_observer.reset(new FullscreenObserver(request, this)); | |
294 } | |
295 | |
296 if (stopping_stream) { | |
297 request->fullscreen_observer.reset(); | |
298 } | |
299 | |
300 request->last_status = request->status; | |
301 request->status = next_state; | |
302 | |
303 // We will get duplicate events if we requested both audio and video, so only | |
304 // send new events. | |
305 if (request->last_status != request->status) { | |
306 DispatchStatusChangeEvent(request); | |
307 } | |
308 } | 307 } |
309 | 308 |
310 void TabCaptureRegistry::DispatchStatusChangeEvent( | 309 void TabCaptureRegistry::DispatchStatusChangeEvent( |
311 const TabCaptureRequest* request) const { | 310 const LiveRequest* request) const { |
312 EventRouter* router = EventRouter::Get(browser_context_); | 311 EventRouter* router = EventRouter::Get(browser_context_); |
313 if (!router) | 312 if (!router) |
314 return; | 313 return; |
315 | 314 |
316 scoped_ptr<tab_capture::CaptureInfo> info(new tab_capture::CaptureInfo()); | |
317 info->tab_id = request->tab_id; | |
318 info->status = request->status; | |
319 info->fullscreen = request->fullscreen; | |
320 | |
321 scoped_ptr<base::ListValue> args(new base::ListValue()); | 315 scoped_ptr<base::ListValue> args(new base::ListValue()); |
322 args->Append(info->ToValue().release()); | 316 tab_capture::CaptureInfo info; |
| 317 request->GetCaptureInfo(&info); |
| 318 args->Append(info.ToValue().release()); |
323 scoped_ptr<Event> event(new Event(tab_capture::OnStatusChanged::kEventName, | 319 scoped_ptr<Event> event(new Event(tab_capture::OnStatusChanged::kEventName, |
324 args.Pass())); | 320 args.Pass())); |
325 event->restrict_to_browser_context = browser_context_; | 321 event->restrict_to_browser_context = browser_context_; |
326 | 322 |
327 router->DispatchEventToExtension(request->extension_id, event.Pass()); | 323 router->DispatchEventToExtension(request->extension_id(), event.Pass()); |
328 } | 324 } |
329 | 325 |
330 TabCaptureRequest* TabCaptureRegistry::FindCaptureRequest( | 326 TabCaptureRegistry::LiveRequest* TabCaptureRegistry::FindRequest( |
331 int render_process_id, int render_view_id) const { | 327 const content::WebContents* target_contents) const { |
332 for (ScopedVector<TabCaptureRequest>::const_iterator it = requests_.begin(); | 328 for (ScopedVector<LiveRequest>::const_iterator it = requests_.begin(); |
333 it != requests_.end(); ++it) { | 329 it != requests_.end(); ++it) { |
334 if ((*it)->render_process_id == render_process_id && | 330 if ((*it)->target_contents() == target_contents) |
335 (*it)->render_view_id == render_view_id) { | |
336 return *it; | 331 return *it; |
337 } | |
338 } | 332 } |
339 return NULL; | 333 return NULL; |
340 } | 334 } |
341 | 335 |
342 void TabCaptureRegistry::DeleteCaptureRequest(int render_process_id, | 336 TabCaptureRegistry::LiveRequest* TabCaptureRegistry::FindRequest( |
343 int render_view_id) { | 337 int original_target_render_process_id, |
344 for (ScopedVector<TabCaptureRequest>::iterator it = requests_.begin(); | 338 int original_target_render_frame_id) const { |
| 339 for (ScopedVector<LiveRequest>::const_iterator it = requests_.begin(); |
345 it != requests_.end(); ++it) { | 340 it != requests_.end(); ++it) { |
346 if ((*it)->render_process_id == render_process_id && | 341 if ((*it)->WasOriginallyTargettingRenderFrameID( |
347 (*it)->render_view_id == render_view_id) { | 342 original_target_render_process_id, |
| 343 original_target_render_frame_id)) |
| 344 return *it; |
| 345 } |
| 346 return NULL; |
| 347 } |
| 348 |
| 349 void TabCaptureRegistry::KillRequest(LiveRequest* request) { |
| 350 for (ScopedVector<LiveRequest>::iterator it = requests_.begin(); |
| 351 it != requests_.end(); ++it) { |
| 352 if ((*it) == request) { |
348 requests_.erase(it); | 353 requests_.erase(it); |
349 return; | 354 return; |
350 } | 355 } |
351 } | 356 } |
| 357 NOTREACHED(); |
352 } | 358 } |
353 | 359 |
354 } // namespace extensions | 360 } // namespace extensions |
OLD | NEW |