]> git.sesse.net Git - casparcg/commitdiff
Added timeline support to the CLK protocol. Also refactored parts of the CLK parser...
authorhellgore <hellgore@362d55ac-95cf-4e76-9f9a-cbaa9c17b72d>
Tue, 18 Sep 2012 12:41:10 +0000 (12:41 +0000)
committerhellgore <hellgore@362d55ac-95cf-4e76-9f9a-cbaa9c17b72d>
Tue, 18 Sep 2012 12:41:10 +0000 (12:41 +0000)
git-svn-id: https://casparcg.svn.sourceforge.net/svnroot/casparcg/server/trunk@3312 362d55ac-95cf-4e76-9f9a-cbaa9c17b72d

protocol/clk/CLKCommand.cpp [deleted file]
protocol/clk/CLKProtocolStrategy.cpp
protocol/clk/CLKProtocolStrategy.h
protocol/clk/clk_command_processor.cpp [new file with mode: 0644]
protocol/clk/clk_command_processor.h [new file with mode: 0644]
protocol/clk/clk_commands.cpp [new file with mode: 0644]
protocol/clk/clk_commands.h [moved from protocol/clk/CLKCommand.h with 56% similarity]
protocol/protocol.vcxproj
protocol/protocol.vcxproj.filters
protocol/util/ProtocolStrategy.h

diff --git a/protocol/clk/CLKCommand.cpp b/protocol/clk/CLKCommand.cpp
deleted file mode 100644 (file)
index b01d4d6..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-/*\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: Nicklas P Andersson\r
-*/\r
-\r
\r
-#include "..\stdafx.h"\r
-#include <algorithm>\r
-#include <locale>\r
-#include "CLKCommand.h"\r
-\r
-namespace caspar { namespace protocol { namespace CLK {\r
-\r
-CLKCommand::CLKCommand() : clockID_(0), command_(CLKInvalidCommand) {}\r
-\r
-CLKCommand::~CLKCommand() {}\r
-\r
-const std::wstring& CLKCommand::GetData() \r
-{\r
-       std::wstringstream dataStream;\r
-\r
-       dataStream << TEXT("<templateData>");   \r
-       dataStream << TEXT("<componentData id=\"command\">");\r
-       dataStream << TEXT("<command id=\"") << commandString_ << TEXT("\" time=\"") << time_ << TEXT("\" clockID=\"") << clockID_ << TEXT("\">");\r
-\r
-       std::vector<std::wstring>::const_iterator it = parameters_.begin();\r
-       std::vector<std::wstring>::const_iterator end = parameters_.end();\r
-       for(; it != end; ++it) {\r
-               dataStream << TEXT("<parameter>") << (*it) << TEXT("</parameter>"); \r
-       }\r
-\r
-       dataStream << TEXT("</command>"); \r
-       dataStream << TEXT("</componentData>"); \r
-       dataStream << TEXT("</templateData>");\r
-\r
-       dataCache_ = dataStream.str();\r
-       return dataCache_;\r
-}\r
-\r
-bool CLKCommand::SetCommand() \r
-{\r
-       bool bResult = true;\r
-       std::transform(commandString_.begin(), commandString_.end(), commandString_.begin(), toupper);\r
-\r
-       if(commandString_ == TEXT("DUR"))\r
-               command_ = CLKDuration;\r
-       else if(commandString_ == TEXT("NEWDUR"))\r
-               command_ = CLKNewDuration;\r
-       else if(commandString_ == TEXT("NEXTEVENT"))\r
-               command_ = CLKNextEvent;\r
-       else if(commandString_ == TEXT("STOP"))\r
-               command_ = CLKStop;\r
-       else if(commandString_ == TEXT("UNTIL"))\r
-               command_ = CLKUntil;\r
-       else if(commandString_ == TEXT("ADD"))\r
-               command_ = CLKAdd;\r
-       else if(commandString_ == TEXT("SUB"))\r
-               command_ = CLKSub;\r
-       else if(commandString_ == TEXT("RESET"))\r
-               command_ = CLKReset;\r
-       else \r
-       {\r
-               command_ = CLKInvalidCommand;\r
-               bResult = false;\r
-       }\r
-\r
-       return bResult;\r
-}\r
-\r
-void CLKCommand::Clear() \r
-{\r
-       dataCache_.clear();\r
-       commandString_.clear();\r
-       time_.clear();\r
-       command_ = CLKDuration;\r
-       clockID_ = 0;\r
-       parameters_.clear();\r
-}\r
-\r
-}}}
\ No newline at end of file
index 45117389399e5d35f63703a8d6ba1f1d3a26c24e..4ce1a23e6133e8348a313c511785a541188186a7 100644 (file)
 #include "..\stdafx.h"\r
 \r
 #include "CLKProtocolStrategy.h"\r
