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