]> git.sesse.net Git - casparcg/blobdiff - shell/server.cpp
* started using final keyword on classes where previously sealed or commented final
[casparcg] / shell / server.cpp
index fd1e62b7a0d85b3b8a713febc61d6ed570040b5f..ec9cac979a7bbef01e1b9996c221d50cb8985948 100644 (file)
@@ -29,6 +29,7 @@
 #include <common/utf.h>
 #include <common/memory.h>
 #include <common/polling_filesystem_monitor.h>
+#include <common/diagnostics/graph.h>
 
 #include <core/video_channel.h>
 #include <core/video_format.h>
 #include <modules/screen/consumer/screen_consumer.h>
 #include <modules/ffmpeg/consumer/ffmpeg_consumer.h>
 
+#include <protocol/asio/io_service_manager.h>
 #include <protocol/amcp/AMCPProtocolStrategy.h>
 #include <protocol/cii/CIIProtocolStrategy.h>
 #include <protocol/CLK/CLKProtocolStrategy.h>
 #include <protocol/util/AsyncEventServer.h>
 #include <protocol/util/strategy_adapters.h>
+#include <protocol/osc/client.h>
 
 #include <boost/algorithm/string.hpp>
 #include <boost/thread.hpp>
 #include <boost/lexical_cast.hpp>
-#include <boost/foreach.hpp>
 #include <boost/property_tree/ptree.hpp>
 #include <boost/property_tree/xml_parser.hpp>
 