+#include "clk_commands.h"\r
 \r
 #include <modules/flash/producer/cg_producer.h>\r
 \r
 #include <string>\r
-#include <sstream>\r
 #include <algorithm>\r
+#include <locale>\r
 \r
 namespace caspar { namespace protocol { namespace CLK {\r
        \r
-CLKProtocolStrategy::CLKProtocolStrategy(const std::vector<safe_ptr<core::video_channel>>& channels) \r
-       : currentState_(ExpectingNewCommand), bClockLoaded_(false), pChannel_(channels.at(0))\r
-{}\r
+CLKProtocolStrategy::CLKProtocolStrategy(\r
+       const std::vector<safe_ptr<core::video_channel>>& channels) \r
+       : currentState_(ExpectingNewCommand)\r
+{\r
+       add_command_handlers(command_processor_, channels.at(0));\r
+}\r
+\r
+void CLKProtocolStrategy::reset()\r
+{\r
+       currentState_ = ExpectingNewCommand;\r
+       currentCommandString_.str(L"");\r
+       command_name_.clear();\r
+       parameters_.clear();\r
+}\r
 \r
 void CLKProtocolStrategy::Parse(const TCHAR* pData, int charCount, IO::ClientInfoPtr pClientInfo) \r
 {\r
-       for(int index = 0; index < charCount; ++index) \r
+       for (int index = 0; index < charCount; ++index) \r
        {\r
-               if(currentState_ == ExpectingNewCommand)\r
-                       currentCommandString_.str(TEXT(""));\r
-\r
                TCHAR currentByte = pData[index];\r
-               if(currentByte < 32)\r
-                       currentCommandString_ << TEXT("<") << (int)currentByte << TEXT(">");\r
+               \r
+               if (currentByte < 32)\r
+                       currentCommandString_ << L"<" << static_cast<int>(currentByte) << L">";\r
                else\r
                        currentCommandString_ << currentByte;\r
 \r
-               if(currentByte != 0)\r
+               if (currentByte != 0)\r
                {\r
-                       switch(currentState_)\r
+                       switch (currentState_)\r
                        {\r
                                case ExpectingNewCommand:\r
-                                       if(currentByte == 1) \r
-                                               currentState_ = ExpectingCommand;                                       \r
+                                       if (currentByte == 1) \r
+                                               currentState_ = ExpectingCommand;\r
                                        //just throw anything else away\r
                                        break;\r
-\r
                                case ExpectingCommand:\r
-                                       if(currentByte == 2) \r
-                                       {\r
-                                               if(!currentCommand_.SetCommand()) \r
-                                               {\r
-                                                       CASPAR_LOG(error) << "CLK: Failed to interpret command";\r
-                                                       currentState_ = ExpectingNewCommand;\r
-                                                       currentCommand_.Clear();\r
-                                               }\r
-                                               else \r
-                                                       currentState_ = ExpectingClockID;                                               \r
-                                       }\r
-                                       else\r
-                                               currentCommand_.commandString_ += currentByte;\r
-                                       break;\r
-\r
-                               case ExpectingClockID:\r
-                                       if(currentByte == 2)\r
-                                               currentState_ = currentCommand_.NeedsTime() ? ExpectingTime : ExpectingParameter;\r
-                                       else\r
-                                               currentCommand_.clockID_ = currentByte - TCHAR('0');\r
-                                       break;\r
-\r
-                               case ExpectingTime:\r
-                                       if(currentByte == 2)\r
+                                       if (currentByte == 2) \r
                                                currentState_ = ExpectingParameter;\r
                                        else\r
-                                               currentCommand_.time_ += currentByte;\r
+                                               command_name_ += currentByte;\r
                                        break;\r
-\r
                                case ExpectingParameter:\r
                                        //allocate new parameter\r
-                                       if(currentCommand_.parameters_.size() == 0 || currentByte == 2)\r
-                                               currentCommand_.parameters_.push_back(std::wstring());\r
+                                       if (parameters_.size() == 0 || currentByte == 2)\r
+                                               parameters_.push_back(std::wstring());\r
 \r
-                                       //add the character to end end of the last parameter\r
-                                       if(currentByte == TEXT('<'))\r
-                                               currentCommand_.parameters_[currentCommand_.parameters_.size()-1] += TEXT("&lt;");\r
-                                       else if(currentByte == TEXT('>'))\r
-                                               currentCommand_.parameters_[currentCommand_.parameters_.size()-1] += TEXT("&gt;");\r
-                                       else if(currentByte == TEXT('\"'))\r
-                                               currentCommand_.parameters_[currentCommand_.parameters_.size()-1] += TEXT("&quot;");\r
-                                       else\r
-                                               currentCommand_.parameters_[currentCommand_.parameters_.size()-1] += currentByte;\r
+                                       if (currentByte != 2)\r
+                                       {\r
+                                               //add the character to end end of the last parameter\r
+                                               if (currentByte == L'<')\r
+                                                       parameters_.back() += L"&lt;";\r
+                                               else if (currentByte == L'>')\r
+                                                       parameters_.back() += L"&gt;";\r
+                                               else if (currentByte == L'\"')\r
+                                                       parameters_.back() += L"&quot;";\r
+                                               else\r
+                                                       parameters_.back() += currentByte;\r
+                                       }\r
 \r
                                        break;\r
                        }\r
                }\r
                else \r
                {\r
-                       if(currentState_ == ExpectingCommand)\r
-                       {\r
-                               if(!currentCommand_.SetCommand())\r
-                                       CASPAR_LOG(error) << "CLK: Failed to interpret command";\r
-                       }\r
+                       std::transform(\r
+                               command_name_.begin(), command_name_.end(), \r
+                               command_name_.begin(), \r
+                               toupper);\r
 \r
-                       if(currentCommand_.command_ == CLKCommand::CLKReset) \r
-                       {\r
-                               pChannel_->stage()->clear(flash::cg_producer::DEFAULT_LAYER);\r
-                               bClockLoaded_ = false;\r
-                               \r
-                               CASPAR_LOG(info) << L"CLK: Recieved and executed reset-command";\r
-                       }\r
-                       else if(currentCommand_.command_ != CLKCommand::CLKInvalidCommand)\r
+                       try\r
                        {\r
-                               if(!bClockLoaded_) \r
+                               if (!command_processor_.handle(command_name_, parameters_))\r
                                {\r
-                                       flash::get_default_cg_producer(pChannel_)->add(0, TEXT("hawrysklocka/clock.ft"), true, TEXT(""), currentCommand_.GetData());\r
-                                       bClockLoaded_ = true;\r
+                                       CASPAR_LOG(error) << "CLK: Unknown command: " << command_name_;\r
                                }\r
-                               else \r
-                                       flash::get_default_cg_producer(pChannel_)->update(0, currentCommand_.GetData());\r
-                               \r
-                               CASPAR_LOG(debug) << L"CLK: Clockdata sent: " << currentCommand_.GetData();\r
-                               CASPAR_LOG(debug) << L"CLK: Executed valid command: " << currentCommandString_.str();\r
+                               else\r
+                               {\r
+                                       CASPAR_LOG(debug) << L"CLK: Executed valid command: " \r                                         << currentCommandString_.str();\r                                }\r
+                       } \r
+                       catch (...)\r
+                       {\r
+                               CASPAR_LOG_CURRENT_EXCEPTION();\r
+                               CASPAR_LOG(error) << "CLK: Failed to interpret command: " \r
+                                       << currentCommandString_.str();\r
                        }\r
 \r
-                       currentState_ = ExpectingNewCommand;\r
-                       currentCommand_.Clear();\r
+                       reset();\r
                }\r
        }\r
 }\r
 \r
-}      //namespace CLK\r
-}}     //namespace caspar
\ No newline at end of file
+}}}\r
index 4b89eb365131d85ab9535f9fa83386fb5b5eed09..89af7872aca1ec877c4def59af99941059924147 100644 (file)
  \r
 #pragma once\r
 \r
