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