]> git.sesse.net Git - casparcg/blobdiff - protocol/cii/CIIProtocolStrategy.cpp
* Enabled modules like flash and html (will be merged soon) to hook in CG functionali...
[casparcg] / protocol / cii / CIIProtocolStrategy.cpp
index 76f8fbf60566e12e22a3ca4389765e700d90fcdf..cd0b79bd47af22f65384ee0a0211db6aba75bfb8 100644 (file)
-/*\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("&quot;");         \r
-               else if(message[charIndex] == TEXT('<')) \r
-                       currentToken << TEXT("&lt;");           \r
-               else if(message[charIndex] == TEXT('>')) \r
-                       currentToken << TEXT("&gt;");           \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"&quot;";
+               else if(message[charIndex] == L'<')
+                       currentToken << L"&lt;";
+               else if(message[charIndex] == L'>')
+                       currentToken << L"&gt;";
+               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;
+}
+
+}}}