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