-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Nicklas P Andersson\r
-*/\r
-\r
- \r
-#include "../StdAfx.h"\r
-\r
-#include <string>\r
-#include <sstream>\r
-#include <algorithm>\r
-#include "CIIProtocolStrategy.h"\r
-#include "CIICommandsimpl.h"\r
-#include <modules/flash/producer/flash_producer.h>\r
-#include <core/producer/transition/transition_producer.h>\r
-#include <core/mixer/mixer.h>\r
-#include <common/env.h>\r
-\r
-#if defined(_MSC_VER)\r
-#pragma warning (push, 1) // TODO: Legacy code, just disable warnings\r
-#endif\r
-\r
-namespace caspar { namespace protocol { namespace cii {\r
- \r
-using namespace core;\r
-\r
-const std::wstring CIIProtocolStrategy::MessageDelimiter = TEXT("\r\n");\r
-const TCHAR CIIProtocolStrategy::TokenDelimiter = TEXT('\\');\r
-\r
-CIIProtocolStrategy::CIIProtocolStrategy(const std::vector<safe_ptr<core::video_channel>>& channels) : pChannel_(channels.at(0)), executor_("CIIProtocolStrategy")\r
-{\r
-}\r
-\r
-void CIIProtocolStrategy::Parse(const TCHAR* pData, int charCount, IO::ClientInfoPtr pClientInfo) \r
-{\r
- std::size_t pos;\r
- std::wstring msg(pData, charCount);\r
- std::wstring availibleData = currentMessage_ + msg;\r
-\r
- while(true)\r
- {\r
- pos = availibleData.find(MessageDelimiter);\r
- if(pos != std::wstring::npos)\r
- {\r
- std::wstring message = availibleData.substr(0,pos);\r
-\r
- if(message.length() > 0) {\r
- ProcessMessage(message);\r
- if(pClientInfo != 0)\r
- pClientInfo->Send(TEXT("*\r\n"));\r
- }\r
-\r
- std::size_t nextStartPos = pos + MessageDelimiter.length();\r
- if(nextStartPos < availibleData.length())\r
- availibleData = availibleData.substr(nextStartPos);\r
- else \r
- {\r
- availibleData.clear();\r
- break;\r
- }\r
- }\r
- else\r
- break;\r
- }\r
- currentMessage_ = availibleData;\r
-}\r
-\r
-void CIIProtocolStrategy::ProcessMessage(const std::wstring& message)\r
-{\r
- CASPAR_LOG(debug) << message.c_str();\r
-\r
- std::vector<std::wstring> tokens;\r
- int tokenCount = TokenizeMessage(message, &tokens);\r
-\r
- CIICommandPtr pCommand = Create(tokens[0]);\r
- if((pCommand != 0) && (tokenCount-1) >= pCommand->GetMinimumParameters()) \r
- {\r
- pCommand->Setup(tokens);\r
- executor_.begin_invoke([=]{pCommand->Execute();});\r
- }\r
- else {} //report error \r
-}\r
-\r
-int CIIProtocolStrategy::TokenizeMessage(const std::wstring& message, std::vector<std::wstring>* pTokenVector)\r
-{\r
- std::wstringstream currentToken;\r
-\r
- for(unsigned int charIndex=0; charIndex<message.size(); ++charIndex) \r
- {\r
- if(message[charIndex] == TokenDelimiter) \r
- {\r
- pTokenVector->push_back(currentToken.str());\r
- currentToken.str(TEXT(""));\r
- continue;\r
- }\r
-\r
- if(message[charIndex] == TEXT('\"')) \r
- currentToken << TEXT("""); \r
- else if(message[charIndex] == TEXT('<')) \r
- currentToken << TEXT("<"); \r
- else if(message[charIndex] == TEXT('>')) \r
- currentToken << TEXT(">"); \r
- else \r
- currentToken << message[charIndex];\r
- }\r
-\r
- if(currentToken.str().size() > 0)\r
- pTokenVector->push_back(currentToken.str()); \r
-\r
- return (int)pTokenVector->size();\r
-}\r
-\r
-/************\r
-// Examples (<X> = ASCIICHAR X)\r
-\r
-I\25\3\VII\\ sätter outputtype till 'vii'\r
-I\25\4\1\\ enablar framebuffer (ignore this)\r
-\r
-M\C/SVTNEWS\\ pekar ut vilken grafisk profil som skall användas\r
-\r
-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
-\r
-T\7\4009.VII\A\\ lägger ut skylt 4009\r
-\r
-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
-\r
-V\5\3\1\1\namn.tga\1\\ lägger ut bilden namn.tga\r
-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
-\r
-*************/\r
-\r
-/**********************\r
-New Commands to support the Netupe automation system\r
-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
-Y\<27>\\ Stop. Här kommer ett lagerID också att skickas med (<27> = ESC)\r
-Y\<254>\\ Clear Canvas. Här kommer ett lagerID också att skickas med, utan det skall allt tömmas\r
-Y\<213><243>\\ Play. Här kommer ett lagerID också att skickas med\r
-\r
-**********************/\r
-CIICommandPtr CIIProtocolStrategy::Create(const std::wstring& name)\r
-{\r
- switch(name[0])\r
- {\r
- case TEXT('M'): return std::make_shared<MediaCommand>(this);\r
- case TEXT('W'): return std::make_shared<WriteCommand>(this);\r
- case TEXT('T'): return std::make_shared<ImagestoreCommand>(this);\r
- case TEXT('V'): return std::make_shared<MiscellaneousCommand>(this);\r
- case TEXT('Y'): return std::make_shared<KeydataCommand>(this);\r
- default: return nullptr;\r
- }\r
-}\r
-\r
-void CIIProtocolStrategy::WriteTemplateData(const std::wstring& templateName, const std::wstring& titleName, const std::wstring& xmlData) \r
-{\r
- std::wstring fullTemplateFilename = u16(env::template_folder());\r
- if(currentProfile_.size() > 0)\r
- {\r
- fullTemplateFilename += currentProfile_;\r
- fullTemplateFilename += TEXT("\\");\r
- }\r
- fullTemplateFilename += templateName;\r
- fullTemplateFilename = u16(flash::find_template(u8(fullTemplateFilename)));\r
- if(fullTemplateFilename.empty())\r
- {\r
- CASPAR_LOG(error) << "Failed to save instance of " << u8(templateName) << " as " << u8(titleName) << ", template " << u8(fullTemplateFilename) << " not found";\r
- return;\r
- }\r
- \r
- auto producer = flash::create_producer(this->GetChannel()->mixer(), boost::assign::list_of(env::template_folder()+"CG.fth"));\r
-\r
- std::wstringstream flashParam;\r
- 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
- producer->call(u8(flashParam.str()));\r
-\r
- CASPAR_LOG(info) << "Saved an instance of " << u8(templateName) << " as " << u8(titleName);\r
-\r
- PutPreparedTemplate(titleName, safe_ptr<core::frame_producer>(std::move(producer)));\r
- \r
-}\r
-\r
-void CIIProtocolStrategy::DisplayTemplate(const std::wstring& titleName)\r
-{\r
- try\r
- {\r
- pChannel_->stage()->load(0, GetPreparedTemplate(titleName));\r
- pChannel_->stage()->play(0);\r
-\r
- CASPAR_LOG(info) << "Displayed title " << u8(titleName);\r
- }\r
- catch(caspar_exception&)\r
- {\r
- CASPAR_LOG(error) << "Failed to display title " << u8(titleName);\r
- }\r
-}\r
-\r
-void CIIProtocolStrategy::DisplayMediaFile(const std::wstring& filename) \r
-{\r
- transition_info transition;\r
- transition.type = transition::mix;\r
- transition.duration = 12;\r
-\r
- auto pFP = create_producer(GetChannel()->mixer(), u8(filename));\r
- auto pTransition = create_transition_producer(GetChannel()->get_video_format_desc().field_mode, pFP, transition);\r
-\r
- try\r
- {\r
- pChannel_->stage()->load(0, pTransition);\r
- }\r
- catch(...)\r
- {\r
- CASPAR_LOG_CURRENT_EXCEPTION();\r
- CASPAR_LOG(error) << "Failed to display " << u8(filename);\r
- return;\r
- }\r
-\r
- pChannel_->stage()->play(0);\r
-\r
- CASPAR_LOG(info) << "Displayed " << u8(filename);\r
-}\r
-\r
-safe_ptr<core::frame_producer> CIIProtocolStrategy::GetPreparedTemplate(const std::wstring& titleName)\r
-{\r
- safe_ptr<core::frame_producer> result(frame_producer::empty());\r
-\r
- TitleList::iterator it = std::find(titles_.begin(), titles_.end(), titleName);\r
- if(it != titles_.end()) {\r
- CASPAR_LOG(debug) << "Found title with name " << u8(it->titleName);\r
- result = (*it).pframe_producer;\r
- }\r
- else \r
- CASPAR_LOG(error) << "Could not find title with name " << u8(titleName);\r
-\r
- return result;\r
-}\r
-\r
-void CIIProtocolStrategy::PutPreparedTemplate(const std::wstring& titleName, safe_ptr<core::frame_producer>& pFP)\r
-{\r
- CASPAR_LOG(debug) << "Saved title with name " << u8(titleName);\r
-\r
- TitleList::iterator it = std::find(titles_.begin(), titles_.end(), titleName);\r
- if(it != titles_.end()) {\r
- titles_.remove((*it));\r
- }\r
-\r
- titles_.push_front(TitleHolder(titleName, pFP));\r
-\r
- if(titles_.size() >= 6)\r
- titles_.resize(5);\r
-}\r
-\r
-bool operator==(const CIIProtocolStrategy::TitleHolder& lhs, const std::wstring& rhs) \r
-{\r
- return lhs.titleName == rhs;\r
-}\r
-\r
-bool operator==(const std::wstring& lhs, const CIIProtocolStrategy::TitleHolder& rhs)\r
-{\r
- return lhs == rhs.titleName;\r
-}\r
-\r
-}}}\r
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Nicklas P Andersson
+*/
+
+
+#include "../StdAfx.h"
+
+#include <string>
+#include <sstream>
+#include <algorithm>
+#include "CIIProtocolStrategy.h"
+#include "CIICommandsImpl.h"
+#include <core/producer/transition/transition_producer.h>
+#include <core/mixer/mixer.h>
+#include <core/diagnostics/call_context.h>
+#include <common/env.h>
+
+#include <boost/algorithm/string/replace.hpp>
+
+#if defined(_MSC_VER)
+#pragma warning (push, 1) // TODO: Legacy code, just disable warnings
+#endif
+
+namespace caspar { namespace protocol { namespace cii {
+
+using namespace core;
+
+const std::wstring CIIProtocolStrategy::MessageDelimiter = L"\r\n";
+const wchar_t CIIProtocolStrategy::TokenDelimiter = L'\\';
+
+CIIProtocolStrategy::CIIProtocolStrategy(
+ const std::vector<spl::shared_ptr<core::video_channel>>& channels,
+ const spl::shared_ptr<core::cg_producer_registry>& cg_registry)
+ : executor_(L"CIIProtocolStrategy")
+ , pChannel_(channels.at(0))
+ , cg_registry_(cg_registry)
+{
+}
+
+//The paser method expects message to be complete messages with the delimiter stripped away.
+//Thesefore the AMCPProtocolStrategy should be decorated with a delimiter_based_chunking_strategy
+void CIIProtocolStrategy::Parse(const std::wstring& message, IO::ClientInfoPtr client)
+{
+ if(message.length() > 0)
+ {
+ ProcessMessage(message, client);
+ client->send(std::wstring(L"*\r\n"));
+ }
+}
+
+void CIIProtocolStrategy::ProcessMessage(const std::wstring& message, IO::ClientInfoPtr pClientInfo)
+{
+ CASPAR_LOG(info) << L"Received message from " << pClientInfo->print() << ": " << message << L"\\r\\n";
+
+ std::vector<std::wstring> tokens;
+ int tokenCount = TokenizeMessage(message, &tokens);
+
+ CIICommandPtr pCommand = Create(tokens[0]);
+ if((pCommand != 0) && (tokenCount-1) >= pCommand->GetMinimumParameters())
+ {
+ pCommand->Setup(tokens);
+ executor_.begin_invoke([=]{pCommand->Execute();});
+ }
+ else {} //report error
+}
+
+int CIIProtocolStrategy::TokenizeMessage(const std::wstring& message, std::vector<std::wstring>* pTokenVector)
+{
+ std::wstringstream currentToken;
+
+ for(unsigned int charIndex=0; charIndex<message.size(); ++charIndex)
+ {
+ if(message[charIndex] == TokenDelimiter)
+ {
+ pTokenVector->push_back(currentToken.str());
+ currentToken.str(L"");
+ continue;
+ }
+
+ if(message[charIndex] == L'\"')
+ currentToken << L""";
+ else if(message[charIndex] == L'<')
+ currentToken << L"<";
+ else if(message[charIndex] == L'>')
+ currentToken << L">";
+ else
+ currentToken << message[charIndex];
+ }
+
+ if(currentToken.str().size() > 0)
+ pTokenVector->push_back(currentToken.str());
+
+ return (int)pTokenVector->size();
+}
+
+/************
+// Examples (<X> = ASCIICHAR X)
+
+I\25\3\VII\\ s�tter outputtype till 'vii'
+I\25\4\1\\ enablar framebuffer (ignore this)
+
+M\C/SVTNEWS\\ pekar ut vilken grafisk profil som skall anv�ndas
+
+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
+
+T\7\4009.VII\A\\ l�gger ut skylt 4009
+
+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)
+
+V\5\3\1\1\namn.tga\1\\ l�gger ut bilden namn.tga
+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.
+
+*************/
+
+/**********************
+New Commands to support the Netupe automation system
+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
+Y\<27>\\ Stop. H�r kommer ett lagerID ocks� att skickas med (<27> = ESC)
+Y\<254>\\ Clear Canvas. H�r kommer ett lagerID ocks� att skickas med, utan det skall allt t�mmas
+Y\<213><243>\\ Play. H�r kommer ett lagerID ocks� att skickas med
+
+**********************/
+CIICommandPtr CIIProtocolStrategy::Create(const std::wstring& name)
+{
+ switch(name[0])
+ {
+ case L'M': return std::make_shared<MediaCommand>(this);
+ case L'W': return std::make_shared<WriteCommand>(this);
+ case L'T': return std::make_shared<ImagestoreCommand>(this);
+ case L'V': return std::make_shared<MiscellaneousCommand>(this);
+ case L'Y': return std::make_shared<KeydataCommand>(this);
+ default: return nullptr;
+ }
+}
+
+void CIIProtocolStrategy::WriteTemplateData(const std::wstring& templateName, const std::wstring& titleName, const std::wstring& xmlData)
+{
+ std::wstring fullTemplateFilename = templateName;
+
+ if (!currentProfile_.empty())
+ fullTemplateFilename = currentProfile_ + L"/" + templateName;
+
+ core::diagnostics::scoped_call_context save;
+ core::diagnostics::call_context::for_thread().video_channel = 1;
+ core::diagnostics::call_context::for_thread().layer = 0;
+ auto producer = cg_registry_->create_producer(GetChannel(), fullTemplateFilename);
+
+ if (producer == core::frame_producer::empty())
+ {
+ CASPAR_LOG(error) << "Failed to save instance of " << templateName << L" as " << titleName << L", template " << fullTemplateFilename << L"not found";
+ return;
+ }
+
+ cg_registry_->get_proxy(producer)->add(1, fullTemplateFilename, true, L"", xmlData);
+
+ CASPAR_LOG(info) << "Saved an instance of " << templateName << L" as " << titleName ;
+
+ PutPreparedTemplate(titleName, spl::shared_ptr<core::frame_producer>(std::move(producer)));
+
+}
+
+void CIIProtocolStrategy::DisplayTemplate(const std::wstring& titleName)
+{
+ try
+ {
+ pChannel_->stage().load(0, GetPreparedTemplate(titleName));
+ pChannel_->stage().play(0);
+
+ CASPAR_LOG(info) << L"Displayed title " << titleName ;
+ }
+ catch(caspar_exception&)
+ {
+ CASPAR_LOG(error) << L"Failed to display title " << titleName;
+ }
+}
+
+void CIIProtocolStrategy::DisplayMediaFile(const std::wstring& filename)
+{
+ transition_info transition;
+ transition.type = transition_type::mix;
+ transition.duration = 12;
+
+ core::diagnostics::scoped_call_context save;
+ core::diagnostics::call_context::for_thread().video_channel = 1;
+ core::diagnostics::call_context::for_thread().layer = 0;
+
+ auto pFP = create_producer(GetChannel()->frame_factory(), GetChannel()->video_format_desc(), filename);
+ auto pTransition = create_transition_producer(GetChannel()->video_format_desc().field_mode, pFP, transition);
+
+ try
+ {
+ pChannel_->stage().load(0, pTransition);
+ }
+ catch(...)
+ {
+ CASPAR_LOG_CURRENT_EXCEPTION();
+ CASPAR_LOG(error) << L"Failed to display " << filename ;
+ return;
+ }
+
+ pChannel_->stage().play(0);
+
+ CASPAR_LOG(info) << L"Displayed " << filename;
+}
+
+spl::shared_ptr<core::frame_producer> CIIProtocolStrategy::GetPreparedTemplate(const std::wstring& titleName)
+{
+ spl::shared_ptr<core::frame_producer> result(frame_producer::empty());
+
+ TitleList::iterator it = std::find(titles_.begin(), titles_.end(), titleName);
+ if(it != titles_.end()) {
+ CASPAR_LOG(debug) << L"Found title with name " << it->titleName;
+ result = (*it).pframe_producer;
+ }
+ else
+ CASPAR_LOG(error) << L"Could not find title with name " << titleName;
+
+ return result;
+}
+
+void CIIProtocolStrategy::PutPreparedTemplate(const std::wstring& titleName, const spl::shared_ptr<core::frame_producer>& pFP)
+{
+ CASPAR_LOG(debug) << L"Saved title with name " << titleName;
+
+ TitleList::iterator it = std::find(titles_.begin(), titles_.end(), titleName);
+ if(it != titles_.end()) {
+ titles_.remove((*it));
+ }
+
+ titles_.push_front(TitleHolder(titleName, pFP));
+
+ if(titles_.size() >= 6)
+ titles_.resize(5);
+}
+
+bool operator==(const CIIProtocolStrategy::TitleHolder& lhs, const std::wstring& rhs)
+{
+ return lhs.titleName == rhs;
+}
+
+bool operator==(const std::wstring& lhs, const CIIProtocolStrategy::TitleHolder& rhs)
+{
+ return lhs == rhs.titleName;
+}
+
+}}}