diff options
author | wjia@chromium.org <wjia@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-05-04 16:53:12 +0000 |
---|---|---|
committer | wjia@chromium.org <wjia@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-05-04 16:53:12 +0000 |
commit | 216e2be340f2203c6d188f1f14a5833f7ad1b305 (patch) | |
tree | 2f5f182797675f6b2cd0abc66bb29f2c38ea82aa /content/browser | |
parent | 904b19af79ea2f08b5645659bb169cb13e3b7eeb (diff) | |
download | chromium_src-216e2be340f2203c6d188f1f14a5833f7ad1b305.zip chromium_src-216e2be340f2203c6d188f1f14a5833f7ad1b305.tar.gz chromium_src-216e2be340f2203c6d188f1f14a5833f7ad1b305.tar.bz2 |
Fix media stream stop.
When a capture session is closed, that capture session should be stopped in VideoCaptureController as well.
This use case is a bit strange since <video> is not aware of the closure of the captrue session and it will hang there.
BUG=124994
TEST=run with the html page in the bug.
Review URL: https://chromiumcodereview.appspot.com/10250004
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@135363 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content/browser')
4 files changed, 75 insertions, 4 deletions
diff --git a/content/browser/renderer_host/media/video_capture_controller.cc b/content/browser/renderer_host/media/video_capture_controller.cc index cee8106..bda3d8b 100644 --- a/content/browser/renderer_host/media/video_capture_controller.cc +++ b/content/browser/renderer_host/media/video_capture_controller.cc @@ -27,6 +27,7 @@ struct VideoCaptureController::ControllerClient { event_handler(handler), render_process_handle(render_process), parameters(params), + session_closed(false), report_ready_to_delete(false) { } @@ -43,6 +44,9 @@ struct VideoCaptureController::ControllerClient { // Buffers used by this client. std::list<int> buffers; + // State of capture session, controlled by VideoCaptureManager directly. + bool session_closed; + // Record client's status when it has called StopCapture, but haven't // returned all buffers. bool report_ready_to_delete; @@ -79,6 +83,13 @@ void VideoCaptureController::StartCapture( base::ProcessHandle render_process, const media::VideoCaptureParams& params) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + DVLOG(1) << "VideoCaptureController::StartCapture, id " << id.device_id + << ", (" << params.width + << ", " << params.height + << ", " << params.frame_per_second + << ", " << params.session_id + << ")"; + // Signal error in case device is already in error state. if (state_ == video_capture::kError) { event_handler->OnError(id); @@ -136,6 +147,7 @@ void VideoCaptureController::StopCapture( VideoCaptureControllerEventHandler* event_handler, bool force_buffer_return) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + DVLOG(1) << "VideoCaptureController::StopCapture, id " << id.device_id; ControllerClient* client = FindClient(id, event_handler, pending_clients_); // If the client is still in pending queue, just remove it. @@ -193,6 +205,19 @@ void VideoCaptureController::StopCapture( } } +void VideoCaptureController::StopSession( + int session_id) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + DVLOG(1) << "VideoCaptureController::StopSession, id " << session_id; + + ControllerClient* client = FindClient(session_id, pending_clients_); + if (!client) + client = FindClient(session_id, controller_clients_); + + if (client) + client->session_closed = true; +} + void VideoCaptureController::ReturnBuffer( const VideoCaptureControllerID& id, VideoCaptureControllerEventHandler* event_handler, @@ -376,7 +401,8 @@ void VideoCaptureController::DoIncomingCapturedFrameOnIOThread( if (state_ == video_capture::kStarted) { for (ControllerClients::iterator client_it = controller_clients_.begin(); client_it != controller_clients_.end(); client_it++) { - if ((*client_it)->report_ready_to_delete) + if ((*client_it)->report_ready_to_delete || + (*client_it)->session_closed) continue; (*client_it)->event_handler->OnBufferReady((*client_it)->controller_id, @@ -486,6 +512,19 @@ VideoCaptureController::FindClient( return NULL; } +VideoCaptureController::ControllerClient* +VideoCaptureController::FindClient( + int session_id, + const ControllerClients& clients) { + for (ControllerClients::const_iterator client_it = clients.begin(); + client_it != clients.end(); client_it++) { + if ((*client_it)->parameters.session_id == session_id) { + return *client_it; + } + } + return NULL; +} + // This function is called when all buffers have been returned to controller, // or when device is stopped. It decides whether the device needs to be // restarted. diff --git a/content/browser/renderer_host/media/video_capture_controller.h b/content/browser/renderer_host/media/video_capture_controller.h index 1d7e2da..94111cc 100644 --- a/content/browser/renderer_host/media/video_capture_controller.h +++ b/content/browser/renderer_host/media/video_capture_controller.h @@ -59,6 +59,10 @@ class VideoCaptureController VideoCaptureControllerEventHandler* event_handler, bool force_buffer_return); + // API called directly by VideoCaptureManager in case the device is + // prematurely closed. + void StopSession(int session_id); + // Return a buffer previously given in // VideoCaptureControllerEventHandler::OnBufferReady. void ReturnBuffer(const VideoCaptureControllerID& id, @@ -100,6 +104,10 @@ class VideoCaptureController const VideoCaptureControllerID& id, VideoCaptureControllerEventHandler* handler, const ControllerClients& clients); + // Find a client of |session_id| in |clients|. + ControllerClient* FindClient( + int session_id, + const ControllerClients& clients); // Decide what to do after kStopping state. Dependent on events, controller // can stay in kStopping state, or go to kStopped, or restart capture. void PostStopping(); diff --git a/content/browser/renderer_host/media/video_capture_host.cc b/content/browser/renderer_host/media/video_capture_host.cc index 09f6981..a0c7941 100644 --- a/content/browser/renderer_host/media/video_capture_host.cc +++ b/content/browser/renderer_host/media/video_capture_host.cc @@ -177,6 +177,12 @@ bool VideoCaptureHost::OnMessageReceived(const IPC::Message& message, void VideoCaptureHost::OnStartCapture(int device_id, const media::VideoCaptureParams& params) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + DVLOG(1) << "VideoCaptureHost::OnStartCapture, device_id " << device_id + << ", (" << params.width + << ", " << params.height + << ", " << params.frame_per_second + << ", " << params.session_id + << ")"; VideoCaptureControllerID controller_id(device_id); DCHECK(entries_.find(controller_id) == entries_.end()); @@ -223,6 +229,8 @@ void VideoCaptureHost::DoControllerAddedOnIOThread( void VideoCaptureHost::OnStopCapture(int device_id) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + DVLOG(1) << "VideoCaptureHost::OnStopCapture, device_id " << device_id; + VideoCaptureControllerID controller_id(device_id); EntryMap::iterator it = entries_.find(controller_id); diff --git a/content/browser/renderer_host/media/video_capture_manager.cc b/content/browser/renderer_host/media/video_capture_manager.cc index 4b0102e..806b189 100644 --- a/content/browser/renderer_host/media/video_capture_manager.cc +++ b/content/browser/renderer_host/media/video_capture_manager.cc @@ -154,6 +154,7 @@ void VideoCaptureManager::OnOpen(int capture_session_id, const StreamDeviceInfo& device) { DCHECK(IsOnCaptureDeviceThread()); DCHECK(devices_.find(capture_session_id) == devices_.end()); + DVLOG(1) << "VideoCaptureManager::OnOpen, id " << capture_session_id; // Check if another session has already opened this device. If so, just // use that opened device. @@ -186,6 +187,7 @@ void VideoCaptureManager::OnOpen(int capture_session_id, void VideoCaptureManager::OnClose(int capture_session_id) { DCHECK(IsOnCaptureDeviceThread()); + DVLOG(1) << "VideoCaptureManager::OnClose, id " << capture_session_id; media::VideoCaptureDevice* video_capture_device = NULL; VideoCaptureDevices::iterator device_it = devices_.find(capture_session_id); @@ -203,6 +205,14 @@ void VideoCaptureManager::OnClose(int capture_session_id) { controllers_.erase(cit); } delete video_capture_device; + } else { + Controllers::iterator cit = controllers_.find(video_capture_device); + if (cit != controllers_.end()) { + BrowserThread::PostTask( + BrowserThread::IO, FROM_HERE, + base::Bind(&VideoCaptureController::StopSession, + cit->second->controller, capture_session_id)); + } } } PostOnClosed(capture_session_id); @@ -213,6 +223,11 @@ void VideoCaptureManager::OnStart( media::VideoCaptureDevice::EventHandler* video_capture_receiver) { DCHECK(IsOnCaptureDeviceThread()); DCHECK(video_capture_receiver != NULL); + DVLOG(1) << "VideoCaptureManager::OnStart, (" << capture_params.width + << ", " << capture_params.height + << ", " << capture_params.frame_per_second + << ", " << capture_params.session_id + << ")"; media::VideoCaptureDevice* video_capture_device = GetDeviceInternal(capture_params.session_id); @@ -238,6 +253,7 @@ void VideoCaptureManager::OnStop( const media::VideoCaptureSessionId capture_session_id, base::Closure stopped_cb) { DCHECK(IsOnCaptureDeviceThread()); + DVLOG(1) << "VideoCaptureManager::OnStop, id " << capture_session_id; VideoCaptureDevices::iterator it = devices_.find(capture_session_id); if (it != devices_.end()) { @@ -318,9 +334,9 @@ void VideoCaptureManager::PostOnOpened(int capture_session_id) { void VideoCaptureManager::PostOnClosed(int capture_session_id) { DCHECK(IsOnCaptureDeviceThread()); BrowserThread::PostTask(BrowserThread::IO, - FROM_HERE, - base::Bind(&VideoCaptureManager::OnClosed, this, - capture_session_id)); + FROM_HERE, + base::Bind(&VideoCaptureManager::OnClosed, this, + capture_session_id)); } void VideoCaptureManager::PostOnDevicesEnumerated( |