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

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: Media class renames/moves 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 void TabCaptureRegistry::MediaObserverProxy::Attach(
139 TabCaptureRegistry* request_handler) {
140 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
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 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
149 handler_ = NULL;
150 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
151 base::Bind(&TabCaptureRegistry::MediaObserverProxy::
152 RegisterAsMediaObserverOnIOThread, this, true));
153 }
154
155 void TabCaptureRegistry::MediaObserverProxy::RegisterAsMediaObserverOnIOThread(
156 bool unregister) {
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