]> git.sesse.net Git - casparcg/blob - protocol/cii/CIIProtocolStrategy.cpp
2.0.0.2:
[casparcg] / protocol / cii / CIIProtocolStrategy.cpp
1 /*\r
2 * copyright (c) 2010 Sveriges Television AB <info@casparcg.com>\r
3 *\r
4 *  This file is part of CasparCG.\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 */\r
20  \r
21 #include "../StdAfx.h"\r
22 \r
23 #include <string>\r
24 #include <sstream>\r
25 #include <algorithm>\r
26 #include "../media.h"\r
27 #include "CIIProtocolStrategy.h"\r
28 #include "CIICommandsimpl.h"\r
29 #include <core/producer/flash/flash_producer.h>\r
30 #include <core/producer/transition/transition_producer.h>\r
31 #include <core/producer/frame_producer.h>\r
32 #include <common/env.h>\r
33 \r
34 #if defined(_MSC_VER)\r
35 #pragma warning (push, 1) // TODO: Legacy code, just disable warnings\r
36 #endif\r
37 \r
38 namespace caspar { namespace protocol { namespace cii {\r
39         \r
40 using namespace core;\r
41 \r
42 const std::wstring CIIProtocolStrategy::MessageDelimiter = TEXT("\r\n");\r
43 const TCHAR CIIProtocolStrategy::TokenDelimiter = TEXT('\\');\r
44 \r
45 CIIProtocolStrategy::CIIProtocolStrategy(const std::vector<safe_ptr<core::channel>>& channels) : pChannel_(channels.at(0))\r
46 {\r
47         executor_.start();\r
48 }\r
49 \r
50 void CIIProtocolStrategy::Parse(const TCHAR* pData, int charCount, IO::ClientInfoPtr pClientInfo) \r
51 {\r
52         std::size_t pos;\r
53         std::wstring msg(pData, charCount);\r
54         std::wstring availibleData = currentMessage_ + msg;\r
55 \r
56         while(true)\r
57         {\r
58                 pos = availibleData.find(MessageDelimiter);\r
59                 if(pos != std::wstring::npos)\r
60                 {\r
61                         std::wstring message = availibleData.substr(0,pos);\r
62 \r
63                         if(message.length() > 0) {\r
64                                 ProcessMessage(message);\r
65                                 if(pClientInfo != 0)\r
66                                         pClientInfo->Send(TEXT("*\r\n"));\r
67                         }\r
68 \r
69                         std::size_t nextStartPos = pos + MessageDelimiter.length();\r
70                         if(nextStartPos < availibleData.length())\r
71                                 availibleData = availibleData.substr(nextStartPos);\r
72                         else \r
73                         {\r
74                                 availibleData.clear();\r
75                                 break;\r
76                         }\r
77                 }\r
78                 else\r
79                         break;\r
80         }\r
81         currentMessage_ = availibleData;\r
82 }\r
83 \r
84 void CIIProtocolStrategy::ProcessMessage(const std::wstring& message)\r
85 {\r
86         CASPAR_LOG(debug) << message.c_str();\r
87 \r
88         std::vector<std::wstring> tokens;\r
89         int tokenCount = TokenizeMessage(message, &tokens);\r
90 \r
91         CIICommandPtr pCommand = Create(tokens[0]);\r
92         if((pCommand != 0) && (tokenCount-1) >= pCommand->GetMinimumParameters()) \r
93         {\r
94                 pCommand->Setup(tokens);\r
95                 executor_.begin_invoke([=]{pCommand->Execute();});\r
96         }\r
97         else {} //report error  \r
98 }\r
99 \r
100 int CIIProtocolStrategy::TokenizeMessage(const std::wstring& message, std::vector<std::wstring>* pTokenVector)\r
101 {\r
102         std::wstringstream currentToken;\r
103 \r
104         for(unsigned int charIndex=0; charIndex<message.size(); ++charIndex) \r
105         {\r
106                 if(message[charIndex] == TokenDelimiter) \r
107                 {\r
108                         pTokenVector->push_back(currentToken.str());\r
109                         currentToken.str(TEXT(""));\r
110                         continue;\r
111                 }\r
112 \r
113                 if(message[charIndex] == TEXT('\"')) \r
114                         currentToken << TEXT("&quot;");         \r
115                 else if(message[charIndex] == TEXT('<')) \r
116                         currentToken << TEXT("&lt;");           \r
117                 else if(message[charIndex] == TEXT('>')) \r
118                         currentToken << TEXT("&gt;");           \r
119                 else \r
120                         currentToken << message[charIndex];\r
121         }\r
122 \r
123         if(currentToken.str().size() > 0)\r
124                 pTokenVector->push_back(currentToken.str());    \r
125 \r
126         return (int)pTokenVector->size();\r
127 }\r
128 \r
129 /************\r
130 // Examples (<X> = ASCIICHAR X)\r
131 \r
132 I\25\3\VII\\                                                                    sätter outputtype till 'vii'\r
133 I\25\4\1\\                                                                              enablar framebuffer (ignore this)\r
134 \r
135 M\C/SVTNEWS\\                                                                   pekar ut vilken grafisk profil som skall användas\r
136 \r
137 W\4009\4067\Jonas Björkman\\                                    Skriver "Jonas Björkman" till första textfältet i template 4067 och sparar den färdiga skylten som 4009\r
138 \r
139 T\7\4009.VII\A\\                                                                lägger ut skylt 4009\r
140 \r
141 Y\<205><247><202><196><192><192><200><248>\\    lägger ut skylten 4008 (<205><247><202><196><192><192><200><248> = "=g:4008h" om man drar bort 144 från varje asciivärde)\r
142 \r
143 V\5\3\1\1\namn.tga\1\\                                                  lägger ut bilden namn.tga\r
144 V\0\1\D\C\10\0\0\0\\                                                    gör någon inställning som har med föregående kommando att göra.\r
145 \r
146 *************/\r
147 \r
148 /**********************\r
149 New Commands to support the Netupe automation system\r
150 V\5\13\1\1\Template\0\TabField1\TabField2...\\          Build. Ettan före Template indikerar vilket lager den nya templaten skall laddas in i. OBS. Skall inte visas efter det här steget\r
151 Y\<27>\\                                                                                        Stop. Här kommer ett lagerID också att skickas med (<27> = ESC)\r
152 Y\<254>\\                                                                                       Clear Canvas. Här kommer ett lagerID också att skickas med, utan det skall allt tömmas\r
153 Y\<213><243>\\                                                                          Play. Här kommer ett lagerID också att skickas med\r
154 \r
155 **********************/\r
156 CIICommandPtr CIIProtocolStrategy::Create(const std::wstring& name)\r
157 {\r
158         switch(name[0])\r
159         {\r
160                 case TEXT('M'): return std::make_shared<MediaCommand>(this);\r
161                 case TEXT('W'): return std::make_shared<WriteCommand>(this);\r
162                 case TEXT('T'): return std::make_shared<ImagestoreCommand>(this);\r
163                 case TEXT('V'): return std::make_shared<MiscellaneousCommand>(this);\r
164                 case TEXT('Y'): return std::make_shared<KeydataCommand>(this);\r
165                 default:                return nullptr;\r
166         }\r
167 }\r
168 \r
169 void CIIProtocolStrategy::WriteTemplateData(const std::wstring& templateName, const std::wstring& titleName, const std::wstring& xmlData) \r
170 {\r
171         std::wstring fullTemplateFilename = env::template_folder();\r
172         if(currentProfile_.size() > 0)\r
173         {\r
174                 fullTemplateFilename += currentProfile_;\r
175                 fullTemplateFilename += TEXT("\\");\r
176         }\r
177         fullTemplateFilename += templateName;\r
178         fullTemplateFilename = core::flash::flash_producer::find_template(fullTemplateFilename);\r
179         if(fullTemplateFilename.empty())\r
180         {\r
181                 CASPAR_LOG(error) << "Failed to save instance of " << templateName << TEXT(" as ") << titleName << TEXT(", template ") << fullTemplateFilename << " not found";\r
182                 return;\r
183         }\r
184         \r
185         auto producer = core::flash::flash_producer(env::template_folder()+TEXT("CG.fth"));\r
186 \r
187         std::wstringstream flashParam;\r
188         flashParam << TEXT("<invoke name=\"Add\" returntype=\"xml\"><arguments><number>1</number><string>") << currentProfile_ << '/' <<  templateName << TEXT("</string><number>0</number><true/><string> </string><string><![CDATA[ ") << xmlData << TEXT(" ]]></string></arguments></invoke>");\r
189         producer.param(flashParam.str());\r
190 \r
191         CASPAR_LOG(info) << "Saved an instance of " << templateName << TEXT(" as ") << titleName ;\r
192 \r
193         PutPreparedTemplate(titleName, safe_ptr<core::frame_producer>(std::move(producer)));\r
194         \r
195 }\r
196 \r
197 void CIIProtocolStrategy::DisplayTemplate(const std::wstring& titleName)\r
198 {\r
199         try\r
200         {\r
201                 pChannel_->load(0, GetPreparedTemplate(titleName));\r
202                 pChannel_->play(0);\r
203 \r
204                 CASPAR_LOG(info) << L"Displayed title " << titleName ;\r
205         }\r
206         catch(caspar_exception&)\r
207         {\r
208                 CASPAR_LOG(error) << L"Failed to display title " << titleName;\r
209         }\r
210 }\r
211 \r
212 void CIIProtocolStrategy::DisplayMediaFile(const std::wstring& filename) \r
213 {\r
214         transition_info transition;\r
215         transition.type = transition::mix;\r
216         transition.duration = 12;\r
217 \r
218         auto pFP = create_producer(boost::assign::list_of(filename));\r
219         auto pTransition = safe_ptr<core::frame_producer>(transition_producer(pFP, transition));\r
220 \r
221         try\r
222         {\r
223                 pChannel_->load(0, pTransition);\r
224         }\r
225         catch(...)\r
226         {\r
227                 CASPAR_LOG_CURRENT_EXCEPTION();\r
228                 CASPAR_LOG(error) << L"Failed to display " << filename ;\r
229                 return;\r
230         }\r
231 \r
232         pChannel_->play(0);\r
233 \r
234         CASPAR_LOG(info) << L"Displayed " << filename;\r
235 }\r
236 \r
237 safe_ptr<core::frame_producer> CIIProtocolStrategy::GetPreparedTemplate(const std::wstring& titleName)\r
238 {\r
239         safe_ptr<core::frame_producer> result(frame_producer::empty());\r
240 \r
241         TitleList::iterator it = std::find(titles_.begin(), titles_.end(), titleName);\r
242         if(it != titles_.end()) {\r
243                 CASPAR_LOG(debug) << L"Found title with name " << it->titleName;\r
244                 result = (*it).pframe_producer;\r
245         }\r
246         else \r
247                 CASPAR_LOG(error) << L"Could not find title with name " << titleName;\r
248 \r
249         return result;\r
250 }\r
251 \r
252 void CIIProtocolStrategy::PutPreparedTemplate(const std::wstring& titleName, safe_ptr<core::frame_producer>& pFP)\r
253 {\r
254         CASPAR_LOG(debug) << L"Saved title with name " << titleName;\r
255 \r
256         TitleList::iterator it = std::find(titles_.begin(), titles_.end(), titleName);\r
257         if(it != titles_.end()) {\r
258                 titles_.remove((*it));\r
259         }\r
260 \r
261         titles_.push_front(TitleHolder(titleName, pFP));\r
262 \r
263         if(titles_.size() >= 6)\r
264                 titles_.resize(5);\r
265 }\r
266 \r
267 bool operator==(const CIIProtocolStrategy::TitleHolder& lhs, const std::wstring& rhs) \r
268 {\r
269         return lhs.titleName == rhs;\r
270 }\r
271 \r
272 bool operator==(const std::wstring& lhs, const CIIProtocolStrategy::TitleHolder& rhs)\r
273 {\r
274         return lhs == rhs.titleName;\r
275 }\r
276 \r
277 }}}\r