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)), executor_(L"CIIProtocolStrategy")
\r
47 void CIIProtocolStrategy::Parse(const TCHAR* pData, int charCount, IO::ClientInfoPtr pClientInfo)
\r
50 std::wstring msg(pData, charCount);
\r
51 std::wstring availibleData = currentMessage_ + msg;
\r
55 pos = availibleData.find(MessageDelimiter);
\r
56 if(pos != std::wstring::npos)
\r
58 std::wstring message = availibleData.substr(0,pos);
\r
60 if(message.length() > 0) {
\r
61 ProcessMessage(message);
\r
62 if(pClientInfo != 0)
\r
63 pClientInfo->Send(TEXT("*\r\n"));
\r
66 std::size_t nextStartPos = pos + MessageDelimiter.length();
\r
67 if(nextStartPos < availibleData.length())
\r
68 availibleData = availibleData.substr(nextStartPos);
\r
71 availibleData.clear();
\r
78 currentMessage_ = availibleData;
\r
81 void CIIProtocolStrategy::ProcessMessage(const std::wstring& message)
\r
83 CASPAR_LOG(debug) << message.c_str();
\r
85 std::vector<std::wstring> tokens;
\r
86 int tokenCount = TokenizeMessage(message, &tokens);
\r
88 CIICommandPtr pCommand = Create(tokens[0]);
\r
89 if((pCommand != 0) && (tokenCount-1) >= pCommand->GetMinimumParameters())
\r
91 pCommand->Setup(tokens);
\r
92 executor_.begin_invoke([=]{pCommand->Execute();});
\r
94 else {} //report error
\r
97 int CIIProtocolStrategy::TokenizeMessage(const std::wstring& message, std::vector<std::wstring>* pTokenVector)
\r
99 std::wstringstream currentToken;
\r
101 for(unsigned int charIndex=0; charIndex<message.size(); ++charIndex)
\r
103 if(message[charIndex] == TokenDelimiter)
\r
105 pTokenVector->push_back(currentToken.str());
\r
106 currentToken.str(TEXT(""));
\r
110 if(message[charIndex] == TEXT('\"'))
\r
111 currentToken << TEXT(""");
\r
112 else if(message[charIndex] == TEXT('<'))
\r
113 currentToken << TEXT("<");
\r
114 else if(message[charIndex] == TEXT('>'))
\r
115 currentToken << TEXT(">");
\r
117 currentToken << message[charIndex];
\r
120 if(currentToken.str().size() > 0)
\r
121 pTokenVector->push_back(currentToken.str());
\r
123 return (int)pTokenVector->size();
\r
127 // Examples (<X> = ASCIICHAR X)
\r
129 I\25\3\VII\\ sätter outputtype till 'vii'
\r
130 I\25\4\1\\ enablar framebuffer (ignore this)
\r
132 M\C/SVTNEWS\\ pekar ut vilken grafisk profil som skall användas
\r
134 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 T\7\4009.VII\A\\ lägger ut skylt 4009
\r
138 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 V\5\3\1\1\namn.tga\1\\ lägger ut bilden namn.tga
\r
141 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
145 /**********************
\r
146 New Commands to support the Netupe automation system
\r
147 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
148 Y\<27>\\ Stop. Här kommer ett lagerID också att skickas med (<27> = ESC)
\r
149 Y\<254>\\ Clear Canvas. Här kommer ett lagerID också att skickas med, utan det skall allt tömmas
\r
150 Y\<213><243>\\ Play. Här kommer ett lagerID också att skickas med
\r
152 **********************/
\r
153 CIICommandPtr CIIProtocolStrategy::Create(const std::wstring& name)
\r
157 case TEXT('M'): return std::make_shared<MediaCommand>(this);
\r
158 case TEXT('W'): return std::make_shared<WriteCommand>(this);
\r
159 case TEXT('T'): return std::make_shared<ImagestoreCommand>(this);
\r
160 case TEXT('V'): return std::make_shared<MiscellaneousCommand>(this);
\r
161 case TEXT('Y'): return std::make_shared<KeydataCommand>(this);
\r
162 default: return nullptr;
\r
166 void CIIProtocolStrategy::WriteTemplateData(const std::wstring& templateName, const std::wstring& titleName, const std::wstring& xmlData)
\r
168 std::wstring fullTemplateFilename = env::template_folder();
\r
169 if(currentProfile_.size() > 0)
\r
171 fullTemplateFilename += currentProfile_;
\r
172 fullTemplateFilename += TEXT("\\");
\r
174 fullTemplateFilename += templateName;
\r
175 fullTemplateFilename = find_flash_template(fullTemplateFilename);
\r
176 if(fullTemplateFilename.empty())
\r
178 CASPAR_LOG(error) << "Failed to save instance of " << templateName << TEXT(" as ") << titleName << TEXT(", template ") << fullTemplateFilename << " not found";
\r
182 auto producer = create_flash_producer(this->GetChannel()->mixer(), boost::assign::list_of(env::template_folder()+TEXT("CG.fth")));
\r
184 std::wstringstream flashParam;
\r
185 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
186 producer->param(flashParam.str());
\r
188 CASPAR_LOG(info) << "Saved an instance of " << templateName << TEXT(" as ") << titleName ;
\r
190 PutPreparedTemplate(titleName, safe_ptr<core::frame_producer>(std::move(producer)));
\r
194 void CIIProtocolStrategy::DisplayTemplate(const std::wstring& titleName)
\r
198 pChannel_->producer()->load(0, GetPreparedTemplate(titleName));
\r
199 pChannel_->producer()->play(0);
\r
201 CASPAR_LOG(info) << L"Displayed title " << titleName ;
\r
203 catch(caspar_exception&)
\r
205 CASPAR_LOG(error) << L"Failed to display title " << titleName;
\r
209 void CIIProtocolStrategy::DisplayMediaFile(const std::wstring& filename)
\r
211 transition_info transition;
\r
212 transition.type = transition::mix;
\r
213 transition.duration = 12;
\r
215 auto pFP = create_producer(GetChannel()->mixer(), boost::assign::list_of(filename));
\r
216 auto pTransition = create_transition_producer(GetChannel()->get_video_format_desc().mode, pFP, transition);
\r
220 pChannel_->producer()->load(0, pTransition);
\r
224 CASPAR_LOG_CURRENT_EXCEPTION();
\r
225 CASPAR_LOG(error) << L"Failed to display " << filename ;
\r
229 pChannel_->producer()->play(0);
\r
231 CASPAR_LOG(info) << L"Displayed " << filename;
\r
234 safe_ptr<core::frame_producer> CIIProtocolStrategy::GetPreparedTemplate(const std::wstring& titleName)
\r
236 safe_ptr<core::frame_producer> result(frame_producer::empty());
\r
238 TitleList::iterator it = std::find(titles_.begin(), titles_.end(), titleName);
\r
239 if(it != titles_.end()) {
\r
240 CASPAR_LOG(debug) << L"Found title with name " << it->titleName;
\r
241 result = (*it).pframe_producer;
\r
244 CASPAR_LOG(error) << L"Could not find title with name " << titleName;
\r
249 void CIIProtocolStrategy::PutPreparedTemplate(const std::wstring& titleName, safe_ptr<core::frame_producer>& pFP)
\r
251 CASPAR_LOG(debug) << L"Saved title with name " << titleName;
\r
253 TitleList::iterator it = std::find(titles_.begin(), titles_.end(), titleName);
\r
254 if(it != titles_.end()) {
\r
255 titles_.remove((*it));
\r
258 titles_.push_front(TitleHolder(titleName, pFP));
\r
260 if(titles_.size() >= 6)
\r
264 bool operator==(const CIIProtocolStrategy::TitleHolder& lhs, const std::wstring& rhs)
\r
266 return lhs.titleName == rhs;
\r
269 bool operator==(const std::wstring& lhs, const CIIProtocolStrategy::TitleHolder& rhs)
\r
271 return lhs == rhs.titleName;
\r