-#include "CLKCommand.h"\r
-#include "../util/ProtocolStrategy.h"\r
+#include <vector>\r
+#include <string>\r
+#include <sstream>\r
+\r
 #include <core/video_channel.h>\r
 \r
+#include "clk_command_processor.h"\r
+#include "../util/ProtocolStrategy.h"\r
+\r
 namespace caspar { namespace protocol { namespace CLK {\r
 \r
+/**\r
+ * TODO:\r
+ * Can only handle one connection at a time safely. Works with multiple if\r
+ * every Parse call contains a complete command, but this will not happen if\r
+ * the client sends one command in multiple chunks, then partial commands can\r
+ * be interlieved with each other from different clients, causing the parser\r
+ * to be confused.\r
+ */\r
 class CLKProtocolStrategy : public IO::IProtocolStrategy\r
 {\r
 public:\r
@@ -37,22 +50,20 @@ public:
        UINT GetCodepage() { return 28591; }    //ISO 8859-1\r
        \r
 private:\r
+       void reset();\r
+\r
        enum ParserState\r
        {\r
                ExpectingNewCommand,\r
                ExpectingCommand,\r
-               ExpectingClockID,\r
-               ExpectingTime,\r
                ExpectingParameter\r
        };\r
 \r
        ParserState     currentState_;\r
-       CLKCommand currentCommand_;\r
        std::wstringstream currentCommandString_;\r
-\r
-       safe_ptr<core::video_channel> pChannel_;\r
-\r
-       bool bClockLoaded_;\r
+       std::wstring command_name_;\r
+       std::vector<std::wstring> parameters_;\r
+       clk_command_processor command_processor_;\r
 };\r
 \r
 }}}\r
