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