2 * copyright (c) 2010 Sveriges Television AB <info@casparcg.com>
\r
4 * This file is part of CasparCG.
\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
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
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
21 #include "../StdAfx.h"
\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
33 #if defined(_MSC_VER)
\r
34 #pragma warning (push, 1) // TODO: Legacy code, just disable warnings
\r
37 namespace caspar { namespace protocol { namespace cii {
\r
39 using namespace core;
\r
41 const std::wstring CIIProtocolStrategy::MessageDelimiter = TEXT("\r\n");
\r
42 const TCHAR CIIProtocolStrategy::TokenDelimiter = TEXT('\\');
\r
44 CIIProtocolStrategy::CIIProtocolStrategy(const std::vector<safe_ptr<core::channel>>& channels) : pChannel_(channels.at(0))
\r
49 void CIIProtocolStrategy::Parse(const TCHAR* pData, int charCount, IO::ClientInfoPtr pClientInfo)
\r
52 std::wstring msg(pData, charCount);
\r
53 std::wstring availibleData = currentMessage_ + msg;
\r
57 pos = availibleData.find(MessageDelimiter);
\r
58 if(pos != std::wstring::npos)
\r
60 std::wstring message = availibleData.substr(0,pos);
\r
62 if(message.length() > 0) {
\r
63 ProcessMessage(message);
\r
64 if(pClientInfo != 0)
\r
65 pClientInfo->Send(TEXT("*\r\n"));
\r
68 std::size_t nextStartPos = pos + MessageDelimiter.length();
\r
69 if(nextStartPos < availibleData.length())
\r
70 availibleData = availibleData.substr(nextStartPos);
\r
73 availibleData.clear();
\r
80 currentMessage_ = availibleData;
\r
83 void CIIProtocolStrategy::ProcessMessage(const std::wstring& message)
\r
85 CASPAR_LOG(debug) << message.c_str();
\r
87 std::vector<std::wstring> tokens;
\r
88 int tokenCount = TokenizeMessage(message, &tokens);
\r
90 CIICommandPtr pCommand = Create(tokens[0]);
\r
91 if((pCommand != 0) && (tokenCount-1) >= pCommand->GetMinimumParameters())
\r
93 pCommand->Setup(tokens);
\r
94 executor_.begin_invoke([=]{pCommand->Execute();});
\r
96 else {} //report error
\r
99 int CIIProtocolStrategy::TokenizeMessage(const std::wstring& message, std::vector<std::wstring>* pTokenVector)
\r
101 std::wstringstream currentToken;
\r
103 for(unsigned int charIndex=0; charIndex<message.size(); ++charIndex)
\r
105 if(message[charIndex] == TokenDelimiter)
\r
107 pTokenVector->push_back(currentToken.str());
\r
108 currentToken.str(TEXT(""));
\r
112 if(message[charIndex] == TEXT('\"'))
\r
113 currentToken << TEXT(""");
\r
114 else if(message[charIndex] == TEXT('<'))
\r
115 currentToken << TEXT("<");
\r
116 else if(message[charIndex] == TEXT('>'))
\r
117 currentToken << TEXT(">");
\r
119 currentToken << message[charIndex];
\r
122 if(currentToken.str().size() > 0)
\r
123 pTokenVector->push_back(currentToken.str());
\r
125 return (int)pTokenVector->size();
\r
129 // Examples (<X> = ASCIICHAR X)
\r
131 I\25\3\VII\\ sätter outputtype till 'vii'
\r
132 I\25\4\1\\ enablar framebuffer (ignore this)
\r
134 M\C/SVTNEWS\\ pekar ut vilken grafisk profil som skall användas
\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
138 T\7\4009.VII\A\\ lägger ut skylt 4009
\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
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
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
154 **********************/
\r
155 CIICommandPtr CIIProtocolStrategy::Create(const std::wstring& name)
\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
168 void CIIProtocolStrategy::WriteTemplateData(const std::wstring& templateName, const std::wstring& titleName, const std::wstring& xmlData)
\r
170 std::wstring fullTemplateFilename = env::template_folder();
\r
171 if(currentProfile_.size() > 0)
\r
173 fullTemplateFilename += currentProfile_;
\r
174 fullTemplateFilename += TEXT("\\");
\r
176 fullTemplateFilename += templateName;
\r
177 fullTemplateFilename = flash_producer::find_template(fullTemplateFilename);
\r
178 if(fullTemplateFilename.empty())
\r
180 CASPAR_LOG(error) << "Failed to save instance of " << templateName << TEXT(" as ") << titleName << TEXT(", template ") << fullTemplateFilename << " not found";
\r
184 auto producer = flash_producer(env::template_folder()+TEXT("CG.fth"));
\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
190 CASPAR_LOG(info) << "Saved an instance of " << templateName << TEXT(" as ") << titleName ;
\r
192 PutPreparedTemplate(titleName, safe_ptr<core::frame_producer>(std::move(producer)));
\r
196 void CIIProtocolStrategy::DisplayTemplate(const std::wstring& titleName)
\r
200 pChannel_->producer().load(0, GetPreparedTemplate(titleName));
\r
201 pChannel_->producer().play(0);
\r
203 CASPAR_LOG(info) << L"Displayed title " << titleName ;
\r
205 catch(caspar_exception&)
\r
207 CASPAR_LOG(error) << L"Failed to display title " << titleName;
\r
211 void CIIProtocolStrategy::DisplayMediaFile(const std::wstring& filename)
\r
213 transition_info transition;
\r
214 transition.type = transition::mix;
\r
215 transition.duration = 12;
\r
217 auto pFP = create_producer(boost::assign::list_of(filename));
\r
218 auto pTransition = make_safe<core::transition_producer>(pFP, transition);
\r
222 pChannel_->producer().load(0, pTransition);
\r
226 CASPAR_LOG_CURRENT_EXCEPTION();
\r
227 CASPAR_LOG(error) << L"Failed to display " << filename ;
\r
231 pChannel_->producer().play(0);
\r
233 CASPAR_LOG(info) << L"Displayed " << filename;
\r
236 safe_ptr<core::frame_producer> CIIProtocolStrategy::GetPreparedTemplate(const std::wstring& titleName)
\r
238 safe_ptr<core::frame_producer> result(frame_producer::empty());
\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
246 CASPAR_LOG(error) << L"Could not find title with name " << titleName;
\r
251 void CIIProtocolStrategy::PutPreparedTemplate(const std::wstring& titleName, safe_ptr<core::frame_producer>& pFP)
\r
253 CASPAR_LOG(debug) << L"Saved title with name " << titleName;
\r
255 TitleList::iterator it = std::find(titles_.begin(), titles_.end(), titleName);
\r
256 if(it != titles_.end()) {
\r
257 titles_.remove((*it));
\r
260 titles_.push_front(TitleHolder(titleName, pFP));
\r
262 if(titles_.size() >= 6)
\r
266 bool operator==(const CIIProtocolStrategy::TitleHolder& lhs, const std::wstring& rhs)
\r
268 return lhs.titleName == rhs;
\r
271 bool operator==(const std::wstring& lhs, const CIIProtocolStrategy::TitleHolder& rhs)
\r
273 return lhs == rhs.titleName;
\r