Add thread checks to the CaptureManager.
It looks like it is being used single threadedly, except that in some cases it is created and/or destroyed in threads other than the one running its operations. As such, CaptureManager() contains 'thread_checker_.DetachFromThread()' and ~CaptureManager() does not have a DCHECK.
BUG=
R=perkj@webrtc.org, tommi@webrtc.org
Review URL: https://webrtc-codereview.appspot.com/36279004
Cr-Commit-Position: refs/heads/master@{#8498}
git-svn-id: http://webrtc.googlecode.com/svn/trunk@8498 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/talk/libjingle_tests.gyp b/talk/libjingle_tests.gyp
index 4a6f909..5b70088 100755
--- a/talk/libjingle_tests.gyp
+++ b/talk/libjingle_tests.gyp
@@ -92,8 +92,7 @@
'libjingle_unittest_main',
],
'sources': [
- # TODO(ronghuawu): Reenable this test.
- # 'media/base/capturemanager_unittest.cc',
+ 'media/base/capturemanager_unittest.cc',
'media/base/codec_unittest.cc',
'media/base/filemediaengine_unittest.cc',
'media/base/rtpdataengine_unittest.cc',
diff --git a/talk/media/base/capturemanager.cc b/talk/media/base/capturemanager.cc
index 06f4b83..a68c91c 100644
--- a/talk/media/base/capturemanager.cc
+++ b/talk/media/base/capturemanager.cc
@@ -32,6 +32,7 @@
#include "talk/media/base/videocapturer.h"
#include "talk/media/base/videoprocessor.h"
#include "talk/media/base/videorenderer.h"
+#include "webrtc/base/checks.h"
#include "webrtc/base/logging.h"
namespace cricket {
@@ -50,10 +51,19 @@
int IncCaptureStartRef();
int DecCaptureStartRef();
- CaptureRenderAdapter* adapter() { return adapter_.get(); }
- VideoCapturer* GetVideoCapturer() { return adapter()->video_capturer(); }
+ CaptureRenderAdapter* adapter() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ return adapter_.get();
+ }
+ VideoCapturer* GetVideoCapturer() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ return adapter()->video_capturer();
+ }
- int start_count() const { return start_count_; }
+ int start_count() const {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ return start_count_;
+ }
private:
struct CaptureResolutionInfo {
@@ -64,6 +74,7 @@
explicit VideoCapturerState(CaptureRenderAdapter* adapter);
+ rtc::ThreadChecker thread_checker_;
rtc::scoped_ptr<CaptureRenderAdapter> adapter_;
int start_count_;
@@ -77,6 +88,7 @@
VideoCapturerState::VideoCapturerState(CaptureRenderAdapter* adapter)
: adapter_(adapter), start_count_(1) {}
+// static
VideoCapturerState* VideoCapturerState::Create(VideoCapturer* video_capturer) {
CaptureRenderAdapter* adapter = CaptureRenderAdapter::Create(video_capturer);
if (!adapter) {
@@ -87,6 +99,7 @@
void VideoCapturerState::AddCaptureResolution(
const VideoFormat& desired_format) {
+ DCHECK(thread_checker_.CalledOnValidThread());
for (CaptureFormats::iterator iter = capture_formats_.begin();
iter != capture_formats_.end(); ++iter) {
if (desired_format == iter->video_format) {
@@ -99,6 +112,7 @@
}
bool VideoCapturerState::RemoveCaptureResolution(const VideoFormat& format) {
+ DCHECK(thread_checker_.CalledOnValidThread());
for (CaptureFormats::iterator iter = capture_formats_.begin();
iter != capture_formats_.end(); ++iter) {
if (format == iter->video_format) {
@@ -114,6 +128,7 @@
VideoFormat VideoCapturerState::GetHighestFormat(
VideoCapturer* video_capturer) const {
+ DCHECK(thread_checker_.CalledOnValidThread());
VideoFormat highest_format(0, 0, VideoFormat::FpsToInterval(1), FOURCC_ANY);
if (capture_formats_.empty()) {
VideoFormat default_format(kDefaultCaptureFormat);
@@ -134,9 +149,13 @@
return highest_format;
}
-int VideoCapturerState::IncCaptureStartRef() { return ++start_count_; }
+int VideoCapturerState::IncCaptureStartRef() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ return ++start_count_;
+}
int VideoCapturerState::DecCaptureStartRef() {
+ DCHECK(thread_checker_.CalledOnValidThread());
if (start_count_ > 0) {
// Start count may be 0 if a capturer was added but never started.
--start_count_;
@@ -144,25 +163,25 @@
return start_count_;
}
+CaptureManager::CaptureManager() {
+ // Allowing construction of manager in any thread as long as subsequent calls
+ // are all from the same thread.
+ thread_checker_.DetachFromThread();
+}
+
CaptureManager::~CaptureManager() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
// Since we don't own any of the capturers, all capturers should have been
// cleaned up before we get here. In fact, in the normal shutdown sequence,
// all capturers *will* be shut down by now, so trying to stop them here
// will crash. If we're still tracking any, it's a dangling pointer.
- if (!capture_states_.empty()) {
- ASSERT(false &&
- "CaptureManager destructing while still tracking capturers!");
- // Delete remaining VideoCapturerStates, but don't touch the capturers.
- do {
- CaptureStates::iterator it = capture_states_.begin();
- delete it->second;
- capture_states_.erase(it);
- } while (!capture_states_.empty());
- }
+ CHECK(capture_states_.empty());
}
bool CaptureManager::StartVideoCapture(VideoCapturer* video_capturer,
const VideoFormat& desired_format) {
+ DCHECK(thread_checker_.CalledOnValidThread());
if (desired_format.width == 0 || desired_format.height == 0) {
return false;
}
@@ -195,6 +214,7 @@
bool CaptureManager::StopVideoCapture(VideoCapturer* video_capturer,
const VideoFormat& format) {
+ DCHECK(thread_checker_.CalledOnValidThread());
VideoCapturerState* capture_state = GetCaptureState(video_capturer);
if (!capture_state) {
return false;
@@ -215,6 +235,7 @@
const VideoFormat& previous_format,
const VideoFormat& desired_format,
CaptureManager::RestartOptions options) {
+ DCHECK(thread_checker_.CalledOnValidThread());
if (!IsCapturerRegistered(video_capturer)) {
LOG(LS_ERROR) << "RestartVideoCapture: video_capturer is not registered.";
return false;
@@ -267,6 +288,7 @@
bool CaptureManager::AddVideoRenderer(VideoCapturer* video_capturer,
VideoRenderer* video_renderer) {
+ DCHECK(thread_checker_.CalledOnValidThread());
if (!video_capturer || !video_renderer) {
return false;
}
@@ -279,6 +301,7 @@
bool CaptureManager::RemoveVideoRenderer(VideoCapturer* video_capturer,
VideoRenderer* video_renderer) {
+ DCHECK(thread_checker_.CalledOnValidThread());
if (!video_capturer || !video_renderer) {
return false;
}
@@ -291,6 +314,7 @@
bool CaptureManager::AddVideoProcessor(VideoCapturer* video_capturer,
VideoProcessor* video_processor) {
+ DCHECK(thread_checker_.CalledOnValidThread());
if (!video_capturer || !video_processor) {
return false;
}
@@ -303,6 +327,7 @@
bool CaptureManager::RemoveVideoProcessor(VideoCapturer* video_capturer,
VideoProcessor* video_processor) {
+ DCHECK(thread_checker_.CalledOnValidThread());
if (!video_capturer || !video_processor) {
return false;
}
@@ -313,10 +338,12 @@
}
bool CaptureManager::IsCapturerRegistered(VideoCapturer* video_capturer) const {
+ DCHECK(thread_checker_.CalledOnValidThread());
return GetCaptureState(video_capturer) != NULL;
}
bool CaptureManager::RegisterVideoCapturer(VideoCapturer* video_capturer) {
+ DCHECK(thread_checker_.CalledOnValidThread());
VideoCapturerState* capture_state =
VideoCapturerState::Create(video_capturer);
if (!capture_state) {
@@ -329,6 +356,7 @@
void CaptureManager::UnregisterVideoCapturer(
VideoCapturerState* capture_state) {
+ DCHECK(thread_checker_.CalledOnValidThread());
VideoCapturer* video_capturer = capture_state->GetVideoCapturer();
capture_states_.erase(video_capturer);
delete capture_state;
@@ -351,6 +379,7 @@
bool CaptureManager::StartWithBestCaptureFormat(
VideoCapturerState* capture_state, VideoCapturer* video_capturer) {
+ DCHECK(thread_checker_.CalledOnValidThread());
VideoFormat highest_asked_format =
capture_state->GetHighestFormat(video_capturer);
VideoFormat capture_format;
@@ -377,6 +406,7 @@
VideoCapturerState* CaptureManager::GetCaptureState(
VideoCapturer* video_capturer) const {
+ DCHECK(thread_checker_.CalledOnValidThread());
CaptureStates::const_iterator iter = capture_states_.find(video_capturer);
if (iter == capture_states_.end()) {
return NULL;
@@ -386,6 +416,7 @@
CaptureRenderAdapter* CaptureManager::GetAdapter(
VideoCapturer* video_capturer) const {
+ DCHECK(thread_checker_.CalledOnValidThread());
VideoCapturerState* capture_state = GetCaptureState(video_capturer);
if (!capture_state) {
return NULL;
diff --git a/talk/media/base/capturemanager.h b/talk/media/base/capturemanager.h
index 16e8091..680300d 100644
--- a/talk/media/base/capturemanager.h
+++ b/talk/media/base/capturemanager.h
@@ -49,6 +49,7 @@
#include "talk/media/base/capturerenderadapter.h"
#include "talk/media/base/videocommon.h"
#include "webrtc/base/sigslotrepeater.h"
+#include "webrtc/base/thread_checker.h"
namespace cricket {
@@ -64,7 +65,7 @@
kForceRestart
};
- CaptureManager() {}
+ CaptureManager();
virtual ~CaptureManager();
virtual bool StartVideoCapture(VideoCapturer* video_capturer,
@@ -106,6 +107,7 @@
VideoCapturerState* GetCaptureState(VideoCapturer* video_capturer) const;
CaptureRenderAdapter* GetAdapter(VideoCapturer* video_capturer) const;
+ rtc::ThreadChecker thread_checker_;
CaptureStates capture_states_;
};
diff --git a/talk/session/media/channelmanager.cc b/talk/session/media/channelmanager.cc
index b507d4b..eb74df6 100644
--- a/talk/session/media/channelmanager.cc
+++ b/talk/session/media/channelmanager.cc
@@ -149,10 +149,10 @@
// shutdown.
ShutdownSrtp();
}
- // Always delete the media engine on the worker thread to match how it was
- // created.
+ // Some deletes need to be on the worker thread for thread safe destruction,
+ // this includes the media engine and capture manager.
worker_thread_->Invoke<void>(Bind(
- &ChannelManager::DeleteMediaEngine_w, this));
+ &ChannelManager::DestructorDeletes_w, this));
}
bool ChannelManager::SetVideoRtxEnabled(bool enable) {
@@ -310,9 +310,10 @@
initialized_ = false;
}
-void ChannelManager::DeleteMediaEngine_w() {
+void ChannelManager::DestructorDeletes_w() {
ASSERT(worker_thread_ == rtc::Thread::Current());
media_engine_.reset(NULL);
+ capture_manager_.reset(NULL);
}
void ChannelManager::Terminate_w() {
diff --git a/talk/session/media/channelmanager.h b/talk/session/media/channelmanager.h
index 6bbfc5a..ae9224a 100644
--- a/talk/session/media/channelmanager.h
+++ b/talk/session/media/channelmanager.h
@@ -268,7 +268,7 @@
CaptureManager* cm,
rtc::Thread* worker_thread);
bool InitMediaEngine_w();
- void DeleteMediaEngine_w();
+ void DestructorDeletes_w();
void Terminate_w();
VoiceChannel* CreateVoiceChannel_w(
BaseSession* session, const std::string& content_name, bool rtcp);