]> git.sesse.net Git - casparcg/commitdiff
* Removed hard dependencies to XML based consumer factories, so that server.cpp does...
authorHelge Norberg <helge.norberg@svt.se>
Thu, 9 Apr 2015 13:53:18 +0000 (15:53 +0200)
committerHelge Norberg <helge.norberg@svt.se>
Thu, 9 Apr 2015 13:53:18 +0000 (15:53 +0200)
22 files changed:
core/consumer/frame_consumer.cpp
core/consumer/frame_consumer.h
modules/bluefish/bluefish.cpp
modules/bluefish/consumer/bluefish_consumer.cpp
modules/bluefish/consumer/bluefish_consumer.h
modules/decklink/consumer/decklink_consumer.cpp
modules/decklink/consumer/decklink_consumer.h
modules/decklink/decklink.cpp
modules/ffmpeg/consumer/ffmpeg_consumer.cpp
modules/ffmpeg/consumer/ffmpeg_consumer.h
modules/ffmpeg/ffmpeg.cpp
modules/image/consumer/image_consumer.cpp
modules/image/consumer/image_consumer.h
modules/image/image.cpp
modules/oal/consumer/oal_consumer.cpp
modules/oal/consumer/oal_consumer.h
modules/oal/oal.cpp
modules/screen/consumer/screen_consumer.cpp
modules/screen/consumer/screen_consumer.h
modules/screen/screen.cpp
protocol/amcp/AMCPCommandsImpl.cpp
shell/server.cpp

index 3cc4e768ba5910812a833b9ddd36e648e348da0e..afe509fb85aabc9eb363ed8bb3a85f123e0448d2 100644 (file)
 #include <boost/thread.hpp>
 
 #include <future>
+#include <vector>
+#include <map>
 
 namespace caspar { namespace core {
                
 std::vector<consumer_factory_t> g_factories;
+std::map<std::wstring, preconfigured_consumer_factory_t> g_preconfigured_factories;
 
 void register_consumer_factory(const consumer_factory_t& factory)
 {
        g_factories.push_back(factory);
 }
 
+void register_preconfigured_consumer_factory(
+               const std::wstring& element_name,
+               const preconfigured_consumer_factory_t& factory)
+{
+       g_preconfigured_factories.insert(std::make_pair(element_name, factory));
+}
+
 class destroy_consumer_proxy : public frame_consumer
 {      
        std::shared_ptr<frame_consumer> consumer_;
@@ -220,7 +230,8 @@ public:
        monitor::subject& monitor_output() override                                                             {return consumer_->monitor_output();}                                                                           
 };
 
-spl::shared_ptr<core::frame_consumer> create_consumer(const std::vector<std::wstring>& params)
+spl::shared_ptr<core::frame_consumer> create_consumer(
+               const std::vector<std::wstring>& params, interaction_sink* sink)
 {
        if(params.empty())
                CASPAR_THROW_EXCEPTION(invalid_argument() << arg_name_info("params") << arg_value_info(""));
@@ -230,7 +241,7 @@ spl::shared_ptr<core::frame_consumer> create_consumer(const std::vector<std::wst
                {
                        try
                        {
-                               consumer = factory(params);
+                               consumer = factory(params, sink);
                        }
                        catch(...)
                        {
@@ -249,6 +260,24 @@ spl::shared_ptr<core::frame_consumer> create_consumer(const std::vector<std::wst
                           std::move(consumer)))));
 }
 
+spl::shared_ptr<frame_consumer> create_consumer(
+               const std::wstring& element_name,
+               const boost::property_tree::wptree& element,
+               interaction_sink* sink)
+{
+       auto found = g_preconfigured_factories.find(element_name);
+
+       if (found == g_preconfigured_factories.end())
+               CASPAR_THROW_EXCEPTION(file_not_found()
+                       << msg_info(L"No consumer factory registered for element name " + element_name));
+
+       return spl::make_shared<destroy_consumer_proxy>(
+                       spl::make_shared<print_consumer_proxy>(
+                                       spl::make_shared<recover_consumer_proxy>(
+                                                       spl::make_shared<cadence_guard>(
+                                                                       found->second(element, sink)))));
+}
+
 const spl::shared_ptr<frame_consumer>& frame_consumer::empty()
 {
        class empty_frame_consumer : public frame_consumer
index cbd36480a3e9ad793f09851692f5cdacfb405838..39ffba2d5e711fde56b0e99393a282d31e4bb14b 100644 (file)
@@ -34,6 +34,8 @@
 
 namespace caspar { namespace core {
 
+struct interaction_sink;
+
 // Interface
 class frame_consumer
 {
@@ -69,9 +71,23 @@ public:
        virtual int                                                             index() const = 0;
 };
 
-typedef std::function<spl::shared_ptr<frame_consumer>(const std::vector<std::wstring>&)> consumer_factory_t;
+typedef std::function<spl::shared_ptr<frame_consumer>(
+               const std::vector<std::wstring>&,
+               interaction_sink* sink)> consumer_factory_t;
+typedef std::function<spl::shared_ptr<frame_consumer>(
+               const boost::property_tree::wptree& element,
+               interaction_sink* sink)> preconfigured_consumer_factory_t;
 
 void register_consumer_factory(const consumer_factory_t& factory);
-spl::shared_ptr<frame_consumer> create_consumer(const std::vector<std::wstring>& params);
-
-}}
\ No newline at end of file
+void register_preconfigured_consumer_factory(
+               const std::wstring& element_name,
+               const preconfigured_consumer_factory_t& factory);
+spl::shared_ptr<frame_consumer> create_consumer(
+               const std::vector<std::wstring>& params,
+               interaction_sink* sink);
+spl::shared_ptr<frame_consumer> create_consumer(
+               const std::wstring& element_name,
+               const boost::property_tree::wptree& element,
+               interaction_sink* sink);
+
+}}
index 785ac469744a7ee73f384e0e0450ab10a5ab178d..0f897b8292b9e85eb97a83fdb3d58a65c143234d 100644 (file)
@@ -84,10 +84,8 @@ void init(const spl::shared_ptr<core::system_info_provider_repository>& repo)
        }
        catch(...){}
 
