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