| OLD | NEW | 
| (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 | 
| OLD | NEW |