| 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 |