diff --git a/protocol/clk/clk_command_processor.cpp b/protocol/clk/clk_command_processor.cpp
new file mode 100644 (file)
index 0000000..d614a6a
--- /dev/null
@@ -0,0 +1,49 @@
+/*\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: Helge Norberg, helge.norberg@svt.se\r
+*/\r
+\r
+#include "../stdafx.h"\r
+\r
+#include "clk_command_processor.h"\r
+\r
+namespace caspar { namespace protocol { namespace CLK {\r
+\r
+clk_command_processor& clk_command_processor::add_handler(\r
+       const std::wstring& command_name, const clk_command_handler& handler)\r
+{\r
+       handlers_.insert(std::make_pair(command_name, handler));\r
+\r
+       return *this;\r
+}\r
+\r
+bool clk_command_processor::handle(\r
+       const std::wstring& command_name, const std::vector<std::wstring>& parameters)\r
+{\r
+       auto handler = handlers_.find(command_name);\r
+\r
+       if (handler == handlers_.end())\r
+               return false;\r
+\r
+       handler->second(parameters);\r
+\r
+       return true;\r
+}\r
+\r
+}}}\r
diff --git a/protocol/clk/clk_command_processor.h b/protocol/clk/clk_command_processor.h
new file mode 100644 (file)
index 0000000..6882cba
--- /dev/null
@@ -0,0 +1,71 @@
+/*\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: Helge Norberg, helge.norberg@svt.se\r
+*/\r
+\r
+#pragma once\r
+\r
+#include <vector>\r
+#include <string>\r
+#include <map>\r
+\r
+#include <common/memory/safe_ptr.h>\r
+\r
+#include <boost/function.hpp>\r
+\r
+namespace caspar { namespace protocol { namespace CLK {\r
+\r
+typedef boost::function<void (const std::vector<std::wstring>&)> clk_command_handler;\r
+\r
+/**\r
+ * CLK command processor composed by multiple command handlers.\r
+ *\r
+ * Not thread-safe.\r
+ */\r
+class clk_command_processor\r
+{\r
+       std::map<std::wstring, clk_command_handler> handlers_;\r
+public:\r
+       /**\r
+        * Register a handler for a specific command.\r
+        *\r
+        * @param command_name The command name to use this handler for.\r
+        * @param handler      The handler that will handle all commands with the\r
+        *                     specified name.\r
+        *\r
+        * @return this command processor for method chaining.\r
+        */\r
+       clk_command_processor& add_handler(\r
+               const std::wstring& command_name, const clk_command_handler& handler);\r
+\r
+       /**\r
+        * Handle an incoming command.\r
+        *\r
+        * @param command_name The command name.\r
+        * @param parameters   The raw parameters supplied with the command.\r
+        *\r
+        * @return true if the command was handled, false if no handler was\r
+        *         registered to handle the command.\r
+        */\r
+       bool handle(\r
+               const std::wstring& command_name, \r
+               const std::vector<std::wstring>& parameters);\r
+};\r
+\r
+}}}\r
diff --git a/protocol/clk/clk_commands.cpp b/protocol/clk/clk_commands.cpp
new file mode 100644 (file)
index 0000000..502fb78
--- /dev/null
@@ -0,0 +1,182 @@
+/*\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: Helge Norberg, helge.norberg@svt.se\r
+*/\r
+\r
+#include "../stdafx.h"\r
+\r
+#include <stdexcept>\r
+#include <sstream>\r
+\r
+#include <boost/lexical_cast.hpp>\r
+\r
+#include <common/log/log.h>\r
+\r
+#include <modules/flash/producer/cg_producer.h>\r
+\r
+#include "clk_commands.h"\r
+\r
+namespace caspar { namespace protocol { namespace CLK {\r
+\r
+class command_context\r
+{\r
+       bool clock_loaded_;\r
+       safe_ptr<core::video_channel> channel_;\r
+public:\r
+       command_context(const safe_ptr<core::video_channel>& channel)\r
+               : clock_loaded_(false)\r
+               , channel_(channel)\r
+       {\r
+       }\r
+\r
+       void send_to_flash(const std::wstring& data)\r
+       {\r
+               if (!clock_loaded_) \r
+               {\r
+                       flash::get_default_cg_producer(channel_)->add(\r
+                               0, L"hawrysklocka/clock.ft", true, L"", data);\r
+                       clock_loaded_ = true;\r
+               }\r
+               else\r
+               {\r
+                       flash::get_default_cg_producer(channel_)->update(0, data);\r
+               }\r
+                               \r
+               CASPAR_LOG(debug) << L"CLK: Clockdata sent: " << data;\r
+       }\r
+\r
+       void reset()\r
+       {\r
+               channel_->stage()->clear(flash::cg_producer::DEFAULT_LAYER);\r
+               clock_loaded_ = false;\r
+               CASPAR_LOG(info) << L"CLK: Recieved and executed reset-command";\r
+       }\r
+};\r
+\r
+template<class T>\r
+T require_param(\r
+       std::vector<std::wstring>::const_iterator& params_current,\r
+       const std::vector<std::wstring>::const_iterator& params_end,\r
+       const std::string& param_name)\r
+{\r
+       if (params_current == params_end)\r
+               throw std::runtime_error(param_name + " required");\r
+\r
+       T value = boost::lexical_cast<T>(*params_current);\r
+\r
+       ++params_current;\r
+\r
+       return std::move(value);\r
+}\r
+\r
+std::wstring get_xml(\r
+       const std::wstring& command_name,\r
+       bool has_clock_id,\r
+       bool has_time,\r
+       const std::vector<std::wstring>& parameters)\r
+{\r
+       std::wstringstream stream;\r
+\r
+       stream << L"<templateData>";    \r
+       stream << L"<componentData id=\"command\">";\r
+       stream << L"<command id=\"" << command_name << "\"";\r
+       \r
+       std::vector<std::wstring>::const_iterator it = parameters.begin();\r
+       std::vector<std::wstring>::const_iterator end = parameters.end();\r
+\r
+       if (has_clock_id)\r
+       {\r
+               stream << L" clockID=\""\r
+                       << require_param<int>(it, end, "clock id") << L"\"";\r
+       }\r
+\r
+       if (has_time)\r
+       {\r
+               stream << L" time=\""\r
+                       << require_param<std::wstring>(it, end, "time") << L"\"";\r
+       }\r
+\r
+       bool has_parameters = it != end;\r
+\r
+       stream << (has_parameters ? L">" : L" />");\r
+\r
+       if (has_parameters)\r
+       {\r
+               for (; it != end; ++it)\r
+               {\r
+                       stream << L"<parameter>" << (*it) << L"</parameter>";\r
+               }\r
+\r
+               stream << L"</command>";\r
+       }\r
+\r
+       stream << L"</componentData>";\r
+       stream << L"</templateData>";\r
+\r
+       return stream.str();\r
+}\r
+\r
+clk_command_handler create_send_xml_handler(\r
+       const std::wstring& command_name, \r
+       bool expect_clock, \r
+       bool expect_time, \r
+       const safe_ptr<command_context>& context)\r
+{\r
+       return [=] (const std::vector<std::wstring>& params)\r
+       {\r
+               context->send_to_flash(get_xml(\r
+                       command_name, expect_clock, expect_time, params));\r
+       };\r
+}\r
+\r
+void add_command_handlers(\r
+       clk_command_processor& processor, \r
+       const safe_ptr<core::video_channel>& channel)\r
+{\r
+       auto context = make_safe<command_context>(channel);\r
+\r
+       processor\r
+               .add_handler(L"DUR", \r
+                       create_send_xml_handler(L"DUR", true, true, context))\r
+               .add_handler(L"NEWDUR", \r
+                       create_send_xml_handler(L"NEWDUR", true, true, context))\r
+               .add_handler(L"UNTIL", \r
+                       create_send_xml_handler(L"UNTIL", true, true, context))\r
+               .add_handler(L"NEXTEVENT", \r
+                       create_send_xml_handler(L"NEXTEVENT", true, false, context))\r
+               .add_handler(L"STOP", \r
+                       create_send_xml_handler(L"STOP", true, false, context))\r
+               .add_handler(L"ADD", \r
+                       create_send_xml_handler(L"ADD", true, true, context))\r
+               .add_handler(L"SUB", \r
+                       create_send_xml_handler(L"SUB", true, true, context))\r
+               .add_handler(L"TIMELINE_LOAD", \r
+                       create_send_xml_handler(L"TIMELINE_LOAD", false, false, context))\r
+               .add_handler(L"TIMELINE_PLAY", \r
+                       create_send_xml_handler(L"TIMELINE_PLAY", false, false, context))\r
+               .add_handler(L"TIMELINE_STOP", \r
+                       create_send_xml_handler(L"TIMELINE_STOP", false, false, context))\r
+               .add_handler(L"RESET", [=] (const std::vector<std::wstring>& params)\r
+               {\r
+                       context->reset();\r
+               })\r
+               ;\r
+}\r
+\r
+}}}\r
similarity index 56%
rename from protocol/clk/CLKCommand.h
rename to protocol/clk/clk_commands.h
index e0b95ef5a0fef686f019a27850784548eb6f2997..af6f1e83bedc58e7c7ab6ab800b16838d1149a30 100644 (file)
 * 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: Nicklas P Andersson\r
