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 <core/producer/transition/transition_producer.h>
31 #include <core/mixer/mixer.h>
32 #include <core/diagnostics/call_context.h>
33 #include <common/env.h>
35 #include <boost/algorithm/string/replace.hpp>
38 #pragma warning (push, 1) // TODO: Legacy code, just disable warnings
41 namespace caspar { namespace protocol { namespace cii {
45 const std::wstring CIIProtocolStrategy::MessageDelimiter = L"\r\n";
46 const wchar_t CIIProtocolStrategy::TokenDelimiter = L'\\';
48 CIIProtocolStrategy::CIIProtocolStrategy(
49 const std::vector<spl::shared_ptr<core::video_channel>>& channels,
50 const spl::shared_ptr<core::cg_producer_registry>& cg_registry,
51 const spl::shared_ptr<const core::frame_producer_registry>& producer_registry)
52 : executor_(L"CIIProtocolStrategy")
53 , pChannel_(channels.at(0))
55 , cg_registry_(cg_registry)
56 , producer_registry_(producer_registry)
60 //The paser method expects message to be complete messages with the delimiter stripped away.
61 //Thesefore the AMCPProtocolStrategy should be decorated with a delimiter_based_chunking_strategy
62 void CIIProtocolStrategy::Parse(const std::wstring& message, IO::ClientInfoPtr client)
64 if(message.length() > 0)
66 ProcessMessage(message, client);
67 client->send(std::wstring(L"*\r\n"));
71 void CIIProtocolStrategy::ProcessMessage(const std::wstring& message, IO::ClientInfoPtr pClientInfo)
73 CASPAR_LOG(info) << L"Received message from " << pClientInfo->address() << ": " << message << L"\\r\\n";
75 std::vector<std::wstring> tokens;
76 int tokenCount = TokenizeMessage(message, &tokens);
78 CIICommandPtr pCommand = Create(tokens[0]);
79 if((pCommand != 0) && (tokenCount-1) >= pCommand->GetMinimumParameters())
81 pCommand->Setup(tokens);
82 executor_.begin_invoke([=]{pCommand->Execute();});
84 else {} //report error
87 int CIIProtocolStrategy::TokenizeMessage(const std::wstring& message, std::vector<std::wstring>* pTokenVector)
89 std::wstringstream currentToken;
91 for(unsigned int charIndex=0; charIndex<message.size(); ++charIndex)
93 if(message[charIndex] == TokenDelimiter)
95 pTokenVector->push_back(currentToken.str());
96 currentToken.str(L"");
100 if(message[charIndex] == L'\"')
101 currentToken << L""";
102 else if(message[charIndex] == L'<')
103 currentToken << L"<";
104 else if(message[charIndex] == L'>')
105 currentToken << L">";
107 currentToken << message[charIndex];
110 if(currentToken.str().size() > 0)
111 pTokenVector->push_back(currentToken.str());
113 return (int)pTokenVector->size();
117 // Examples (<X> = ASCIICHAR X)
119 I\25\3\VII\\ s�tter outputtype till 'vii'
120 I\25\4\1\\ enablar framebuffer (ignore this)
122 M\C/SVTNEWS\\ pekar ut vilken grafisk profil som skall anv�ndas
124 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
126 T\7\4009.VII\A\\ l�gger ut skylt 4009
128 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)
130 V\5\3\1\1\namn.tga\1\\ l�gger ut bilden namn.tga
131 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.
135 /**********************
136 New Commands to support the Netupe automation system
137 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
138 Y\<27>\\ Stop. H�r kommer ett lagerID ocks� att skickas med (<27> = ESC)
139 Y\<254>\\ Clear Canvas. H�r kommer ett lagerID ocks� att skickas med, utan det skall allt t�mmas
140 Y\<213><243>\\ Play. H�r kommer ett lagerID ocks� att skickas med
142 **********************/
143 CIICommandPtr CIIProtocolStrategy::Create(const std::wstring& name)
147 case L'M': return std::make_shared<MediaCommand>(this);
148 case L'W': return std::make_shared<WriteCommand>(this);
149 case L'T': return std::make_shared<ImagestoreCommand>(this);
150 case L'V': return std::make_shared<MiscellaneousCommand>(this);
151 case L'Y': return std::make_shared<KeydataCommand>(this);
152 default: return nullptr;
156 void CIIProtocolStrategy::WriteTemplateData(const std::wstring& templateName, const std::wstring& titleName, const std::wstring& xmlData)
158 std::wstring fullTemplateFilename = templateName;
160 if (!currentProfile_.empty())
161 fullTemplateFilename = currentProfile_ + L"/" + templateName;
163 core::diagnostics::scoped_call_context save;
164 core::diagnostics::call_context::for_thread().video_channel = 1;
165 core::diagnostics::call_context::for_thread().layer = 0;
166 auto producer = cg_registry_->create_producer(get_dependencies(), fullTemplateFilename);
168 if (producer == core::frame_producer::empty())
170 CASPAR_LOG(error) << "Failed to save instance of " << templateName << L" as " << titleName << L", template " << fullTemplateFilename << L"not found";
174 cg_registry_->get_proxy(producer)->add(1, fullTemplateFilename, true, L"", xmlData);
176 CASPAR_LOG(info) << "Saved an instance of " << templateName << L" 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 = get_producer_registry()->create_producer(get_dependencies(), 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(info) << 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, const spl::shared_ptr<core::frame_producer>& pFP)
243 CASPAR_LOG(info) << 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;