-       core::register_consumer_factory([](const std::vector<std::wstring>& params)
-       {
-               return create_consumer(params);
-       });
+       core::register_consumer_factory(create_consumer);
+       core::register_preconfigured_consumer_factory(L"bluefish", create_preconfigured_consumer);
        repo->register_system_info_provider([](boost::property_tree::wptree& info)
        {
                info.add(L"system.bluefish.version", version());
index 2138f3c209bdefc911e589bb2ae0039a7a25ccaa..06b94899224a24e2f38ca08958e1289c3039dcec 100644 (file)
@@ -371,7 +371,8 @@ public:
        }
 };     
 
-spl::shared_ptr<core::frame_consumer> create_consumer(const std::vector<std::wstring>& params)
+spl::shared_ptr<core::frame_consumer> create_consumer(
+               const std::vector<std::wstring>& params, core::interaction_sink*)
 {
        if(params.size() < 1 || params[0] != L"BLUEFISH")
                return core::frame_consumer::empty();
@@ -384,7 +385,8 @@ spl::shared_ptr<core::frame_consumer> create_consumer(const std::vector<std::wst
        return spl::make_shared<bluefish_consumer_proxy>(device_index, embedded_audio, key_only);
 }
 
-spl::shared_ptr<core::frame_consumer> create_consumer(const boost::property_tree::wptree& ptree) 
+spl::shared_ptr<core::frame_consumer> create_preconfigured_consumer(
+               const boost::property_tree::wptree& ptree, core::interaction_sink*)
 {      
        const auto device_index         = ptree.get(L"device",                  1);
        const auto embedded_audio       = ptree.get(L"embedded-audio",  false);
index 91fbeb1d0968cd930145ddb3f3268fbe31801e2d..850482a18c192bd76d5d65318f7cd0a62c1ec765 100644 (file)
@@ -31,11 +31,14 @@ namespace caspar {
 
 namespace core {
        class frame_consumer;
+       struct interaction_sink;
 }
         
 namespace bluefish {
 
-spl::shared_ptr<core::frame_consumer> create_consumer(const std::vector<std::wstring>& params);
-spl::shared_ptr<core::frame_consumer> create_consumer(const boost::property_tree::wptree& ptree);
+spl::shared_ptr<core::frame_consumer> create_consumer(
+               const std::vector<std::wstring>& params, core::interaction_sink*);
+spl::shared_ptr<core::frame_consumer> create_preconfigured_consumer(
+               const boost::property_tree::wptree& ptree, core::interaction_sink*);
 
 }}
\ No newline at end of file
index 84203b5ec4291414e982af94c6fbd9fae14c2527..e58551174498799fde5e40243dd8b1dcc419ce39 100644 (file)
@@ -577,7 +577,8 @@ public:
        }
 };     
 
