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

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

Powered by Google App Engine
This is Rietveld 408576698