+#include <future>
+
 namespace caspar {
 
 using namespace core;
@@ -76,14 +80,21 @@ using namespace protocol;
 
 struct server::impl : boost::noncopyable
 {
-       monitor::basic_subject                                                          event_subject_;
+       protocol::asio::io_service_manager                                      io_service_manager_;
+       spl::shared_ptr<monitor::subject>                                       monitor_subject_;
        accelerator::accelerator                                                        accelerator_;
-       std::vector<spl::shared_ptr<IO::AsyncEventServer>>      async_servers_; 
+       std::vector<spl::shared_ptr<IO::AsyncEventServer>>      async_servers_;
+       std::shared_ptr<IO::AsyncEventServer>                           primary_amcp_server_;
+       osc::client                                                                                     osc_client_;
+       std::vector<std::shared_ptr<void>>                                      predefined_osc_subscriptions_;
        std::vector<spl::shared_ptr<video_channel>>                     channels_;
        std::shared_ptr<thumbnail_generator>                            thumbnail_generator_;
+       std::promise<bool>&                                                                     shutdown_server_now_;
 
-       impl()          
+       explicit impl(std::promise<bool>& shutdown_server_now)          
                : accelerator_(env::properties().get(L"configuration.accelerator", L"auto"))
+               , osc_client_(io_service_manager_.service())
+               , shutdown_server_now_(shutdown_server_now)
        {       
 
                ffmpeg::init();
@@ -123,10 +134,15 @@ struct server::impl : boost::noncopyable
 
                setup_controllers(env::properties());
                CASPAR_LOG(info) << L"Initialized controllers.";
+
+               setup_osc(env::properties());
+               CASPAR_LOG(info) << L"Initialized osc.";
        }
 
        ~impl()
-       {               
+       {
+               thumbnail_generator_.reset();
+               primary_amcp_server_.reset();
                async_servers_.clear();
                channels_.clear();
 
@@ -135,12 +151,13 @@ struct server::impl : boost::noncopyable
 
                image::uninit();
                ffmpeg::uninit();
+               diagnostics::shutdown();
        }
                                
        void setup_channels(const boost::property_tree::wptree& pt)
        {   
                using boost::property_tree::wptree;
-               BOOST_FOREACH(auto& xml_channel, pt.get_child(L"configuration.channels"))
+               for (auto& xml_channel : pt.get_child(L"configuration.channels"))
                {               
                        auto format_desc = video_format_desc(xml_channel.second.get(L"video-mode", L"PAL"));            
                        if(format_desc.format == video_format::invalid)
@@ -148,7 +165,7 @@ struct server::impl : boost::noncopyable
                        
                        auto channel = spl::make_shared<video_channel>(static_cast<int>(channels_.size()+1), format_desc, accelerator_.create_image_mixer());
                        
-                       BOOST_FOREACH(auto& xml_consumer, xml_channel.second.get_child(L"consumers"))
+                       for (auto& xml_consumer : xml_channel.second.get_child(L"consumers"))
                        {
                                try
                                {
@@ -172,7 +189,7 @@ struct server::impl : boost::noncopyable
                                }
                        }               
 
-                   channel->subscribe(monitor::observable::observer_ptr(event_subject_));
+                   channel->monitor_output().attach_parent(monitor_subject_);
                        channels_.push_back(channel);
                }
 
@@ -181,6 +198,50 @@ struct server::impl : boost::noncopyable
                        channels_.push_back(spl::make_shared<video_channel>(static_cast<int>(channels_.size()+1), core::video_format_desc(core::video_format::x576p2500), accelerator_.create_image_mixer()));
        }
 
+       void setup_osc(const boost::property_tree::wptree& pt)
+       {               
+               using boost::property_tree::wptree;
+               using namespace boost::asio::ip;
+
+               monitor_subject_->attach_parent(osc_client_.sink());
+               
+               auto default_port =
+                               pt.get<unsigned short>(L"configuration.osc.default-port", 6250);
+               auto predefined_clients =
+                               pt.get_child_optional(L"configuration.osc.predefined-clients");
+
+               if (predefined_clients)
+               {
+                       for (auto& predefined_client : *predefined_clients)
+                       {
+                               const auto address =
+                                               predefined_client.second.get<std::wstring>(L"address");
+                               const auto port =
+                                               predefined_client.second.get<unsigned short>(L"port");
+                               predefined_osc_subscriptions_.push_back(
+                                               osc_client_.get_subscription_token(udp::endpoint(
+                                                               address_v4::from_string(u8(address)),
+                                                               port)));
+                       }
+               }
+
+               if (primary_amcp_server_)
+                       primary_amcp_server_->add_client_lifecycle_object_factory(
+                                       [=] (const std::string& ipv4_address)
+                                                       -> std::pair<std::wstring, std::shared_ptr<void>>
+                                       {
+                                               using namespace boost::asio::ip;
+
+                                               return std::make_pair(
+                                                               std::wstring(L"osc_subscribe"),
+                                                               osc_client_.get_subscription_token(
+                                                                               udp::endpoint(
+                                                                                               address_v4::from_string(
+                                                                                                               ipv4_address),
+                                                                                               default_port)));
+                                       });
+       }
+
        void setup_thumbnail_generation(const boost::property_tree::wptree& pt)
        {
                if (!pt.get(L"configuration.thumbnails.generate-thumbnails", true))
@@ -206,7 +267,7 @@ struct server::impl : boost::noncopyable
        void setup_controllers(const boost::property_tree::wptree& pt)
        {               
                using boost::property_tree::wptree;
-               BOOST_FOREACH(auto& xml_controller, pt.get_child(L"configuration.controllers"))
+               for (auto& xml_controller : pt.get_child(L"configuration.controllers"))
                {
                        try
                        {
@@ -219,11 +280,8 @@ struct server::impl : boost::noncopyable
                                        auto asyncbootstrapper = spl::make_shared<IO::AsyncEventServer>(create_protocol(protocol), port);
                                        async_servers_.push_back(asyncbootstrapper);
 
-                                       //TODO: remove - test
-                                       asyncbootstrapper->add_client_lifecycle_object_factory([=] (const std::string& ipv4_address) {
-                                                                                                                                                                       return std::pair<std::wstring, std::shared_ptr<void>>(L"log", std::shared_ptr<void>(nullptr, [] (void*) 
-                                                                                                                                                                       { CASPAR_LOG(info) << "Client disconnect (lifecycle)"; }));
-                                                                                                                                                               });
+                                       if (!primary_amcp_server_ && boost::iequals(protocol, L"AMCP"))
+                                               primary_amcp_server_ = asyncbootstrapper;
                                }
                                else
                                        CASPAR_LOG(warning) << "Invalid controller: " << name;  
@@ -240,7 +298,7 @@ struct server::impl : boost::noncopyable
                using namespace IO;
 
                if(boost::iequals(name, L"AMCP"))
-                       return wrap_legacy_protocol("\r\n", spl::make_shared<amcp::AMCPProtocolStrategy>(channels_, thumbnail_generator_));
+                       return wrap_legacy_protocol("\r\n", spl::make_shared<amcp::AMCPProtocolStrategy>(channels_, thumbnail_generator_, shutdown_server_now_));
                else if(boost::iequals(name, L"CII"))
                        return wrap_legacy_protocol("\r\n", spl::make_shared<cii::CIIProtocolStrategy>(channels_));
                else if(boost::iequals(name, L"CLOCK"))
@@ -253,14 +311,13 @@ struct server::impl : boost::noncopyable
 
 };
 
-server::server() : impl_(new impl()){}
+server::server(std::promise<bool>& shutdown_server_now) : impl_(new impl(shutdown_server_now)){}
 
 const std::vector<spl::shared_ptr<video_channel>> server::channels() const
 {
        return impl_->channels_;
 }
 std::shared_ptr<core::thumbnail_generator> server::get_thumbnail_generator() const {return impl_->thumbnail_generator_; }
-void server::subscribe(const monitor::observable::observer_ptr& o){impl_->event_subject_.subscribe(o);}
-void server::unsubscribe(const monitor::observable::observer_ptr& o){impl_->event_subject_.unsubscribe(o);}
+core::monitor::subject& server::monitor_output() { return *impl_->monitor_subject_; }
 
 }
\ No newline at end of file