]> git.sesse.net Git - casparcg/blob - protocol/clk/clk_commands.cpp
* Merged layer_producer and channel_producer from 2.0 to the reroute module (replacin...
[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         std::vector<spl::shared_ptr<core::video_channel>>       channels_;\r
45         spl::shared_ptr<core::video_channel>                            channel_;\r
46         spl::shared_ptr<core::cg_producer_registry>                     cg_registry_;\r
47 public:\r
48         command_context(\r
49                         const std::vector<spl::shared_ptr<core::video_channel>>& channels,\r
50                         const spl::shared_ptr<core::video_channel>& channel,\r
51                         const spl::shared_ptr<core::cg_producer_registry>& cg_registry)\r
52                 : channels_(channels)\r
53                 , channel_(channel)\r
54                 , cg_registry_(cg_registry)\r
55         {\r
56         }\r
57 \r
58         void send_to_flash(const std::wstring& data)\r
59         {\r
60                 if (!clock_loaded_) \r
61                 {\r
62                         core::frame_producer_dependencies dependencies(channel_->frame_factory(), channels_, channel_->video_format_desc());\r
63                         cg_registry_->get_or_create_proxy(channel_, dependencies, core::cg_proxy::DEFAULT_LAYER, L"hawrysklocka/clock")->add(\r
64                                 0, L"hawrysklocka/clock", true, L"", data);\r
65                         clock_loaded_ = true;\r
66                 }\r
67                 else\r
68                 {\r
69                         cg_registry_->get_proxy(channel_, core::cg_proxy::DEFAULT_LAYER)->update(0, data);\r
70                 }\r
71                                 \r
72                 CASPAR_LOG(debug) << L"CLK: Clockdata sent: " << data;\r
73         }\r
74 \r
75         void reset()\r
76         {\r
77                 channel_->stage().clear(core::cg_proxy::DEFAULT_LAYER);\r
78                 clock_loaded_ = false;\r
79                 CASPAR_LOG(info) << L"CLK: Recieved and executed reset-command";\r
80         }\r
81 };\r
82 \r
83 template<class T>\r
84 T require_param(\r
85         std::vector<std::wstring>::const_iterator& params_current,\r
86         const std::vector<std::wstring>::const_iterator& params_end,\r
87         const std::string& param_name)\r
88 {\r
89         if (params_current == params_end)\r
90                 throw std::runtime_error(param_name + " required");\r
91 \r
92         T value = boost::lexical_cast<T>(*params_current);\r
93 \r
94         ++params_current;\r
95 \r
96         return std::move(value);\r
97 }\r
98 \r
99 std::wstring get_xml(\r
100         const std::wstring& command_name,\r
101         bool has_clock_id,\r
102         bool has_time,\r
103         const std::vector<std::wstring>& parameters)\r
104 {\r
105         std::wstringstream stream;\r
106 \r
107         stream << L"<templateData>";    \r
108         stream << L"<componentData id=\"command\">";\r
109         stream << L"<command id=\"" << command_name << "\"";\r
110         \r
111         std::vector<std::wstring>::const_iterator it = parameters.begin();\r
112         std::vector<std::wstring>::const_iterator end = parameters.end();\r
113 \r
114         if (has_clock_id)\r
115         {\r
116                 stream << L" clockID=\""\r
117                         << require_param<int>(it, end, "clock id") << L"\"";\r
118         }\r
119 \r
120         if (has_time)\r
121         {\r
122                 stream << L" time=\""\r
123                         << require_param<std::wstring>(it, end, "time") << L"\"";\r
124         }\r
125 \r
126         bool has_parameters = it != end;\r
127 \r
128         stream << (has_parameters ? L">" : L" />");\r
129 \r
130         if (has_parameters)\r
131         {\r
132                 for (; it != end; ++it)\r
133                 {\r
134                         stream << L"<parameter>" << (*it) << L"</parameter>";\r
135                 }\r
136 \r
137                 stream << L"</command>";\r
138         }\r
139 \r
140         stream << L"</componentData>";\r
141         stream << L"</templateData>";\r
142 \r
143         return stream.str();\r
144 }\r
145 \r
146 clk_command_handler create_send_xml_handler(\r
147         const std::wstring& command_name, \r
148         bool expect_clock, \r
149         bool expect_time, \r
150         const spl::shared_ptr<command_context>& context)\r
151 {\r
152         return [=] (const std::vector<std::wstring>& params)\r
153         {\r
154                 context->send_to_flash(get_xml(\r
155                         command_name, expect_clock, expect_time, params));\r
156         };\r
157 }\r
158 \r
159 void add_command_handlers(\r
160         clk_command_processor& processor,\r
161         const std::vector<spl::shared_ptr<core::video_channel>>& channels,\r
162         const spl::shared_ptr<core::video_channel>& channel,\r
163         const spl::shared_ptr<core::cg_producer_registry>& cg_registry)\r
164 {\r
165         auto context = spl::make_shared<command_context>(channels, channel, cg_registry);\r
166 \r
167         processor\r
168                 .add_handler(L"DUR", \r
169                         create_send_xml_handler(L"DUR", true, true, context))\r
170                 .add_handler(L"NEWDUR", \r
171                         create_send_xml_handler(L"NEWDUR", true, true, context))\r
172                 .add_handler(L"UNTIL", \r
173                         create_send_xml_handler(L"UNTIL", true, true, context))\r
174                 .add_handler(L"NEXTEVENT", \r
175                         create_send_xml_handler(L"NEXTEVENT", true, false, context))\r
176                 .add_handler(L"STOP", \r
177                         create_send_xml_handler(L"STOP", true, false, context))\r
178                 .add_handler(L"ADD", \r
179                         create_send_xml_handler(L"ADD", true, true, context))\r
180                 .add_handler(L"SUB", \r
181                         create_send_xml_handler(L"SUB", true, true, context))\r
182                 .add_handler(L"TIMELINE_LOAD", \r
183                         create_send_xml_handler(L"TIMELINE_LOAD", false, false, context))\r
184                 .add_handler(L"TIMELINE_PLAY", \r
185                         create_send_xml_handler(L"TIMELINE_PLAY", false, false, context))\r
186                 .add_handler(L"TIMELINE_STOP", \r
187                         create_send_xml_handler(L"TIMELINE_STOP", false, false, context))\r
188                 .add_handler(L"RESET", [=] (const std::vector<std::wstring>& params)\r
189                 {\r
190                         context->reset();\r
191                 })\r
192                 ;\r
193 }\r
194 \r
195 }}}\r