]> git.sesse.net Git - casparcg/blob - protocol/amcp/AMCPCommandsImpl.cpp
2.0.0.2: Renamed "processor" to "mixer".
[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 MixerCommand::DoExecute()\r
170 {       \r
171         //Perform loading of the clip\r
172         try\r
173         {       \r
174                 if(_parameters[0] == L"VIDEO")\r
175                 {\r
176                         if(_parameters[1] == L"OPACITY")\r
177                         {\r
178                                 double value = boost::lexical_cast<double>(_parameters[2]);\r
179                                 GetChannel()->set_video_opacity(GetLayerIndex(), value);\r
180                         }\r
181                         else if(_parameters[1] == L"GAIN")\r
182                         {\r
183                                 double value = boost::lexical_cast<double>(_parameters[2]);\r
184                                 GetChannel()->set_video_gain(GetLayerIndex(), value);\r
185                         }\r
186                         else if(_parameters[1] == L"RESET")\r
187                         {\r
188                                 GetChannel()->set_video_opacity(GetLayerIndex(), 1.0);\r
189                                 GetChannel()->set_video_gain(GetLayerIndex(), 1.0);\r
190                         }\r
191                 }\r
192                 else if(_parameters[0] == L"AUDIO")\r
193                 {\r
194                         if(_parameters[1] == L"GAIN")\r
195                         {\r
196                                 double value = boost::lexical_cast<double>(_parameters[2]);\r
197                                 GetChannel()->set_audio_gain(GetLayerIndex(), value);\r
198                         }\r
199                         else if(_parameters[1] == L"RESET")\r
200                         {\r
201                                 GetChannel()->set_audio_gain(GetLayerIndex(), 1.0);\r
202                         }\r
203                 }\r
204                 else if(_parameters[0] == L"RESET")\r
205                 {\r
206                         GetChannel()->set_video_opacity(GetLayerIndex(), 1.0);\r
207                         GetChannel()->set_video_gain(GetLayerIndex(), 1.0);\r
208                         GetChannel()->set_audio_gain(GetLayerIndex(), 1.0);\r
209                 }\r
210         \r
211                 SetReplyString(TEXT("202 MIXER OK\r\n"));\r
212 \r
213                 return true;\r
214         }\r
215         catch(file_not_found&)\r
216         {\r
217                 CASPAR_LOG_CURRENT_EXCEPTION();\r
218                 SetReplyString(TEXT("404 MIXER ERROR\r\n"));\r
219                 return false;\r
220         }\r
221         catch(...)\r
222         {\r
223                 CASPAR_LOG_CURRENT_EXCEPTION();\r
224                 SetReplyString(TEXT("502 MIXER FAILED\r\n"));\r
225                 return false;\r
226         }\r
227 }\r
228 \r
229 bool AddCommand::DoExecute()\r
230 {       \r
231         //Perform loading of the clip\r
232         try\r
233         {\r
234                 auto consumer = create_consumer(_parameters);           \r
235                 GetChannel()->add(GetLayerIndex(), consumer);\r
236         \r
237                 CASPAR_LOG(info) << "Added " <<  _parameters[0] << TEXT(" successfully");\r
238 \r
239                 SetReplyString(TEXT("202 ADD OK\r\n"));\r
240 \r
241                 return true;\r
242         }\r
243         catch(file_not_found&)\r
244         {\r
245                 CASPAR_LOG_CURRENT_EXCEPTION();\r
246                 SetReplyString(TEXT("404 ADD ERROR\r\n"));\r
247                 return false;\r
248         }\r
249         catch(...)\r
250         {\r
251                 CASPAR_LOG_CURRENT_EXCEPTION();\r
252                 SetReplyString(TEXT("502 ADD FAILED\r\n"));\r
253                 return false;\r
254         }\r
255 }\r
256 \r
257 bool RemoveCommand::DoExecute()\r
258 {       \r
259         //Perform loading of the clip\r
260         try\r
261         {\r
262                 GetChannel()->remove(GetLayerIndex());\r
263         \r
264                 CASPAR_LOG(info) << "Removed " << TEXT(" successfully");\r
265 \r
266                 SetReplyString(TEXT("202 REMOVE OK\r\n"));\r
267 \r
268                 return true;\r
269         }\r
270         catch(file_not_found&)\r
271         {\r
272                 CASPAR_LOG_CURRENT_EXCEPTION();\r
273                 SetReplyString(TEXT("404 REMOVE ERROR\r\n"));\r
274                 return false;\r
275         }\r
276         catch(...)\r
277         {\r
278                 CASPAR_LOG_CURRENT_EXCEPTION();\r
279                 SetReplyString(TEXT("502 REMOVE FAILED\r\n"));\r
280                 return false;\r
281         }\r
282 }\r
283 \r
284 bool LoadCommand::DoExecute()\r
285 {       \r
286         //Perform loading of the clip\r
287         try\r
288         {\r
289                 _parameters[0] = _parameters[0];\r
290                 auto pFP = create_producer(_parameters);                \r
291                 GetChannel()->preview(GetLayerIndex(), pFP);\r
292         \r
293                 CASPAR_LOG(info) << "Loaded " <<  _parameters[0] << TEXT(" successfully");\r
294 \r
295                 SetReplyString(TEXT("202 LOAD OK\r\n"));\r
296 \r
297                 return true;\r
298         }\r
299         catch(file_not_found&)\r
300         {\r
301                 CASPAR_LOG_CURRENT_EXCEPTION();\r
302                 SetReplyString(TEXT("404 LOADBG ERROR\r\n"));\r
303                 return false;\r
304         }\r
305         catch(...)\r
306         {\r
307                 CASPAR_LOG_CURRENT_EXCEPTION();\r
308                 SetReplyString(TEXT("502 LOADBG FAILED\r\n"));\r
309                 return false;\r
310         }\r
311 }\r
312 \r
313 bool LoadbgCommand::DoExecute()\r
314 {\r
315         transition_info transitionInfo;\r
316         \r
317         bool bLoop = false;\r
318         unsigned short transitionParameterIndex = 1;\r
319 \r
320         if(_parameters.size() > 1 && _parameters[1] == TEXT("LOOP"))\r
321                 ++transitionParameterIndex;\r
322 \r
323         //Setup transition info\r
324         if(_parameters.size() > transitionParameterIndex)       //type\r
325         {\r
326                 std::wstring transitionType = _parameters[transitionParameterIndex];\r
327 \r
328                 if(transitionType == TEXT("CUT"))\r
329                         transitionInfo.type = transition::cut;\r
330                 else if(transitionType == TEXT("MIX"))\r
331                         transitionInfo.type = transition::mix;\r
332                 else if(transitionType == TEXT("PUSH"))\r
333                         transitionInfo.type = transition::push;\r
334                 else if(transitionType == TEXT("SLIDE"))\r
335                         transitionInfo.type = transition::slide;\r
336                 else if(transitionType == TEXT("WIPE"))\r
337                         transitionInfo.type = transition::wipe;\r
338 \r
339                 if(_parameters.size() > static_cast<unsigned short>(transitionParameterIndex+1))        //duration\r
340                 {\r
341                         int duration = _ttoi(_parameters[transitionParameterIndex+1].c_str());\r
342                         if(duration > 0)\r
343                                 transitionInfo.duration = duration;\r
344 \r
345                         if(_parameters.size() > static_cast<unsigned short>(transitionParameterIndex+2))        //direction\r
346                         {\r
347                                 std::wstring direction = _parameters[transitionParameterIndex+2];\r
348 \r
349                                 if(direction == TEXT("FROMLEFT"))\r
350                                         transitionInfo.direction = transition_direction::from_left;\r
351                                 else if(direction == TEXT("FROMRIGHT"))\r
352                                         transitionInfo.direction = transition_direction::from_right;\r
353                                 else if(direction == TEXT("LEFT"))\r
354                                         transitionInfo.direction = transition_direction::from_right;\r
355                                 else if(direction == TEXT("RIGHT"))\r
356                                         transitionInfo.direction = transition_direction::from_left;\r
357                         }\r
358                 }\r
359         }\r
360 \r
361         //Perform loading of the clip\r
362         try\r
363         {\r
364                 _parameters[0] = _parameters[0];\r
365                 auto pFP = create_producer(_parameters);\r
366                 if(pFP == frame_producer::empty())\r
367                         BOOST_THROW_EXCEPTION(file_not_found() << msg_info(_parameters.size() > 0 ? narrow(_parameters[0]) : ""));\r
368 \r
369                 pFP = safe_ptr<core::frame_producer>(transition_producer(pFP, transitionInfo));\r
370                 bool autoPlay = std::find(_parameters.begin(), _parameters.end(), TEXT("AUTOPLAY")) != _parameters.end();\r
371                 GetChannel()->load(GetLayerIndex(), pFP, autoPlay); // TODO: LOOP\r
372         \r
373                 CASPAR_LOG(info) << "Loaded " << _parameters[0] << TEXT(" successfully to background");\r
374                 SetReplyString(TEXT("202 LOADBG OK\r\n"));\r
375 \r
376                 return true;\r
377         }\r
378         catch(file_not_found&)\r
379         {\r
380                 CASPAR_LOG_CURRENT_EXCEPTION();\r
381                 SetReplyString(TEXT("404 LOADBG ERROR\r\n"));\r
382                 return false;\r
383         }\r
384         catch(...)\r
385         {\r
386                 CASPAR_LOG_CURRENT_EXCEPTION();\r
387                 SetReplyString(TEXT("502 LOADBG FAILED\r\n"));\r
388                 return false;\r
389         }\r
390 }\r
391 \r
392 bool PauseCommand::DoExecute()\r
393 {\r
394         try\r
395         {\r
396                 GetChannel()->pause(GetLayerIndex());\r
397                 SetReplyString(TEXT("202 PAUSE OK\r\n"));\r
398                 return true;\r
399         }\r
400         catch(...)\r
401         {\r
402                 SetReplyString(TEXT("501 PAUSE FAILED\r\n"));\r
403         }\r
404 \r
405         return false;\r
406 }\r
407 \r
408 bool PlayCommand::DoExecute()\r
409 {\r
410         try\r
411         {\r
412                 GetChannel()->play(GetLayerIndex());\r
413                 SetReplyString(TEXT("202 PLAY OK\r\n"));\r
414                 return true;\r
415         }\r
416         catch(...)\r
417         {\r
418                 SetReplyString(TEXT("501 PLAY FAILED\r\n"));\r
419         }\r
420 \r
421         return false;\r
422 }\r
423 \r
424 bool StopCommand::DoExecute()\r
425 {\r
426         try\r
427         {\r
428                 GetChannel()->stop(GetLayerIndex());\r
429                 SetReplyString(TEXT("202 STOP OK\r\n"));\r
430                 return true;\r
431         }\r
432         catch(...)\r
433         {\r
434                 SetReplyString(TEXT("501 STOP FAILED\r\n"));\r
435         }\r
436 \r
437         return false;\r
438 }\r
439 \r
440 bool ClearCommand::DoExecute()\r
441 {\r
442         GetChannel()->clear(GetLayerIndex());\r
443                 \r
444         SetReplyString(TEXT("202 CLEAR OK\r\n"));\r
445 \r
446         return true;\r
447 }\r
448 \r
449 bool CGCommand::DoExecute()\r
450 {\r
451         std::wstring command = _parameters[0];\r
452         if(command == TEXT("ADD"))\r
453                 return DoExecuteAdd();\r
454         else if(command == TEXT("PLAY"))\r
455                 return DoExecutePlay();\r
456         else if(command == TEXT("STOP"))\r
457                 return DoExecuteStop();\r
458         else if(command == TEXT("NEXT"))\r
459                 return DoExecuteNext();\r
460         else if(command == TEXT("REMOVE"))\r
461                 return DoExecuteRemove();\r
462         else if(command == TEXT("CLEAR"))\r
463                 return DoExecuteClear();\r
464         else if(command == TEXT("UPDATE"))\r
465                 return DoExecuteUpdate();\r
466         else if(command == TEXT("INVOKE"))\r
467                 return DoExecuteInvoke();\r
468         else if(command == TEXT("INFO"))\r
469                 return DoExecuteInfo();\r
470 \r
471         SetReplyString(TEXT("403 CG ERROR\r\n"));\r
472         return false;\r
473 }\r
474 \r
475 bool CGCommand::ValidateLayer(const std::wstring& layerstring) {\r
476         int length = layerstring.length();\r
477         for(int i = 0; i < length; ++i) {\r
478                 if(!_istdigit(layerstring[i])) {\r
479                         return false;\r
480                 }\r
481         }\r
482 \r
483         return true;\r
484 }\r
485 \r
486 bool CGCommand::DoExecuteAdd() {\r
487         //CG 1 ADD 0 "template_folder/templatename" [STARTLABEL] 0/1 [DATA]\r
488 \r
489         int layer = 0;                          //_parameters[1]\r
490 //      std::wstring templateName;      //_parameters[2]\r
491         std::wstring label;             //_parameters[3]\r
492         bool bDoStart = false;          //_parameters[3] alt. _parameters[4]\r
493 //      std::wstring data;                      //_parameters[4] alt. _parameters[5]\r
494 \r
495         if(_parameters.size() < 4) \r
496         {\r
497                 SetReplyString(TEXT("402 CG ERROR\r\n"));\r
498                 return false;\r
499         }\r
500         unsigned int dataIndex = 4;\r
501 \r
502         if(!ValidateLayer(_parameters[1])) \r
503         {\r
504                 SetReplyString(TEXT("403 CG ERROR\r\n"));\r
505                 return false;\r
506         }\r
507 \r
508         layer = _ttoi(_parameters[1].c_str());\r
509 \r
510         if(_parameters[3].length() > 1) \r
511         {       //read label\r
512                 label = _parameters[3];\r
513                 ++dataIndex;\r
514 \r
515                 if(_parameters.size() > 4 && _parameters[4].length() > 0)       //read play-on-load-flag\r
516                         bDoStart = (_parameters[4][0]==TEXT('1')) ? true : false;\r
517                 else \r
518                 {\r
519                         SetReplyString(TEXT("402 CG ERROR\r\n"));\r
520                         return false;\r
521                 }\r
522         }\r
523         else if(_parameters[3].length() > 0) {  //read play-on-load-flag\r
524                 bDoStart = (_parameters[3][0]==TEXT('1')) ? true : false;\r
525         }\r
526         else \r
527         {\r
528                 SetReplyString(TEXT("403 CG ERROR\r\n"));\r
529                 return false;\r
530         }\r
531 \r
532         const TCHAR* pDataString = 0;\r
533         std::wstringstream data;\r
534         std::wstring dataFromFile;\r
535         if(_parameters.size() > dataIndex) \r
536         {       //read data\r
537                 const std::wstring& dataString = _parameters[dataIndex];\r
538 \r
539                 if(dataString[0] == TEXT('<')) //the data is an XML-string\r
540                         pDataString = dataString.c_str();\r
541                 else \r
542                 {\r
543                         //The data is not an XML-string, it must be a filename\r
544                         std::wstring filename = env::data_folder();\r
545                         filename.append(dataString);\r
546                         filename.append(TEXT(".ftd"));\r
547 \r
548                         //open file\r
549                         std::wifstream datafile(filename.c_str());\r
550                         if(datafile) \r
551                         {\r
552                                 //read all data\r
553                                 data << datafile.rdbuf();\r
554                                 datafile.close();\r
555 \r
556                                 //extract data to _parameters\r
557                                 dataFromFile = data.str();\r
558                                 pDataString = dataFromFile.c_str();\r
559                         }\r
560                 }\r
561         }\r
562 \r
563         std::wstring fullFilename = core::flash::flash_producer::find_template(env::template_folder() + _parameters[2]);\r
564         if(!fullFilename.empty())\r
565         {\r
566                 std::wstring extension = boost::filesystem::wpath(fullFilename).extension();\r
567                 std::wstring filename = _parameters[2];\r
568                 filename.append(extension);\r
569 \r
570                 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
571                 SetReplyString(TEXT("202 CG OK\r\n"));\r
572         }\r
573         else\r
574         {\r
575                 CASPAR_LOG(warning) << "Could not find template " << _parameters[2];\r
576                 SetReplyString(TEXT("404 CG ERROR\r\n"));\r
577         }\r
578         return true;\r
579 }\r
580 \r
581 bool CGCommand::DoExecutePlay()\r
582 {\r
583         if(_parameters.size() > 1)\r
584         {\r
585                 if(!ValidateLayer(_parameters[1])) \r
586                 {\r
587                         SetReplyString(TEXT("403 CG ERROR\r\n"));\r
588                         return false;\r
589                 }\r
590                 int layer = _ttoi(_parameters[1].c_str());\r
591                 core::flash::get_default_cg_producer(safe_ptr<core::channel>(GetChannel()), GetLayerIndex(core::flash::cg_producer::DEFAULT_LAYER))->play(layer);\r
592         }\r
593         else\r
594         {\r
595                 SetReplyString(TEXT("402 CG ERROR\r\n"));\r
596                 return true;\r
597         }\r
598 \r
599         SetReplyString(TEXT("202 CG OK\r\n"));\r
600         return true;\r
601 }\r
602 \r
603 bool CGCommand::DoExecuteStop() \r
604 {\r
605         if(_parameters.size() > 1)\r
606         {\r
607                 if(!ValidateLayer(_parameters[1])) \r
608                 {\r
609                         SetReplyString(TEXT("403 CG ERROR\r\n"));\r
610                         return false;\r
611                 }\r
612                 int layer = _ttoi(_parameters[1].c_str());\r
613                 core::flash::get_default_cg_producer(safe_ptr<core::channel>(GetChannel()), GetLayerIndex(core::flash::cg_producer::DEFAULT_LAYER))->stop(layer, 0);\r
614         }\r
615         else \r
616         {\r
617                 SetReplyString(TEXT("402 CG ERROR\r\n"));\r
618                 return true;\r
619         }\r
620 \r
621         SetReplyString(TEXT("202 CG OK\r\n"));\r
622         return true;\r
623 }\r
624 \r
625 bool CGCommand::DoExecuteNext()\r
626 {\r
627         if(_parameters.size() > 1) \r
628         {\r
629                 if(!ValidateLayer(_parameters[1])) \r
630                 {\r
631                         SetReplyString(TEXT("403 CG ERROR\r\n"));\r
632                         return false;\r
633                 }\r
634                 int layer = _ttoi(_parameters[1].c_str());\r
635                 core::flash::get_default_cg_producer(safe_ptr<core::channel>(GetChannel()), GetLayerIndex(core::flash::cg_producer::DEFAULT_LAYER))->next(layer);\r
636         }\r
637         else \r
638         {\r
639                 SetReplyString(TEXT("402 CG ERROR\r\n"));\r
640                 return true;\r
641         }\r
642 \r
643         SetReplyString(TEXT("202 CG OK\r\n"));\r
644         return true;\r
645 }\r
646 \r
647 bool CGCommand::DoExecuteRemove() \r
648 {\r
649         if(_parameters.size() > 1) \r
650         {\r
651                 if(!ValidateLayer(_parameters[1])) \r
652                 {\r
653                         SetReplyString(TEXT("403 CG ERROR\r\n"));\r
654                         return false;\r
655                 }\r
656                 int layer = _ttoi(_parameters[1].c_str());\r
657                 core::flash::get_default_cg_producer(safe_ptr<core::channel>(GetChannel()), GetLayerIndex(core::flash::cg_producer::DEFAULT_LAYER))->remove(layer);\r
658         }\r
659         else \r
660         {\r
661                 SetReplyString(TEXT("402 CG ERROR\r\n"));\r
662                 return true;\r
663         }\r
664 \r
665         SetReplyString(TEXT("202 CG OK\r\n"));\r
666         return true;\r
667 }\r
668 \r
669 bool CGCommand::DoExecuteClear() \r
670 {\r
671         core::flash::get_default_cg_producer(safe_ptr<core::channel>(GetChannel()), GetLayerIndex(core::flash::cg_producer::DEFAULT_LAYER))->clear();\r
672         SetReplyString(TEXT("202 CG OK\r\n"));\r
673         return true;\r
674 }\r
675 \r
676 bool CGCommand::DoExecuteUpdate() \r
677 {\r
678         if(_parameters.size() > 2) \r
679         {\r
680                 if(!ValidateLayer(_parameters[1]))\r
681                 {\r
682                         SetReplyString(TEXT("403 CG ERROR\r\n"));\r
683                         return false;\r
684                 }\r
685                 int layer = _ttoi(_parameters[1].c_str());\r
686                 //TODO: Implement indirect data loading from file. Same as in Add\r
687                 core::flash::get_default_cg_producer(safe_ptr<core::channel>(GetChannel()), GetLayerIndex(core::flash::cg_producer::DEFAULT_LAYER))->update(layer, _parameters[2]);\r
688         }\r
689         else \r
690         {\r
691                 SetReplyString(TEXT("402 CG ERROR\r\n"));\r
692                 return true;\r
693         }\r
694 \r
695         SetReplyString(TEXT("202 CG OK\r\n"));\r
696         return true;\r
697 }\r
698 \r
699 bool CGCommand::DoExecuteInvoke() \r
700 {\r
701         if(_parameters.size() > 2)\r
702         {\r
703                 if(!ValidateLayer(_parameters[1]))\r
704                 {\r
705                         SetReplyString(TEXT("403 CG ERROR\r\n"));\r
706                         return false;\r
707                 }\r
708                 int layer = _ttoi(_parameters[1].c_str());\r
709                 core::flash::get_default_cg_producer(safe_ptr<core::channel>(GetChannel()), GetLayerIndex(core::flash::cg_producer::DEFAULT_LAYER))->invoke(layer, _parameters[2]);\r
710         }\r
711         else \r
712         {\r
713                 SetReplyString(TEXT("402 CG ERROR\r\n"));\r
714                 return true;\r
715         }\r
716 \r
717         SetReplyString(TEXT("202 CG OK\r\n"));\r
718         return true;\r
719 }\r
720 \r
721 bool CGCommand::DoExecuteInfo() \r
722 {\r
723         // TODO\r
724         //core::flash::get_default_cg_producer(GetChannel())->Info();\r
725         SetReplyString(TEXT("600 CG FAILED\r\n"));\r
726         return true;\r
727 }\r
728 \r
729 bool DataCommand::DoExecute()\r
730 {\r
731         std::wstring command = _parameters[0];\r
732         if(command == TEXT("STORE"))\r
733                 return DoExecuteStore();\r
734         else if(command == TEXT("RETRIEVE"))\r
735                 return DoExecuteRetrieve();\r
736         else if(command == TEXT("LIST"))\r
737                 return DoExecuteList();\r
738 \r
739         SetReplyString(TEXT("403 DATA ERROR\r\n"));\r
740         return false;\r
741 }\r
742 \r
743 bool DataCommand::DoExecuteStore() \r
744 {\r
745         if(_parameters.size() < 3) \r
746         {\r
747                 SetReplyString(TEXT("402 DATA STORE ERROR\r\n"));\r
748                 return false;\r
749         }\r
750 \r
751         std::wstring filename = env::data_folder();\r
752         filename.append(_parameters[1]);\r
753         filename.append(TEXT(".ftd"));\r
754 \r
755         std::wofstream datafile(filename.c_str());\r
756         if(!datafile) \r
757         {\r
758                 SetReplyString(TEXT("501 DATA STORE FAILED\r\n"));\r
759                 return false;\r
760         }\r
761 \r
762         datafile << _parameters[2];\r
763         datafile.close();\r
764 \r
765         std::wstring replyString = TEXT("202 DATA STORE OK\r\n");\r
766         SetReplyString(replyString);\r
767         return true;\r
768 }\r
769 \r
770 bool DataCommand::DoExecuteRetrieve() \r
771 {\r
772         if(_parameters.size() < 2) \r
773         {\r
774                 SetReplyString(TEXT("402 DATA RETRIEVE ERROR\r\n"));\r
775                 return false;\r
776         }\r
777 \r
778         std::wstring filename = env::data_folder();\r
779         filename.append(_parameters[1]);\r
780         filename.append(TEXT(".ftd"));\r
781 \r
782         std::wifstream datafile(filename.c_str());\r
783         if(!datafile) \r
784         {\r
785                 SetReplyString(TEXT("404 DATA RETRIEVE ERROR\r\n"));\r
786                 return false;\r
787         }\r
788 \r
789         std::wstringstream reply(TEXT("201 DATA RETRIEVE OK\r\n"));\r
790         std::wstring line;\r
791         bool bFirstLine = true;\r
792         while(std::getline(datafile, line))\r
793         {\r
794                 if(!bFirstLine)\r
795                         reply << "\\n";\r
796                 else\r
797                         bFirstLine = false;\r
798 \r
799                 reply << line;\r
800         }\r
801         datafile.close();\r
802 \r
803         reply << "\r\n";\r
804         SetReplyString(reply.str());\r
805         return true;\r
806 }\r
807 \r
808 bool DataCommand::DoExecuteList() \r
809 {\r
810         std::wstringstream replyString;\r
811         replyString << TEXT("200 DATA LIST OK\r\n");\r
812         replyString << ListMedia();\r
813         replyString << TEXT("\r\n");\r
814 \r
815         SetReplyString(boost::to_upper_copy(replyString.str()));\r
816         return true;\r
817 }\r
818 \r
819 bool CinfCommand::DoExecute()\r
820 {\r
821         std::wstringstream replyString;\r
822 \r
823         std::wstring filename = _parameters[0];\r
824 \r
825         // TODO:\r
826 \r
827         //FileInfo fileInfo;\r
828 \r
829         //MediaManagerPtr pMediaManager = GetApplication()->FindMediaFile(filename, &fileInfo);\r
830         //if(pMediaManager != 0 && fileInfo.filetype.length() >0)       //File was found\r
831         //{\r
832         //      if(pMediaManager->getFileInfo(&fileInfo))\r
833         //      {\r
834         //              TCHAR numBuffer[32];\r
835         //              _ui64tot_s(fileInfo.size, numBuffer, 32, 10);\r
836 \r
837         //              replyString << TEXT("201 CINF OK\r\n\"") << fileInfo.filename << TEXT("\" ") << fileInfo.type << TEXT("/") << fileInfo.filetype << TEXT("/") << fileInfo.encoding << TEXT(" ") << numBuffer << TEXT("\r\n");\r
838 \r
839         //              SetReplyString(replyString.str());\r
840         //              return true;\r
841         //      }\r
842         //}\r
843 \r
844         SetReplyString(TEXT("404 CINF ERROR\r\n"));\r
845         return false;\r
846 }\r
847 \r
848 void GenerateChannelInfo(int index, const safe_ptr<core::channel>& pChannel, std::wstringstream& replyString)\r
849 {\r
850         replyString << index << TEXT(" ") << pChannel->get_video_format_desc().name  << TEXT("\r\n") << (pChannel->foreground(0).get()->print());\r
851 }\r
852 \r
853 bool InfoCommand::DoExecute()\r
854 {\r
855         std::wstringstream replyString;\r
856 \r
857         if(_parameters.size() >= 1)\r
858         {\r
859                 int channelIndex = _ttoi(_parameters[0].c_str())-1;\r
860 \r
861                 if(channelIndex < channels_.size())\r
862                 {\r
863                         replyString << TEXT("201 INFO OK\r\n");\r
864                         GenerateChannelInfo(channelIndex, channels_[channelIndex], replyString);\r
865                 }\r
866                 else\r
867                 {\r
868                         SetReplyString(TEXT("401 INFO ERROR\r\n"));\r
869                         return false;\r
870                 }\r
871         }\r
872         else\r
873         {\r
874                 replyString << TEXT("200 INFO OK\r\n");\r
875                 for(size_t n = 0; n < channels_.size(); ++n)\r
876                         GenerateChannelInfo(n, channels_[n], replyString);\r
877                 replyString << TEXT("\r\n");\r
878         }\r
879 \r
880         SetReplyString(replyString.str());\r
881         return true;\r
882 }\r
883 \r
884 bool ClsCommand::DoExecute()\r
885 {\r
886 /*\r
887                 wav = audio\r
888                 mp3 = audio\r
889                 swf     = movie\r
890                 dv  = movie\r
891                 tga = still\r
892                 col = still\r
893         */\r
894         std::wstringstream replyString;\r
895         replyString << TEXT("200 CLS OK\r\n");\r
896         replyString << ListMedia();\r
897         replyString << TEXT("\r\n");\r
898         SetReplyString(boost::to_upper_copy(replyString.str()));\r
899         return true;\r
900 }\r
901 \r
902 bool TlsCommand::DoExecute()\r
903 {\r
904         std::wstringstream replyString;\r
905         replyString << TEXT("200 TLS OK\r\n");\r
906 \r
907         replyString << ListTemplates();\r
908         replyString << TEXT("\r\n");\r
909 \r
910         SetReplyString(replyString.str());\r
911         return true;\r
912 }\r
913 \r
914 bool VersionCommand::DoExecute()\r
915 {\r
916         std::wstringstream replyString;\r
917         replyString << TEXT("201 VERSION OK\r\n") << env::version() << TEXT("\r\n");\r
918 \r
919         SetReplyString(replyString.str());\r
920         return true;\r
921 }\r
922 \r
923 bool ByeCommand::DoExecute()\r
924 {\r
925         GetClientInfo()->Disconnect();\r
926         return true;\r
927 }\r
928 \r
929 bool SetCommand::DoExecute()\r
930 {\r
931         std::wstring name = _parameters[0];\r
932         std::transform(name.begin(), name.end(), name.begin(), toupper);\r
933 \r
934         std::wstring value = _parameters[1];\r
935         std::transform(value.begin(), value.end(), value.begin(), toupper);\r
936 \r
937         if(name == TEXT("MODE"))\r
938         {\r
939                 //if(this->GetChannel()->SetVideoFormat(value)) TODO\r
940                 //      this->SetReplyString(TEXT("202 SET MODE OK\r\n"));\r
941                 //else\r
942                         this->SetReplyString(TEXT("501 SET MODE FAILED\r\n"));\r
943         }\r
944         else\r
945         {\r
946                 this->SetReplyString(TEXT("403 SET ERROR\r\n"));\r
947         }\r
948 \r
949         return true;\r
950 }\r
951 \r
952 \r
953 }       //namespace amcp\r
954 }}      //namespace caspar