SetThreadPriority(GetCurrentThread(), BELOW_NORMAL_PRIORITY_CLASS);\r
});\r
}\r
+ \r
+ void clear()\r
+ { \r
+ std::function<void()> func;\r
+ while(execution_queue_[normal_priority].try_pop(func));\r
+ while(execution_queue_[high_priority].try_pop(func));\r
+ }\r
\r
void stop() // noexcept\r
{\r
\r
safe_ptr<frame_producer> create_channel_producer(const safe_ptr<core::frame_factory>& frame_factory, const safe_ptr<video_channel>& channel)\r
{\r
- return make_safe<channel_producer>(frame_factory, channel);\r
+ return create_producer_print_proxy(\r
+ make_safe<channel_producer>(frame_factory, channel));\r
}\r
\r
}}
\ No newline at end of file
if(color2.length() != 9 || color2[0] != '#')\r
return core::frame_producer::empty();\r
\r
- return make_safe<color_producer>(frame_factory, color2);\r
+ return create_producer_print_proxy(\r
+ make_safe<color_producer>(frame_factory, color2));\r
}\r
safe_ptr<core::write_frame> create_color_frame(void* tag, const safe_ptr<core::frame_factory>& frame_factory, const std::wstring& color)\r
{\r
try\r
{\r
if(!producer->unique())\r
- CASPAR_LOG(trace) << str << L" Not destroyed on safe asynchronous destruction thread: " << producer->use_count();\r
+ CASPAR_LOG(trace) << str << L" Not destroyed on asynchronous destruction thread: " << producer->use_count();\r
else\r
- CASPAR_LOG(trace) << str << L" Destroying on safe asynchronous destruction thread.";\r
+ CASPAR_LOG(trace) << str << L" Destroying on asynchronous destruction thread.";\r
}\r
catch(...){}\r
\r
CASPAR_LOG_CURRENT_EXCEPTION();\r
try\r
{\r
- auto str = (*producer_)->print();\r
producer_.reset();\r
- CASPAR_LOG(debug) << str << L" Destroyed.";\r
}\r
catch(...){}\r
}\r
print_producer_proxy(safe_ptr<frame_producer>&& producer) \r
: producer_(std::move(producer))\r
{\r
- CASPAR_LOG(info) << producer_->print() << L" Initialized";\r
+ CASPAR_LOG(info) << producer_->print() << L" Initialized.";\r
}\r
\r
~print_producer_proxy()\r
{ \r
auto str = producer_->print();\r
+ CASPAR_LOG(trace) << str << L" Uninitializing.";\r
producer_.reset();\r
- CASPAR_LOG(info) << str << L" Uninitialized";\r
+ CASPAR_LOG(info) << str << L" Uninitialized.";\r
}\r
\r
virtual safe_ptr<basic_frame> receive(int hints) override {return (producer_)->receive(hints);}\r
if(producer == frame_producer::empty())\r
producer = create_playlist_producer(my_frame_factory, params);\r
\r
- if(producer != frame_producer::empty())\r
- producer = create_producer_print_proxy(producer);\r
-\r
return producer;\r
}\r
\r
safe_ptr<core::frame_producer> create_producer(const safe_ptr<frame_factory>&, const std::vector<std::wstring>& params);\r
safe_ptr<core::frame_producer> create_producer(const safe_ptr<frame_factory>&, const std::wstring& params);\r
safe_ptr<core::frame_producer> create_producer_destroy_proxy(safe_ptr<core::frame_producer> producer);\r
+safe_ptr<core::frame_producer> create_producer_print_proxy(safe_ptr<core::frame_producer> producer);\r
\r
}}\r
\r
safe_ptr<frame_producer> create_separated_producer(const safe_ptr<frame_producer>& fill, const safe_ptr<frame_producer>& key)\r
{\r
- return make_safe<separated_producer>(fill, key);\r
+ return create_producer_print_proxy(\r
+ make_safe<separated_producer>(fill, key));\r
}\r
\r
}}\r
\r
safe_ptr<frame_producer> create_transition_producer(const field_mode::type& mode, const safe_ptr<frame_producer>& destination, const transition_info& info)\r
{\r
- return make_safe<transition_producer>(mode, destination, info);\r
+ return create_producer_print_proxy(\r
+ make_safe<transition_producer>(mode, destination, info));\r
}\r
\r
}}\r
\r
struct configuration\r
{\r
- int device_index;\r
+ int device_index;\r
bool embedded_audio;\r
bool internal_key;\r
bool low_latency;\r
bool key_only;\r
- int base_buffer_depth;\r
- int buffer_depth;\r
+ int base_buffer_depth;\r
+ int buffer_depth;\r
\r
configuration()\r
: device_index(1)\r
const core::video_format_desc format_desc_;\r
\r
const bool key_only_;\r
- std::vector<uint8_t, tbb::cache_aligned_allocator<uint8_t>> key_data_;\r
+ std::vector<uint8_t, tbb::cache_aligned_allocator<uint8_t>> data_;\r
public:\r
decklink_frame(const safe_ptr<core::read_frame>& frame, const core::video_format_desc& format_desc, bool key_only)\r
: frame_(frame)\r
{\r
ref_count_ = 0;\r
}\r
+ \r
+ // IUnknown\r
\r
- const boost::iterator_range<const int32_t*> audio_data()\r
+ STDMETHOD (QueryInterface(REFIID, LPVOID*)) \r
{\r
- return frame_->audio_data();\r
+ return E_NOINTERFACE;\r
}\r
\r
- STDMETHOD (QueryInterface(REFIID, LPVOID*)) {return E_NOINTERFACE;}\r
STDMETHOD_(ULONG, AddRef()) \r
{\r
return ++ref_count_;\r
}\r
+\r
STDMETHOD_(ULONG, Release()) \r
{\r
- --ref_count_;\r
- if(ref_count_ == 0)\r
+ if(--ref_count_ == 0)\r
delete this;\r
return ref_count_;\r
}\r
\r
+ // IDecklinkVideoFrame\r
+\r
STDMETHOD_(long, GetWidth()) {return format_desc_.width;} \r
STDMETHOD_(long, GetHeight()) {return format_desc_.height;} \r
STDMETHOD_(long, GetRowBytes()) {return format_desc_.width*4;} \r
\r
STDMETHOD(GetBytes(void** buffer))\r
{\r
- static std::vector<uint8_t, tbb::cache_aligned_allocator<uint8_t>> zeros(1920*1080*4, 0);\r
- if(static_cast<size_t>(frame_->image_data().size()) != format_desc_.size)\r
- {\r
- *buffer = zeros.data();\r
- return S_OK;\r
- }\r
-\r
- if(!key_only_)\r
- *buffer = const_cast<uint8_t*>(frame_->image_data().begin());\r
- else\r
+ try\r
{\r
- if(key_data_.empty())\r
+ if(static_cast<int>(frame_->image_data().size()) != format_desc_.size)\r
{\r
- key_data_.resize(frame_->image_data().size());\r
- aligned_memshfl(key_data_.data(), frame_->image_data().begin(), frame_->image_data().size(), 0x0F0F0F0F, 0x0B0B0B0B, 0x07070707, 0x03030303);\r
- frame_.reset();\r
+ data_.resize(format_desc_.size, 0);\r
+ *buffer = data_.data();\r
}\r
- *buffer = key_data_.data();\r
+ else if(key_only_)\r
+ {\r
+ if(data_.empty())\r
+ {\r
+ data_.resize(frame_->image_data().size());\r
+ aligned_memshfl(data_.data(), frame_->image_data().begin(), frame_->image_data().size(), 0x0F0F0F0F, 0x0B0B0B0B, 0x07070707, 0x03030303);\r
+ frame_.reset();\r
+ }\r
+ *buffer = data_.data();\r
+ }\r
+ else\r
+ *buffer = const_cast<uint8_t*>(frame_->image_data().begin());\r
+ }\r
+ catch(...)\r
+ {\r
+ CASPAR_LOG_CURRENT_EXCEPTION();\r
+ return E_FAIL;\r
}\r
\r
return S_OK;\r
\r
STDMETHOD(GetTimecode(BMDTimecodeFormat format, IDeckLinkTimecode** timecode)){return S_FALSE;} \r
STDMETHOD(GetAncillaryData(IDeckLinkVideoFrameAncillary** ancillary)) {return S_FALSE;}\r
+\r
+ // decklink_frame \r
+\r
+ const boost::iterator_range<const int32_t*> audio_data()\r
+ {\r
+ return frame_->audio_data();\r
+ }\r
};\r
\r
struct decklink_consumer : public IDeckLinkVideoOutputCallback, public IDeckLinkAudioOutputCallback, boost::noncopyable\r
\r
const std::wstring model_name_;\r
const core::video_format_desc format_desc_;\r
- const size_t buffer_size_;\r
+ const int buffer_size_;\r
\r
long long video_scheduled_;\r
long long audio_scheduled_;\r
\r
- size_t preroll_count_;\r
+ int preroll_count_;\r
\r
boost::circular_buffer<std::vector<int32_t>> audio_container_;\r
\r
if(config.embedded_audio) \r
output_->BeginAudioPreroll(); \r
\r
- for(size_t n = 0; n < buffer_size_; ++n)\r
+ for(int n = 0; n < buffer_size_; ++n)\r
schedule_next_video(make_safe<core::read_frame>());\r
\r
if(!config.embedded_audio)\r
void enable_audio()\r
{\r
if(FAILED(output_->EnableAudioOutput(bmdAudioSampleRate48kHz, bmdAudioSampleType32bitInteger, 2, bmdAudioOutputStreamTimestamped)))\r
- BOOST_THROW_EXCEPTION(caspar_exception() << wmsg_info(print() + L" Could not enable audio output."));\r
+ BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(u8(print()) + " Could not enable audio output."));\r
\r
if(FAILED(output_->SetAudioCallback(this)))\r
- BOOST_THROW_EXCEPTION(caspar_exception() << wmsg_info(print() + L" Could not set audio callback."));\r
+ BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(u8(print()) + " Could not set audio callback."));\r
\r
CASPAR_LOG(info) << print() << L" Enabled embedded-audio.";\r
}\r
void enable_video(BMDDisplayMode display_mode)\r
{\r
if(FAILED(output_->EnableVideoOutput(display_mode, bmdVideoOutputFlagDefault))) \r
- BOOST_THROW_EXCEPTION(caspar_exception() << wmsg_info(print() + L" Could not enable video output."));\r
+ BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(u8(print()) + " Could not enable video output."));\r
\r
if(FAILED(output_->SetScheduledFrameCompletionCallback(this)))\r
BOOST_THROW_EXCEPTION(caspar_exception() \r
- << wmsg_info(print() + L" Failed to set playback completion callback.")\r
+ << msg_info(u8(print()) + " Failed to set playback completion callback.")\r
<< boost::errinfo_api_function("SetScheduledFrameCompletionCallback"));\r
}\r
\r
void start_playback()\r
{\r
if(FAILED(output_->StartScheduledPlayback(0, format_desc_.time_scale, 1.0))) \r
- BOOST_THROW_EXCEPTION(caspar_exception() << wmsg_info(print() + L" Failed to schedule playback."));\r
+ BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(u8(print()) + " Failed to schedule playback."));\r
}\r
\r
STDMETHOD (QueryInterface(REFIID, LPVOID*)) {return E_NOINTERFACE;}\r
template<typename T>\r
void schedule_next_audio(const T& audio_data)\r
{\r
- const int sample_frame_count = static_cast<int>(audio_data.size())/format_desc_.audio_channels;\r
+ auto sample_frame_count = static_cast<int>(audio_data.size()/format_desc_.audio_channels);\r
\r
audio_container_.push_back(std::vector<int32_t>(audio_data.begin(), audio_data.end()));\r
\r
}\r
\r
if(!is_running_)\r
- BOOST_THROW_EXCEPTION(caspar_exception() << wmsg_info(print() + L" Is not running."));\r
+ BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(u8(print()) + " Is not running."));\r
\r
if(config_.embedded_audio)\r
audio_frame_buffer_.push(frame); \r
\r
virtual bool send(const safe_ptr<core::read_frame>& frame) override\r
{\r
- CASPAR_VERIFY(audio_cadence_.front() == static_cast<size_t>(frame->audio_data().size()));\r
+ CASPAR_VERIFY(audio_cadence_.front() == static_cast<int>(frame->audio_data().size()));\r
boost::range::rotate(audio_cadence_, std::begin(audio_cadence_)+1);\r
\r
context_->send(frame);\r
if(format_desc.format == core::video_format::invalid)\r
format_desc = frame_factory->get_video_format_desc();\r
\r
- return create_producer_destroy_proxy(make_safe<decklink_producer_proxy>(frame_factory, format_desc, device_index, filter_str, length));\r
+ return create_producer_print_proxy(\r
+ create_producer_destroy_proxy(\r
+ make_safe<decklink_producer_proxy>(frame_factory, format_desc, device_index, filter_str, length)));\r
}\r
\r
}}
\ No newline at end of file
#include <core/mixer/write_frame.h>\r
\r
#include <common/env.h>\r
-#include <common/concurrency/com_context.h>\r
+#include <common/concurrency/executor.h>\r
+#include <common/concurrency/lock.h>\r
#include <common/diagnostics/graph.h>\r
#include <common/utility/timer.h>\r
\r
int width_;\r
int height_;\r
\r
- com_context<flash_renderer> context_; \r
+ tbb::atomic<bool> is_running_;\r
+ std::unique_ptr<flash_renderer> renderer_;\r
\r
+ executor executor_; \r
public:\r
flash_producer(const safe_ptr<core::frame_factory>& frame_factory, const std::wstring& filename, int width, int height) \r
: filename_(filename) \r
, last_frame_(core::basic_frame::empty())\r
, width_(width > 0 ? width : frame_factory->get_video_format_desc().width)\r
, height_(height > 0 ? height : frame_factory->get_video_format_desc().height)\r
- , context_(L"flash_producer")\r
+ , executor_(L"flash_producer")\r
{ \r
fps_ = 0;\r
+ is_running_ = true;\r
\r
graph_->set_color("output-buffer-count", diagnostics::color(1.0f, 1.0f, 0.0f)); \r
graph_->set_color("underflow", diagnostics::color(0.6f, 0.3f, 0.9f)); \r
\r
frame_buffer_.set_capacity(frame_factory_->get_video_format_desc().fps > 30.0 ? 2 : 1);\r
\r
- initialize(); \r
+ executor_.begin_invoke([]\r
+ {\r
+ ::CoInitialize(nullptr);\r
+ }); \r
}\r
\r
~flash_producer()\r
{\r
- frame_buffer_.clear();\r
+ is_running_ = false;\r
+\r
+ safe_ptr<core::basic_frame> frame;\r
+ for(int n = 0; n < 3; ++n)\r
+ frame_buffer_.try_pop(frame);\r
+\r
+ executor_.invoke([this]\r
+ {\r
+ renderer_.reset();\r
+ ::CoUninitialize();\r
+ });\r
}\r
\r
// frame_producer\r
graph_->set_value("output-buffer-count", static_cast<float>(frame_buffer_.size())/static_cast<float>(frame_buffer_.capacity()));\r
\r
auto frame = core::basic_frame::late();\r
- if(!frame_buffer_.try_pop(frame) && context_)\r
+ if(!frame_buffer_.try_pop(frame) && renderer_)\r
graph_->set_tag("underflow");\r
\r
return frame;\r
\r
virtual safe_ptr<core::basic_frame> last_frame() const override\r
{\r
- tbb::spin_mutex::scoped_lock lock(last_frame_mutex_);\r
- return last_frame_;\r
+ return lock(last_frame_mutex_, [this]\r
+ {\r
+ return last_frame_;\r
+ });\r
} \r
\r
virtual boost::unique_future<std::wstring> call(const std::wstring& param) override\r
{ \r
- return context_.begin_invoke([=]() -> std::wstring\r
+ return executor_.begin_invoke([=]() -> std::wstring\r
{\r
- if(!context_)\r
- initialize();\r
+ if(!is_running_)\r
+ return L"";\r
+\r
+ if(!renderer_)\r
+ {\r
+ renderer_.reset(new flash_renderer(safe_ptr<diagnostics::graph>(graph_), frame_factory_, filename_, width_, height_));\r
+ while(frame_buffer_.try_push(core::basic_frame::empty()));\r
+ render(renderer_.get());\r
+ }\r
\r
try\r
{\r
- return context_->call(param); \r
+ return renderer_->call(param); \r
\r
//const auto& format_desc = frame_factory_->get_video_format_desc();\r
//if(abs(context_->fps() - format_desc.fps) > 0.01 && abs(context_->fps()/2.0 - format_desc.fps) > 0.01)\r
catch(...)\r
{\r
CASPAR_LOG_CURRENT_EXCEPTION();\r
- context_.reset(nullptr);\r
+ renderer_.reset(nullptr);\r
frame_buffer_.push(core::basic_frame::empty());\r
}\r
\r
return L"";\r
- });\r
+ }, high_priority);\r
}\r
\r
virtual std::wstring print() const override\r
}\r
\r
// flash_producer\r
-\r
- void initialize()\r
- {\r
- context_.reset([&]{return new flash_renderer(safe_ptr<diagnostics::graph>(graph_), frame_factory_, filename_, width_, height_);});\r
- while(frame_buffer_.try_push(core::basic_frame::empty())){} \r
- render(context_.get());\r
- }\r
-\r
+ \r
safe_ptr<core::basic_frame> render_frame()\r
{\r
- auto frame = context_->render_frame(frame_buffer_.size() < frame_buffer_.capacity()); \r
- tbb::spin_mutex::scoped_lock lock(last_frame_mutex_);\r
- last_frame_ = make_safe<core::basic_frame>(frame);\r
+ auto frame = renderer_->render_frame(frame_buffer_.size() < frame_buffer_.capacity()); \r
+ lock(last_frame_mutex_, [&]\r
+ {\r
+ last_frame_ = make_safe<core::basic_frame>(frame);\r
+ });\r
return frame;\r
}\r
\r
void render(const flash_renderer* renderer)\r
{ \r
- context_.begin_invoke([=]\r
+ executor_.begin_invoke([=]\r
{\r
- if(context_.get() != renderer) // Since initialize will start a new recursive call make sure the recursive calls are only for a specific instance.\r
+ if(!is_running_ || renderer_.get() != renderer) // Since initialize will start a new recursive call make sure the recursive calls are only for a specific instance.\r
return;\r
\r
try\r
{ \r
const auto& format_desc = frame_factory_->get_video_format_desc();\r
\r
- if(abs(context_->fps()/2.0 - format_desc.fps) < 2.0) // flash == 2 * format -> interlace\r
+ if(abs(renderer_->fps()/2.0 - format_desc.fps) < 2.0) // flash == 2 * format -> interlace\r
{\r
auto frame1 = render_frame();\r
auto frame2 = render_frame();\r
frame_buffer_.push(core::basic_frame::interlace(frame1, frame2, format_desc.field_mode));\r
}\r
- else if(abs(context_->fps()- format_desc.fps/2.0) < 2.0) // format == 2 * flash -> duplicate\r
+ else if(abs(renderer_->fps()- format_desc.fps/2.0) < 2.0) // format == 2 * flash -> duplicate\r
{\r
auto frame = render_frame();\r
frame_buffer_.push(frame);\r
frame_buffer_.push(frame);\r
}\r
\r
- if(context_->is_empty())\r
+ if(renderer_->is_empty())\r
{\r
- context_.reset(nullptr);\r
+ renderer_.reset(nullptr);\r
return;\r
}\r
\r
graph_->set_value("output-buffer-count", static_cast<float>(frame_buffer_.size())/static_cast<float>(frame_buffer_.capacity())); \r
- fps_.fetch_and_store(static_cast<int>(context_->fps()*100.0)); \r
+ fps_.fetch_and_store(static_cast<int>(renderer_->fps()*100.0)); \r
graph_->set_text(print());\r
\r
render(renderer);\r
catch(...)\r
{\r
CASPAR_LOG_CURRENT_EXCEPTION();\r
- context_.reset(nullptr);\r
+ renderer_.reset(nullptr);\r
frame_buffer_.push(core::basic_frame::empty());\r
}\r
});\r
if(!boost::filesystem::exists(filename))\r
BOOST_THROW_EXCEPTION(file_not_found() << boost::errinfo_file_name(u8(filename))); \r
\r
- return create_producer_destroy_proxy(make_safe<flash_producer>(frame_factory, filename, template_host.width, template_host.height));\r
+ return create_producer_print_proxy(\r
+ create_producer_destroy_proxy(\r
+ make_safe<flash_producer>(frame_factory, filename, template_host.width, template_host.height)));\r
}\r
\r
std::wstring find_template(const std::wstring& template_name)\r
if(ext == extensions.end())\r
return core::frame_producer::empty();\r
\r
- return make_safe<image_producer>(frame_factory, filename + *ext);\r
+ return create_producer_print_proxy(\r
+ make_safe<image_producer>(frame_factory, filename + *ext));\r
}\r
\r
\r
if(speed == 0)\r
return core::frame_producer::empty();\r
\r
- return make_safe<image_scroll_producer>(frame_factory, filename + L"." + *ext, speed);\r
+ return create_producer_print_proxy(\r
+ make_safe<image_scroll_producer>(frame_factory, filename + L"." + *ext, speed));\r
}\r
\r
}}
\ No newline at end of file
virtual std::wstring print() const = 0;\r
\r
void SetScheduling(AMCPCommandScheduling s){scheduling_ = s;}\r
+ void SetReplyString(const std::wstring& str){replyString_ = str;}\r
\r
protected:\r
- void SetReplyString(const std::wstring& str){replyString_ = str;}\r
std::vector<std::wstring> _parameters;\r
std::vector<std::wstring> _parameters2;\r
\r
if(!pCurrentCommand)\r
return;\r
\r
- //if(pNewCommand->GetScheduling() == ImmediatelyAndClear)\r
- // executor_.clear();\r
+ if(pCurrentCommand->GetScheduling() == ImmediatelyAndClear)\r
+ executor_.clear();\r
+\r
+ if(executor_.size() > 64)\r
+ {\r
+ try\r
+ {\r
+ CASPAR_LOG(error) << "AMCP Command Queue Overflow.";\r
+ CASPAR_LOG(error) << "Failed to execute command:" << pCurrentCommand->print();\r
+ pCurrentCommand->SetReplyString(L"500 FAILED");\r
+ pCurrentCommand->SendReply();\r
+ }\r
+ catch(...)\r
+ {\r
+ CASPAR_LOG_CURRENT_EXCEPTION();\r
+ }\r
+ }\r
\r
executor_.begin_invoke([=]\r
{\r
try\r
{\r
if(pCurrentCommand->Execute()) \r
- CASPAR_LOG(trace) << "Executed command: " << pCurrentCommand->print();\r
+ CASPAR_LOG(debug) << "Executed command: " << pCurrentCommand->print();\r
else \r
CASPAR_LOG(warning) << "Failed to execute command: " << pCurrentCommand->print();\r
}\r
\r
if(!result.timed_wait(boost::posix_time::seconds(2)))\r
BOOST_THROW_EXCEPTION(timed_out());\r
-\r
- CASPAR_LOG(info) << "Executed call: " << _parameters[0] << TEXT(" successfully");\r
- \r
+ \r
std::wstringstream replyString;\r
if(result.get().empty())\r
replyString << TEXT("202 CALL OK\r\n");\r
auto ch2 = GetChannels().at(boost::lexical_cast<int>(_parameters[0])-1);\r
ch1->stage()->swap_layers(ch2->stage());\r
}\r
-\r
- CASPAR_LOG(info) << "Swapped successfully";\r
-\r
+ \r
SetReplyString(TEXT("202 SWAP OK\r\n"));\r
\r
return true;\r
auto consumer = create_consumer(_parameters);\r
GetChannel()->output()->add(GetLayerIndex(consumer->index()), consumer);\r
\r
- CASPAR_LOG(info) << "Added " << _parameters[0] << TEXT(" successfully");\r
-\r
SetReplyString(TEXT("202 ADD OK\r\n"));\r
\r
return true;\r
auto pFP = create_producer(GetChannel()->frame_factory(), _parameters); \r
GetChannel()->stage()->load(GetLayerIndex(), pFP, true);\r
\r
- CASPAR_LOG(info) << "Loaded " << _parameters[0] << TEXT(" successfully");\r
-\r
SetReplyString(TEXT("202 LOAD OK\r\n"));\r
\r
return true;\r
auto pFP2 = create_transition_producer(GetChannel()->get_video_format_desc().field_mode, pFP, transitionInfo);\r
GetChannel()->stage()->load(GetLayerIndex(), pFP2, false, auto_play ? transitionInfo.duration : -1); // TODO: LOOP\r
\r
- CASPAR_LOG(info) << "Loaded " << _parameters[0] << TEXT(" successfully to background");\r
SetReplyString(TEXT("202 LOADBG OK\r\n"));\r
\r
return true;\r
for(auto it = _parameters.begin(); it != _parameters.end(); ++it)\r
lbg.AddParameter(*it);\r
if(!lbg.Execute())\r
- CASPAR_LOG(warning) << " Failed to play.";\r
-\r
- CASPAR_LOG(info) << "Playing " << _parameters[0];\r
+ throw std::exception();\r
}\r
\r
GetChannel()->stage()->play(GetLayerIndex());\r
bool DoExecute();\r
};\r
\r
-class ClearCommand : public AMCPCommandBase<true, AddToQueue, 0>\r
+class ClearCommand : public AMCPCommandBase<true, ImmediatelyAndClear, 0>\r
{\r
std::wstring print() const { return L"ClearCommand";}\r
bool DoExecute();\r
\r
#include <boost/algorithm/string/trim.hpp>\r
#include <boost/algorithm/string/split.hpp>\r
+#include <boost/algorithm/string/replace.hpp>\r
#include <boost/lexical_cast.hpp>\r
\r
#if defined(_MSC_VER)\r
}\r
\r
void AMCPProtocolStrategy::ProcessMessage(const std::wstring& message, ClientInfoPtr& pClientInfo)\r
-{\r
+{ \r
+ CASPAR_LOG(info) << L"Received message from " << pClientInfo->print() << ": " << message + L"\\r\\n";\r
+ \r
bool bError = true;\r
MessageParserState state = New;\r
\r
#include <core/mixer/mixer.h>\r
#include <common/env.h>\r
\r
+#include <boost/algorithm/string/replace.hpp>\r
+\r
#if defined(_MSC_VER)\r
#pragma warning (push, 1) // TODO: Legacy code, just disable warnings\r
#endif\r
std::wstring message = availibleData.substr(0,pos);\r
\r
if(message.length() > 0) {\r
- ProcessMessage(message);\r
+ ProcessMessage(message, pClientInfo);\r
if(pClientInfo != 0)\r
pClientInfo->Send(TEXT("*\r\n"));\r
}\r
currentMessage_ = availibleData;\r
}\r
\r
-void CIIProtocolStrategy::ProcessMessage(const std::wstring& message)\r
-{\r
+void CIIProtocolStrategy::ProcessMessage(const std::wstring& message, IO::ClientInfoPtr pClientInfo)\r
+{ \r
+ CASPAR_LOG(info) << L"Received message from " << pClientInfo->print() << ": " << message + L"\\r\\n";\r
+\r
std::vector<std::wstring> tokens;\r
int tokenCount = TokenizeMessage(message, &tokens);\r
\r
static const TCHAR TokenDelimiter;\r
static const std::wstring MessageDelimiter;\r
\r
- void ProcessMessage(const std::wstring& message);\r
+ void ProcessMessage(const std::wstring& message, IO::ClientInfoPtr pClientInfo);\r
int TokenizeMessage(const std::wstring& message, std::vector<std::wstring>* pTokenVector);\r
CIICommandPtr Create(const std::wstring& name);\r
\r
#include "SocketInfo.h"\r
\r
#include <common/log/log.h>\r
-\r
-#include <boost/algorithm/string/replace.hpp>\r
-\r
#include <string>\r
#include <algorithm>\r
+#include <boost/algorithm/string/replace.hpp>\r
\r
#if defined(_MSC_VER)\r
#pragma warning (push, 1) // TODO: Legacy code, just disable warnings, will replace with boost::asio in future\r
}\r
\r
//Convert to widechar\r
- if(ConvertMultiByteToWideChar(pProtocolStrategy_->GetCodepage(), pSI->recvBuffer_, recvResult + pSI->recvLeftoverOffset_, pSI->wideRecvBuffer_, pSI->recvLeftoverOffset_))\r
- {\r
- auto msg = std::wstring(pSI->wideRecvBuffer_.begin(), pSI->wideRecvBuffer_.end());\r
- boost::replace_all(msg, L"\n", L"\\n");\r
- boost::replace_all(msg, L"\r", L"\\r");\r
-\r
- CASPAR_LOG(info) << L"Received message from " << pSI->host_.c_str() << ": "<< msg;\r
- pProtocolStrategy_->Parse(&pSI->wideRecvBuffer_[0], pSI->wideRecvBuffer_.size(), pSI);\r
- }\r
+ if(ConvertMultiByteToWideChar(pProtocolStrategy_->GetCodepage(), pSI->recvBuffer_, recvResult + pSI->recvLeftoverOffset_, pSI->wideRecvBuffer_, pSI->recvLeftoverOffset_)) \r
+ pProtocolStrategy_->Parse(&pSI->wideRecvBuffer_[0], pSI->wideRecvBuffer_.size(), pSI); \r
else \r
CASPAR_LOG(error) << "Read from " << pSI->host_.c_str() << TEXT(" failed, could not convert command to UNICODE");\r
\r
\r
virtual void Send(const std::wstring& data) = 0;\r
virtual void Disconnect() = 0;\r
+ virtual std::wstring print() const = 0;\r
\r
std::wstring currentMessage_;\r
};\r
std::wcout << (L"#" + data);\r
}\r
void Disconnect(){}\r
+ virtual std::wstring print() const {return L"Console";}\r
};\r
\r
}}\r
\r
void Send(const std::wstring& data);\r
void Disconnect();\r
+ virtual std::wstring print() const override {return host_;}\r
\r
SOCKET socket_;\r
HANDLE event_;\r