+* Author: Helge Norberg, helge.norberg@svt.se\r
 */\r
 \r
\r
 #pragma once\r
 \r
-namespace caspar { namespace protocol { namespace CLK {\r
-\r
-class CLKCommand\r
-{\r
-public:\r
-       enum CLKCommands \r
-       {\r
-               CLKDuration,\r
-               CLKNewDuration,\r
-               CLKNextEvent,\r
-               CLKStop,\r
-               CLKUntil,\r
-               CLKAdd,\r
-               CLKSub,\r
-               CLKReset,\r
-               CLKInvalidCommand\r
-       };\r
+#include <core/video_channel.h>\r
 \r
-       CLKCommand();\r
-       virtual ~CLKCommand();\r
+#include "clk_command_processor.h"\r
 \r
-       bool SetCommand();\r
-       bool NeedsTime() const \r
-       {\r
-               return !(command_ == CLKNextEvent || command_ == CLKStop);\r
-       }\r
-\r
-       void Clear();\r
-       const std::wstring& GetData();\r
+namespace caspar { namespace protocol { namespace CLK {\r
 \r
-       std::wstring dataCache_;\r
-       std::wstring commandString_;\r
-       CLKCommands command_;\r
-       int clockID_;\r
-       std::wstring time_;\r
-       std::vector<std::wstring> parameters_;\r
-};\r
+/**\r
+ * Add the CLK command handlers to a command processor.\r
+ *\r
+ * @param processor The command processor to add the command handlers to.\r
+ * @param channel   The channel to play the flash graphics on.\r
+ */\r
+void add_command_handlers(\r
+       clk_command_processor& processor, const safe_ptr<core::video_channel>& channel);\r
 \r
-}}}
\ No newline at end of file
+}}}\r
index 92d2fc2e3879ee4a1dfb6cb64e5bb7eb3999ce7e..cc0041a3dc12f3b5e9fd4336671495bdbd25333e 100644 (file)
@@ -40,8 +40,9 @@
     <ClInclude Include="cii\CIICommand.h" />\r
     <ClInclude Include="cii\CIICommandsImpl.h" />\r
     <ClInclude Include="cii\CIIProtocolStrategy.h" />\r
