Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(632)

Side by Side Diff: chrome/browser/extensions/api/tab_capture/tab_capture_registry.cc

Issue 11038021: Implement Chrome Extension TabCapture API. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebase Created 8 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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.
4
5 #include "chrome/browser/extensions/api/tab_capture/tab_capture_registry.h"
6
7 #include "content/public/browser/browser_thread.h"
8 #include "chrome/browser/extensions/event_names.h"
9 #include "chrome/browser/extensions/event_router.h"
10 #include "chrome/browser/media/media_internals.h"
11 #include "chrome/browser/profiles/profile.h"
12 #include "chrome/browser/profiles/profile_dependency_manager.h"
13 #include "chrome/common/chrome_notification_types.h"
14 #include "chrome/common/extensions/extension.h"
15 #include "content/public/browser/notification_details.h"
16 #include "content/public/browser/notification_source.h"
17
18 namespace events = extensions::event_names;
19 using content::BrowserThread;
20
21 namespace extensions {
22
23 TabCaptureRegistry::TabCaptureRegistry(Profile* profile)
24 : proxy_(new MediaObserverProxy()), profile_(profile) {
25 proxy_->Attach(this);
26 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED,
27 content::Source<Profile>(profile_));
28 }
29
30 TabCaptureRegistry::~TabCaptureRegistry() {
31 proxy_->Detach();
32 }
33
34 void TabCaptureRegistry::HandleRequestUpdateOnUIThread(
35 const content::MediaStreamDevice& device,
36 const content::MediaRequestState new_state) {
37 EventRouter* router = profile_ ? profile_->GetExtensionEventRouter() : NULL;
38 if (!router)
39 return;
40
41 if (requests_.find(device.device_id) == requests_.end())
42 return;
43
44 tab_capture::TabCaptureState state =
45 tab_capture::TAB_CAPTURE_TAB_CAPTURE_STATE_NONE;
46 switch (new_state) {
47 case content::MEDIA_REQUEST_STATE_REQUESTED:
48 state = tab_capture::TAB_CAPTURE_TAB_CAPTURE_STATE_REQUESTED;
49 break;
50 case content::MEDIA_REQUEST_STATE_PENDING_APPROVAL:
51 state = tab_capture::TAB_CAPTURE_TAB_CAPTURE_STATE_PENDING;
52 break;
53 case content::MEDIA_REQUEST_STATE_DONE:
54 state = tab_capture::TAB_CAPTURE_TAB_CAPTURE_STATE_ACTIVE;
55 break;
56 case content::MEDIA_REQUEST_STATE_CLOSING:
57 state = tab_capture::TAB_CAPTURE_TAB_CAPTURE_STATE_STOPPED;
58 break;
59 case content::MEDIA_REQUEST_STATE_ERROR:
60 state = tab_capture::TAB_CAPTURE_TAB_CAPTURE_STATE_ERROR;
61 break;
62 default:
63 // TODO(justinlin): Implement muted state notification.
64 break;
65 }
66
67 if (state == tab_capture::TAB_CAPTURE_TAB_CAPTURE_STATE_NONE) {
68 // This is a state we don't handle.
69 return;
70 }
71
72 TabCaptureRegistry::TabCaptureRequest& request_info =
73 requests_[device.device_id];
74 request_info.status = state;
75
76 scoped_ptr<tab_capture::CaptureInfo> info(new tab_capture::CaptureInfo());
77 info->tab_id = request_info.tab_id;
78 info->status = request_info.status;
79
80 scoped_ptr<base::ListValue> args(new ListValue());
81 args->Append(info->ToValue().release());
82 router->DispatchEventToExtension(request_info.extension_id,
83 events::kOnTabCaptureStatusChanged, args.Pass(), profile_, GURL());
84 }
85
86 const TabCaptureRegistry::CaptureRequestList
87 TabCaptureRegistry::GetCapturedTabs(const std::string& extension_id) {
88 CaptureRequestList list;
89 for (DeviceCaptureRequestMap::iterator it = requests_.begin();
90 it != requests_.end(); ++it) {
91 if (it->second.extension_id == extension_id) {
92 list.push_back(it->second);
93 }
94 }
95 return list;
96 }
97
98 void TabCaptureRegistry::Observe(int type,
99 const content::NotificationSource& source,
100 const content::NotificationDetails& details) {
101 switch (type) {
102 case chrome::NOTIFICATION_EXTENSION_UNLOADED: {
103 // Cleanup all the requested media streams for this extension. We might
104 // accumulate too many requests left in the closed state otherwise.
105 std::string extension_id =
106 content::Details<extensions::UnloadedExtensionInfo>(details)->
107 extension->id();
108 for (DeviceCaptureRequestMap::iterator it = requests_.begin();
109 it != requests_.end();) {
110 if (it->second.extension_id == extension_id) {
111 requests_.erase(it++);
112 } else {
113 ++it;
114 }
115 }
116 break;
117 }
118 }
119 }
120
121 bool TabCaptureRegistry::AddRequest(
122 const std::string& key, const TabCaptureRequest& request) {
123 // Currently, we do not allow multiple active captures for same tab.
124 DCHECK(!key.empty());
125 if (requests_.find(key) != requests_.end())
126 if (requests_[key].status !=
127 tab_capture::TAB_CAPTURE_TAB_CAPTURE_STATE_STOPPED &&
128 requests_[key].status !=
129 tab_capture::TAB_CAPTURE_TAB_CAPTURE_STATE_ERROR)
130 return false;
131 requests_[key] = request;
132 return true;
133 }
134
135 bool TabCaptureRegistry::VerifyRequest(const std::string& key) {
136 return requests_.find(key) != requests_.end();
137 }
138
139 void TabCaptureRegistry::MediaObserverProxy::Attach(
140 TabCaptureRegistry* request_handler) {
141 handler_ = request_handler;
142 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
143 base::Bind(&TabCaptureRegistry::MediaObserverProxy::
144 RegisterAsMediaObserverOnIOThread, this, false));
145 }
146
147 void TabCaptureRegistry::MediaObserverProxy::Detach() {
148 handler_ = NULL;
149 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
150 base::Bind(&TabCaptureRegistry::MediaObserverProxy::
151 RegisterAsMediaObserverOnIOThread, this, true));
152 }
153
154 void TabCaptureRegistry::MediaObserverProxy::RegisterAsMediaObserverOnIOThread(
155 bool unregister) {
156 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
157 if (MediaInternals::GetInstance()) {
158 if (!unregister)
159 MediaInternals::GetInstance()->AddObserver(this);
160 else
161 MediaInternals::GetInstance()->RemoveObserver(this);
162 }
163 }
164
165 void TabCaptureRegistry::MediaObserverProxy::OnRequestUpdate(
166 const content::MediaStreamDevice& device,
167 const content::MediaRequestState new_state) {
168 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
169
170 // TODO(justinlin): We drop audio device events since they will occur in
171 // parallel with the video device events (we would get duplicate events). When
172 // audio mirroring is implemented, we will want to grab those events when
173 // video is not requested.
174 if (device.type != content::MEDIA_TAB_VIDEO_CAPTURE)
175 return;
176
177 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
178 base::Bind(&TabCaptureRegistry::MediaObserverProxy::UpdateOnUIThread,
179 this, device, new_state));
180 }
181
182 void TabCaptureRegistry::MediaObserverProxy::UpdateOnUIThread(
183 const content::MediaStreamDevice& device,
184 const content::MediaRequestState new_state) {
185 if (handler_)
186 handler_->HandleRequestUpdateOnUIThread(device, new_state);
187 }
188
189 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698