Chromium Code Reviews| Index: content/browser/media_stream/video_capture_manager.cc |
| =================================================================== |
| --- content/browser/media_stream/video_capture_manager.cc (revision 0) |
| +++ content/browser/media_stream/video_capture_manager.cc (revision 0) |
| @@ -0,0 +1,460 @@ |
| +// Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "content/browser/media_stream/video_capture_manager.h" |
| + |
| +#include "base/memory/scoped_ptr.h" |
| +#include "content/browser/browser_thread.h" |
| +#include "media/video/capture/fake_video_capture_device.h" |
| +#include "media/video/capture/video_capture_device.h" |
| + |
| +namespace media_stream { |
| + |
| +// Starting id for the first capture session |
| +enum { kFirstSessionId = 1}; |
| + |
| +static ::base::LazyInstance<VideoCaptureManager> g_video_capture_manager( |
| + base::LINKER_INITIALIZED); |
| + |
| +bool VideoCaptureManager::use_fake_device_ = false; |
| + |
| +VideoCaptureManager* VideoCaptureManager::Get() { |
| + return g_video_capture_manager.Pointer(); |
| +} |
| + |
| +void VideoCaptureManager::CreateTestManager() { |
| + VideoCaptureManager* vcm = g_video_capture_manager.Pointer(); |
| + vcm->UseFakeDevice(); |
| +} |
| + |
| +VideoCaptureManager::VideoCaptureManager() |
| + : vc_device_thread_("VideoCaptureManagerThread"), |
| + listener_(NULL), |
| + new_capture_session_id_(kFirstSessionId), |
| + devices_() { |
| + vc_device_thread_.Start(); |
| +} |
| + |
| +VideoCaptureManager::~VideoCaptureManager() { |
| + vc_device_thread_.Stop(); |
| + devices_.clear(); |
| +} |
| + |
| +int VideoCaptureManager::Register(MediaStreamType service_type, |
| + MediaStreamProviderListener* listener) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| + if (service_type != kVideoCapture) { |
| + // Not a valid service type |
| + return -1; |
| + } |
| + if (listener_) { |
| + // Already registered, unregister first. |
| + return -1; |
| + } |
| + listener_ = listener; |
| + return 0; |
| +} |
| + |
| +void VideoCaptureManager::Unregister(MediaStreamType service_type, |
| + MediaStreamProviderListener* listener) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| + if (service_type != kVideoCapture) { |
| + return; |
| + } |
| + listener_ = NULL; |
| + return; |
| +} |
| + |
| +void VideoCaptureManager::EnumerateDevices(MediaStreamType service_type) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| + if (listener_ == NULL) { |
| + return; |
| + } |
| + if (service_type != kVideoCapture) { |
| + PostOnError(-1, kInvalidMediaStreamType); |
| + return; |
| + } |
| + |
| + vc_device_thread_.message_loop()->PostTask( |
| + FROM_HERE, |
| + NewRunnableMethod(this, |
| + &VideoCaptureManager::OnEnumerateDevices)); |
| + return; |
| +} |
| + |
| +MediaCaptureSessionId VideoCaptureManager::Open( |
| + MediaStreamType service_type, const MediaCaptureDeviceInfo& device) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| + if (listener_ == NULL) { |
| + return -1; |
| + } |
| + if (service_type != kVideoCapture) { |
| + PostOnError(-1, kInvalidMediaStreamType); |
| + return -1; |
| + } |
| + |
| + // Generate a new id for this device |
| + MediaCaptureSessionId video_capture_session_id = new_capture_session_id_++; |
| + |
| + vc_device_thread_.message_loop()->PostTask( |
| + FROM_HERE, |
| + NewRunnableMethod(this, |
| + &VideoCaptureManager::OnOpen, |
| + video_capture_session_id, |
| + device)); |
| + |
| + return video_capture_session_id; |
| +} |
| + |
| +void VideoCaptureManager::Close(MediaStreamType service_type, |
| + MediaCaptureSessionId capture_session_id) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| + if (listener_ == NULL) { |
| + return; |
| + } |
| + if (service_type != kVideoCapture) { |
| + PostOnError(-1, kInvalidMediaStreamType); |
| + return; |
| + } |
| + |
| + vc_device_thread_.message_loop()->PostTask( |
| + FROM_HERE, |
| + NewRunnableMethod(this, |
| + &VideoCaptureManager::OnClose, |
| + capture_session_id)); |
| + return; |
| +} |
| + |
| +void VideoCaptureManager::Start( |
| + const media::VideoCaptureParams& capture_params, |
| + media::VideoCaptureDevice::EventHandler* video_capture_receiver) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| + |
| + vc_device_thread_.message_loop()->PostTask( |
| + FROM_HERE, |
| + NewRunnableMethod(this, |
| + &VideoCaptureManager::OnStart, |
| + capture_params, |
| + video_capture_receiver)); |
| +} |
| + |
| +void VideoCaptureManager::Stop( |
| + const media::VideoCaptureSessionId capture_session_id, Task* stopped_task) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| + |
| + vc_device_thread_.message_loop()->PostTask( |
| + FROM_HERE, |
| + NewRunnableMethod(this, |
| + &VideoCaptureManager::OnStop, |
| + capture_session_id, |
| + stopped_task)); |
| +} |
| + |
| +void VideoCaptureManager::OnEnumerateDevices() { |
| + DCHECK(IsOnCaptureDeviceThread()); |
| + |
| + scoped_ptr<media::VideoCaptureDevice::Names> device_names( |
| + new media::VideoCaptureDevice::Names()); |
| + GetAvailableDevices(device_names.get()); |
| + |
| + MediaCaptureDevices devices; |
| + for (media::VideoCaptureDevice::Names::iterator it = |
| + device_names.get()->begin(); it != device_names.get()->end(); ++it) { |
|
wjia(left Chromium)
2011/05/06 00:11:31
one more space indent
mflodman1
2011/05/06 11:52:38
What is the indent-rule here? I thought it was 4 s
|
| + bool opened = DeviceOpened(*it); |
| + devices.push_back(MediaCaptureDeviceInfo(kVideoCapture, it->device_name, |
| + it->unique_id, opened)); |
| + } |
| + |
| + // Let the listener know the result |
| + PostOnDevicesEnumerated(devices); |
| + |
| + // Clean-up |
| + devices.clear(); |
| + device_names.get()->clear(); |
| + |
| + return; |
| +} |
| + |
| +void VideoCaptureManager::OnOpen(MediaCaptureSessionId capture_session_id, |
| + const MediaCaptureDeviceInfo device) { |
| + DCHECK(IsOnCaptureDeviceThread()); |
| + if (devices_.find(capture_session_id) != devices_.end()) { |
| + // id already exists! |
| + PostOnError(capture_session_id, kInvalidSession); |
| + return; |
| + } |
| + |
| + // Check if another session has already opened this device, only one user per |
| + // device is supported. |
|
wjia(left Chromium)
2011/05/06 00:11:31
looks like you can use DeviceOpened() here.
mflodman1
2011/05/06 11:52:38
DeviceOpened has a different input type, but I cre
|
| + for (VideoCaptureDevices::iterator it = devices_.begin(); |
| + it != devices_.end(); |
| + it++) { |
| + media::VideoCaptureDevice* vc_device = it->second; |
| + if (vc_device != NULL) { |
|
wjia(left Chromium)
2011/05/06 00:11:31
if vc_device == NULL here, is it an error?
mflodman1
2011/05/06 11:52:38
Removed.
vc_device == null only if a device can't
|
| + if (device.device_id.compare(vc_device->device_name().unique_id) == 0) { |
| + PostOnError(capture_session_id, kDeviceAlreadyInUse); |
| + return; |
| + } |
| + } |
| + } |
| + |
| + // Open the device |
| + media::VideoCaptureDevice::Name vc_device_name; |
| + vc_device_name.device_name = device.name; |
| + vc_device_name.unique_id = device.device_id; |
| + |
| + media::VideoCaptureDevice* video_capture_device = NULL; |
| + if (!use_fake_device_) { |
| + video_capture_device = media::VideoCaptureDevice::Create(vc_device_name); |
| + } else { |
| + video_capture_device = |
| + media::FakeVideoCaptureDevice::Create(vc_device_name); |
| + } |
| + if (video_capture_device == NULL) { |
| + PostOnError(capture_session_id, kDeviceNotAvailable); |
| + return; |
| + } |
| + |
| + devices_[capture_session_id] = video_capture_device; |
| + PostOnOpened(capture_session_id); |
| + return; |
| +} |
| + |
| +void VideoCaptureManager::OnClose( |
| + MediaCaptureSessionId capture_session_id) { |
| + DCHECK(IsOnCaptureDeviceThread()); |
| + if (devices_.find(capture_session_id) == devices_.end()) { |
| + return; |
| + } |
| + |
| + VideoCaptureDevices::iterator it = devices_.find(capture_session_id); |
| + if (it == devices_.end()) { |
| + // Device not opened |
| + PostOnClosed(capture_session_id); |
| + return; |
| + } |
| + // Deallocate (if not done already) and delete the device |
| + media::VideoCaptureDevice* video_capture_device = it->second; |
| + video_capture_device->DeAllocate(); |
| + delete video_capture_device; |
| + devices_.erase(it); |
| + |
| + PostOnClosed(capture_session_id); |
| + return; |
| +} |
| + |
| +void VideoCaptureManager::OnStart( |
| + const media::VideoCaptureParams capture_params, |
| + media::VideoCaptureDevice::EventHandler* video_capture_receiver) { |
| + DCHECK(IsOnCaptureDeviceThread()); |
| + |
| + // Solution for not using MediaStreamManager |
| + // This session id won't be returned by Open() |
| + if (capture_params.session_id == kStartOpenSessionId) { |
| + // Start() is called without using Open(), we need to open a device |
| + scoped_ptr<media::VideoCaptureDevice::Names> device_names( |
| + new media::VideoCaptureDevice::Names()); |
| + GetAvailableDevices(device_names.get()); |
| + |
| + MediaCaptureDeviceInfo device(kVideoCapture, |
| + device_names.get()->front().device_name, |
| + device_names.get()->front().unique_id, false); |
| + |
| + // Call OnOpen to open using the first device in the list |
| + OnOpen(capture_params.session_id, device); |
| + device_names.get()->clear(); |
|
wjia(left Chromium)
2011/05/06 00:11:31
clear() is not needed. scoped_ptr should take care
mflodman1
2011/05/06 11:52:38
Done.
|
| + } |
| + |
| + VideoCaptureDevices::iterator it = devices_.find(capture_params.session_id); |
| + if (it == devices_.end()) { |
| + // Invalid session id |
| + video_capture_receiver->OnError(); |
| + return; |
| + } |
| + media::VideoCaptureDevice* video_capture_device = it->second; |
| + |
| + // Possible errors are signaled to host |
|
wjia(left Chromium)
2011/05/06 00:11:31
comment doesn't match.
mflodman1
2011/05/06 11:52:38
Comment updated.
|
| + video_capture_device->Allocate(capture_params.width, capture_params.height, |
| + capture_params.frame_per_second, |
| + video_capture_receiver); |
| + video_capture_device->Start(); |
| + return; |
| +} |
| + |
| +void VideoCaptureManager::OnStop( |
| + const media::VideoCaptureSessionId capture_session_id, |
| + Task* stopped_task) { |
| + DCHECK(IsOnCaptureDeviceThread()); |
| + |
| + VideoCaptureDevices::iterator it = devices_.find(capture_session_id); |
| + if (it != devices_.end()) { |
| + media::VideoCaptureDevice* video_capture_device = it->second; |
| + // Possible errors are signaled by video_capture_device |
|
wjia(left Chromium)
2011/05/06 00:11:31
comment doesn't match.
mflodman1
2011/05/06 11:52:38
Comment updated.
|
| + video_capture_device->Stop(); |
| + video_capture_device->DeAllocate(); |
| + } |
| + |
| + if (stopped_task) { |
| + stopped_task->Run(); |
| + delete stopped_task; |
| + } |
| + |
| + if (capture_session_id == kStartOpenSessionId) { |
| + // This device was opened from Start(), not Open(). Close it! |
| + OnClose(capture_session_id); |
| + } |
| + return; |
| +} |
| + |
| +void VideoCaptureManager::OnOpened( |
| + MediaCaptureSessionId capture_session_id) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| + if (listener_ == NULL) { |
| + // Listener has been removed |
| + return; |
| + } |
| + listener_->Opened(kVideoCapture, capture_session_id); |
| + return; |
| +} |
| + |
| +void VideoCaptureManager::OnClosed( |
| + MediaCaptureSessionId capture_session_id) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| + if (listener_ == NULL) { |
| + // Listener has been removed |
| + return; |
| + } |
| + listener_->Closed(kVideoCapture, capture_session_id); |
| + return; |
| +} |
| + |
| +void VideoCaptureManager::OnDevicesEnumerated( |
| + const MediaCaptureDevices& devices) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| + if (listener_ == NULL) { |
| + // Listener has been removed |
| + return; |
| + } |
| + listener_->DevicesEnumerated(kVideoCapture, devices); |
| + return; |
| +} |
| + |
| +void VideoCaptureManager::OnError(MediaCaptureSessionId capture_session_id, |
| + MediaStreamProviderError error) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| + if (listener_ == NULL) { |
| + // Listener has been removed |
| + return; |
| + } |
| + listener_->Error(kVideoCapture, capture_session_id, error); |
| + return; |
| +} |
| + |
| +void VideoCaptureManager::PostOnOpened( |
| + MediaCaptureSessionId capture_session_id) { |
| + DCHECK(IsOnCaptureDeviceThread()); |
| + |
| + BrowserThread::PostTask(BrowserThread::IO, |
| + FROM_HERE, |
| + NewRunnableFunction( |
| + &VideoCaptureManager::OnOpenedProxy, |
| + capture_session_id)); |
|
wjia(left Chromium)
2011/05/06 00:11:31
there is no need for On*Proxy. You can use:
Bro
mflodman1
2011/05/06 11:52:38
Done.
|
| + return; |
| +} |
| + |
| +void VideoCaptureManager::PostOnClosed( |
| + MediaCaptureSessionId capture_session_id) { |
| + DCHECK(IsOnCaptureDeviceThread()); |
| + BrowserThread::PostTask(BrowserThread::IO, |
| + FROM_HERE, |
| + NewRunnableFunction( |
| + &VideoCaptureManager::OnClosedProxy, |
| + capture_session_id)); |
| + return; |
| +} |
| + |
| +void VideoCaptureManager::PostOnDevicesEnumerated( |
| + const MediaCaptureDevices& devices) { |
| + DCHECK(IsOnCaptureDeviceThread()); |
| + BrowserThread::PostTask(BrowserThread::IO, |
| + FROM_HERE, |
| + NewRunnableFunction( |
| + &VideoCaptureManager::OnDevicesEnumeratedProxy, |
| + devices)); |
| + return; |
| +} |
| + |
| +void VideoCaptureManager::PostOnError(MediaCaptureSessionId capture_session_id, |
| + MediaStreamProviderError error) { |
| + DCHECK(IsOnCaptureDeviceThread()); |
| + BrowserThread::PostTask(BrowserThread::IO, |
| + FROM_HERE, |
| + NewRunnableFunction( |
| + &VideoCaptureManager::OnErrorProxy, |
| + capture_session_id, |
| + error)); |
| + return; |
| +} |
| + |
| +void VideoCaptureManager::OnOpenedProxy( |
| + MediaCaptureSessionId capture_session_id) { |
| + Get()->OnOpened(capture_session_id); |
| +} |
| + |
| +void VideoCaptureManager::OnClosedProxy( |
| + MediaCaptureSessionId capture_session_id) { |
| + Get()->OnClosed(capture_session_id); |
| +} |
| + |
| +void VideoCaptureManager::OnDevicesEnumeratedProxy( |
| + const MediaCaptureDevices devices) { |
| + Get()->OnDevicesEnumerated(devices); |
| +} |
| + |
| +void VideoCaptureManager::OnErrorProxy(MediaCaptureSessionId capture_session_id, |
| + MediaStreamProviderError error) { |
| + Get()->OnError(capture_session_id, error); |
| +} |
| + |
| +bool VideoCaptureManager::IsOnCaptureDeviceThread() const { |
| + return MessageLoop::current() == vc_device_thread_.message_loop(); |
| +} |
| + |
| +void VideoCaptureManager::GetAvailableDevices( |
| + media::VideoCaptureDevice::Names* device_names) { |
| + DCHECK(IsOnCaptureDeviceThread()); |
| + |
| + if (!use_fake_device_) { |
| + media::VideoCaptureDevice::GetDeviceNames(device_names); |
| + } else { |
| + media::FakeVideoCaptureDevice::GetDeviceNames(device_names); |
| + } |
| + return; |
| +} |
| + |
| +bool VideoCaptureManager::DeviceOpened( |
| + const media::VideoCaptureDevice::Name& device_name) { |
| + DCHECK(IsOnCaptureDeviceThread()); |
| + |
| + for (VideoCaptureDevices::iterator it = devices_.begin(); |
| + it != devices_.end(); |
| + ++it) { |
| + if (device_name.unique_id.compare(it->second->device_name().unique_id) |
| + == 0 ) { |
| + // We've found the device! |
| + return true; |
| + } |
| + } |
| + return false; |
| +} |
| + |
| +void VideoCaptureManager::UseFakeDevice() { |
| + use_fake_device_ = true; |
| +} |
| + |
| +MessageLoop* VideoCaptureManager::GetMessageLoop() { |
| + return vc_device_thread_.message_loop(); |
| +} |
| + |
| +} // namespace media |
|
mflodman1
2011/05/05 11:11:22
Will add newline in next upload.
mflodman1
2011/05/06 11:52:38
Done.
|