-    <ClInclude Include="clk\CLKCommand.h" />\r
     <ClInclude Include="clk\CLKProtocolStrategy.h" />\r
+    <ClInclude Include="clk\clk_commands.h" />\r
+    <ClInclude Include="clk\clk_command_processor.h" />\r
     <ClInclude Include="StdAfx.h" />\r
     <ClInclude Include="util\AsyncEventServer.h" />\r
     <ClInclude Include="util\ClientInfo.h" />\r
       <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
       <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Develop|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
     </ClCompile>\r
-    <ClCompile Include="clk\CLKCommand.cpp">\r
+    <ClCompile Include="clk\CLKProtocolStrategy.cpp">\r
       <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
       <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
       <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
       <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Develop|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
     </ClCompile>\r
-    <ClCompile Include="clk\CLKProtocolStrategy.cpp">\r
+    <ClCompile Include="clk\clk_commands.cpp">\r
       <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
       <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
+      <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Develop|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
       <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
+    </ClCompile>\r
+    <ClCompile Include="clk\clk_command_processor.cpp">\r
+      <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
+      <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
       <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Develop|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
+      <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
     </ClCompile>\r
     <ClCompile Include="StdAfx.cpp">\r
       <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>\r
index fe16c366f9c4837a62651297d3c96b1c087fdfcd..6e323a49153340d08fecccf20546cfd9ae15e667 100644 (file)
@@ -45,9 +45,6 @@
     <ClInclude Include="clk\CLKProtocolStrategy.h">\r
       <Filter>source\clk</Filter>\r
     </ClInclude>\r
