]> git.sesse.net Git - casparcg/blob - protocol/clk/clk_commands.cpp
* Enabled modules like flash and html (will be merged soon) to hook in CG functionali...
[casparcg] / protocol / clk / clk_commands.cpp
1 /*\r
2 * Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
3 *\r
4 * This file is part of CasparCG (www.casparcg.com).\r
5 *\r
6 * CasparCG is free software: you can redistribute it and/or modify\r
7 * it under the terms of the GNU General Public License as published by\r
8 * the Free Software Foundation, either version 3 of the License, or\r
9 * (at your option) any later version.\r
10 *\r
11 * CasparCG is distributed in the hope that it will be useful,\r
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
14 * GNU General Public License for more details.\r
15 *\r
16 * You should have received a copy of the GNU General Public License\r
17 * along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
18 *\r
19 * Author: Helge Norberg, helge.norberg@svt.se\r
20 */\r
21 \r
22 #include "../StdAfx.h"\r
23 \r
24 #include <stdexcept>\r
25 #include <sstream>\r
26 #include <future>\r
27 \r
28 #include <boost/lexical_cast.hpp>\r
29 \r
30 #include <common/log.h>\r
31 #include <common/memory.h>\r
32 \r
33 #include <core/video_channel.h>\r
34 #include <core/producer/stage.h>\r
35 #include <core/producer/cg_proxy.h>\r
36 \r
37 #include "clk_commands.h"\r
38 \r
39 namespace caspar { namespace protocol { namespace CLK {\r
40 \r
41 class command_context\r
42 {\r
43         bool                                                                            clock_loaded_ = false;\r
44         spl::shared_ptr<core::video_channel>            channel_;\r
45         spl::shared_ptr<core::cg_producer_registry>     cg_registry_;\r
46 public:\r
47         command_context(\r
48                         const spl::shared_ptr<core::video_channel>& channel,\r
49                         const spl::shared_ptr<core::cg_producer_registry>& cg_registry)\r
50                 : channel_(channel)\r
51                 , cg_registry_(cg_registry)\r
52         {\r
53         }\r
54 \r
55         void send_to_flash(const std::wstring& data)\r
56         {\r
57                 if (!clock_loaded_) \r
58                 {\r
59                         cg_registry_->get_or_create_proxy(channel_, core::cg_proxy::DEFAULT_LAYER, L"hawrysklocka/clock")->add(\r
60                                 0, L"hawrysklocka/clock", true, L"", data);\r
61                         clock_loaded_ = true;\r
62                 }\r
63                 else\r
64                 {\r
65                         cg_registry_->get_proxy(channel_, core::cg_proxy::DEFAULT_LAYER)->update(0, data);\r
66                 }\r
67                                 \r
68                 CASPAR_LOG(debug) << L"CLK: Clockdata sent: " << data;\r
69         }\r
70 \r
71         void reset()\r
72         {\r
73                 channel_->stage().clear(core::cg_proxy::DEFAULT_LAYER);\r
74                 clock_loaded_ = false;\r
75                 CASPAR_LOG(info) << L"CLK: Recieved and executed reset-command";\r
76         }\r
77 };\r
78 \r
79 template<class T>\r
80 T require_param(\r
81         std::vector<std::wstring>::const_iterator& params_current,\r
82         const std::vector<std::wstring>::const_iterator& params_end,\r
83         const std::string& param_name)\r
84 {\r
85         if (params_current == params_end)\r
86                 throw std::runtime_error(param_name + " required");\r
87 \r
88         T value = boost::lexical_cast<T>(*params_current);\r
89 \r
90         ++params_current;\r
91 \r
92         return std::move(value);\r
93 }\r
94 \r
95 std::wstring get_xml(\r
96         const std::wstring& command_name,\r
97         bool has_clock_id,\r
98         bool has_time,\r
99         const std::vector<std::wstring>& parameters)\r
100 {\r
101         std::wstringstream stream;\r
102 \r
103         stream << L"<templateData>";    \r
104         stream << L"<componentData id=\"command\">";\r
105         stream << L"<command id=\"" << command_name << "\"";\r
106         \r
107         std::vector<std::wstring>::const_iterator it = parameters.begin();\r
108         std::vector<std::wstring>::const_iterator end = parameters.end();\r
109 \r
110         if (has_clock_id)\r
111         {\r
112                 stream << L" clockID=\""\r
113                         << require_param<int>(it, end, "clock id") << L"\"";\r
114         }\r
115 \r
116         if (has_time)\r
117         {\r
118                 stream << L" time=\""\r
119                         << require_param<std::wstring>(it, end, "time") << L"\"";\r
120         }\r
121 \r
122         bool has_parameters = it != end;\r
123 \r
124         stream << (has_parameters ? L">" : L" />");\r
125 \r
126         if (has_parameters)\r
127         {\r
128                 for (; it != end; ++it)\r
129                 {\r
130                         stream << L"<parameter>" << (*it) << L"</parameter>";\r
131                 }\r
132 \r
133                 stream << L"</command>";\r
134         }\r
135 \r
136         stream << L"</componentData>";\r
137         stream << L"</templateData>";\r
138 \r
139         return stream.str();\r
140 }\r
141 \r
142 clk_command_handler create_send_xml_handler(\r
143         const std::wstring& command_name, \r
144         bool expect_clock, \r
145         bool expect_time, \r
146         const spl::shared_ptr<command_context>& context)\r
147 {\r
148         return [=] (const std::vector<std::wstring>& params)\r
149         {\r
150                 context->send_to_flash(get_xml(\r
151                         command_name, expect_clock, expect_time, params));\r
152         };\r
153 }\r
154 \r
155 void add_command_handlers(\r
156         clk_command_processor& processor, \r
157         const spl::shared_ptr<core::video_channel>& channel,\r
158         const spl::shared_ptr<core::cg_producer_registry>& cg_registry)\r
159 {\r
160         auto context = spl::make_shared<command_context>(channel, cg_registry);\r
161 \r
162         processor\r
163                 .add_handler(L"DUR", \r
164                         create_send_xml_handler(L"DUR", true, true, context))\r
165                 .add_handler(L"NEWDUR", \r
166                         create_send_xml_handler(L"NEWDUR", true, true, context))\r
167                 .add_handler(L"UNTIL", \r
168                         create_send_xml_handler(L"UNTIL", true, true, context))\r
169                 .add_handler(L"NEXTEVENT", \r
170                         create_send_xml_handler(L"NEXTEVENT", true, false, context))\r
171                 .add_handler(L"STOP", \r
172                         create_send_xml_handler(L"STOP", true, false, context))\r
173                 .add_handler(L"ADD", \r
174                         create_send_xml_handler(L"ADD", true, true, context))\r
175                 .add_handler(L"SUB", \r
176                         create_send_xml_handler(L"SUB", true, true, context))\r
177                 .add_handler(L"TIMELINE_LOAD", \r
178                         create_send_xml_handler(L"TIMELINE_LOAD", false, false, context))\r
179                 .add_handler(L"TIMELINE_PLAY", \r
180                         create_send_xml_handler(L"TIMELINE_PLAY", false, false, context))\r
181                 .add_handler(L"TIMELINE_STOP", \r
182                         create_send_xml_handler(L"TIMELINE_STOP", false, false, context))\r
183                 .add_handler(L"RESET", [=] (const std::vector<std::wstring>& params)\r
184                 {\r
185                         context->reset();\r
186                 })\r
187                 ;\r
188 }\r
189 \r
190 }}}\r