-spl::shared_ptr<core::frame_consumer> create_consumer(const std::vector<std::wstring>& params) 
+spl::shared_ptr<core::frame_consumer> create_consumer(
+               const std::vector<std::wstring>& params, core::interaction_sink*)
 {
        if(params.size() < 1 || params[0] != L"DECKLINK")
                return core::frame_consumer::empty();
@@ -603,7 +604,8 @@ spl::shared_ptr<core::frame_consumer> create_consumer(const std::vector<std::wst
        return spl::make_shared<decklink_consumer_proxy>(config);
 }
 
-spl::shared_ptr<core::frame_consumer> create_consumer(const boost::property_tree::wptree& ptree) 
+spl::shared_ptr<core::frame_consumer> create_preconfigured_consumer(
+               const boost::property_tree::wptree& ptree, core::interaction_sink*)
 {
        configuration config;
 
index 5991a466c1d1ad673acef3bd0a7b7484ad8fe4d8..4447baf8d48c8dd33b191dcd5b72ff3e4e8c408e 100644 (file)
@@ -34,11 +34,14 @@ namespace caspar {
 
 namespace core {
        class frame_consumer;
+       struct interaction_sink;
 }
 
 namespace decklink {
 
-spl::shared_ptr<core::frame_consumer> create_consumer(const std::vector<std::wstring>& params);
-spl::shared_ptr<core::frame_consumer> create_consumer(const boost::property_tree::wptree& ptree);
+spl::shared_ptr<core::frame_consumer> create_consumer(
+               const std::vector<std::wstring>& params, core::interaction_sink*);
+spl::shared_ptr<core::frame_consumer> create_preconfigured_consumer(
+               const boost::property_tree::wptree& ptree, core::interaction_sink*);
 
 }}
\ No newline at end of file
index 7d0a4580658db1a61ec476759e94b0908187832c..ca2e41fe6abae159d50224158cbaa87bf4d21a3c 100644 (file)
@@ -110,7 +110,8 @@ void init(const spl::shared_ptr<core::system_info_provider_repository>& repo)
        if(FAILED(pDecklinkIterator.CoCreateInstance(CLSID_CDeckLinkIterator)))         
                return;
                
-       core::register_consumer_factory([](const std::vector<std::wstring>& params){return create_consumer(params);});
+       core::register_consumer_factory(create_consumer);
+       core::register_preconfigured_consumer_factory(L"decklink", create_preconfigured_consumer);
        core::register_producer_factory(create_producer);
        repo->register_system_info_provider([](boost::property_tree::wptree& info)
        {
index 0447ff94cb7bbee7b5d89a80732f053db2ad9ae6..e5e9898518652b40080d82a65c266e711d8768f7 100644 (file)
@@ -848,7 +848,8 @@ public:
                return consumer_->monitor_output();
        }
 };     
-spl::shared_ptr<core::frame_consumer> create_consumer(const std::vector<std::wstring>& params)
+spl::shared_ptr<core::frame_consumer> create_consumer(
+               const std::vector<std::wstring>& params, core::interaction_sink*)
 {
        auto params2 = params;
        auto separate_key_it = std::find(params2.begin(), params2.end(), L"SEPARATE_KEY");
@@ -887,7 +888,8 @@ spl::shared_ptr<core::frame_consumer> create_consumer(const std::vector<std::wst
        return spl::make_shared<ffmpeg_consumer_proxy>(env::media_folder() + path["PATH"].str(), options, separate_key);
 }
 
-spl::shared_ptr<core::frame_consumer> create_consumer(const boost::property_tree::wptree& ptree)
+spl::shared_ptr<core::frame_consumer> create_preconfigured_consumer(
+               const boost::property_tree::wptree& ptree, core::interaction_sink*)
 {
        auto filename           = ptree.get<std::wstring>(L"path");
        auto codec                      = ptree.get(L"vcodec", L"libx264");
index 29226f4fdb94f7052381d037afa969be9e32f5da..51b96af5e57ac829ea1dfa05f90d9c9453b16e6b 100644 (file)
@@ -32,12 +32,12 @@ namespace caspar {
 
 namespace core {
        class frame_consumer;
+       struct interaction_sink;
 }
 
 namespace ffmpeg {
 
-       
-spl::shared_ptr<core::frame_consumer> create_consumer(const std::vector<std::wstring>& params);
-spl::shared_ptr<core::frame_consumer> create_consumer(const boost::property_tree::wptree& ptree);
+spl::shared_ptr<core::frame_consumer> create_consumer(const std::vector<std::wstring>& params, core::interaction_sink*);
+spl::shared_ptr<core::frame_consumer> create_preconfigured_consumer(const boost::property_tree::wptree& ptree, core::interaction_sink*);
 
 }}
\ No newline at end of file
index b0b59ae8002ec3da1feb45cb592ea4fc5aa93a7e..871d984b2c9ca3204af86b037e1c1eb1c2e77af5 100644 (file)
@@ -248,7 +248,8 @@ void init(
     avformat_network_init();
     avcodec_register_all();
        
-       core::register_consumer_factory([](const std::vector<std::wstring>& params){return create_consumer(params);});
+       core::register_consumer_factory(create_consumer);
+       core::register_preconfigured_consumer_factory(L"file", create_preconfigured_consumer);
        core::register_producer_factory(create_producer);
        
        media_info_repo->register_extractor(
index db2608e19f5aa434f4c823f425c4209f0e0b207e..76843f1df59acdfffe4880d257858211adebd1c6 100644 (file)
@@ -145,7 +145,7 @@ public:
        }
 };
 
-spl::shared_ptr<core::frame_consumer> create_consumer(const std::vector<std::wstring>& params)
+spl::shared_ptr<core::frame_consumer> create_consumer(const std::vector<std::wstring>& params, core::interaction_sink*)
 {
        if (params.size() < 1 || params[0] != L"IMAGE")
                return core::frame_consumer::empty();
index 7ee8a4570243ebe9b0500768ad612a6802ce506e..d1d5f0440c13c45fd706f4a2e64e9918e194e3bf 100644 (file)
@@ -35,13 +35,13 @@ namespace caspar {
 
 namespace image {
        
-       void write_cropped_png(
+void write_cropped_png(
                const class core::const_frame& frame,
                const core::video_format_desc& format_desc,
                const boost::filesystem::wpath& output_file,
                int width,
                int height);
 
-spl::shared_ptr<core::frame_consumer> create_consumer(const std::vector<std::wstring>& params);
+spl::shared_ptr<core::frame_consumer> create_consumer(const std::vector<std::wstring>& params, struct core::interaction_sink*);
 
 }}
\ No newline at end of file
index ffad16b3a4d3bde56a92372222e53d9633b7f301..7146feaca06f9a681ca2647b739af86238ba9e42 100644 (file)
@@ -52,7 +52,7 @@ void init(
        core::register_producer_factory(create_scroll_producer);
        core::register_producer_factory(create_producer);
        core::register_thumbnail_producer_factory(create_thumbnail_producer);
-       core::register_consumer_factory([](const std::vector<std::wstring>& params){return create_consumer(params);});
+       core::register_consumer_factory(create_consumer);
        repo->register_extractor([](const std::wstring& file, const std::wstring& extension, core::media_info& info)
        {
                if (extension == L".TGA"
index e49e6661f35326a231140bb89a208222266b35ac..596337b5e68a3d5cabae0dfa2ca65c99c7793f0c 100644 (file)
@@ -260,7 +260,7 @@ public:
        }
 };
 
-spl::shared_ptr<core::frame_consumer> create_consumer(const std::vector<std::wstring>& params)
+spl::shared_ptr<core::frame_consumer> create_consumer(const std::vector<std::wstring>& params, core::interaction_sink*)
 {
        if(params.size() < 1 || params[0] != L"AUDIO")
                return core::frame_consumer::empty();
@@ -268,7 +268,7 @@ spl::shared_ptr<core::frame_consumer> create_consumer(const std::vector<std::wst
        return spl::make_shared<oal_consumer>();
 }
 
-spl::shared_ptr<core::frame_consumer> create_consumer()
+spl::shared_ptr<core::frame_consumer> create_preconfigured_consumer(const boost::property_tree::wptree&, core::interaction_sink*)
 {
        return spl::make_shared<oal_consumer>();
 }
index e9f956bc517e0a1f76c9af75bc25bb5cb72adb22..a894da414b359867a9fe4e51503ca19a61f7b740 100644 (file)
 
 #include <vector>
 
+#include <boost/property_tree/ptree_fwd.hpp>
+
 namespace caspar { 
 
 namespace core {
        class frame_consumer;
+       struct interaction_sink;
 }      
 
 namespace oal {
        
-spl::shared_ptr<core::frame_consumer> create_consumer(const std::vector<std::wstring>& params);
-spl::shared_ptr<core::frame_consumer> create_consumer();
+spl::shared_ptr<core::frame_consumer> create_consumer(
+               const std::vector<std::wstring>& params, core::interaction_sink*);
+spl::shared_ptr<core::frame_consumer> create_preconfigured_consumer(
+               const boost::property_tree::wptree&, core::interaction_sink*);
 
 }}
\ No newline at end of file
index a2c191050ac42c774a114a99a0615747105007b2..f7276462443c822e55f3a0e02383c4f9e7d7eb47 100644 (file)
@@ -29,7 +29,8 @@ namespace caspar { namespace oal {
 
 void init()
 {
-       core::register_consumer_factory([](const std::vector<std::wstring>& params){return create_consumer(params);});
+       core::register_consumer_factory(create_consumer);
+       core::register_preconfigured_consumer_factory(L"system-audio", create_preconfigured_consumer);
 }
 
 }}
\ No newline at end of file
index cd2262e4f4692addc1b9bf0fccea369079b8afd5..bdc6ac7f408b5ac2c90ae98f002b5017650313d0 100644 (file)
@@ -41,6 +41,7 @@
 #include <core/video_format.h>
 #include <core/frame/frame.h>
 #include <core/consumer/frame_consumer.h>
+#include <core/interaction/interaction_sink.h>
 
 #include <boost/timer.hpp>
 #include <boost/circular_buffer.hpp>
@@ -623,7 +624,7 @@ public:
        }
 };     
 
-spl::shared_ptr<core::frame_consumer> create_consumer(const std::vector<std::wstring>& params)
+spl::shared_ptr<core::frame_consumer> create_consumer(const std::vector<std::wstring>& params, core::interaction_sink* sink)
 {
        if(params.size() < 1 || params[0] != L"SCREEN")
                return core::frame_consumer::empty();
@@ -633,17 +634,18 @@ spl::shared_ptr<core::frame_consumer> create_consumer(const std::vector<std::wst
        if(params.size() > 1)
                config.screen_index = boost::lexical_cast<int>(params[1]);
                
-       config.key_only = std::find(params.begin(), params.end(), L"WINDOWED") != params.end();
-       config.key_only = std::find(params.begin(), params.end(), L"KEY_ONLY") != params.end();
+       config.windowed         = std::find(params.begin(), params.end(), L"WINDOWED") != params.end();
+       config.key_only         = std::find(params.begin(), params.end(), L"KEY_ONLY") != params.end();
+       config.interactive      = std::find(params.begin(), params.end(), L"INTERACTIVE") != params.end();
 
        auto name_it    = std::find(params.begin(), params.end(), L"NAME");
        if(name_it != params.end() && ++name_it != params.end())
                config.name = *name_it;
 
-       return spl::make_shared<screen_consumer_proxy>(config, nullptr);
+       return spl::make_shared<screen_consumer_proxy>(config, sink);
 }
 
-spl::shared_ptr<core::frame_consumer> create_consumer(const boost::property_tree::wptree& ptree, core::interaction_sink* sink) 
+spl::shared_ptr<core::frame_consumer> create_preconfigured_consumer(const boost::property_tree::wptree& ptree, core::interaction_sink* sink) 
 {
        configuration config;
        config.name                             = ptree.get(L"name",     config.name);
index 5c076999d492f6347374ba807589c1f19069071e..fdbc41148664046d6520107ccd16686e4d972ed8 100644 (file)
@@ -22,7 +22,6 @@
 #pragma once
 
 #include <common/memory.h>
-#include <core/interaction/interaction_sink.h>
 
 #include <vector>
 #include <boost/property_tree/ptree.hpp>
@@ -31,12 +30,17 @@ namespace caspar {
        
 namespace core {
        class frame_consumer;
+       struct interaction_sink;
 }
 
 namespace screen {
 
 
-spl::shared_ptr<core::frame_consumer> create_consumer(const std::vector<std::wstring>& params);
-spl::shared_ptr<core::frame_consumer> create_consumer(const boost::property_tree::wptree& ptree, core::interaction_sink* sink);
+spl::shared_ptr<core::frame_consumer> create_consumer(
+               const std::vector<std::wstring>& params,
+               core::interaction_sink* sink);
+spl::shared_ptr<core::frame_consumer> create_preconfigured_consumer(
+               const boost::property_tree::wptree& ptree,
+               core::interaction_sink* sink);
 
 }}
\ No newline at end of file
index ba0b38e0e6dc3f82c4a82b1eabdc2ee2c62b6762..0e6e90d7460a84116b47e6e6a5ce3106478da8a7 100644 (file)
@@ -29,7 +29,8 @@ namespace caspar { namespace screen {
 
 void init()
 {
-       caspar::core::register_consumer_factory([](const std::vector<std::wstring>& params){return create_consumer(params);});
+       core::register_consumer_factory(create_consumer);
+       core::register_preconfigured_consumer_factory(L"screen", create_preconfigured_consumer);
 }
 
 }}
\ No newline at end of file
index 305228a50013020a1fd6ba38b22df902a444e3d7..0911faab297c64d2c3e2583a0de049ce7ec90e67 100644 (file)
@@ -309,7 +309,7 @@ bool ChannelGridCommand::DoExecute()
        params.push_back(L"0");
        params.push_back(L"NAME");
        params.push_back(L"Channel Grid Window");
-       auto screen = create_consumer(params);
+       auto screen = create_consumer(params, &self->stage());
 
        self->output().add(screen);
 
@@ -660,7 +660,7 @@ bool AddCommand::DoExecute()
                core::diagnostics::scoped_call_context save;
                core::diagnostics::call_context::for_thread().video_channel = channel_index() + 1;
 
-               auto consumer = create_consumer(parameters());
+               auto consumer = create_consumer(parameters(), &channel()->stage());
                channel()->output().add(layer_index(consumer->index()), consumer);
        
                SetReplyString(L"202 ADD OK\r\n");
@@ -695,7 +695,7 @@ bool RemoveCommand::DoExecute()
                                boost::to_upper(str);
                        }
 
-                       index = create_consumer(parameters())->index();
+                       index = create_consumer(parameters(), &channel()->stage())->index();
                }
 
                channel()->output().remove(index);
@@ -912,7 +912,7 @@ bool ClearCommand::DoExecute()
 
 bool PrintCommand::DoExecute()
 {
-       channel()->output().add(create_consumer({ L"IMAGE" }));
+       channel()->output().add(create_consumer({ L"IMAGE" }, &channel()->stage()));
                
        SetReplyString(L"202 PRINT OK\r\n");
 
index 3102c8de3833bcd883e1765f8e31819e57898edb..072cd82e194f3ea6a3d2199a6c2ba3d87fde63e8 100644 (file)
 #include <modules/image/consumer/image_consumer.h>
 #include <modules/psd/psd_scene_producer.h>
 
-#include <modules/oal/consumer/oal_consumer.h>
-#include <modules/bluefish/consumer/bluefish_consumer.h>
-#include <modules/decklink/consumer/decklink_consumer.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>
@@ -206,18 +200,9 @@ struct server::impl : boost::noncopyable
                                try
                                {
                                        auto name = xml_consumer.first;
-                                       if(name == L"screen")
-                                               channel->output().add(caspar::screen::create_consumer(xml_consumer.second, &channel->stage()));                                 
-                                       else if(name == L"bluefish")                                    
-                                               channel->output().add(bluefish::create_consumer(xml_consumer.second));                                  
-                                       else if(name == L"decklink")                                    
-                                               channel->output().add(decklink::create_consumer(xml_consumer.second));                          
-                                       else if(name == L"file")                                        
-                                               channel->output().add(ffmpeg::create_consumer(xml_consumer.second));                                            
-                                       else if(name == L"system-audio")
-                                               channel->output().add(oal::create_consumer());          
-                                       else if(name != L"<xmlcomment>")
-                                               CASPAR_LOG(warning) << "Invalid consumer: " << name;    
+                                       
+                                       if (name != L"<xmlcomment>")
+                                               channel->output().add(create_consumer(name, xml_consumer.second, &channel->stage()));
                                }
                                catch(...)
                                {