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 "../media.h"
\r
27 #include "CIIProtocolStrategy.h"
\r
28 #include "CIICommandsimpl.h"
\r
29 #include <core/producer/flash/flash_producer.h>
\r
30 #include <core/producer/transition/transition_producer.h>
\r
31 #include <core/producer/frame_producer.h>
\r
32 #include <common/env.h>
\r
34 #if defined(_MSC_VER)
\r
35 #pragma warning (push, 1) // TODO: Legacy code, just disable warnings
\r
38 namespace caspar { namespace protocol { namespace cii {
\r
40 using namespace core;
\r
42 const std::wstring CIIProtocolStrategy::MessageDelimiter = TEXT("\r\n");
\r
43 const TCHAR CIIProtocolStrategy::TokenDelimiter = TEXT('\\');
\r
45 CIIProtocolStrategy::CIIProtocolStrategy(const std::vector<safe_ptr<core::channel>>& channels) : pChannel_(channels.at(0))
\r
50 void CIIProtocolStrategy::Parse(const TCHAR* pData, int charCount, IO::ClientInfoPtr pClientInfo)
\r
53 std::wstring msg(pData, charCount);
\r
54 std::wstring availibleData = currentMessage_ + msg;
\r
58 pos = availibleData.find(MessageDelimiter);
\r
59 if(pos != std::wstring::npos)
\r
61 std::wstring message = availibleData.substr(0,pos);
\r
63 if(message.length() > 0) {
\r
64 ProcessMessage(message);
\r
65 if(pClientInfo != 0)
\r
66 pClientInfo->Send(TEXT("*\r\n"));
\r
69 std::size_t nextStartPos = pos + MessageDelimiter.length();
\r
70 if(nextStartPos < availibleData.length())
\r
71 availibleData = availibleData.substr(nextStartPos);
\r
74 availibleData.clear();
\r
81 currentMessage_ = availibleData;
\r
84 void CIIProtocolStrategy::ProcessMessage(const std::wstring& message)
\r
86 CASPAR_LOG(debug) << message.c_str();
\r
88 std::vector<std::wstring> tokens;
\r
89 int tokenCount = TokenizeMessage(message, &tokens);
\r
91 CIICommandPtr pCommand = Create(tokens[0]);
\r
92 if((pCommand != 0) && (tokenCount-1) >= pCommand->GetMinimumParameters())
\r
94 pCommand->Setup(tokens);
\r
95 executor_.begin_invoke([=]{pCommand->Execute();});
\r
97 else {} //report error
\r
100 int CIIProtocolStrategy::TokenizeMessage(const std::wstring& message, std::vector<std::wstring>* pTokenVector)
\r
102 std::wstringstream currentToken;
\r
104 for(unsigned int charIndex=0; charIndex<message.size(); ++charIndex)
\r
106 if(message[charIndex] == TokenDelimiter)
\r
108 pTokenVector->push_back(currentToken.str());
\r
109 currentToken.str(TEXT(""));
\r
113 if(message[charIndex] == TEXT('\"'))
\r
114 currentToken << TEXT(""");
\r
115 else if(message[charIndex] == TEXT('<'))
\r
116 currentToken << TEXT("<");
\r
117 else if(message[charIndex] == TEXT('>'))
\r
118 currentToken << TEXT(">");
\r
120 currentToken << message[charIndex];
\r
123 if(currentToken.str().size() > 0)
\r
124 pTokenVector->push_back(currentToken.str());
\r
126 return (int)pTokenVector->size();
\r
130 // Examples (<X> = ASCIICHAR X)
\r
132 I\25\3\VII\\ sätter outputtype till 'vii'
\r
133 I\25\4\1\\ enablar framebuffer (ignore this)
\r
135 M\C/SVTNEWS\\ pekar ut vilken grafisk profil som skall användas
\r
137 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
139 T\7\4009.VII\A\\ lägger ut skylt 4009
\r
141 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
143 V\5\3\1\1\namn.tga\1\\ lägger ut bilden namn.tga
\r
144 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
148 /**********************
\r
149 New Commands to support the Netupe automation system
\r
150 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
151 Y\<27>\\ Stop. Här kommer ett lagerID också att skickas med (<27> = ESC)
\r
152 Y\<254>\\ Clear Canvas. Här kommer ett lagerID också att skickas med, utan det skall allt tömmas
\r
153 Y\<213><243>\\ Play. Här kommer ett lagerID också att skickas med
\r
155 **********************/
\r
156 CIICommandPtr CIIProtocolStrategy::Create(const std::wstring& name)
\r
160 case TEXT('M'): return std::make_shared<MediaCommand>(this);
\r
161 case TEXT('W'): return std::make_shared<WriteCommand>(this);
\r
162 case TEXT('T'): return std::make_shared<ImagestoreCommand>(this);
\r
163 case TEXT('V'): return std::make_shared<MiscellaneousCommand>(this);
\r
164 case TEXT('Y'): return std::make_shared<KeydataCommand>(this);
\r
165 default: return nullptr;
\r
169 void CIIProtocolStrategy::WriteTemplateData(const std::wstring& templateName, const std::wstring& titleName, const std::wstring& xmlData)
\r
171 std::wstring fullTemplateFilename = env::template_folder();
\r
172 if(currentProfile_.size() > 0)
\r
174 fullTemplateFilename += currentProfile_;
\r
175 fullTemplateFilename += TEXT("\\");
\r
177 fullTemplateFilename += templateName;
\r
178 fullTemplateFilename = core::flash::flash_producer::find_template(fullTemplateFilename);
\r
179 if(fullTemplateFilename.empty())
\r
181 CASPAR_LOG(error) << "Failed to save instance of " << templateName << TEXT(" as ") << titleName << TEXT(", template ") << fullTemplateFilename << " not found";
\r
185 auto producer = core::flash::flash_producer(env::template_folder()+TEXT("CG.fth"));
\r
187 std::wstringstream flashParam;
\r
188 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
189 producer.param(flashParam.str());
\r
191 CASPAR_LOG(info) << "Saved an instance of " << templateName << TEXT(" as ") << titleName ;
\r
193 PutPreparedTemplate(titleName, safe_ptr<core::frame_producer>(std::move(producer)));
\r
197 void CIIProtocolStrategy::DisplayTemplate(const std::wstring& titleName)
\r
201 pChannel_->load(0, GetPreparedTemplate(titleName));
\r
202 pChannel_->play(0);
\r
204 CASPAR_LOG(info) << L"Displayed title " << titleName ;
\r
206 catch(caspar_exception&)
\r
208 CASPAR_LOG(error) << L"Failed to display title " << titleName;
\r
212 void CIIProtocolStrategy::DisplayMediaFile(const std::wstring& filename)
\r
214 transition_info transition;
\r
215 transition.type = transition::mix;
\r
216 transition.duration = 12;
\r
218 auto pFP = create_producer(boost::assign::list_of(filename));
\r
219 auto pTransition = safe_ptr<core::frame_producer>(transition_producer(pFP, transition));
\r
223 pChannel_->load(0, pTransition);
\r
227 CASPAR_LOG_CURRENT_EXCEPTION();
\r
228 CASPAR_LOG(error) << L"Failed to display " << filename ;
\r
232 pChannel_->play(0);
\r
234 CASPAR_LOG(info) << L"Displayed " << filename;
\r
237 safe_ptr<core::frame_producer> CIIProtocolStrategy::GetPreparedTemplate(const std::wstring& titleName)
\r
239 safe_ptr<core::frame_producer> result(frame_producer::empty());
\r
241 TitleList::iterator it = std::find(titles_.begin(), titles_.end(), titleName);
\r
242 if(it != titles_.end()) {
\r
243 CASPAR_LOG(debug) << L"Found title with name " << it->titleName;
\r
244 result = (*it).pframe_producer;
\r
247 CASPAR_LOG(error) << L"Could not find title with name " << titleName;
\r
252 void CIIProtocolStrategy::PutPreparedTemplate(const std::wstring& titleName, safe_ptr<core::frame_producer>& pFP)
\r
254 CASPAR_LOG(debug) << L"Saved title with name " << titleName;
\r
256 TitleList::iterator it = std::find(titles_.begin(), titles_.end(), titleName);
\r
257 if(it != titles_.end()) {
\r
258 titles_.remove((*it));
\r
261 titles_.push_front(TitleHolder(titleName, pFP));
\r
263 if(titles_.size() >= 6)
\r
267 bool operator==(const CIIProtocolStrategy::TitleHolder& lhs, const std::wstring& rhs)
\r
269 return lhs.titleName == rhs;
\r
272 bool operator==(const std::wstring& lhs, const CIIProtocolStrategy::TitleHolder& rhs)
\r
274 return lhs == rhs.titleName;
\r