--- /dev/null
+/*\r
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
+*\r
+* This file is part of CasparCG (www.casparcg.com).\r
+*\r
+* CasparCG is free software: you can redistribute it and/or modify\r
+* it under the terms of the GNU General Public License as published by\r
+* the Free Software Foundation, either version 3 of the License, or\r
+* (at your option) any later version.\r
+*\r
+* CasparCG is distributed in the hope that it will be useful,\r
+* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+* GNU General Public License for more details.\r
+*\r
+* You should have received a copy of the GNU General Public License\r
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
+*\r
+* Author: Robert Nagy, ronag89@gmail.com\r
+*/\r
+\r
+#pragma once\r
+\r
+#include "executor.h"\r
+\r
+#include "../log/log.h"\r
+#include "../exception/exceptions.h"\r
+\r
+#define NOMINMAX\r
+#define WIN32_LEAN_AND_MEAN\r
+\r
+#include <Windows.h>\r
+\r
+#include <boost/noncopyable.hpp>\r
+#include <boost/thread/future.hpp>\r
+\r
+#include <functional>\r
+\r
+namespace caspar {\r
+\r
+template<typename T>\r
+class com_context : public executor\r
+{\r
+ std::unique_ptr<T> instance_;\r
+public:\r
+ com_context(const std::wstring& name) : executor(name)\r
+ {\r
+ executor::begin_invoke([]\r
+ {\r
+ ::CoInitialize(nullptr);\r
+ });\r
+ }\r
+\r
+ ~com_context()\r
+ {\r
+ if(!executor::begin_invoke([&]\r
+ {\r
+ instance_.reset(nullptr);\r
+ ::CoUninitialize();\r
+ }).timed_wait(boost::posix_time::milliseconds(500)))\r
+ {\r
+ CASPAR_LOG(error) << L"[com_contex] Timer expired, deadlock detected and released, leaking resources.";\r
+ }\r
+ }\r
+ \r
+ void reset(const std::function<T*()>& factory = nullptr)\r
+ {\r
+ executor::invoke([&]\r
+ {\r
+ instance_.reset();\r
+ if(factory)\r
+ instance_.reset(factory());\r
+ });\r
+ }\r
+\r
+ T& operator*() const \r
+ {\r
+ if(instance_ == nullptr)\r
+ BOOST_THROW_EXCEPTION(invalid_operation() << msg_info("Tried to access null context."));\r
+\r
+ return *instance_.get();\r
+ } // noexcept\r
+\r
+ T* operator->() const \r
+ {\r
+ if(instance_ == nullptr)\r
+ BOOST_THROW_EXCEPTION(invalid_operation() << msg_info("Tried to access null context."));\r
+ return instance_.get();\r
+ } // noexcept\r
+\r
+ T* get() const\r
+ {\r
+ return instance_.get();\r
+ } // noexcept\r
+\r
+ operator bool() const {return get() != nullptr;}\r
+};\r
+\r
+}
\ No newline at end of file
\r
#include <core/mixer/read_frame.h>\r
\r
-#include <common/concurrency/executor.h>\r
-#include <common/concurrency/lock.h>\r
+#include <common/concurrency/com_context.h>\r
#include <common/diagnostics/graph.h>\r
#include <common/exception/exceptions.h>\r
#include <common/memory/memcpy.h>\r
}\r
catch(...)\r
{\r
- lock(exception_mutex_, [this]\r
- {\r
- exception_ = std::current_exception();\r
- });\r
+ tbb::spin_mutex::scoped_lock lock(exception_mutex_);\r
+ exception_ = std::current_exception();\r
return E_FAIL;\r
}\r
\r
}\r
catch(...)\r
{\r
- lock(exception_mutex_, [this]\r
- {\r
- exception_ = std::current_exception();\r
- });\r
+ tbb::spin_mutex::scoped_lock lock(exception_mutex_);\r
+ exception_ = std::current_exception();\r
return E_FAIL;\r
}\r
\r
\r
void send(const safe_ptr<core::read_frame>& frame)\r
{\r
- auto exception = lock(exception_mutex_, [this]\r
{\r
- return exception_;\r
- });\r
+ tbb::spin_mutex::scoped_lock lock(exception_mutex_);\r
+ if(exception_ != nullptr)\r
+ std::rethrow_exception(exception_);\r
+ }\r
\r
- if(exception != nullptr)\r
- std::rethrow_exception(exception);\r
- \r
if(!is_running_)\r
BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(narrow(print()) + " Is not running."));\r
\r
\r
struct decklink_consumer_proxy : public core::frame_consumer\r
{\r
- const configuration config_;\r
- std::unique_ptr<decklink_consumer> consumer_;\r
- std::vector<size_t> audio_cadence_;\r
- executor executor_;\r
+ const configuration config_;\r
+ com_context<decklink_consumer> context_;\r
+ std::vector<size_t> audio_cadence_;\r
public:\r
\r
decklink_consumer_proxy(const configuration& config)\r
: config_(config)\r
- , executor_(L"decklink_consumer[" + boost::lexical_cast<std::wstring>(config.device_index) + L"]")\r
+ , context_(L"decklink_consumer[" + boost::lexical_cast<std::wstring>(config.device_index) + L"]")\r
{\r
- executor_.begin_invoke([=]\r
- {\r
- ::CoInitialize(nullptr);\r
- });\r
}\r
\r
~decklink_consumer_proxy()\r
{\r
- executor_.invoke([=]\r
+ if(context_)\r
{\r
- if(consumer_)\r
- {\r
- auto str = print();\r
- consumer_.reset();\r
- CASPAR_LOG(info) << str << L" Successfully Uninitialized."; \r
- }\r
- });\r
- \r
- executor_.invoke([=]\r
- {\r
- ::CoUninitialize();\r
- });\r
+ auto str = print();\r
+ context_.reset();\r
+ CASPAR_LOG(info) << str << L" Successfully Uninitialized."; \r
+ }\r
}\r
\r
// frame_consumer\r
\r
virtual void initialize(const core::video_format_desc& format_desc, int channel_index) override\r
{\r
- executor_.invoke([=]\r
- {\r
- consumer_.reset(new decklink_consumer(config_, format_desc, channel_index)); \r
- audio_cadence_ = format_desc.audio_cadence; \r
+ context_.reset([&]{return new decklink_consumer(config_, format_desc, channel_index);}); \r
+ audio_cadence_ = format_desc.audio_cadence; \r
\r
- CASPAR_LOG(info) << print() << L" Successfully Initialized.";\r
- });\r
+ CASPAR_LOG(info) << print() << L" Successfully Initialized."; \r
}\r
\r
virtual bool send(const safe_ptr<core::read_frame>& frame) override\r
CASPAR_VERIFY(audio_cadence_.front() == static_cast<size_t>(frame->audio_data().size()));\r
boost::range::rotate(audio_cadence_, std::begin(audio_cadence_)+1);\r
\r
- consumer_->send(frame);\r
+ context_->send(frame);\r
return true;\r
}\r
\r
virtual std::wstring print() const override\r
{\r
- return consumer_ ? consumer_->print() : L"[decklink_consumer]";\r
+ return context_ ? context_->print() : L"[decklink_consumer]";\r
} \r
\r
virtual boost::property_tree::wptree info() const override\r