2 * Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
4 * This file is part of CasparCG (www.casparcg.com).
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.
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.
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/>.
19 * Author: Nicklas P Andersson
23 #include "../StdAfx.h"
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 <core/diagnostics/call_context.h>
34 #include <common/env.h>
36 #include <boost/algorithm/string/replace.hpp>
39 #pragma warning (push, 1) // TODO: Legacy code, just disable warnings
42 namespace caspar { namespace protocol { namespace cii {
46 const std::wstring CIIProtocolStrategy::MessageDelimiter = L"\r\n";
47 const wchar_t CIIProtocolStrategy::TokenDelimiter = L'\\';
49 CIIProtocolStrategy::CIIProtocolStrategy(const std::vector<spl::shared_ptr<core::video_channel>>& channels) : pChannel_(channels.at(0)), executor_(L"CIIProtocolStrategy")
53 //The paser method expects message to be complete messages with the delimiter stripped away.
54 //Thesefore the AMCPProtocolStrategy should be decorated with a delimiter_based_chunking_strategy
55 void CIIProtocolStrategy::Parse(const std::wstring& message, IO::ClientInfoPtr client)
57 if(message.length() > 0)
59 ProcessMessage(message, client);
60 client->send(std::wstring(L"*\r\n"));
64 void CIIProtocolStrategy::ProcessMessage(const std::wstring& message, IO::ClientInfoPtr pClientInfo)
66 CASPAR_LOG(info) << L"Received message from " << pClientInfo->print() << ": " << message << L"\\r\\n";
68 std::vector<std::wstring> tokens;
69 int tokenCount = TokenizeMessage(message, &tokens);
71 CIICommandPtr pCommand = Create(tokens[0]);
72 if((pCommand != 0) && (tokenCount-1) >= pCommand->GetMinimumParameters())
74 pCommand->Setup(tokens);
75 executor_.begin_invoke([=]{pCommand->Execute();});
77 else {} //report error
80 int CIIProtocolStrategy::TokenizeMessage(const std::wstring& message, std::vector<std::wstring>* pTokenVector)
82 std::wstringstream currentToken;
84 for(unsigned int charIndex=0; charIndex<message.size(); ++charIndex)
86 if(message[charIndex] == TokenDelimiter)
88 pTokenVector->push_back(currentToken.str());
89 currentToken.str(TEXT(""));
93 if(message[charIndex] == TEXT('\"'))
94 currentToken << TEXT(""");
95 else if(message[charIndex] == TEXT('<'))
96 currentToken << TEXT("<");
97 else if(message[charIndex] == TEXT('>'))
98 currentToken << TEXT(">");
100 currentToken << message[charIndex];
103 if(currentToken.str().size() > 0)
104 pTokenVector->push_back(currentToken.str());
106 return (int)pTokenVector->size();
110 // Examples (<X> = ASCIICHAR X)
112 I\25\3\VII\\ sätter outputtype till 'vii'
113 I\25\4\1\\ enablar framebuffer (ignore this)
115 M\C/SVTNEWS\\ pekar ut vilken grafisk profil som skall användas
117 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
119 T\7\4009.VII\A\\ lägger ut skylt 4009
121 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)
123 V\5\3\1\1\namn.tga\1\\ lägger ut bilden namn.tga
124 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.
128 /**********************
129 New Commands to support the Netupe automation system
130 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
131 Y\<27>\\ Stop. Här kommer ett lagerID också att skickas med (<27> = ESC)
132 Y\<254>\\ Clear Canvas. Här kommer ett lagerID också att skickas med, utan det skall allt tömmas
133 Y\<213><243>\\ Play. Här kommer ett lagerID också att skickas med
135 **********************/
136 CIICommandPtr CIIProtocolStrategy::Create(const std::wstring& name)
140 case TEXT('M'): return std::make_shared<MediaCommand>(this);
141 case TEXT('W'): return std::make_shared<WriteCommand>(this);
142 case TEXT('T'): return std::make_shared<ImagestoreCommand>(this);
143 case TEXT('V'): return std::make_shared<MiscellaneousCommand>(this);
144 case TEXT('Y'): return std::make_shared<KeydataCommand>(this);
145 default: return nullptr;
149 void CIIProtocolStrategy::WriteTemplateData(const std::wstring& templateName, const std::wstring& titleName, const std::wstring& xmlData)
151 std::wstring fullTemplateFilename = env::template_folder();
152 if(currentProfile_.size() > 0)
154 fullTemplateFilename += currentProfile_;
155 fullTemplateFilename += TEXT("\\");
157 fullTemplateFilename += templateName;
158 fullTemplateFilename = flash::find_template(fullTemplateFilename);
159 if(fullTemplateFilename.empty())
161 CASPAR_LOG(error) << "Failed to save instance of " << templateName << TEXT(" as ") << titleName << TEXT(", template ") << fullTemplateFilename << " not found";
164 core::diagnostics::scoped_call_context save;
165 core::diagnostics::call_context::for_thread().video_channel = 1;
166 core::diagnostics::call_context::for_thread().layer = 0;
168 auto producer = flash::create_producer(this->GetChannel()->frame_factory(), this->GetChannel()->video_format_desc(), { env::template_folder() + TEXT("CG.fth") });
170 std::wstringstream flashParam;
171 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>");
172 std::vector<std::wstring> params;
173 params.push_back(flashParam.str());
174 producer->call(std::move(params));
176 CASPAR_LOG(info) << "Saved an instance of " << templateName << TEXT(" as ") << titleName ;
178 PutPreparedTemplate(titleName, spl::shared_ptr<core::frame_producer>(std::move(producer)));
182 void CIIProtocolStrategy::DisplayTemplate(const std::wstring& titleName)
186 pChannel_->stage().load(0, GetPreparedTemplate(titleName));
187 pChannel_->stage().play(0);
189 CASPAR_LOG(info) << L"Displayed title " << titleName ;
191 catch(caspar_exception&)
193 CASPAR_LOG(error) << L"Failed to display title " << titleName;
197 void CIIProtocolStrategy::DisplayMediaFile(const std::wstring& filename)
199 transition_info transition;
200 transition.type = transition_type::mix;
201 transition.duration = 12;
203 core::diagnostics::scoped_call_context save;
204 core::diagnostics::call_context::for_thread().video_channel = 1;
205 core::diagnostics::call_context::for_thread().layer = 0;
207 auto pFP = create_producer(GetChannel()->frame_factory(), GetChannel()->video_format_desc(), filename);
208 auto pTransition = create_transition_producer(GetChannel()->video_format_desc().field_mode, pFP, transition);
212 pChannel_->stage().load(0, pTransition);
216 CASPAR_LOG_CURRENT_EXCEPTION();
217 CASPAR_LOG(error) << L"Failed to display " << filename ;
221 pChannel_->stage().play(0);
223 CASPAR_LOG(info) << L"Displayed " << filename;
226 spl::shared_ptr<core::frame_producer> CIIProtocolStrategy::GetPreparedTemplate(const std::wstring& titleName)
228 spl::shared_ptr<core::frame_producer> result(frame_producer::empty());
230 TitleList::iterator it = std::find(titles_.begin(), titles_.end(), titleName);
231 if(it != titles_.end()) {
232 CASPAR_LOG(debug) << L"Found title with name " << it->titleName;
233 result = (*it).pframe_producer;
236 CASPAR_LOG(error) << L"Could not find title with name " << titleName;
241 void CIIProtocolStrategy::PutPreparedTemplate(const std::wstring& titleName, spl::shared_ptr<core::frame_producer>& pFP)
243 CASPAR_LOG(debug) << L"Saved title with name " << titleName;
245 TitleList::iterator it = std::find(titles_.begin(), titles_.end(), titleName);
246 if(it != titles_.end()) {
247 titles_.remove((*it));
250 titles_.push_front(TitleHolder(titleName, pFP));
252 if(titles_.size() >= 6)
256 bool operator==(const CIIProtocolStrategy::TitleHolder& lhs, const std::wstring& rhs)
258 return lhs.titleName == rhs;
261 bool operator==(const std::wstring& lhs, const CIIProtocolStrategy::TitleHolder& rhs)
263 return lhs == rhs.titleName;