-    <ClInclude Include="clk\CLKCommand.h">\r
-      <Filter>source\clk</Filter>\r
-    </ClInclude>\r
     <ClInclude Include="util\ClientInfo.h">\r
       <Filter>source\util</Filter>\r
     </ClInclude>\r
       <Filter>source\util</Filter>\r
     </ClInclude>\r
     <ClInclude Include="StdAfx.h" />\r
+    <ClInclude Include="clk\clk_command_processor.h">\r
+      <Filter>source\clk</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="clk\clk_commands.h">\r
+      <Filter>source\clk</Filter>\r
+    </ClInclude>\r
   </ItemGroup>\r
   <ItemGroup>\r
     <ClCompile Include="amcp\AMCPCommandQueue.cpp">\r
@@ -81,9 +84,6 @@
     <ClCompile Include="cii\CIIProtocolStrategy.cpp">\r
       <Filter>source\cii</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="clk\CLKCommand.cpp">\r
-      <Filter>source\clk</Filter>\r
-    </ClCompile>\r
     <ClCompile Include="clk\CLKProtocolStrategy.cpp">\r
       <Filter>source\clk</Filter>\r
     </ClCompile>\r
       <Filter>source\util</Filter>\r
     </ClCompile>\r
     <ClCompile Include="StdAfx.cpp" />\r
+    <ClCompile Include="clk\clk_command_processor.cpp">\r
+      <Filter>source\clk</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="clk\clk_commands.cpp">\r
+      <Filter>source\clk</Filter>\r
+    </ClCompile>\r
   </ItemGroup>\r
 </Project>
\ No newline at end of file
index 8c11be981fd0bad7368a7b09a97ab4d95d0387f0..8c95e970af9a44c6066045e5737b27203e1803be 100644 (file)
@@ -22,7 +22,7 @@
  #pragma once\r
 \r
 #include <string>\r
-#include "clientInfo.h"\r
+#include "ClientInfo.h"\r
 \r
 namespace caspar { namespace IO {\r
 \r