]> git.sesse.net Git - casparcg/blob - protocol/amcp/AMCPCommandsImpl.cpp
2.0.0.2: Started with decklink producer.
[casparcg] / protocol / amcp / AMCPCommandsImpl.cpp
1 /*\r
2 * copyright (c) 2010 Sveriges Television AB <info@casparcg.com>\r
3 *\r
4 *  This file is part of CasparCG.\r
5 *\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
10 *\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
15 \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
18 *\r
19 */\r
20 \r
21 #include "../StdAfx.h"\r
22 \r
23 #include "AMCPCommandsImpl.h"\r
24 #include "AMCPProtocolStrategy.h"\r
25 #include "../media.h"\r
26 \r
27 #include <core/producer/frame_producer.h>\r
28 #include <core/video_format.h>\r
29 #include <core/producer/flash/flash_producer.h>\r
30 #include <core/producer/transition/transition_producer.h>\r
31 #include <core/producer/flash/cg_producer.h>\r
32 \r
33 #include <common/env.h>\r
34 \r
35 #include <algorithm>\r
36 #include <locale>\r
37 #include <fstream>\r
38 #include <cctype>\r
39 #include <io.h>\r
40 \r
41 #include <boost/date_time/posix_time/posix_time.hpp>\r
42 #include <boost/lexical_cast.hpp>\r
43 #include <boost/algorithm/string.hpp>\r
44 #include <boost/filesystem.hpp>\r
45 \r
46 #if defined(_MSC_VER)\r
47 #pragma warning (push, 1) // TODO: Legacy code, just disable warnings\r
48 #endif\r
49 \r
50 /* Return codes\r
51 \r
52 100 [action]                    Information om att något har hänt  \r
53 101 [action]                    Information om att något har hänt, en rad data skickas  \r
54 \r
55 202 [kommando] OK               Kommandot har utförts  \r
56 201 [kommando] OK               Kommandot har utförts, och en rad data skickas tillbaka  \r
57 200 [kommando] OK               Kommandot har utförts, och flera rader data skickas tillbaka. Avslutas med tomrad  \r
58 \r
59 400 ERROR                               Kommandot kunde inte förstås  \r
60 401 [kommando] ERROR    Ogiltig kanal  \r
61 402 [kommando] ERROR    Parameter saknas  \r
62 403 [kommando] ERROR    Ogiltig parameter  \r
63 404 [kommando] ERROR    Mediafilen hittades inte  \r
64 \r
65 500 FAILED                              Internt configurationfel  \r
66 501 [kommando] FAILED   Internt configurationfel  \r
67 502 [kommando] FAILED   Oläslig mediafil  \r
68 \r
69 600 [kommando] FAILED   funktion ej implementerad\r
70 */\r
71 \r
72 namespace caspar { namespace protocol {\r
73 \r
74 using namespace core;\r
75 \r
76 std::wstring ListMedia()\r
77 {       \r
78         std::wstringstream replyString;\r
79         for (boost::filesystem::wrecursive_directory_iterator itr(env::media_folder()), end; itr != end; ++itr)\r
80         {                       \r
81                 if(boost::filesystem::is_regular_file(itr->path()))\r
82                 {\r
83                         std::wstring clipttype = TEXT(" N/A ");\r
84                         std::wstring extension = boost::to_upper_copy(itr->path().extension());\r
85                         if(extension == TEXT(".TGA") || extension == TEXT(".COL"))\r
86                                 clipttype = TEXT(" STILL ");\r
87                         else if(extension == TEXT(".SWF") || extension == TEXT(".DV") || extension == TEXT(".MOV") || extension == TEXT(".MPG") || \r
88                                         extension == TEXT(".AVI") || extension == TEXT(".FLV") || extension == TEXT(".F4V") || extension == TEXT(".MP4"))\r
89                                 clipttype = TEXT(" MOVIE ");\r
90                         else if(extension == TEXT(".WAV") || extension == TEXT(".MP3"))\r
91                                 clipttype = TEXT(" STILL ");\r
92 \r
93                         if(clipttype != TEXT(" N/A "))\r
94                         {               \r
95                                 auto is_not_digit = [](char c){ return std::isdigit(c) == 0; };\r
96 \r
97                                 auto relativePath = boost::filesystem::wpath(itr->path().file_string().substr(env::media_folder().size()-1, itr->path().file_string().size()));\r
98 \r
99                                 auto writeTimeStr = boost::posix_time::to_iso_string(boost::posix_time::from_time_t(boost::filesystem::last_write_time(itr->path())));\r
100                                 writeTimeStr.erase(std::remove_if(writeTimeStr.begin(), writeTimeStr.end(), is_not_digit), writeTimeStr.end());\r
101                                 auto writeTimeWStr = std::wstring(writeTimeStr.begin(), writeTimeStr.end());\r
102 \r
103                                 auto sizeStr = boost::lexical_cast<std::wstring>(boost::filesystem::file_size(itr->path()));\r
104                                 sizeStr.erase(std::remove_if(sizeStr.begin(), sizeStr.end(), is_not_digit), sizeStr.end());\r
105                                 auto sizeWStr = std::wstring(sizeStr.begin(), sizeStr.end());\r
106 \r
107                                 replyString << TEXT("\"") << relativePath.replace_extension(TEXT(""))\r
108                                                         << TEXT("\" ") << clipttype \r
109                                                         << TEXT(" ") << sizeStr\r
110                                                         << TEXT(" ") << writeTimeWStr\r
111                                                         << TEXT("\r\n");\r
112                         }       \r
113                 }\r
114         }\r
115         return boost::to_upper_copy(replyString.str());\r
116 }\r
117 \r
118 std::wstring ListTemplates() \r
119 {\r
120         std::wstringstream replyString;\r
121 \r
122         for (boost::filesystem::wrecursive_directory_iterator itr(env::template_folder()), end; itr != end; ++itr)\r
123         {               \r
124                 if(boost::filesystem::is_regular_file(itr->path()) && itr->path().extension() == L".ft")\r
125                 {\r
126                         auto relativePath = boost::filesystem::wpath(itr->path().file_string().substr(env::template_folder().size()-1, itr->path().file_string().size()));\r
127 \r
128                         auto writeTimeStr = boost::posix_time::to_iso_string(boost::posix_time::from_time_t(boost::filesystem::last_write_time(itr->path())));\r
129                         writeTimeStr.erase(std::remove_if(writeTimeStr.begin(), writeTimeStr.end(), [](char c){ return std::isdigit(c) == 0;}), writeTimeStr.end());\r
130                         auto writeTimeWStr = std::wstring(writeTimeStr.begin(), writeTimeStr.end());\r
131 \r
132                         auto sizeStr = boost::lexical_cast<std::string>(boost::filesystem::file_size(itr->path()));\r
133                         sizeStr.erase(std::remove_if(sizeStr.begin(), sizeStr.end(), [](char c){ return std::isdigit(c) == 0;}), sizeStr.end());\r
134 \r
135                         auto sizeWStr = std::wstring(sizeStr.begin(), sizeStr.end());\r
136                         \r
137                         replyString << TEXT("\"") << relativePath.replace_extension(TEXT(""))\r
138                                                 << TEXT("\" ") << sizeWStr\r
139                                                 << TEXT(" ") << writeTimeWStr\r
140                                                 << TEXT("\r\n");                \r
141                 }\r
142         }\r
143         return boost::to_upper_copy(replyString.str());\r
144 }\r
145 \r
146 namespace amcp {\r
147         \r
148 AMCPCommand::AMCPCommand() : channelIndex_(0), scheduling_(Default), layerIndex_(-1)\r
149 {}\r
150 \r
151 void AMCPCommand::SendReply()\r
152 {\r
153         if(!pClientInfo_) \r
154                 return;\r
155 \r
156         if(replyString_.empty())\r
157                 return;\r
158         pClientInfo_->Send(replyString_);\r
159 }\r
160 \r
161 void AMCPCommand::Clear() \r
162 {\r
163         pChannel_->clear();\r
164         pClientInfo_.reset();\r
165         channelIndex_ = 0;\r
166         _parameters.clear();\r
167 }\r
168 \r
169 bool LoadCommand::DoExecute()\r
170 {       \r
171         //Perform loading of the clip\r
172         try\r
173         {\r
174                 _parameters[0] = _parameters[0];\r
175                 auto pFP = load_media(_parameters);             \r
176                 GetChannel()->preview(GetLayerIndex(), pFP);\r
177         \r
178                 CASPAR_LOG(info) << "Loaded " <<  _parameters[0] << TEXT(" successfully");\r
179 \r
180                 SetReplyString(TEXT("202 LOAD OK\r\n"));\r
181 \r
182                 return true;\r
183         }\r
184         catch(file_not_found&)\r
185         {\r
186                 CASPAR_LOG_CURRENT_EXCEPTION();\r
187                 SetReplyString(TEXT("404 LOADBG ERROR\r\n"));\r
188                 return false;\r
189         }\r
190         catch(...)\r
191         {\r
192                 CASPAR_LOG_CURRENT_EXCEPTION();\r
193                 SetReplyString(TEXT("502 LOADBG FAILED\r\n"));\r
194                 return false;\r
195         }\r
196 }\r
197 \r
198 bool LoadbgCommand::DoExecute()\r
199 {\r
200         transition_info transitionInfo;\r
201         \r
202         bool bLoop = false;\r
203         unsigned short transitionParameterIndex = 1;\r
204 \r
205         if(_parameters.size() > 1 && _parameters[1] == TEXT("LOOP"))\r
206                 ++transitionParameterIndex;\r
207 \r
208         //Setup transition info\r
209         if(_parameters.size() > transitionParameterIndex)       //type\r
210         {\r
211                 std::wstring transitionType = _parameters[transitionParameterIndex];\r
212 \r
213                 if(transitionType == TEXT("CUT"))\r
214                         transitionInfo.type = transition::cut;\r
215                 else if(transitionType == TEXT("MIX"))\r
216                         transitionInfo.type = transition::mix;\r
217                 else if(transitionType == TEXT("PUSH"))\r
218                         transitionInfo.type = transition::push;\r
219                 else if(transitionType == TEXT("SLIDE"))\r
220                         transitionInfo.type = transition::slide;\r
221                 else if(transitionType == TEXT("WIPE"))\r
222                         transitionInfo.type = transition::wipe;\r
223 \r
224                 if(_parameters.size() > static_cast<unsigned short>(transitionParameterIndex+1))        //duration\r
225                 {\r
226                         int duration = _ttoi(_parameters[transitionParameterIndex+1].c_str());\r
227                         if(duration > 0)\r
228                                 transitionInfo.duration = duration;\r
229 \r
230                         if(_parameters.size() > static_cast<unsigned short>(transitionParameterIndex+2))        //direction\r
231                         {\r
232                                 std::wstring direction = _parameters[transitionParameterIndex+2];\r
233 \r
234                                 if(direction == TEXT("FROMLEFT"))\r
235                                         transitionInfo.direction = transition_direction::from_left;\r
236                                 else if(direction == TEXT("FROMRIGHT"))\r
237                                         transitionInfo.direction = transition_direction::from_right;\r
238                                 else if(direction == TEXT("LEFT"))\r
239                                         transitionInfo.direction = transition_direction::from_right;\r
240                                 else if(direction == TEXT("RIGHT"))\r
241                                         transitionInfo.direction = transition_direction::from_left;\r
242                         }\r
243                 }\r
244         }\r
245 \r
246         //Perform loading of the clip\r
247         try\r
248         {\r
249                 _parameters[0] = _parameters[0];\r
250                 auto pFP = load_media(_parameters);\r
251                 if(pFP == frame_producer::empty())\r
252                         BOOST_THROW_EXCEPTION(file_not_found() << msg_info(_parameters.size() > 0 ? narrow(_parameters[0]) : ""));\r
253 \r
254                 pFP = safe_ptr<core::frame_producer>(transition_producer(pFP, transitionInfo));\r
255                 bool autoPlay = std::find(_parameters.begin(), _parameters.end(), TEXT("AUTOPLAY")) != _parameters.end();\r
256                 GetChannel()->load(GetLayerIndex(), pFP, autoPlay); // TODO: LOOP\r
257         \r
258                 CASPAR_LOG(info) << "Loaded " << _parameters[0] << TEXT(" successfully to background");\r
259                 SetReplyString(TEXT("202 LOADBG OK\r\n"));\r
260 \r
261                 return true;\r
262         }\r
263         catch(file_not_found&)\r
264         {\r
265                 CASPAR_LOG_CURRENT_EXCEPTION();\r
266                 SetReplyString(TEXT("404 LOADBG ERROR\r\n"));\r
267                 return false;\r
268         }\r
269         catch(...)\r
270         {\r
271                 CASPAR_LOG_CURRENT_EXCEPTION();\r
272                 SetReplyString(TEXT("502 LOADBG FAILED\r\n"));\r
273                 return false;\r
274         }\r
275 }\r
276 \r
277 bool PauseCommand::DoExecute()\r
278 {\r
279         try\r
280         {\r
281                 GetChannel()->pause(GetLayerIndex());\r
282                 SetReplyString(TEXT("202 PAUSE OK\r\n"));\r
283                 return true;\r
284         }\r
285         catch(...)\r
286         {\r
287                 SetReplyString(TEXT("501 PAUSE FAILED\r\n"));\r
288         }\r
289 \r
290         return false;\r
291 }\r
292 \r
293 bool PlayCommand::DoExecute()\r
294 {\r
295         try\r
296         {\r
297                 GetChannel()->play(GetLayerIndex());\r
298                 SetReplyString(TEXT("202 PLAY OK\r\n"));\r
299                 return true;\r
300         }\r
301         catch(...)\r
302         {\r
303                 SetReplyString(TEXT("501 PLAY FAILED\r\n"));\r
304         }\r
305 \r
306         return false;\r
307 }\r
308 \r
309 bool StopCommand::DoExecute()\r
310 {\r
311         try\r
312         {\r
313                 GetChannel()->stop(GetLayerIndex());\r
314                 SetReplyString(TEXT("202 STOP OK\r\n"));\r
315                 return true;\r
316         }\r
317         catch(...)\r
318         {\r
319                 SetReplyString(TEXT("501 STOP FAILED\r\n"));\r
320         }\r
321 \r
322         return false;\r
323 }\r
324 \r
325 bool ClearCommand::DoExecute()\r
326 {\r
327         GetChannel()->clear(GetLayerIndex());\r
328         SetReplyString(TEXT("202 CLEAR OK\r\n"));\r
329 \r
330         return true;\r
331 }\r
332 \r
333 bool CGCommand::DoExecute()\r
334 {\r
335         std::wstring command = _parameters[0];\r
336         if(command == TEXT("ADD"))\r
337                 return DoExecuteAdd();\r
338         else if(command == TEXT("PLAY"))\r
339                 return DoExecutePlay();\r
340         else if(command == TEXT("STOP"))\r
341                 return DoExecuteStop();\r
342         else if(command == TEXT("NEXT"))\r
343                 return DoExecuteNext();\r
344         else if(command == TEXT("REMOVE"))\r
345                 return DoExecuteRemove();\r
346         else if(command == TEXT("CLEAR"))\r
347                 return DoExecuteClear();\r
348         else if(command == TEXT("UPDATE"))\r
349                 return DoExecuteUpdate();\r
350         else if(command == TEXT("INVOKE"))\r
351                 return DoExecuteInvoke();\r
352         else if(command == TEXT("INFO"))\r
353                 return DoExecuteInfo();\r
354 \r
355         SetReplyString(TEXT("403 CG ERROR\r\n"));\r
356         return false;\r
357 }\r
358 \r
359 bool CGCommand::ValidateLayer(const std::wstring& layerstring) {\r
360         int length = layerstring.length();\r
361         for(int i = 0; i < length; ++i) {\r
362                 if(!_istdigit(layerstring[i])) {\r
363                         return false;\r
364                 }\r
365         }\r
366 \r
367         return true;\r
368 }\r
369 \r
370 bool CGCommand::DoExecuteAdd() {\r
371         //CG 1 ADD 0 "template_folder/templatename" [STARTLABEL] 0/1 [DATA]\r
372 \r
373         int layer = 0;                          //_parameters[1]\r
374 //      std::wstring templateName;      //_parameters[2]\r
375         std::wstring label;             //_parameters[3]\r
376         bool bDoStart = false;          //_parameters[3] alt. _parameters[4]\r
377 //      std::wstring data;                      //_parameters[4] alt. _parameters[5]\r
378 \r
379         if(_parameters.size() < 4) \r
380         {\r
381                 SetReplyString(TEXT("402 CG ERROR\r\n"));\r
382                 return false;\r
383         }\r
384         unsigned int dataIndex = 4;\r
385 \r
386         if(!ValidateLayer(_parameters[1])) \r
387         {\r
388                 SetReplyString(TEXT("403 CG ERROR\r\n"));\r
389                 return false;\r
390         }\r
391 \r
392         layer = _ttoi(_parameters[1].c_str());\r
393 \r
394         if(_parameters[3].length() > 1) \r
395         {       //read label\r
396                 label = _parameters[3];\r
397                 ++dataIndex;\r
398 \r
399                 if(_parameters.size() > 4 && _parameters[4].length() > 0)       //read play-on-load-flag\r
400                         bDoStart = (_parameters[4][0]==TEXT('1')) ? true : false;\r
401                 else \r
402                 {\r
403                         SetReplyString(TEXT("402 CG ERROR\r\n"));\r
404                         return false;\r
405                 }\r
406         }\r
407         else if(_parameters[3].length() > 0) {  //read play-on-load-flag\r
408                 bDoStart = (_parameters[3][0]==TEXT('1')) ? true : false;\r
409         }\r
410         else \r
411         {\r
412                 SetReplyString(TEXT("403 CG ERROR\r\n"));\r
413                 return false;\r
414         }\r
415 \r
416         const TCHAR* pDataString = 0;\r
417         std::wstringstream data;\r
418         std::wstring dataFromFile;\r
419         if(_parameters.size() > dataIndex) \r
420         {       //read data\r
421                 const std::wstring& dataString = _parameters[dataIndex];\r
422 \r
423                 if(dataString[0] == TEXT('<')) //the data is an XML-string\r
424                         pDataString = dataString.c_str();\r
425                 else \r
426                 {\r
427                         //The data is not an XML-string, it must be a filename\r
428                         std::wstring filename = env::data_folder();\r
429                         filename.append(dataString);\r
430                         filename.append(TEXT(".ftd"));\r
431 \r
432                         //open file\r
433                         std::wifstream datafile(filename.c_str());\r
434                         if(datafile) \r
435                         {\r
436                                 //read all data\r
437                                 data << datafile.rdbuf();\r
438                                 datafile.close();\r
439 \r
440                                 //extract data to _parameters\r
441                                 dataFromFile = data.str();\r
442                                 pDataString = dataFromFile.c_str();\r
443                         }\r
444                 }\r
445         }\r
446 \r
447         std::wstring fullFilename = core::flash::flash_producer::find_template(env::template_folder() + _parameters[2]);\r
448         if(!fullFilename.empty())\r
449         {\r
450                 std::wstring extension = boost::filesystem::wpath(fullFilename).extension();\r
451                 std::wstring filename = _parameters[2];\r
452                 filename.append(extension);\r
453 \r
454                 core::flash::get_default_cg_producer(safe_ptr<core::channel>(GetChannel()), GetLayerIndex(core::flash::cg_producer::DEFAULT_LAYER))->add(layer, filename, bDoStart, label, (pDataString!=0) ? pDataString : TEXT(""));\r
455                 SetReplyString(TEXT("202 CG OK\r\n"));\r
456         }\r
457         else\r
458         {\r
459                 CASPAR_LOG(warning) << "Could not find template " << _parameters[2];\r
460                 SetReplyString(TEXT("404 CG ERROR\r\n"));\r
461         }\r
462         return true;\r
463 }\r
464 \r
465 bool CGCommand::DoExecutePlay()\r
466 {\r
467         if(_parameters.size() > 1)\r
468         {\r
469                 if(!ValidateLayer(_parameters[1])) \r
470                 {\r
471                         SetReplyString(TEXT("403 CG ERROR\r\n"));\r
472                         return false;\r
473                 }\r
474                 int layer = _ttoi(_parameters[1].c_str());\r
475                 core::flash::get_default_cg_producer(safe_ptr<core::channel>(GetChannel()), GetLayerIndex(core::flash::cg_producer::DEFAULT_LAYER))->play(layer);\r
476         }\r
477         else\r
478         {\r
479                 SetReplyString(TEXT("402 CG ERROR\r\n"));\r
480                 return true;\r
481         }\r
482 \r
483         SetReplyString(TEXT("202 CG OK\r\n"));\r
484         return true;\r
485 }\r
486 \r
487 bool CGCommand::DoExecuteStop() \r
488 {\r
489         if(_parameters.size() > 1)\r
490         {\r
491                 if(!ValidateLayer(_parameters[1])) \r
492                 {\r
493                         SetReplyString(TEXT("403 CG ERROR\r\n"));\r
494                         return false;\r
495                 }\r
496                 int layer = _ttoi(_parameters[1].c_str());\r
497                 core::flash::get_default_cg_producer(safe_ptr<core::channel>(GetChannel()), GetLayerIndex(core::flash::cg_producer::DEFAULT_LAYER))->stop(layer, 0);\r
498         }\r
499         else \r
500         {\r
501                 SetReplyString(TEXT("402 CG ERROR\r\n"));\r
502                 return true;\r
503         }\r
504 \r
505         SetReplyString(TEXT("202 CG OK\r\n"));\r
506         return true;\r
507 }\r
508 \r
509 bool CGCommand::DoExecuteNext()\r
510 {\r
511         if(_parameters.size() > 1) \r
512         {\r
513                 if(!ValidateLayer(_parameters[1])) \r
514                 {\r
515                         SetReplyString(TEXT("403 CG ERROR\r\n"));\r
516                         return false;\r
517                 }\r
518                 int layer = _ttoi(_parameters[1].c_str());\r
519                 core::flash::get_default_cg_producer(safe_ptr<core::channel>(GetChannel()), GetLayerIndex(core::flash::cg_producer::DEFAULT_LAYER))->next(layer);\r
520         }\r
521         else \r
522         {\r
523                 SetReplyString(TEXT("402 CG ERROR\r\n"));\r
524                 return true;\r
525         }\r
526 \r
527         SetReplyString(TEXT("202 CG OK\r\n"));\r
528         return true;\r
529 }\r
530 \r
531 bool CGCommand::DoExecuteRemove() \r
532 {\r
533         if(_parameters.size() > 1) \r
534         {\r
535                 if(!ValidateLayer(_parameters[1])) \r
536                 {\r
537                         SetReplyString(TEXT("403 CG ERROR\r\n"));\r
538                         return false;\r
539                 }\r
540                 int layer = _ttoi(_parameters[1].c_str());\r
541                 core::flash::get_default_cg_producer(safe_ptr<core::channel>(GetChannel()), GetLayerIndex(core::flash::cg_producer::DEFAULT_LAYER))->remove(layer);\r
542         }\r
543         else \r
544         {\r
545                 SetReplyString(TEXT("402 CG ERROR\r\n"));\r
546                 return true;\r
547         }\r
548 \r
549         SetReplyString(TEXT("202 CG OK\r\n"));\r
550         return true;\r
551 }\r
552 \r
553 bool CGCommand::DoExecuteClear() \r
554 {\r
555         core::flash::get_default_cg_producer(safe_ptr<core::channel>(GetChannel()), GetLayerIndex(core::flash::cg_producer::DEFAULT_LAYER))->clear();\r
556         SetReplyString(TEXT("202 CG OK\r\n"));\r
557         return true;\r
558 }\r
559 \r
560 bool CGCommand::DoExecuteUpdate() \r
561 {\r
562         if(_parameters.size() > 2) \r
563         {\r
564                 if(!ValidateLayer(_parameters[1]))\r
565                 {\r
566                         SetReplyString(TEXT("403 CG ERROR\r\n"));\r
567                         return false;\r
568                 }\r
569                 int layer = _ttoi(_parameters[1].c_str());\r
570                 //TODO: Implement indirect data loading from file. Same as in Add\r
571                 core::flash::get_default_cg_producer(safe_ptr<core::channel>(GetChannel()), GetLayerIndex(core::flash::cg_producer::DEFAULT_LAYER))->update(layer, _parameters[2]);\r
572         }\r
573         else \r
574         {\r
575                 SetReplyString(TEXT("402 CG ERROR\r\n"));\r
576                 return true;\r
577         }\r
578 \r
579         SetReplyString(TEXT("202 CG OK\r\n"));\r
580         return true;\r
581 }\r
582 \r
583 bool CGCommand::DoExecuteInvoke() \r
584 {\r
585         if(_parameters.size() > 2)\r
586         {\r
587                 if(!ValidateLayer(_parameters[1]))\r
588                 {\r
589                         SetReplyString(TEXT("403 CG ERROR\r\n"));\r
590                         return false;\r
591                 }\r
592                 int layer = _ttoi(_parameters[1].c_str());\r
593                 core::flash::get_default_cg_producer(safe_ptr<core::channel>(GetChannel()), GetLayerIndex(core::flash::cg_producer::DEFAULT_LAYER))->invoke(layer, _parameters[2]);\r
594         }\r
595         else \r
596         {\r
597                 SetReplyString(TEXT("402 CG ERROR\r\n"));\r
598                 return true;\r
599         }\r
600 \r
601         SetReplyString(TEXT("202 CG OK\r\n"));\r
602         return true;\r
603 }\r
604 \r
605 bool CGCommand::DoExecuteInfo() \r
606 {\r
607         // TODO\r
608         //core::flash::get_default_cg_producer(GetChannel())->Info();\r
609         SetReplyString(TEXT("600 CG FAILED\r\n"));\r
610         return true;\r
611 }\r
612 \r
613 bool DataCommand::DoExecute()\r
614 {\r
615         std::wstring command = _parameters[0];\r
616         if(command == TEXT("STORE"))\r
617                 return DoExecuteStore();\r
618         else if(command == TEXT("RETRIEVE"))\r
619                 return DoExecuteRetrieve();\r
620         else if(command == TEXT("LIST"))\r
621                 return DoExecuteList();\r
622 \r
623         SetReplyString(TEXT("403 DATA ERROR\r\n"));\r
624         return false;\r
625 }\r
626 \r
627 bool DataCommand::DoExecuteStore() \r
628 {\r
629         if(_parameters.size() < 3) \r
630         {\r
631                 SetReplyString(TEXT("402 DATA STORE ERROR\r\n"));\r
632                 return false;\r
633         }\r
634 \r
635         std::wstring filename = env::data_folder();\r
636         filename.append(_parameters[1]);\r
637         filename.append(TEXT(".ftd"));\r
638 \r
639         std::wofstream datafile(filename.c_str());\r
640         if(!datafile) \r
641         {\r
642                 SetReplyString(TEXT("501 DATA STORE FAILED\r\n"));\r
643                 return false;\r
644         }\r
645 \r
646         datafile << _parameters[2];\r
647         datafile.close();\r
648 \r
649         std::wstring replyString = TEXT("202 DATA STORE OK\r\n");\r
650         SetReplyString(replyString);\r
651         return true;\r
652 }\r
653 \r
654 bool DataCommand::DoExecuteRetrieve() \r
655 {\r
656         if(_parameters.size() < 2) \r
657         {\r
658                 SetReplyString(TEXT("402 DATA RETRIEVE ERROR\r\n"));\r
659                 return false;\r
660         }\r
661 \r
662         std::wstring filename = env::data_folder();\r
663         filename.append(_parameters[1]);\r
664         filename.append(TEXT(".ftd"));\r
665 \r
666         std::wifstream datafile(filename.c_str());\r
667         if(!datafile) \r
668         {\r
669                 SetReplyString(TEXT("404 DATA RETRIEVE ERROR\r\n"));\r
670                 return false;\r
671         }\r
672 \r
673         std::wstringstream reply(TEXT("201 DATA RETRIEVE OK\r\n"));\r
674         std::wstring line;\r
675         bool bFirstLine = true;\r
676         while(std::getline(datafile, line))\r
677         {\r
678                 if(!bFirstLine)\r
679                         reply << "\\n";\r
680                 else\r
681                         bFirstLine = false;\r
682 \r
683                 reply << line;\r
684         }\r
685         datafile.close();\r
686 \r
687         reply << "\r\n";\r
688         SetReplyString(reply.str());\r
689         return true;\r
690 }\r
691 \r
692 bool DataCommand::DoExecuteList() \r
693 {\r
694         std::wstringstream replyString;\r
695         replyString << TEXT("200 DATA LIST OK\r\n");\r
696         replyString << ListMedia();\r
697         replyString << TEXT("\r\n");\r
698 \r
699         SetReplyString(boost::to_upper_copy(replyString.str()));\r
700         return true;\r
701 }\r
702 \r
703 bool CinfCommand::DoExecute()\r
704 {\r
705         std::wstringstream replyString;\r
706 \r
707         std::wstring filename = _parameters[0];\r
708 \r
709         // TODO:\r
710 \r
711         //FileInfo fileInfo;\r
712 \r
713         //MediaManagerPtr pMediaManager = GetApplication()->FindMediaFile(filename, &fileInfo);\r
714         //if(pMediaManager != 0 && fileInfo.filetype.length() >0)       //File was found\r
715         //{\r
716         //      if(pMediaManager->getFileInfo(&fileInfo))\r
717         //      {\r
718         //              TCHAR numBuffer[32];\r
719         //              _ui64tot_s(fileInfo.size, numBuffer, 32, 10);\r
720 \r
721         //              replyString << TEXT("201 CINF OK\r\n\"") << fileInfo.filename << TEXT("\" ") << fileInfo.type << TEXT("/") << fileInfo.filetype << TEXT("/") << fileInfo.encoding << TEXT(" ") << numBuffer << TEXT("\r\n");\r
722 \r
723         //              SetReplyString(replyString.str());\r
724         //              return true;\r
725         //      }\r
726         //}\r
727 \r
728         SetReplyString(TEXT("404 CINF ERROR\r\n"));\r
729         return false;\r
730 }\r
731 \r
732 void GenerateChannelInfo(int index, const safe_ptr<core::channel>& pChannel, std::wstringstream& replyString)\r
733 {\r
734         replyString << index << TEXT(" ") << pChannel->get_video_format_desc().name  << TEXT("\r\n") << (pChannel->foreground(0).get()->print());\r
735 }\r
736 \r
737 bool InfoCommand::DoExecute()\r
738 {\r
739         std::wstringstream replyString;\r
740 \r
741         if(_parameters.size() >= 1)\r
742         {\r
743                 int channelIndex = _ttoi(_parameters[0].c_str())-1;\r
744 \r
745                 if(channelIndex < channels_.size())\r
746                 {\r
747                         replyString << TEXT("201 INFO OK\r\n");\r
748                         GenerateChannelInfo(channelIndex, channels_[channelIndex], replyString);\r
749                 }\r
750                 else\r
751                 {\r
752                         SetReplyString(TEXT("401 INFO ERROR\r\n"));\r
753                         return false;\r
754                 }\r
755         }\r
756         else\r
757         {\r
758                 replyString << TEXT("200 INFO OK\r\n");\r
759                 for(size_t n = 0; n < channels_.size(); ++n)\r
760                         GenerateChannelInfo(n, channels_[n], replyString);\r
761                 replyString << TEXT("\r\n");\r
762         }\r
763 \r
764         SetReplyString(replyString.str());\r
765         return true;\r
766 }\r
767 \r
768 bool ClsCommand::DoExecute()\r
769 {\r
770 /*\r
771                 wav = audio\r
772                 mp3 = audio\r
773                 swf     = movie\r
774                 dv  = movie\r
775                 tga = still\r
776                 col = still\r
777         */\r
778         std::wstringstream replyString;\r
779         replyString << TEXT("200 CLS OK\r\n");\r
780         replyString << ListMedia();\r
781         replyString << TEXT("\r\n");\r
782         SetReplyString(boost::to_upper_copy(replyString.str()));\r
783         return true;\r
784 }\r
785 \r
786 bool TlsCommand::DoExecute()\r
787 {\r
788         std::wstringstream replyString;\r
789         replyString << TEXT("200 TLS OK\r\n");\r
790 \r
791         replyString << ListTemplates();\r
792         replyString << TEXT("\r\n");\r
793 \r
794         SetReplyString(replyString.str());\r
795         return true;\r
796 }\r
797 \r
798 bool VersionCommand::DoExecute()\r
799 {\r
800         std::wstringstream replyString;\r
801         replyString << TEXT("201 VERSION OK\r\n") << env::version() << TEXT("\r\n");\r
802 \r
803         SetReplyString(replyString.str());\r
804         return true;\r
805 }\r
806 \r
807 bool ByeCommand::DoExecute()\r
808 {\r
809         GetClientInfo()->Disconnect();\r
810         return true;\r
811 }\r
812 \r
813 bool SetCommand::DoExecute()\r
814 {\r
815         std::wstring name = _parameters[0];\r
816         std::transform(name.begin(), name.end(), name.begin(), toupper);\r
817 \r
818         std::wstring value = _parameters[1];\r
819         std::transform(value.begin(), value.end(), value.begin(), toupper);\r
820 \r
821         if(name == TEXT("MODE"))\r
822         {\r
823                 //if(this->GetChannel()->SetVideoFormat(value)) TODO\r
824                 //      this->SetReplyString(TEXT("202 SET MODE OK\r\n"));\r
825                 //else\r
826                         this->SetReplyString(TEXT("501 SET MODE FAILED\r\n"));\r
827         }\r
828         else\r
829         {\r
830                 this->SetReplyString(TEXT("403 SET ERROR\r\n"));\r
831         }\r
832 \r
833         return true;\r
834 }\r
835 \r
836 \r
837 }       //namespace amcp\r
838 }}      //namespace caspar