Commit sponsored by Boffins Technologies.
Notes:
- Based on similar functionality in CasparCG 2.1.
- Note not all events/messages from 2.1 are implemented.
Changes w.r.t CasparCG 2.1:
- Better performance.
- Use UDP instead of TCP.
- Configurable in casparcg.config.
- Use "Microsoft Asynchronous Agents Message Blocks" API (included in VS2010+), instead of custom "reactive" solution.
<ClInclude Include="mixer\image\blend_modes.h" />\r
<ClInclude Include="mixer\image\shader\blending_glsl.h" />\r
<ClInclude Include="mixer\image\shader\image_shader.h" />\r
+ <ClInclude Include="monitor\monitor.h" />\r
<ClInclude Include="producer\channel\channel_producer.h" />\r
- <ClInclude Include="producer\playlist\playlist_producer.h" />\r
<ClInclude Include="thumbnail_generator.h" />\r
<ClInclude Include="video_channel.h" />\r
<ClInclude Include="consumer\output.h" />\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'">../../../stdafx.h</PrecompiledHeaderFile>\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Develop|Win32'">../../../stdafx.h</PrecompiledHeaderFile>\r
</ClCompile>\r
+ <ClCompile Include="monitor\monitor.cpp">\r
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'">../stdafx.h</PrecompiledHeaderFile>\r
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Develop|Win32'">../stdafx.h</PrecompiledHeaderFile>\r
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../stdafx.h</PrecompiledHeaderFile>\r
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../stdafx.h</PrecompiledHeaderFile>\r
+ </ClCompile>\r
<ClCompile Include="producer\channel\channel_producer.cpp">\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'">../../StdAfx.h</PrecompiledHeaderFile>\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../../StdAfx.h</PrecompiledHeaderFile>\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Develop|Win32'">../../StdAfx.h</PrecompiledHeaderFile>\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../../StdAfx.h</PrecompiledHeaderFile>\r
</ClCompile>\r
- <ClCompile Include="producer\playlist\playlist_producer.cpp">\r
- <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'">../../stdafx.h</PrecompiledHeaderFile>\r
- <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../../stdafx.h</PrecompiledHeaderFile>\r
- <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Develop|Win32'">../../stdafx.h</PrecompiledHeaderFile>\r
- <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../../stdafx.h</PrecompiledHeaderFile>\r
- </ClCompile>\r
<ClCompile Include="thumbnail_generator.cpp" />\r
<ClCompile Include="video_channel.cpp" />\r
<ClCompile Include="consumer\frame_consumer.cpp">\r
<Filter Include="source\consumer">\r
<UniqueIdentifier>{35d7835f-f813-4b4b-8d8d-8a35dfef68d3}</UniqueIdentifier>\r
</Filter>\r
- <Filter Include="source\producer\playlist">\r
- <UniqueIdentifier>{80ce21ca-5ecd-48c1-97d2-c20ea8e2f2b6}</UniqueIdentifier>\r
- </Filter>\r
<Filter Include="source\mixer\image\shader">\r
<UniqueIdentifier>{e0a140f8-e217-465c-a934-163b7ea786be}</UniqueIdentifier>\r
</Filter>\r
<Filter Include="source\producer\channel">\r
<UniqueIdentifier>{f2380c6b-6ec8-4a47-8394-357a05eb831a}</UniqueIdentifier>\r
</Filter>\r
+ <Filter Include="source\monitor">\r
+ <UniqueIdentifier>{d8525088-072a-47d2-b6e1-ad662881f505}</UniqueIdentifier>\r
+ </Filter>\r
</ItemGroup>\r
<ItemGroup>\r
<ClInclude Include="producer\transition\transition_producer.h">\r
<ClInclude Include="mixer\audio\audio_util.h">\r
<Filter>source\mixer\audio</Filter>\r
</ClInclude>\r
- <ClInclude Include="producer\playlist\playlist_producer.h">\r
- <Filter>source\producer\playlist</Filter>\r
- </ClInclude>\r
<ClInclude Include="mixer\image\shader\image_shader.h">\r
<Filter>source\mixer\image\shader</Filter>\r
</ClInclude>\r
<ClInclude Include="thumbnail_generator.h">\r
<Filter>source</Filter>\r
</ClInclude>\r
+ <ClInclude Include="monitor\monitor.h">\r
+ <Filter>source\monitor</Filter>\r
+ </ClInclude>\r
</ItemGroup>\r
<ItemGroup>\r
<ClCompile Include="producer\transition\transition_producer.cpp">\r
<ClCompile Include="producer\frame\frame_transform.cpp">\r
<Filter>source\producer\frame</Filter>\r
</ClCompile>\r
- <ClCompile Include="producer\playlist\playlist_producer.cpp">\r
- <Filter>source\producer\playlist</Filter>\r
- </ClCompile>\r
<ClCompile Include="producer\frame_producer.cpp">\r
<Filter>source\producer</Filter>\r
</ClCompile>\r
<ClCompile Include="thumbnail_generator.cpp">\r
<Filter>source</Filter>\r
</ClCompile>\r
+ <ClCompile Include="monitor\monitor.cpp">\r
+ <Filter>source\monitor</Filter>\r
+ </ClCompile>\r
</ItemGroup>\r
</Project>
\ No newline at end of file
--- /dev/null
+#include "../StdAfx.h"
+
+#include "monitor.h"
+
+namespace caspar { namespace core {
+
+}}
\ No newline at end of file
--- /dev/null
+#pragma once
+
+#include <common/memory/safe_ptr.h>
+#include <common/utility/assert.h>
+
+#include <boost/variant.hpp>
+#include <boost/chrono/duration.hpp>
+
+#include <cstdint>
+#include <string>
+#include <vector>
+
+#include <agents.h>
+
+namespace caspar { namespace core { namespace monitor {
+
+typedef boost::variant<bool,
+ std::int32_t,
+ std::int64_t,
+ float,
+ double,
+ std::string,
+ std::wstring,
+ std::vector<std::int8_t>> data_t;
+
+class message
+{
+public:
+
+ message(std::string path, std::vector<data_t> data = std::vector<data_t>())
+ : path_(std::move(path))
+ , data_ptr_(std::make_shared<std::vector<data_t>>(std::move(data)))
+ {
+ CASPAR_ASSERT(path.empty() || path[0] == '/');
+ }
+
+ message(std::string path, safe_ptr<std::vector<data_t>> data_ptr)
+ : path_(std::move(path))
+ , data_ptr_(std::move(data_ptr))
+ {
+ CASPAR_ASSERT(path.empty() || path[0] == '/');
+ }
+
+ const std::string& path() const
+ {
+ return path_;
+ }
+
+ const std::vector<data_t>& data() const
+ {
+ return *data_ptr_;
+ }
+
+ message propagate(const std::string& path) const
+ {
+ return message(path + path_, data_ptr_);
+ }
+
+ template<typename T>
+ message& operator%(T&& data)
+ {
+ data_ptr_->push_back(std::forward<T>(data));
+ return *this;
+ }
+
+private:
+ std::string path_;
+ safe_ptr<std::vector<data_t>> data_ptr_;
+};
+
+class subject : public Concurrency::transformer<monitor::message, monitor::message>
+{
+public:
+ subject(std::string path = "")
+ : Concurrency::transformer<monitor::message, monitor::message>([=](const message& msg)
+ {
+ return msg.propagate(path);
+ })
+ {
+ CASPAR_ASSERT(path.empty() || path[0] == '/');
+ }
+
+ template<typename T>
+ subject& operator<<(T&& msg)
+ {
+ Concurrency::send(*this, std::forward<T>(msg));
+ return *this;
+ }
+};
+
+typedef Concurrency::ISource<monitor::message> source;
+
+
+}}}
\ No newline at end of file
\r
#include "channel_producer.h"\r
\r
+#include "../../monitor/monitor.h"\r
#include "../../consumer/frame_consumer.h"\r
#include "../../consumer/output.h"\r
#include "../../video_channel.h"\r
\r
#include <common/exception/exceptions.h>\r
#include <common/memory/memcpy.h>\r
-#include <common/concurrency/future_util.h>\r\r
+#include <common/concurrency/future_util.h>\r
+\r
#include <tbb/concurrent_queue.h>\r
\r
namespace caspar { namespace core {\r
\r
class channel_producer : public frame_producer\r
{\r
+ monitor::subject monitor_subject_;\r
+\r
const safe_ptr<frame_factory> frame_factory_;\r
const safe_ptr<channel_consumer> consumer_;\r
\r
info.add(L"type", L"channel-producer");\r
return info;\r
}\r
+\r
+ monitor::source& monitor_output() \r
+ {\r
+ return monitor_subject_;\r
+ }\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
#include "color_producer.h"\r
\r
+#include "../../monitor/monitor.h"\r
+\r
#include "../frame/basic_frame.h"\r
#include "../frame/frame_factory.h"\r
#include "../../mixer/write_frame.h"\r
\r
class color_producer : public frame_producer\r
{\r
- safe_ptr<basic_frame> frame_;\r
- const std::wstring color_str_;\r
+ monitor::subject monitor_subject_;\r
+ safe_ptr<basic_frame> frame_;\r
+ const std::wstring color_str_;\r
\r
public:\r
explicit color_producer(const safe_ptr<core::frame_factory>& frame_factory, const std::wstring& color) \r
: color_str_(color)\r
, frame_(create_color_frame(this, frame_factory, color))\r
- {}\r
+ {\r
+ }\r
\r
// frame_producer\r
\r
virtual safe_ptr<basic_frame> receive(int) override\r
{\r
+ monitor_subject_ << monitor::message("/color") % color_str_;\r
+\r
return frame_;\r
} \r
\r
info.add(L"color", color_str_);\r
return info;\r
}\r
+\r
+ monitor::source& monitor_output()\r
+ {\r
+ return monitor_subject_;\r
+ }\r
};\r
\r
std::wstring get_hex_color(const std::wstring& str)\r
#include "frame/frame_transform.h"\r
\r
#include "color/color_producer.h"\r
-#include "playlist/playlist_producer.h"\r
#include "separated/separated_producer.h"\r
\r
#include <common/memory/safe_ptr.h>\r
virtual safe_ptr<frame_producer> get_following_producer() const override {return (*producer_)->get_following_producer();}\r
virtual void set_leading_producer(const safe_ptr<frame_producer>& producer) override {(*producer_)->set_leading_producer(producer);}\r
virtual uint32_t nb_frames() const override {return (*producer_)->nb_frames();}\r
+ virtual monitor::source& monitor_output() {return (*producer_)->monitor_output();}\r
};\r
\r
safe_ptr<core::frame_producer> create_producer_destroy_proxy(safe_ptr<core::frame_producer> producer)\r
virtual safe_ptr<frame_producer> get_following_producer() const override {return (producer_)->get_following_producer();}\r
virtual void set_leading_producer(const safe_ptr<frame_producer>& producer) override {(producer_)->set_leading_producer(producer);}\r
virtual uint32_t nb_frames() const override {return (producer_)->nb_frames();}\r
+ virtual monitor::source& monitor_output() {return (producer_)->monitor_output();}\r
};\r
\r
safe_ptr<core::frame_producer> create_producer_print_proxy(safe_ptr<core::frame_producer> producer)\r
info.add(L"type", L"last-frame-producer");\r
return info;\r
}\r
+ virtual monitor::source& monitor_output()\r
+ {\r
+ static monitor::subject monitor_subject("");\r
+ return monitor_subject;\r
+ }\r
};\r
\r
struct empty_frame_producer : public frame_producer\r
info.add(L"type", L"empty-producer");\r
return info;\r
}\r
+\r
+ virtual monitor::source& monitor_output()\r
+ {\r
+ static monitor::subject monitor_subject("");\r
+ return monitor_subject;\r
+ }\r
};\r
\r
const safe_ptr<frame_producer>& frame_producer::empty() // nothrow\r
\r
if(producer == frame_producer::empty())\r
producer = create_color_producer(my_frame_factory, params);\r
- \r
- if(producer == frame_producer::empty())\r
- producer = create_playlist_producer(my_frame_factory, params);\r
- \r
+ \r
return producer;\r
}\r
\r
\r
#pragma once\r
\r
+#include "../monitor/monitor.h"\r
+\r
#include <common/memory/safe_ptr.h>\r
#include <common/exception/exceptions.h>\r
\r
virtual safe_ptr<basic_frame> create_thumbnail_frame();\r
\r
static const safe_ptr<frame_producer>& empty(); // nothrow\r
+\r
+ virtual monitor::source& monitor_output() = 0;\r
};\r
\r
safe_ptr<basic_frame> receive_and_follow(safe_ptr<frame_producer>& producer, int hints);\r
int64_t frame_number_;\r
int32_t auto_play_delta_;\r
bool is_paused_;\r
+ monitor::subject monitor_subject_;\r
\r
public:\r
- implementation() \r
+ implementation(int index) \r
: foreground_(frame_producer::empty())\r
, background_(frame_producer::empty())\r
, frame_number_(0)\r
, auto_play_delta_(-1)\r
, is_paused_(false)\r
+ , monitor_subject_("/layer/" + boost::lexical_cast<std::string>(index))\r
{\r
}\r
\r
{\r
background_->set_leading_producer(foreground_);\r
\r
- foreground_ = background_;\r
+ set_foreground(background_);\r
+\r
background_ = frame_producer::empty();\r
frame_number_ = 0;\r
auto_play_delta_ = -1; \r
\r
void stop()\r
{\r
- foreground_ = frame_producer::empty();\r
+ set_foreground(frame_producer::empty());\r
+\r
background_ = background_;\r
frame_number_ = 0;\r
auto_play_delta_ = -1;\r
return disable_audio(foreground_->last_frame());\r
}\r
\r
- auto frame = receive_and_follow(foreground_, hints);\r
+ auto foreground = foreground_;\r
+\r
+ auto frame = receive_and_follow(foreground, hints);\r
+\r
+ if(foreground != foreground_)\r
+ set_foreground(foreground);\r
+\r
if(frame == core::basic_frame::late())\r
return foreground_->last_frame();\r
\r
info.add_child(L"background.producer", background_->info());\r
return info;\r
}\r
+\r
+ void set_foreground(safe_ptr<core::frame_producer> producer)\r
+ {\r
+ foreground_->monitor_output().unlink_target(&monitor_subject_);\r
+ foreground_ = producer;\r
+ foreground_->monitor_output().link_target(&monitor_subject_);\r
+ }\r
};\r
\r
-layer::layer() : impl_(new implementation()){}\r
+layer::layer(int index) : impl_(new implementation(index)){}\r
layer::layer(layer&& other) : impl_(std::move(other.impl_)){}\r
layer& layer::operator=(layer&& other)\r
{\r
impl_ = std::move(other.impl_);\r
return *this;\r
}\r
-layer::layer(const layer& other) : impl_(new implementation(*other.impl_)){}\r
-layer& layer::operator=(const layer& other)\r
-{\r
- layer temp(other);\r
- temp.swap(*this);\r
- return *this;\r
-}\r
void layer::swap(layer& other)\r
{ \r
impl_.swap(other.impl_);\r
bool layer::empty() const {return impl_->empty();}\r
boost::unique_future<std::wstring> layer::call(bool foreground, const std::wstring& param){return impl_->call(foreground, param);}\r
boost::property_tree::wptree layer::info() const{return impl_->info();}\r
+monitor::source& layer::monitor_output(){return impl_->monitor_subject_;}\r
}}
\ No newline at end of file
\r
#pragma once\r
\r
+#include "../monitor/monitor.h"\r
+\r
#include <common/memory/safe_ptr.h>\r
\r
#include <boost/noncopyable.hpp>\r
\r
class layer : boost::noncopyable\r
{\r
+ layer(const layer&);\r
+ layer& operator=(const layer&);\r
public:\r
- layer(); // nothrow\r
+ layer(int index = -1); // nothrow\r
layer(layer&& other); // nothrow\r
layer& operator=(layer&& other); // nothrow\r
- layer(const layer&);\r
- layer& operator=(const layer&);\r
\r
void swap(layer& other); // nothrow \r
\r
safe_ptr<basic_frame> receive(int hints); // nothrow\r
\r
boost::property_tree::wptree info() const;\r
+ \r
+ monitor::source& monitor_output();\r
private:\r
struct implementation;\r
safe_ptr<implementation> impl_;\r
+++ /dev/null
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#include "../../stdafx.h"\r
-\r
-#include "playlist_producer.h"\r
-\r
-#include <core/producer/frame_producer.h>\r
-#include <core/producer/frame/basic_frame.h>\r
-\r
-#include <boost/regex.hpp>\r
-#include <boost/property_tree/ptree.hpp>\r
-\r
-#include <deque>\r
-\r
-namespace caspar { namespace core { \r
-\r
-struct playlist_producer : public frame_producer\r
-{ \r
- safe_ptr<frame_factory> factory_;\r
- safe_ptr<basic_frame> last_frame_;\r
- safe_ptr<frame_producer> current_;\r
- bool loop_;\r
-\r
- std::deque<safe_ptr<frame_producer>> producers_;\r
-\r
- playlist_producer(const safe_ptr<frame_factory>& factory, bool loop) \r
- : factory_(factory)\r
- , last_frame_(basic_frame::empty())\r
- , current_(frame_producer::empty())\r
- , loop_(loop)\r
- {\r
- }\r
-\r
- // frame_producer\r
- \r
- virtual safe_ptr<basic_frame> receive(int hints) override\r
- {\r
- if(current_ == frame_producer::empty() && !producers_.empty())\r
- next();\r
-\r
- auto frame = current_->receive(hints);\r
- if(frame == basic_frame::eof())\r
- {\r
- current_ = frame_producer::empty();\r
- return receive(hints);\r
- }\r
-\r
- return last_frame_ = frame;\r
- }\r
-\r
- virtual safe_ptr<core::basic_frame> last_frame() const override\r
- {\r
- return disable_audio(last_frame_);\r
- }\r
-\r
- virtual std::wstring print() const override\r
- {\r
- return L"playlist[" + current_->print() + L"]";\r
- } \r
-\r
- virtual boost::property_tree::wptree info() const override\r
- {\r
- boost::property_tree::wptree info;\r
- info.add(L"type", L"playlist-producer");\r
- return info;\r
- }\r
-\r
- virtual uint32_t nb_frames() const override\r
- {\r
- return std::numeric_limits<uint32_t>::max();\r
- }\r
- \r
- virtual boost::unique_future<std::wstring> call(const std::wstring& param) override\r
- {\r
- boost::promise<std::wstring> promise;\r
- promise.set_value(do_call(param));\r
- return promise.get_future();\r
- } \r
-\r
- // playlist_producer\r
-\r
- std::wstring do_call(const std::wstring& param)\r
- { \r
- static const boost::wregex push_front_exp (L"PUSH_FRONT (?<PARAM>.+)"); \r
- static const boost::wregex push_back_exp (L"(PUSH_BACK|PUSH) (?<PARAM>.+)");\r
- static const boost::wregex pop_front_exp (L"POP_FRONT"); \r
- static const boost::wregex pop_back_exp (L"(POP_BACK|POP)");\r
- static const boost::wregex clear_exp (L"CLEAR");\r
- static const boost::wregex next_exp (L"NEXT");\r
- static const boost::wregex insert_exp (L"INSERT (?<POS>\\d+) (?<PARAM>.+)"); \r
- static const boost::wregex remove_exp (L"REMOVE (?<POS>\\d+) (?<PARAM>.+)"); \r
- static const boost::wregex list_exp (L"LIST"); \r
- static const boost::wregex loop_exp (L"LOOP\\s*(?<VALUE>\\d?)");\r
- \r
- boost::wsmatch what;\r
-\r
- if(boost::regex_match(param, what, push_front_exp))\r
- return push_front(what["PARAM"].str()); \r
- else if(boost::regex_match(param, what, push_back_exp))\r
- return push_back(what["PARAM"].str()); \r
- if(boost::regex_match(param, what, pop_front_exp))\r
- return pop_front(); \r
- else if(boost::regex_match(param, what, pop_back_exp))\r
- return pop_back(); \r
- else if(boost::regex_match(param, what, clear_exp))\r
- return clear();\r
- else if(boost::regex_match(param, what, next_exp))\r
- return next(); \r
- else if(boost::regex_match(param, what, insert_exp))\r
- return insert(boost::lexical_cast<size_t>(what["POS"].str()), what["PARAM"].str());\r
- else if(boost::regex_match(param, what, remove_exp))\r
- return erase(boost::lexical_cast<size_t>(what["POS"].str()));\r
- else if(boost::regex_match(param, what, list_exp))\r
- return list();\r
- else if(boost::regex_match(param, what, loop_exp))\r
- {\r
- if(!what["VALUE"].str().empty())\r
- loop_ = boost::lexical_cast<bool>(what["VALUE"].str());\r
- return boost::lexical_cast<std::wstring>(loop_);\r
- }\r
-\r
- BOOST_THROW_EXCEPTION(invalid_argument());\r
- }\r
- \r
- std::wstring push_front(const std::wstring& str)\r
- {\r
- producers_.push_front(create_producer(factory_, str)); \r
- return L"";\r
- }\r
-\r
- std::wstring push_back(const std::wstring& str)\r
- {\r
- producers_.push_back(create_producer(factory_, str)); \r
- return L"";\r
- }\r
-\r
- std::wstring pop_front()\r
- {\r
- producers_.pop_front();\r
- return L"";\r
- }\r
-\r
- std::wstring pop_back()\r
- {\r
- producers_.pop_back();\r
- return L"";\r
- }\r
- \r
- std::wstring clear()\r
- {\r
- producers_.clear();\r
- return L"";\r
- }\r
-\r
- std::wstring next()\r
- {\r
- if(!producers_.empty())\r
- {\r
- current_ = producers_.front();\r
- producers_.pop_front();\r
- //if(loop_)\r
- // producers_.push_back(current_);\r
- }\r
- return L"";\r
- }\r
- \r
- std::wstring insert(size_t pos, const std::wstring& str)\r
- {\r
- if(pos >= producers_.size())\r
- BOOST_THROW_EXCEPTION(out_of_range());\r
- producers_.insert(std::begin(producers_) + pos, create_producer(factory_, str));\r
- return L"";\r
- }\r
-\r
- std::wstring erase(size_t pos)\r
- {\r
- if(pos >= producers_.size())\r
- BOOST_THROW_EXCEPTION(out_of_range());\r
- producers_.erase(std::begin(producers_) + pos);\r
- return L"";\r
- }\r
-\r
- std::wstring list() const\r
- {\r
- std::wstring result = L"<playlist>\n";\r
- BOOST_FOREACH(auto& producer, producers_) \r
- result += L"\t<producer>" + producer->print() + L"</producer>\n";\r
- return result + L"</playlist>";\r
- }\r
-};\r
-\r
-safe_ptr<frame_producer> create_playlist_producer(const safe_ptr<core::frame_factory>& frame_factory, const std::vector<std::wstring>& params)\r
-{\r
- if(boost::range::find(params, L"[PLAYLIST]") == params.end())\r
- return core::frame_producer::empty();\r
-\r
- bool loop = boost::range::find(params, L"LOOP") != params.end();\r
-\r
- return make_safe<playlist_producer>(frame_factory, loop);\r
-}\r
-\r
-}}\r
-\r
+++ /dev/null
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#include "../frame_producer.h"\r
-\r
-#include <string>\r
-#include <memory>\r
-#include <vector>\r
-\r
-namespace caspar { namespace core {\r
- \r
-safe_ptr<frame_producer> create_playlist_producer(const safe_ptr<core::frame_factory>& frame_factory, const std::vector<std::wstring>& params);\r
-\r
-}}
\ No newline at end of file
\r
#include "../../stdafx.h"\r
\r
+#include "../../monitor/monitor.h"\r
+\r
#include "separated_producer.h"\r
\r
#include <core/producer/frame/basic_frame.h>\r
\r
struct separated_producer : public frame_producer\r
{ \r
+ monitor::subject monitor_subject_;\r
+ monitor::subject key_monitor_subject_;\r
+\r
safe_ptr<frame_producer> fill_producer_;\r
safe_ptr<frame_producer> key_producer_;\r
safe_ptr<basic_frame> fill_;\r
safe_ptr<basic_frame> last_frame_;\r
\r
explicit separated_producer(const safe_ptr<frame_producer>& fill, const safe_ptr<frame_producer>& key) \r
- : fill_producer_(fill)\r
+ : monitor_subject_("")\r
+ , key_monitor_subject_("/keyer")\r
+ , fill_producer_(fill)\r
, key_producer_(key)\r
, fill_(core::basic_frame::late())\r
, key_(core::basic_frame::late())\r
, last_frame_(core::basic_frame::empty())\r
{\r
+ key_monitor_subject_.link_target(&monitor_subject_);\r
+\r
+ key_producer_->monitor_output().link_target(&key_monitor_subject_);\r
+ fill_producer_->monitor_output().link_target(&monitor_subject_);\r
}\r
\r
// frame_producer\r
info.add_child(L"key.producer", key_producer_->info());\r
return info;\r
}\r
+\r
+ monitor::source& monitor_output()\r
+ {\r
+ return monitor_subject_;\r
+ }\r
};\r
\r
safe_ptr<frame_producer> create_separated_producer(const safe_ptr<frame_producer>& fill, const safe_ptr<frame_producer>& key)\r
boost::timer produce_timer_;\r
boost::timer tick_timer_;\r
\r
- std::map<int, layer> layers_; \r
+ std::map<int, std::shared_ptr<layer>> layers_; \r
tbb::concurrent_unordered_map<int, tweened_transform<core::frame_transform>> transforms_; \r
+ \r
+ monitor::subject monitor_subject_;\r
\r
- executor executor_;\r
+ executor executor_;\r
public:\r
implementation(const safe_ptr<diagnostics::graph>& graph, const safe_ptr<stage::target_t>& target, const video_format_desc& format_desc) \r
: graph_(graph)\r
, format_desc_(format_desc)\r
, target_(target)\r
+ , monitor_subject_("/stage")\r
, executor_(L"stage")\r
{\r
graph_->set_color("tick-time", diagnostics::color(0.0f, 0.6f, 0.9f, 0.8)); \r
\r
std::map<int, safe_ptr<basic_frame>> frames;\r
\r
- BOOST_FOREACH(auto& layer, layers_) \r
- frames[layer.first] = basic_frame::empty(); \r
+ for(auto it = layers_.begin(); it != layers_.end(); ++it)\r
+ frames[it->first] = basic_frame::empty(); \r
\r
- tbb::parallel_for_each(layers_.begin(), layers_.end(), [&](std::map<int, layer>::value_type& layer) \r
+ tbb::parallel_for_each(layers_.begin(), layers_.end(), [&](std::map<int, std::shared_ptr<layer>>::value_type& layer) \r
{\r
auto transform = transforms_[layer.first].fetch_and_tick(1);\r
\r
if(transform.is_key)\r
hints |= frame_producer::ALPHA_HINT;\r
\r
- auto frame = layer.second.receive(hints); \r
+ auto frame = layer.second->receive(hints); \r
\r
auto frame1 = make_safe<core::basic_frame>(frame);\r
frame1->get_frame_transform() = transform;\r
}, high_priority);\r
}\r
\r
+ layer& get_layer(int index)\r
+ {\r
+ auto it = layers_.find(index);\r
+ if(it == std::end(layers_))\r
+ {\r
+ it = layers_.insert(std::make_pair(index, std::make_shared<layer>(index))).first;\r
+ it->second->monitor_output().link_target(&monitor_subject_);\r
+ }\r
+ return *it->second;\r
+ }\r
+\r
void load(int index, const safe_ptr<frame_producer>& producer, bool preview, int auto_play_delta)\r
{\r
executor_.begin_invoke([=]\r
{\r
- layers_[index].load(producer, preview, auto_play_delta);\r
+ get_layer(index).load(producer, preview, auto_play_delta);\r
}, high_priority);\r
}\r
\r
{ \r
executor_.begin_invoke([=]\r
{\r
- layers_[index].pause();\r
+ get_layer(index).pause();\r
}, high_priority);\r
}\r
\r
{ \r
executor_.begin_invoke([=]\r
{\r
- layers_[index].play();\r
+ get_layer(index).play();\r
}, high_priority);\r
}\r
\r
{ \r
executor_.begin_invoke([=]\r
{\r
- layers_[index].stop();\r
+ get_layer(index).stop();\r
}, high_priority);\r
}\r
\r
{\r
return std::move(*executor_.invoke([=]\r
{\r
- return std::make_shared<boost::unique_future<std::wstring>>(std::move(layers_[index].call(foreground, param)));\r
+ return std::make_shared<boost::unique_future<std::wstring>>(std::move(get_layer(index).call(foreground, param)));\r
}, high_priority));\r
}\r
\r
- void swap_layers(const safe_ptr<stage>& other)\r
+ void swap_layers(stage& other)\r
{\r
- if(other->impl_.get() == this)\r
+ auto other_impl = other.impl_;\r
+\r
+ if(other_impl.get() == this)\r
return;\r
\r
auto func = [=]\r
{\r
- std::swap(layers_, other->impl_->layers_);\r
+ auto layers = layers_ | boost::adaptors::map_values;\r
+ auto other_layers = other_impl->layers_ | boost::adaptors::map_values;\r
+\r
+ BOOST_FOREACH(auto& layer, layers)\r
+ layer->monitor_output().unlink_target(&monitor_subject_);\r
+ \r
+ BOOST_FOREACH(auto& layer, other_layers)\r
+ layer->monitor_output().unlink_target(&monitor_subject_);\r
+ \r
+ std::swap(layers_, other_impl->layers_);\r
+ \r
+ BOOST_FOREACH(auto& layer, layers)\r
+ layer->monitor_output().link_target(&monitor_subject_);\r
+ \r
+ BOOST_FOREACH(auto& layer, other_layers)\r
+ layer->monitor_output().link_target(&monitor_subject_);\r
}; \r
+\r
executor_.begin_invoke([=]\r
{\r
- other->impl_->executor_.invoke(func, high_priority);\r
- }, high_priority);\r
+ other_impl->executor_.invoke(func, task_priority::high_priority);\r
+ }, task_priority::high_priority);\r
}\r
\r
- void swap_layer(int index, size_t other_index)\r
+ void swap_layer(int index, int other_index)\r
{\r
executor_.begin_invoke([=]\r
{\r
- std::swap(layers_[index], layers_[other_index]);\r
- }, high_priority);\r
+ std::swap(get_layer(index), get_layer(other_index));\r
+ }, task_priority::high_priority);\r
}\r
\r
- void swap_layer(int index, size_t other_index, const safe_ptr<stage>& other)\r
+ void swap_layer(int index, int other_index, stage& other)\r
{\r
- if(other->impl_.get() == this)\r
+ auto other_impl = other.impl_;\r
+\r
+ if(other_impl.get() == this)\r
swap_layer(index, other_index);\r
else\r
{\r
auto func = [=]\r
{\r
- std::swap(layers_[index], other->impl_->layers_[other_index]);\r
+ auto& my_layer = get_layer(index);\r
+ auto& other_layer = other_impl->get_layer(other_index);\r
+\r
+ my_layer.monitor_output().unlink_target(&monitor_subject_);\r
+ other_layer.monitor_output().unlink_target(&other_impl->monitor_subject_);\r
+\r
+ std::swap(my_layer, other_layer);\r
+\r
+ my_layer.monitor_output().link_target(&monitor_subject_);\r
+ other_layer.monitor_output().link_target(&other_impl->monitor_subject_);\r
}; \r
+\r
executor_.begin_invoke([=]\r
{\r
- other->impl_->executor_.invoke(func, high_priority);\r
- }, high_priority);\r
+ other_impl->executor_.invoke(func, task_priority::high_priority);\r
+ }, task_priority::high_priority);\r
}\r
}\r
\r
{\r
return executor_.begin_invoke([=]\r
{\r
- return layers_[index].foreground();\r
+ return get_layer(index).foreground();\r
}, high_priority);\r
}\r
\r
{\r
return executor_.begin_invoke([=]\r
{\r
- return layers_[index].background();\r
+ return get_layer(index).background();\r
}, high_priority);\r
}\r
\r
{\r
boost::property_tree::wptree info;\r
BOOST_FOREACH(auto& layer, layers_) \r
- info.add_child(L"layers.layer", layer.second.info())\r
+ info.add_child(L"layers.layer", layer.second->info())\r
.add(L"index", layer.first); \r
return info;\r
}, high_priority));\r
{\r
return std::move(executor_.begin_invoke([=]() -> boost::property_tree::wptree\r
{\r
- return layers_[index].info();\r
+ return get_layer(index).info();\r
}, high_priority));\r
}\r
};\r
\r
-stage::stage(const safe_ptr<diagnostics::graph>& graph, const safe_ptr<target_t>& target, const video_format_desc& format_desc) : impl_(new implementation(graph, target, format_desc)){}\r
+stage::stage(const safe_ptr<diagnostics::graph>& graph, const safe_ptr<target_t>& target, const video_format_desc& format_desc) \r
+ : impl_(new implementation(graph, target, format_desc)){}\r
void stage::apply_transforms(const std::vector<stage::transform_tuple_t>& transforms){impl_->apply_transforms(transforms);}\r
void stage::apply_transform(int index, const std::function<core::frame_transform(core::frame_transform)>& transform, unsigned int mix_duration, const std::wstring& tween){impl_->apply_transform(index, transform, mix_duration, tween);}\r
void stage::clear_transforms(int index){impl_->clear_transforms(index);}\r
void stage::stop(int index){impl_->stop(index);}\r
void stage::clear(int index){impl_->clear(index);}\r
void stage::clear(){impl_->clear();}\r
-void stage::swap_layers(const safe_ptr<stage>& other){impl_->swap_layers(other);}\r
+void stage::swap_layers(const safe_ptr<stage>& other){impl_->swap_layers(*other);}\r
void stage::swap_layer(int index, size_t other_index){impl_->swap_layer(index, other_index);}\r
-void stage::swap_layer(int index, size_t other_index, const safe_ptr<stage>& other){impl_->swap_layer(index, other_index, other);}\r
+void stage::swap_layer(int index, size_t other_index, const safe_ptr<stage>& other){impl_->swap_layer(index, other_index, *other);}\r
boost::unique_future<safe_ptr<frame_producer>> stage::foreground(int index) {return impl_->foreground(index);}\r
boost::unique_future<safe_ptr<frame_producer>> stage::background(int index) {return impl_->background(index);}\r
boost::unique_future<std::wstring> stage::call(int index, bool foreground, const std::wstring& param){return impl_->call(index, foreground, param);}\r
void stage::set_video_format_desc(const video_format_desc& format_desc){impl_->set_video_format_desc(format_desc);}\r
boost::unique_future<boost::property_tree::wptree> stage::info() const{return impl_->info();}\r
boost::unique_future<boost::property_tree::wptree> stage::info(int index) const{return impl_->info(index);}\r
+monitor::source& stage::monitor_output(){return impl_->monitor_subject_;}\r
}}
\ No newline at end of file
\r
#include "frame_producer.h"\r
\r
+#include "../monitor/monitor.h"\r
+\r
#include <common/memory/safe_ptr.h>\r
#include <common/concurrency/target.h>\r
#include <common/diagnostics/graph.h>\r
class stage : boost::noncopyable\r
{\r
public:\r
+\r
+ // Static Members\r
+\r
typedef std::function<struct frame_transform(struct frame_transform)> transform_func_t;\r
typedef std::tuple<int, transform_func_t, unsigned int, std::wstring> transform_tuple_t;\r
typedef target<std::pair<std::map<int, safe_ptr<basic_frame>>, std::shared_ptr<void>>> target_t;\r
\r
+ // Constructors\r
+\r
explicit stage(const safe_ptr<diagnostics::graph>& graph, const safe_ptr<target_t>& target, const video_format_desc& format_desc);\r
\r
- // stage\r
+ // Methods\r
\r
void apply_transforms(const std::vector<transform_tuple_t>& transforms);\r
void apply_transform(int index, const transform_func_t& transform, unsigned int mix_duration = 0, const std::wstring& tween = L"linear");\r
void swap_layer(int index, size_t other_index, const safe_ptr<stage>& other);\r
\r
boost::unique_future<std::wstring> call(int index, bool foreground, const std::wstring& param);\r
+\r
+ // Properties\r
+\r
boost::unique_future<safe_ptr<frame_producer>> foreground(int index);\r
boost::unique_future<safe_ptr<frame_producer>> background(int index);\r
\r
boost::unique_future<boost::property_tree::wptree> info(int layer) const;\r
\r
void set_video_format_desc(const video_format_desc& format_desc);\r
+ \r
+ monitor::source& monitor_output();\r
\r
private:\r
struct implementation;\r
\r
struct transition_producer : public frame_producer\r
{ \r
+ monitor::subject monitor_subject_;\r
+\r
const field_mode::type mode_;\r
unsigned int current_frame_;\r
\r
, info_(info)\r
, dest_producer_(dest)\r
, source_producer_(frame_producer::empty())\r
- , last_frame_(basic_frame::empty()){}\r
+ , last_frame_(basic_frame::empty())\r
+ {\r
+ dest->monitor_output().link_target(&monitor_subject_);\r
+ }\r
\r
// frame_producer\r
\r
source = source_producer_->last_frame();\r
});\r
\r
+ monitor_subject_ << monitor::message("/transition/frame") % static_cast<std::int32_t>(current_frame_) % static_cast<std::int32_t>(info_.duration)\r
+ << monitor::message("/transition/type") % [&]() -> std::string\r
+ {\r
+ switch(info_.type)\r
+ {\r
+ case transition::mix: return "mix";\r
+ case transition::wipe: return "wipe";\r
+ case transition::slide: return "slide";\r
+ case transition::push: return "push";\r
+ case transition::cut: return "cut";\r
+ default: return "n/a";\r
+ }\r
+ }();\r
+\r
return compose(dest, source);\r
}\r
\r
\r
return basic_frame::combine(s_frame, d_frame);\r
}\r
+\r
+ monitor::source& monitor_output()\r
+ {\r
+ return monitor_subject_;\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
struct video_channel::implementation : boost::noncopyable\r
{\r
+ video_channel& self_;\r
const int index_;\r
video_format_desc format_desc_;\r
const safe_ptr<ogl_device> ogl_;\r
const safe_ptr<caspar::core::output> output_;\r
const safe_ptr<caspar::core::mixer> mixer_;\r
const safe_ptr<caspar::core::stage> stage_;\r
+\r
+ monitor::subject monitor_subject_;\r
\r
public:\r
- implementation(int index, const video_format_desc& format_desc, const safe_ptr<ogl_device>& ogl) \r
- : index_(index)\r
+ implementation(video_channel& self, int index, const video_format_desc& format_desc, const safe_ptr<ogl_device>& ogl) \r
+ : self_(self)\r
+ , index_(index)\r
, format_desc_(format_desc)\r
, ogl_(ogl)\r
, output_(new caspar::core::output(graph_, format_desc, index))\r
, mixer_(new caspar::core::mixer(graph_, output_, format_desc, ogl))\r
, stage_(new caspar::core::stage(graph_, mixer_, format_desc)) \r
+ , monitor_subject_("/channel/" + boost::lexical_cast<std::string>(index))\r
{\r
graph_->set_text(print());\r
diagnostics::register_graph(graph_);\r
for(int n = 0; n < std::max(1, env::properties().get(L"configuration.pipeline-tokens", 2)); ++n)\r
stage_->spawn_token();\r
\r
+ stage_->monitor_output().link_target(&monitor_subject_);\r
+\r
CASPAR_LOG(info) << print() << " Successfully Initialized.";\r
}\r
\r
}\r
};\r
\r
-video_channel::video_channel(int index, const video_format_desc& format_desc, const safe_ptr<ogl_device>& ogl) : impl_(new implementation(index, format_desc, ogl)){}\r
+video_channel::video_channel(int index, const video_format_desc& format_desc, const safe_ptr<ogl_device>& ogl) \r
+ : impl_(new implementation(*this, index, format_desc, ogl)){}\r
safe_ptr<stage> video_channel::stage() { return impl_->stage_;} \r
safe_ptr<mixer> video_channel::mixer() { return impl_->mixer_;} \r
safe_ptr<output> video_channel::output() { return impl_->output_;} \r
void video_channel::set_video_format_desc(const video_format_desc& format_desc){impl_->set_video_format_desc(format_desc);}\r
boost::property_tree::wptree video_channel::info() const{return impl_->info();}\r
int video_channel::index() const {return impl_->index_;}\r
-\r
+monitor::source& video_channel::monitor_output(){return impl_->monitor_subject_;}\r
}}
\ No newline at end of file
\r
#pragma once\r
\r
+#include "monitor/monitor.h"\r
+\r
#include <common/memory/safe_ptr.h>\r
\r
#include <boost/noncopyable.hpp>\r
-\r
#include <boost/property_tree/ptree_fwd.hpp>\r
\r
+#include <agents.h>\r
+\r
namespace caspar { namespace core {\r
\r
class stage;\r
class video_channel : boost::noncopyable\r
{\r
public:\r
+\r
+ // Static Members\r
+\r
+ // Constructors\r
+\r
explicit video_channel(int index, const video_format_desc& format_desc, const safe_ptr<ogl_device>& ogl);\r
\r
+ // Methods\r
+\r
+ // Properties\r
+\r
safe_ptr<stage> stage();\r
safe_ptr<mixer> mixer();\r
safe_ptr<output> output();\r
boost::property_tree::wptree info() const;\r
\r
int index() const;\r
+ \r
+ monitor::source& monitor_output();\r
\r
private:\r
struct implementation;\r
#include <common/memory/memclr.h>\r
#include <common/utility/param.h>\r
\r
+#include <core/monitor/monitor.h>\r
#include <core/mixer/write_frame.h>\r
#include <core/producer/frame/frame_transform.h>\r
#include <core/producer/frame/frame_factory.h>\r
\r
class decklink_producer : boost::noncopyable, public IDeckLinkInputCallback\r
{ \r
+ core::monitor::subject monitor_subject_;\r
safe_ptr<diagnostics::graph> graph_;\r
boost::timer tick_timer_;\r
boost::timer frame_timer_;\r
{\r
return model_name_ + L" [" + boost::lexical_cast<std::wstring>(device_index_) + L"|" + format_desc_.name + L"]";\r
}\r
+\r
+ core::monitor::source& monitor_output()\r
+ {\r
+ return monitor_subject_;\r
+ }\r
};\r
\r
class decklink_producer_proxy : public core::frame_producer\r
info.add(L"type", L"decklink-producer");\r
return info;\r
}\r
+\r
+ core::monitor::source& monitor_output()\r
+ {\r
+ return context_->monitor_output();\r
+ }\r
};\r
\r
safe_ptr<core::frame_producer> create_producer(const safe_ptr<core::frame_factory>& frame_factory, const std::vector<std::wstring>& params)\r
#include <common/utility/param.h>\r
#include <common/diagnostics/graph.h>\r
\r
+#include <core/monitor/monitor.h>\r
#include <core/video_format.h>\r
#include <core/producer/frame_producer.h>\r
#include <core/producer/frame/frame_factory.h>\r
\r
struct ffmpeg_producer : public core::frame_producer\r
{\r
+ core::monitor::subject monitor_subject_;\r
const std::wstring filename_;\r
\r
const safe_ptr<diagnostics::graph> graph_;\r
\r
int64_t frame_number_;\r
uint32_t file_frame_number_;\r
- \r
+ \r
public:\r
explicit ffmpeg_producer(const safe_ptr<core::frame_factory>& frame_factory, const std::wstring& filename, const std::wstring& filter, bool loop, uint32_t start, uint32_t length, bool thumbnail_mode)\r
: filename_(filename)\r
graph_->set_text(print());\r
\r
last_frame_ = frame.first;\r
+ \r
+ monitor_subject_ << core::monitor::message("/profiler/time") % frame_timer_.elapsed() % (1.0/format_desc_.fps); \r
+ \r
+ monitor_subject_ << core::monitor::message("/file/time") % (file_frame_number()/fps_) \r
+ % (file_nb_frames()/fps_)\r
+ << core::monitor::message("/file/frame") % static_cast<int32_t>(file_frame_number())\r
+ % static_cast<int32_t>(file_nb_frames())\r
+ << core::monitor::message("/file/fps") % fps_\r
+ << core::monitor::message("/file/path") % filename_\r
+ << core::monitor::message("/loop") % input_.loop();\r
\r
return frame;\r
}\r
-\r
+ \r
safe_ptr<core::basic_frame> render_specific_frame(uint32_t file_position, int hints)\r
{\r
// Some trial and error and undeterministic stuff here\r
\r
return make_safe<core::basic_frame>(frames);\r
}\r
+ \r
+ uint32_t file_frame_number() const\r
+ {\r
+ return video_decoder_ ? video_decoder_->file_frame_number() : 0;\r
+ }\r
\r
virtual uint32_t nb_frames() const override\r
{\r
for(auto frame = muxer_->poll(); frame; frame = muxer_->poll())\r
frame_buffer_.push(std::make_pair(make_safe_ptr(frame), file_frame_number));\r
}\r
+\r
+ core::monitor::source& monitor_output()\r
+ {\r
+ return monitor_subject_;\r
+ }\r
};\r
\r
safe_ptr<core::frame_producer> create_producer(const safe_ptr<core::frame_factory>& frame_factory, const std::vector<std::wstring>& params)\r
return result.get();\r
return L"";\r
}\r
+\r
+ core::monitor::source& monitor_output()\r
+ {\r
+ return flash_producer_->monitor_output();\r
+ }\r
};\r
\r
safe_ptr<cg_producer> get_default_cg_producer(const safe_ptr<core::video_channel>& video_channel, int render_layer)\r
std::wstring cg_producer::description(int layer){return impl_->timed_description(layer);}\r
std::wstring cg_producer::template_host_info(){return impl_->timed_template_host_info();}\r
boost::property_tree::wptree cg_producer::info() const{return impl_->info();}\r
-\r
+core::monitor::source& cg_producer::monitor_output(){return impl_->monitor_output();}\r
}}
\ No newline at end of file
std::wstring description(int layer);\r
std::wstring template_host_info();\r
\r
+ core::monitor::source& monitor_output();\r
+\r
private:\r
struct implementation;\r
std::shared_ptr<implementation> impl_;\r
\r
#include <core/video_format.h>\r
\r
+#include <core/monitor/monitor.h>\r
#include <core/producer/frame/basic_frame.h>\r
#include <core/producer/frame/frame_factory.h>\r
#include <core/mixer/write_frame.h>\r
\r
struct flash_producer : public core::frame_producer\r
{ \r
+ core::monitor::subject monitor_subject_;\r
const std::wstring filename_; \r
const safe_ptr<core::frame_factory> frame_factory_;\r
const int width_;\r
next();\r
else\r
graph_->set_tag("late-frame");\r
+ \r
+ monitor_subject_ << core::monitor::message("/host/path") % filename_\r
+ << core::monitor::message("/host/width") % width_\r
+ << core::monitor::message("/host/height") % height_\r
+ << core::monitor::message("/host/fps") % fps_\r
+ << core::monitor::message("/buffer") % output_buffer_.size() % buffer_size_;\r
\r
return frame;\r
}\r
});\r
return frame;\r
}\r
+\r
+ core::monitor::source& monitor_output()\r
+ {\r
+ return monitor_subject_;\r
+ }\r
};\r
\r
safe_ptr<core::frame_producer> create_producer(const safe_ptr<core::frame_factory>& frame_factory, const std::vector<std::wstring>& params)\r
\r
#include <core/video_format.h>\r
\r
+#include <core/monitor/monitor.h>\r
#include <core/producer/frame/basic_frame.h>\r
#include <core/producer/frame/frame_factory.h>\r
#include <core/mixer/write_frame.h>\r
\r
struct image_producer : public core::frame_producer\r
{ \r
- const std::wstring filename_;\r
+ core::monitor::subject monitor_subject_;\r
+ const std::wstring filename_;\r
safe_ptr<core::basic_frame> frame_;\r
\r
explicit image_producer(const safe_ptr<core::frame_factory>& frame_factory, const std::wstring& filename) \r
\r
virtual safe_ptr<core::basic_frame> receive(int) override\r
{\r
+ monitor_subject_ << core::monitor::message("/file/path") % filename_;\r
+\r
return frame_;\r
}\r
\r
info.add(L"filename", filename_);\r
return info;\r
}\r
+\r
+ core::monitor::source& monitor_output()\r
+ {\r
+ return monitor_subject_;\r
+ }\r
};\r
\r
safe_ptr<core::frame_producer> create_raw_producer(const safe_ptr<core::frame_factory>& frame_factory, const std::vector<std::wstring>& params)\r
\r
#include <core/video_format.h>\r
\r
+#include <core/monitor/monitor.h>\r
#include <core/producer/frame/basic_frame.h>\r
#include <core/producer/frame/frame_factory.h>\r
#include <core/producer/frame/frame_transform.h>\r
\r
struct image_scroll_producer : public core::frame_producer\r
{ \r
+ core::monitor::subject monitor_subject_;\r
const std::wstring filename_;\r
std::vector<safe_ptr<core::basic_frame>> frames_;\r
core::video_format_desc format_desc_;\r
return static_cast<uint32_t>(length / std::abs(speed_));// + length % std::abs(delta_));\r
}\r
}\r
+\r
+ core::monitor::source& monitor_output()\r
+ {\r
+ return monitor_subject_;\r
+ }\r
};\r
\r
safe_ptr<core::frame_producer> create_scroll_producer(const safe_ptr<core::frame_factory>& frame_factory, const std::vector<std::wstring>& params)\r
--- /dev/null
+/*
+ oscpack -- Open Sound Control packet manipulation library
+ http://www.audiomulch.com/~rossb/oscpack
+
+ Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files
+ (the "Software"), to deal in the Software without restriction,
+ including without limitation the rights to use, copy, modify, merge,
+ publish, distribute, sublicense, and/or sell copies of the Software,
+ and to permit persons to whom the Software is furnished to do so,
+ subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ Any person wishing to distribute modifications to the Software is
+ requested to send the modifications to the original developer so that
+ they can be incorporated into the canonical version.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+#ifndef INCLUDED_MESSAGEMAPPINGOSCPACKETLISTENER_H
+#define INCLUDED_MESSAGEMAPPINGOSCPACKETLISTENER_H
+
+#include <string.h>
+#include <map>
+
+#include "OscPacketListener.h"
+
+
+
+namespace osc{
+
+template< class T >
+class MessageMappingOscPacketListener : public OscPacketListener{
+public:
+ typedef void (T::*function_type)(const osc::ReceivedMessage&, const IpEndpointName&);
+
+protected:
+ void RegisterMessageFunction( const char *addressPattern, function_type f )
+ {
+ functions_.insert( std::make_pair( addressPattern, f ) );
+ }
+
+ virtual void ProcessMessage( const osc::ReceivedMessage& m,
+ const IpEndpointName& remoteEndpoint )
+ {
+ typename function_map_type::iterator i = functions_.find( m.AddressPattern() );
+ if( i != functions_.end() )
+ (dynamic_cast<T*>(this)->*(i->second))( m, remoteEndpoint );
+ }
+
+private:
+ struct cstr_compare{
+ bool operator()( const char *lhs, const char *rhs ) const
+ { return strcmp( lhs, rhs ) < 0; }
+ };
+
+ typedef std::map<const char*, function_type, cstr_compare> function_map_type;
+ function_map_type functions_;
+};
+
+} // namespace osc
+
+#endif /* INCLUDED_MESSAGEMAPPINGOSCPACKETLISTENER_H */
\ No newline at end of file
--- /dev/null
+/*
+ oscpack -- Open Sound Control packet manipulation library
+ http://www.audiomulch.com/~rossb/oscpack
+
+ Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files
+ (the "Software"), to deal in the Software without restriction,
+ including without limitation the rights to use, copy, modify, merge,
+ publish, distribute, sublicense, and/or sell copies of the Software,
+ and to permit persons to whom the Software is furnished to do so,
+ subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ Any person wishing to distribute modifications to the Software is
+ requested to send the modifications to the original developer so that
+ they can be incorporated into the canonical version.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+#ifndef INCLUDED_OSC_EXCEPTION_H
+#define INCLUDED_OSC_EXCEPTION_H
+
+#include <exception>
+
+namespace osc{
+
+class Exception : public std::exception {
+ const char *what_;
+
+public:
+ Exception() throw() {}
+ Exception( const Exception& src ) throw()
+ : what_( src.what_ ) {}
+ Exception( const char *w ) throw()
+ : what_( w ) {}
+ Exception& operator=( const Exception& src ) throw()
+ { what_ = src.what_; return *this; }
+ virtual ~Exception() throw() {}
+ virtual const char* what() const throw() { return what_; }
+};
+
+} // namespace osc
+
+#endif /* INCLUDED_OSC_EXCEPTION_H */
--- /dev/null
+/*
+ oscpack -- Open Sound Control packet manipulation library
+ http://www.audiomulch.com/~rossb/oscpack
+
+ Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files
+ (the "Software"), to deal in the Software without restriction,
+ including without limitation the rights to use, copy, modify, merge,
+ publish, distribute, sublicense, and/or sell copies of the Software,
+ and to permit persons to whom the Software is furnished to do so,
+ subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ Any person wishing to distribute modifications to the Software is
+ requested to send the modifications to the original developer so that
+ they can be incorporated into the canonical version.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+#ifndef OSC_HOSTENDIANNESS_H
+#define OSC_HOSTENDIANNESS_H
+
+//#define OSC_HOST_BIG_ENDIAN 1
+
+//*
+// Make sure either OSC_HOST_LITTLE_ENDIAN or OSC_HOST_BIG_ENDIAN is defined
+//
+// If you know a way to enhance the detection below for Linux and/or MacOSX
+// please let me know! I've tried a few things which don't work.
+//*/
+//
+//#if defined(OSC_HOST_LITTLE_ENDIAN) || defined(OSC_HOST_BIG_ENDIAN)
+//
+// you can define one of the above symbols from the command line
+// then you don't have to edit this file.
+//
+//#elif defined(__WIN32__) || defined(WIN32) || defined(WINCE)
+//
+// assume that __WIN32__ is only defined on little endian systems
+//
+//#define OSC_HOST_LITTLE_ENDIAN 1
+//#undef OSC_HOST_BIG_ENDIAN
+//
+//#elif defined(__APPLE__)
+//
+//#if defined(__LITTLE_ENDIAN__)
+//
+//#define OSC_HOST_LITTLE_ENDIAN 1
+//#undef OSC_HOST_BIG_ENDIAN
+//
+//#elif defined(__BIG_ENDIAN__)
+//
+//#define OSC_HOST_BIG_ENDIAN 1
+//#undef OSC_HOST_LITTLE_ENDIAN
+//
+//#endif
+//
+//#endif
+//
+//#if !defined(OSC_HOST_LITTLE_ENDIAN) && !defined(OSC_HOST_BIG_ENDIAN)
+//
+//#error please edit OSCHostEndianness.h to configure endianness
+//
+//#endif
+
+#endif /* OSC_HOSTENDIANNESS_H */
--- /dev/null
+/*
+ oscpack -- Open Sound Control packet manipulation library
+ http://www.audiomulch.com/~rossb/oscpack
+
+ Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files
+ (the "Software"), to deal in the Software without restriction,
+ including without limitation the rights to use, copy, modify, merge,
+ publish, distribute, sublicense, and/or sell copies of the Software,
+ and to permit persons to whom the Software is furnished to do so,
+ subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ Any person wishing to distribute modifications to the Software is
+ requested to send the modifications to the original developer so that
+ they can be incorporated into the canonical version.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+#undef _CRT_SECURE_NO_WARNINGS
+#define _CRT_SECURE_NO_WARNINGS
+
+#include "OscOutboundPacketStream.h"
+
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#if defined(__WIN32__) || defined(WIN32)
+#include <malloc.h> // for alloca
+#endif
+
+#include "OscHostEndianness.h"
+
+
+namespace osc{
+
+static void FromInt32( char *p, int32 x )
+{
+#ifdef OSC_HOST_LITTLE_ENDIAN
+ union{
+ osc::int32 i;
+ char c[4];
+ } u;
+
+ u.i = x;
+
+ p[3] = u.c[0];
+ p[2] = u.c[1];
+ p[1] = u.c[2];
+ p[0] = u.c[3];
+#else
+ *reinterpret_cast<int32*>(p) = x;
+#endif
+}
+
+
+static void FromUInt32( char *p, uint32 x )
+{
+#ifdef OSC_HOST_LITTLE_ENDIAN
+ union{
+ osc::uint32 i;
+ char c[4];
+ } u;
+
+ u.i = x;
+
+ p[3] = u.c[0];
+ p[2] = u.c[1];
+ p[1] = u.c[2];
+ p[0] = u.c[3];
+#else
+ *reinterpret_cast<uint32*>(p) = x;
+#endif
+}
+
+
+static void FromInt64( char *p, int64 x )
+{
+#ifdef OSC_HOST_LITTLE_ENDIAN
+ union{
+ osc::int64 i;
+ char c[8];
+ } u;
+
+ u.i = x;
+
+ p[7] = u.c[0];
+ p[6] = u.c[1];
+ p[5] = u.c[2];
+ p[4] = u.c[3];
+ p[3] = u.c[4];
+ p[2] = u.c[5];
+ p[1] = u.c[6];
+ p[0] = u.c[7];
+#else
+ *reinterpret_cast<int64*>(p) = x;
+#endif
+}
+
+
+static void FromUInt64( char *p, uint64 x )
+{
+#ifdef OSC_HOST_LITTLE_ENDIAN
+ union{
+ osc::uint64 i;
+ char c[8];
+ } u;
+
+ u.i = x;
+
+ p[7] = u.c[0];
+ p[6] = u.c[1];
+ p[5] = u.c[2];
+ p[4] = u.c[3];
+ p[3] = u.c[4];
+ p[2] = u.c[5];
+ p[1] = u.c[6];
+ p[0] = u.c[7];
+#else
+ *reinterpret_cast<uint64*>(p) = x;
+#endif
+}
+
+
+static inline long RoundUp4( long x )
+{
+ return ((x-1) & (~0x03L)) + 4;
+}
+
+
+OutboundPacketStream::OutboundPacketStream( char *buffer, unsigned long capacity )
+ : data_( buffer )
+ , end_( data_ + capacity )
+ , typeTagsCurrent_( end_ )
+ , messageCursor_( data_ )
+ , argumentCurrent_( data_ )
+ , elementSizePtr_( 0 )
+ , messageIsInProgress_( false )
+{
+
+}
+
+
+OutboundPacketStream::~OutboundPacketStream()
+{
+
+}
+
+
+char *OutboundPacketStream::BeginElement( char *beginPtr )
+{
+ if( elementSizePtr_ == 0 ){
+
+ elementSizePtr_ = reinterpret_cast<uint32*>(data_);
+
+ return beginPtr;
+
+ }else{
+ // store an offset to the old element size ptr in the element size slot
+ // we store an offset rather than the actual pointer to be 64 bit clean.
+ *reinterpret_cast<uint32*>(beginPtr) =
+ (uint32)(reinterpret_cast<char*>(elementSizePtr_) - data_);
+
+ elementSizePtr_ = reinterpret_cast<uint32*>(beginPtr);
+
+ return beginPtr + 4;
+ }
+}
+
+
+void OutboundPacketStream::EndElement( char *endPtr )
+{
+ assert( elementSizePtr_ != 0 );
+
+ if( elementSizePtr_ == reinterpret_cast<uint32*>(data_) ){
+
+ elementSizePtr_ = 0;
+
+ }else{
+ // while building an element, an offset to the containing element's
+ // size slot is stored in the elements size slot (or a ptr to data_
+ // if there is no containing element). We retrieve that here
+ uint32 *previousElementSizePtr =
+ (uint32*)(data_ + *reinterpret_cast<uint32*>(elementSizePtr_));
+
+ // then we store the element size in the slot, note that the element
+ // size does not include the size slot, hence the - 4 below.
+ uint32 elementSize =
+ static_cast<uint32>(endPtr - reinterpret_cast<char*>(elementSizePtr_)) - 4;
+ FromUInt32( reinterpret_cast<char*>(elementSizePtr_), elementSize );
+
+ // finally, we reset the element size ptr to the containing element
+ elementSizePtr_ = previousElementSizePtr;
+ }
+}
+
+
+bool OutboundPacketStream::ElementSizeSlotRequired() const
+{
+ return (elementSizePtr_ != 0);
+}
+
+
+void OutboundPacketStream::CheckForAvailableBundleSpace()
+{
+ unsigned long required = Size() + ((ElementSizeSlotRequired())?4:0) + 16;
+
+ if( required > Capacity() )
+ throw OutOfBufferMemoryException();
+}
+
+
+void OutboundPacketStream::CheckForAvailableMessageSpace( const char *addressPattern )
+{
+ // plus 4 for at least four bytes of type tag
+ unsigned long required = Size() + ((ElementSizeSlotRequired())?4:0)
+ + RoundUp4(static_cast<unsigned long>(strlen(addressPattern)) + 1) + 4;
+
+ if( required > Capacity() )
+ throw OutOfBufferMemoryException();
+}
+
+
+void OutboundPacketStream::CheckForAvailableArgumentSpace( long argumentLength )
+{
+ // plus three for extra type tag, comma and null terminator
+ unsigned long required = static_cast<unsigned long>(argumentCurrent_ - data_) + argumentLength
+ + RoundUp4( static_cast<unsigned long>(end_ - typeTagsCurrent_) + 3 );
+
+ if( required > Capacity() )
+ throw OutOfBufferMemoryException();
+}
+
+
+void OutboundPacketStream::Clear()
+{
+ typeTagsCurrent_ = end_;
+ messageCursor_ = data_;
+ argumentCurrent_ = data_;
+ elementSizePtr_ = 0;
+ messageIsInProgress_ = false;
+}
+
+
+unsigned int OutboundPacketStream::Capacity() const
+{
+ return static_cast<int>(end_ - data_);
+}
+
+
+unsigned int OutboundPacketStream::Size() const
+{
+ unsigned int result = static_cast<unsigned long>(argumentCurrent_ - data_);
+ if( IsMessageInProgress() ){
+ // account for the length of the type tag string. the total type tag
+ // includes an initial comma, plus at least one terminating \0
+ result += RoundUp4( static_cast<unsigned long>(end_ - typeTagsCurrent_) + 2 );
+ }
+
+ return result;
+}
+
+
+const char *OutboundPacketStream::Data() const
+{
+ return data_;
+}
+
+
+bool OutboundPacketStream::IsReady() const
+{
+ return (!IsMessageInProgress() && !IsBundleInProgress());
+}
+
+
+bool OutboundPacketStream::IsMessageInProgress() const
+{
+ return messageIsInProgress_;
+}
+
+
+bool OutboundPacketStream::IsBundleInProgress() const
+{
+ return (elementSizePtr_ != 0);
+}
+
+
+OutboundPacketStream& OutboundPacketStream::operator<<( const BundleInitiator& rhs )
+{
+ if( IsMessageInProgress() )
+ throw MessageInProgressException();
+
+ CheckForAvailableBundleSpace();
+
+ messageCursor_ = BeginElement( messageCursor_ );
+
+ memcpy( messageCursor_, "#bundle\0", 8 );
+ FromUInt64( messageCursor_ + 8, rhs.timeTag );
+
+ messageCursor_ += 16;
+ argumentCurrent_ = messageCursor_;
+
+ return *this;
+}
+
+
+OutboundPacketStream& OutboundPacketStream::operator<<( const BundleTerminator& rhs )
+{
+ (void) rhs;
+
+ if( !IsBundleInProgress() )
+ throw BundleNotInProgressException();
+ if( IsMessageInProgress() )
+ throw MessageInProgressException();
+
+ EndElement( messageCursor_ );
+
+ return *this;
+}
+
+
+OutboundPacketStream& OutboundPacketStream::operator<<( const BeginMessage& rhs )
+{
+ if( IsMessageInProgress() )
+ throw MessageInProgressException();
+
+ CheckForAvailableMessageSpace( rhs.addressPattern );
+
+ messageCursor_ = BeginElement( messageCursor_ );
+
+ strcpy( messageCursor_, rhs.addressPattern );
+ unsigned long rhsLength = static_cast<unsigned long>(strlen(rhs.addressPattern));
+ messageCursor_ += rhsLength + 1;
+
+ // zero pad to 4-byte boundary
+ unsigned long i = rhsLength + 1;
+ while( i & 0x3 ){
+ *messageCursor_++ = '\0';
+ ++i;
+ }
+
+ argumentCurrent_ = messageCursor_;
+ typeTagsCurrent_ = end_;
+
+ messageIsInProgress_ = true;
+
+ return *this;
+}
+
+
+OutboundPacketStream& OutboundPacketStream::operator<<( const MessageTerminator& rhs )
+{
+ (void) rhs;
+
+ if( !IsMessageInProgress() )
+ throw MessageNotInProgressException();
+
+ int typeTagsCount = static_cast<int>(end_ - typeTagsCurrent_);
+
+ if( typeTagsCount ){
+
+ char *tempTypeTags = (char*)alloca(typeTagsCount);
+ memcpy( tempTypeTags, typeTagsCurrent_, typeTagsCount );
+
+ // slot size includes comma and null terminator
+ int typeTagSlotSize = RoundUp4( typeTagsCount + 2 );
+
+ uint32 argumentsSize = static_cast<uint32>(argumentCurrent_ - messageCursor_);
+
+ memmove( messageCursor_ + typeTagSlotSize, messageCursor_, argumentsSize );
+
+ messageCursor_[0] = ',';
+ // copy type tags in reverse (really forward) order
+ for( int i=0; i < typeTagsCount; ++i )
+ messageCursor_[i+1] = tempTypeTags[ (typeTagsCount-1) - i ];
+
+ char *p = messageCursor_ + 1 + typeTagsCount;
+ for( int i=0; i < (typeTagSlotSize - (typeTagsCount + 1)); ++i )
+ *p++ = '\0';
+
+ typeTagsCurrent_ = end_;
+
+ // advance messageCursor_ for next message
+ messageCursor_ += typeTagSlotSize + argumentsSize;
+
+ }else{
+ // send an empty type tags string
+ memcpy( messageCursor_, ",\0\0\0", 4 );
+
+ // advance messageCursor_ for next message
+ messageCursor_ += 4;
+ }
+
+ argumentCurrent_ = messageCursor_;
+
+ EndElement( messageCursor_ );
+
+ messageIsInProgress_ = false;
+
+ return *this;
+}
+
+
+OutboundPacketStream& OutboundPacketStream::operator<<( bool rhs )
+{
+ CheckForAvailableArgumentSpace(0);
+
+ *(--typeTagsCurrent_) = (char)((rhs) ? TRUE_TYPE_TAG : FALSE_TYPE_TAG);
+
+ return *this;
+}
+
+
+OutboundPacketStream& OutboundPacketStream::operator<<( const NilType& rhs )
+{
+ (void) rhs;
+ CheckForAvailableArgumentSpace(0);
+
+ *(--typeTagsCurrent_) = NIL_TYPE_TAG;
+
+ return *this;
+}
+
+
+OutboundPacketStream& OutboundPacketStream::operator<<( const InfinitumType& rhs )
+{
+ (void) rhs;
+ CheckForAvailableArgumentSpace(0);
+
+ *(--typeTagsCurrent_) = INFINITUM_TYPE_TAG;
+
+ return *this;
+}
+
+
+OutboundPacketStream& OutboundPacketStream::operator<<( int32 rhs )
+{
+ CheckForAvailableArgumentSpace(4);
+
+ *(--typeTagsCurrent_) = INT32_TYPE_TAG;
+ FromInt32( argumentCurrent_, rhs );
+ argumentCurrent_ += 4;
+
+ return *this;
+}
+
+
+OutboundPacketStream& OutboundPacketStream::operator<<( float rhs )
+{
+ CheckForAvailableArgumentSpace(4);
+
+ *(--typeTagsCurrent_) = FLOAT_TYPE_TAG;
+
+#ifdef OSC_HOST_LITTLE_ENDIAN
+ union{
+ float f;
+ char c[4];
+ } u;
+
+ u.f = rhs;
+
+ argumentCurrent_[3] = u.c[0];
+ argumentCurrent_[2] = u.c[1];
+ argumentCurrent_[1] = u.c[2];
+ argumentCurrent_[0] = u.c[3];
+#else
+ *reinterpret_cast<float*>(argumentCurrent_) = rhs;
+#endif
+
+ argumentCurrent_ += 4;
+
+ return *this;
+}
+
+
+OutboundPacketStream& OutboundPacketStream::operator<<( char rhs )
+{
+ CheckForAvailableArgumentSpace(4);
+
+ *(--typeTagsCurrent_) = CHAR_TYPE_TAG;
+ FromInt32( argumentCurrent_, rhs );
+ argumentCurrent_ += 4;
+
+ return *this;
+}
+
+
+OutboundPacketStream& OutboundPacketStream::operator<<( const RgbaColor& rhs )
+{
+ CheckForAvailableArgumentSpace(4);
+
+ *(--typeTagsCurrent_) = RGBA_COLOR_TYPE_TAG;
+ FromUInt32( argumentCurrent_, rhs );
+ argumentCurrent_ += 4;
+
+ return *this;
+}
+
+
+OutboundPacketStream& OutboundPacketStream::operator<<( const MidiMessage& rhs )
+{
+ CheckForAvailableArgumentSpace(4);
+
+ *(--typeTagsCurrent_) = MIDI_MESSAGE_TYPE_TAG;
+ FromUInt32( argumentCurrent_, rhs );
+ argumentCurrent_ += 4;
+
+ return *this;
+}
+
+
+OutboundPacketStream& OutboundPacketStream::operator<<( int64 rhs )
+{
+ CheckForAvailableArgumentSpace(8);
+
+ *(--typeTagsCurrent_) = INT64_TYPE_TAG;
+ FromInt64( argumentCurrent_, rhs );
+ argumentCurrent_ += 8;
+
+ return *this;
+}
+
+
+OutboundPacketStream& OutboundPacketStream::operator<<( const TimeTag& rhs )
+{
+ CheckForAvailableArgumentSpace(8);
+
+ *(--typeTagsCurrent_) = TIME_TAG_TYPE_TAG;
+ FromUInt64( argumentCurrent_, rhs );
+ argumentCurrent_ += 8;
+
+ return *this;
+}
+
+
+OutboundPacketStream& OutboundPacketStream::operator<<( double rhs )
+{
+ CheckForAvailableArgumentSpace(8);
+
+ *(--typeTagsCurrent_) = DOUBLE_TYPE_TAG;
+
+#ifdef OSC_HOST_LITTLE_ENDIAN
+ union{
+ double f;
+ char c[8];
+ } u;
+
+ u.f = rhs;
+
+ argumentCurrent_[7] = u.c[0];
+ argumentCurrent_[6] = u.c[1];
+ argumentCurrent_[5] = u.c[2];
+ argumentCurrent_[4] = u.c[3];
+ argumentCurrent_[3] = u.c[4];
+ argumentCurrent_[2] = u.c[5];
+ argumentCurrent_[1] = u.c[6];
+ argumentCurrent_[0] = u.c[7];
+#else
+ *reinterpret_cast<double*>(argumentCurrent_) = rhs;
+#endif
+
+ argumentCurrent_ += 8;
+
+ return *this;
+}
+
+
+OutboundPacketStream& OutboundPacketStream::operator<<( const char *rhs )
+{
+ CheckForAvailableArgumentSpace( RoundUp4(static_cast<long>(strlen(rhs)) + 1) );
+
+ *(--typeTagsCurrent_) = STRING_TYPE_TAG;
+ strcpy( argumentCurrent_, rhs );
+ unsigned long rhsLength = static_cast<unsigned long>(strlen(rhs));
+ argumentCurrent_ += rhsLength + 1;
+
+ // zero pad to 4-byte boundary
+ unsigned long i = rhsLength + 1;
+ while( i & 0x3 ){
+ *argumentCurrent_++ = '\0';
+ ++i;
+ }
+
+ return *this;
+}
+
+
+OutboundPacketStream& OutboundPacketStream::operator<<( const Symbol& rhs )
+{
+ CheckForAvailableArgumentSpace( RoundUp4(static_cast<long>(strlen(rhs)) + 1) );
+
+ *(--typeTagsCurrent_) = SYMBOL_TYPE_TAG;
+ strcpy( argumentCurrent_, rhs );
+ unsigned long rhsLength = static_cast<unsigned long>(strlen(rhs));
+ argumentCurrent_ += rhsLength + 1;
+
+ // zero pad to 4-byte boundary
+ unsigned long i = rhsLength + 1;
+ while( i & 0x3 ){
+ *argumentCurrent_++ = '\0';
+ ++i;
+ }
+
+ return *this;
+}
+
+
+OutboundPacketStream& OutboundPacketStream::operator<<( const Blob& rhs )
+{
+ CheckForAvailableArgumentSpace( 4 + RoundUp4(rhs.size) );
+
+ *(--typeTagsCurrent_) = BLOB_TYPE_TAG;
+ FromUInt32( argumentCurrent_, rhs.size );
+ argumentCurrent_ += 4;
+
+ memcpy( argumentCurrent_, rhs.data, rhs.size );
+ argumentCurrent_ += rhs.size;
+
+ // zero pad to 4-byte boundary
+ unsigned long i = rhs.size;
+ while( i & 0x3 ){
+ *argumentCurrent_++ = '\0';
+ ++i;
+ }
+
+ return *this;
+}
+
+} // namespace osc
+
+
--- /dev/null
+/*
+ oscpack -- Open Sound Control packet manipulation library
+ http://www.audiomulch.com/~rossb/oscpack
+
+ Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files
+ (the "Software"), to deal in the Software without restriction,
+ including without limitation the rights to use, copy, modify, merge,
+ publish, distribute, sublicense, and/or sell copies of the Software,
+ and to permit persons to whom the Software is furnished to do so,
+ subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ Any person wishing to distribute modifications to the Software is
+ requested to send the modifications to the original developer so that
+ they can be incorporated into the canonical version.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+#ifndef INCLUDED_OSCOUTBOUNDPACKET_H
+#define INCLUDED_OSCOUTBOUNDPACKET_H
+
+#include "OscTypes.h"
+#include "OscException.h"
+
+
+namespace osc{
+
+class OutOfBufferMemoryException : public Exception{
+public:
+ OutOfBufferMemoryException( const char *w="out of buffer memory" )
+ : Exception( w ) {}
+};
+
+class BundleNotInProgressException : public Exception{
+public:
+ BundleNotInProgressException(
+ const char *w="call to EndBundle when bundle is not in progress" )
+ : Exception( w ) {}
+};
+
+class MessageInProgressException : public Exception{
+public:
+ MessageInProgressException(
+ const char *w="opening or closing bundle or message while message is in progress" )
+ : Exception( w ) {}
+};
+
+class MessageNotInProgressException : public Exception{
+public:
+ MessageNotInProgressException(
+ const char *w="call to EndMessage when message is not in progress" )
+ : Exception( w ) {}
+};
+
+
+class OutboundPacketStream{
+public:
+ OutboundPacketStream( char *buffer, unsigned long capacity );
+ ~OutboundPacketStream();
+
+ void Clear();
+
+ unsigned int Capacity() const;
+
+ // invariant: size() is valid even while building a message.
+ unsigned int Size() const;
+
+ const char *Data() const;
+
+ // indicates that all messages have been closed with a matching EndMessage
+ // and all bundles have been closed with a matching EndBundle
+ bool IsReady() const;
+
+ bool IsMessageInProgress() const;
+ bool IsBundleInProgress() const;
+
+ OutboundPacketStream& operator<<( const BundleInitiator& rhs );
+ OutboundPacketStream& operator<<( const BundleTerminator& rhs );
+
+ OutboundPacketStream& operator<<( const BeginMessage& rhs );
+ OutboundPacketStream& operator<<( const MessageTerminator& rhs );
+
+ OutboundPacketStream& operator<<( bool rhs );
+ OutboundPacketStream& operator<<( const NilType& rhs );
+ OutboundPacketStream& operator<<( const InfinitumType& rhs );
+ OutboundPacketStream& operator<<( int32 rhs );
+
+//#ifndef __x86_64__
+// OutboundPacketStream& operator<<( int rhs )
+// { *this << (int32)rhs; return *this; }
+//#endif
+
+ OutboundPacketStream& operator<<( float rhs );
+ OutboundPacketStream& operator<<( char rhs );
+ OutboundPacketStream& operator<<( const RgbaColor& rhs );
+ OutboundPacketStream& operator<<( const MidiMessage& rhs );
+ OutboundPacketStream& operator<<( int64 rhs );
+ OutboundPacketStream& operator<<( const TimeTag& rhs );
+ OutboundPacketStream& operator<<( double rhs );
+ OutboundPacketStream& operator<<( const char* rhs );
+ OutboundPacketStream& operator<<( const Symbol& rhs );
+ OutboundPacketStream& operator<<( const Blob& rhs );
+
+private:
+
+ char *BeginElement( char *beginPtr );
+ void EndElement( char *endPtr );
+
+ bool ElementSizeSlotRequired() const;
+ void CheckForAvailableBundleSpace();
+ void CheckForAvailableMessageSpace( const char *addressPattern );
+ void CheckForAvailableArgumentSpace( long argumentLength );
+
+ char *data_;
+ char *end_;
+
+ char *typeTagsCurrent_; // stored in reverse order
+ char *messageCursor_;
+ char *argumentCurrent_;
+
+ // elementSizePtr_ has two special values: 0 indicates that a bundle
+ // isn't open, and elementSizePtr_==data_ indicates that a bundle is
+ // open but that it doesn't have a size slot (ie the outermost bundle)
+ uint32 *elementSizePtr_;
+
+ bool messageIsInProgress_;
+};
+
+} // namespace osc
+
+#endif /* INCLUDED_OSC_OUTBOUND_PACKET_H */
--- /dev/null
+/*
+ oscpack -- Open Sound Control packet manipulation library
+ http://www.audiomulch.com/~rossb/oscpack
+
+ Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files
+ (the "Software"), to deal in the Software without restriction,
+ including without limitation the rights to use, copy, modify, merge,
+ publish, distribute, sublicense, and/or sell copies of the Software,
+ and to permit persons to whom the Software is furnished to do so,
+ subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ Any person wishing to distribute modifications to the Software is
+ requested to send the modifications to the original developer so that
+ they can be incorporated into the canonical version.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+#ifndef INCLUDED_OSCPACKETLISTENER_H
+#define INCLUDED_OSCPACKETLISTENER_H
+
+#include "OscReceivedElements.h"
+#include "../ip/PacketListener.h"
+
+
+namespace osc{
+
+class OscPacketListener : public PacketListener{
+protected:
+ virtual void ProcessBundle( const osc::ReceivedBundle& b,
+ const IpEndpointName& remoteEndpoint )
+ {
+ // ignore bundle time tag for now
+
+ for( ReceivedBundle::const_iterator i = b.ElementsBegin();
+ i != b.ElementsEnd(); ++i ){
+ if( i->IsBundle() )
+ ProcessBundle( ReceivedBundle(*i), remoteEndpoint );
+ else
+ ProcessMessage( ReceivedMessage(*i), remoteEndpoint );
+ }
+ }
+
+ virtual void ProcessMessage( const osc::ReceivedMessage& m,
+ const IpEndpointName& remoteEndpoint ) = 0;
+
+public:
+ virtual void ProcessPacket( const char *data, int size,
+ const IpEndpointName& remoteEndpoint )
+ {
+ osc::ReceivedPacket p( data, size );
+ if( p.IsBundle() )
+ ProcessBundle( ReceivedBundle(p), remoteEndpoint );
+ else
+ ProcessMessage( ReceivedMessage(p), remoteEndpoint );
+ }
+};
+
+} // namespace osc
+
+#endif /* INCLUDED_OSCPACKETLISTENER_H */
--- /dev/null
+/*
+ oscpack -- Open Sound Control packet manipulation library
+ http://www.audiomulch.com/~rossb/oscpack
+
+ Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files
+ (the "Software"), to deal in the Software without restriction,
+ including without limitation the rights to use, copy, modify, merge,
+ publish, distribute, sublicense, and/or sell copies of the Software,
+ and to permit persons to whom the Software is furnished to do so,
+ subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ Any person wishing to distribute modifications to the Software is
+ requested to send the modifications to the original developer so that
+ they can be incorporated into the canonical version.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+#undef _CRT_SECURE_NO_WARNINGS
+#define _CRT_SECURE_NO_WARNINGS
+
+#include "OscPrintReceivedElements.h"
+
+#include <iostream>
+#include <iomanip>
+#include <ctime>
+#include <cstring>
+
+
+namespace osc{
+
+
+std::ostream& operator<<( std::ostream & os,
+ const ReceivedMessageArgument& arg )
+{
+ switch( arg.TypeTag() ){
+ case TRUE_TYPE_TAG:
+ os << "bool:true";
+ break;
+
+ case FALSE_TYPE_TAG:
+ os << "bool:false";
+ break;
+
+ case NIL_TYPE_TAG:
+ os << "(Nil)";
+ break;
+
+ case INFINITUM_TYPE_TAG:
+ os << "(Infinitum)";
+ break;
+
+ case INT32_TYPE_TAG:
+ os << "int32:" << arg.AsInt32Unchecked();
+ break;
+
+ case FLOAT_TYPE_TAG:
+ os << "float32:" << arg.AsFloatUnchecked();
+ break;
+
+ case CHAR_TYPE_TAG:
+ {
+ char s[2] = {0};
+ s[0] = arg.AsCharUnchecked();
+ os << "char:'" << s << "'";
+ }
+ break;
+
+ case RGBA_COLOR_TYPE_TAG:
+ {
+ uint32 color = arg.AsRgbaColorUnchecked();
+
+ os << "RGBA:0x"
+ << std::hex << std::setfill('0')
+ << std::setw(2) << (int)((color>>24) & 0xFF)
+ << std::setw(2) << (int)((color>>16) & 0xFF)
+ << std::setw(2) << (int)((color>>8) & 0xFF)
+ << std::setw(2) << (int)(color & 0xFF)
+ << std::setfill(' ');
+ os.unsetf(std::ios::basefield);
+ }
+ break;
+
+ case MIDI_MESSAGE_TYPE_TAG:
+ {
+ uint32 m = arg.AsMidiMessageUnchecked();
+ os << "midi (port, status, data1, data2):<<"
+ << std::hex << std::setfill('0')
+ << "0x" << std::setw(2) << (int)((m>>24) & 0xFF)
+ << " 0x" << std::setw(2) << (int)((m>>16) & 0xFF)
+ << " 0x" << std::setw(2) << (int)((m>>8) & 0xFF)
+ << " 0x" << std::setw(2) << (int)(m & 0xFF)
+ << std::setfill(' ') << ">>";
+ os.unsetf(std::ios::basefield);
+ }
+ break;
+
+ case INT64_TYPE_TAG:
+ os << "int64:" << arg.AsInt64Unchecked();
+ break;
+
+ case TIME_TAG_TYPE_TAG:
+ {
+ os << "OSC-timetag:" << arg.AsTimeTagUnchecked();
+
+ std::time_t t =
+ (unsigned long)( arg.AsTimeTagUnchecked() >> 32 );
+
+ // strip trailing newline from string returned by ctime
+ const char *timeString = std::ctime( &t );
+ size_t len = strlen( timeString );
+ char *s = new char[ len + 1 ];
+ strcpy( s, timeString );
+ if( len )
+ s[ len - 1 ] = '\0';
+
+ os << " " << s;
+ }
+ break;
+
+ case DOUBLE_TYPE_TAG:
+ os << "double:" << arg.AsDoubleUnchecked();
+ break;
+
+ case STRING_TYPE_TAG:
+ os << "OSC-string:`" << arg.AsStringUnchecked() << "'";
+ break;
+
+ case SYMBOL_TYPE_TAG:
+ os << "OSC-string (symbol):`" << arg.AsSymbolUnchecked() << "'";
+ break;
+
+ case BLOB_TYPE_TAG:
+ {
+ unsigned long size;
+ const void *data;
+ arg.AsBlobUnchecked( data, size );
+ os << "OSC-blob:<<" << std::hex << std::setfill('0');
+ unsigned char *p = (unsigned char*)data;
+ for( unsigned long i = 0; i < size; ++i ){
+ os << "0x" << std::setw(2) << int(p[i]);
+ if( i != size-1 )
+ os << ' ';
+ }
+ os.unsetf(std::ios::basefield);
+ os << ">>" << std::setfill(' ');
+ }
+ break;
+
+ default:
+ os << "unknown";
+ }
+
+ return os;
+}
+
+
+std::ostream& operator<<( std::ostream & os, const ReceivedMessage& m )
+{
+ os << "[";
+ if( m.AddressPatternIsUInt32() )
+ os << m.AddressPatternAsUInt32();
+ else
+ os << m.AddressPattern();
+
+ bool first = true;
+ for( ReceivedMessage::const_iterator i = m.ArgumentsBegin();
+ i != m.ArgumentsEnd(); ++i ){
+ if( first ){
+ os << " ";
+ first = false;
+ }else{
+ os << ", ";
+ }
+
+ os << *i;
+ }
+
+ os << "]";
+
+ return os;
+}
+
+
+std::ostream& operator<<( std::ostream & os, const ReceivedBundle& b )
+{
+ static int indent = 0;
+
+ for( int j=0; j < indent; ++j )
+ os << " ";
+ os << "{ ( ";
+ if( b.TimeTag() == 1 )
+ os << "immediate";
+ else
+ os << b.TimeTag();
+ os << " )\n";
+
+ ++indent;
+
+ for( ReceivedBundle::const_iterator i = b.ElementsBegin();
+ i != b.ElementsEnd(); ++i ){
+ if( i->IsBundle() ){
+ ReceivedBundle b(*i);
+ os << b << "\n";
+ }else{
+ ReceivedMessage m(*i);
+ for( int j=0; j < indent; ++j )
+ os << " ";
+ os << m << "\n";
+ }
+ }
+
+ --indent;
+
+ for( int j=0; j < indent; ++j )
+ os << " ";
+ os << "}";
+
+ return os;
+}
+
+
+std::ostream& operator<<( std::ostream & os, const ReceivedPacket& p )
+{
+ if( p.IsBundle() ){
+ ReceivedBundle b(p);
+ os << b << "\n";
+ }else{
+ ReceivedMessage m(p);
+ os << m << "\n";
+ }
+
+ return os;
+}
+
+} // namespace osc
--- /dev/null
+/*
+ oscpack -- Open Sound Control packet manipulation library
+ http://www.audiomulch.com/~rossb/oscpack
+
+ Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files
+ (the "Software"), to deal in the Software without restriction,
+ including without limitation the rights to use, copy, modify, merge,
+ publish, distribute, sublicense, and/or sell copies of the Software,
+ and to permit persons to whom the Software is furnished to do so,
+ subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ Any person wishing to distribute modifications to the Software is
+ requested to send the modifications to the original developer so that
+ they can be incorporated into the canonical version.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+#ifndef INCLUDED_OSCPRINTRECEIVEDELEMENTS_H
+#define INCLUDED_OSCPRINTRECEIVEDELEMENTS_H
+
+#include <iosfwd>
+
+#ifndef INCLUDED_OSCRECEIVEDELEMENTS_H
+#include "OscReceivedElements.h"
+#endif /* INCLUDED_OSCRECEIVEDELEMENTS_H */
+
+
+namespace osc{
+
+std::ostream& operator<<( std::ostream & os, const ReceivedPacket& p );
+std::ostream& operator<<( std::ostream & os, const ReceivedMessageArgument& arg );
+std::ostream& operator<<( std::ostream & os, const ReceivedMessage& m );
+std::ostream& operator<<( std::ostream & os, const ReceivedBundle& b );
+
+} // namespace osc
+
+#endif /* INCLUDED_OSCPRINTRECEIVEDELEMENTS_H */
--- /dev/null
+/*
+ oscpack -- Open Sound Control packet manipulation library
+ http://www.audiomulch.com/~rossb/oscpack
+
+ Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files
+ (the "Software"), to deal in the Software without restriction,
+ including without limitation the rights to use, copy, modify, merge,
+ publish, distribute, sublicense, and/or sell copies of the Software,
+ and to permit persons to whom the Software is furnished to do so,
+ subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ Any person wishing to distribute modifications to the Software is
+ requested to send the modifications to the original developer so that
+ they can be incorporated into the canonical version.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+#undef _CRT_SECURE_NO_WARNINGS
+#define _CRT_SECURE_NO_WARNINGS
+
+#include "OscReceivedElements.h"
+
+#include <cassert>
+
+#include "OscHostEndianness.h"
+
+
+namespace osc{
+
+
+// return the first 4 byte boundary after the end of a str4
+// be careful about calling this version if you don't know whether
+// the string is terminated correctly.
+static inline const char* FindStr4End( const char *p )
+{
+ if( p[0] == '\0' ) // special case for SuperCollider integer address pattern
+ return p + 4;
+
+ p += 3;
+
+ while( *p )
+ p += 4;
+
+ return p + 1;
+}
+
+
+// return the first 4 byte boundary after the end of a str4
+// returns 0 if p == end or if the string is unterminated
+static inline const char* FindStr4End( const char *p, const char *end )
+{
+ if( p >= end )
+ return 0;
+
+ if( p[0] == '\0' ) // special case for SuperCollider integer address pattern
+ return p + 4;
+
+ p += 3;
+ end -= 1;
+
+ while( p < end && *p )
+ p += 4;
+
+ if( *p )
+ return 0;
+ else
+ return p + 1;
+}
+
+
+static inline unsigned long RoundUp4( unsigned long x )
+{
+ unsigned long remainder = x & 0x3UL;
+ if( remainder )
+ return x + (4 - remainder);
+ else
+ return x;
+}
+
+
+static inline int32 ToInt32( const char *p )
+{
+#ifdef OSC_HOST_LITTLE_ENDIAN
+ union{
+ osc::int32 i;
+ char c[4];
+ } u;
+
+ u.c[0] = p[3];
+ u.c[1] = p[2];
+ u.c[2] = p[1];
+ u.c[3] = p[0];
+
+ return u.i;
+#else
+ return *(int32*)p;
+#endif
+}
+
+
+static inline uint32 ToUInt32( const char *p )
+{
+#ifdef OSC_HOST_LITTLE_ENDIAN
+ union{
+ osc::uint32 i;
+ char c[4];
+ } u;
+
+ u.c[0] = p[3];
+ u.c[1] = p[2];
+ u.c[2] = p[1];
+ u.c[3] = p[0];
+
+ return u.i;
+#else
+ return *(uint32*)p;
+#endif
+}
+
+
+int64 ToInt64( const char *p )
+{
+#ifdef OSC_HOST_LITTLE_ENDIAN
+ union{
+ osc::int64 i;
+ char c[8];
+ } u;
+
+ u.c[0] = p[7];
+ u.c[1] = p[6];
+ u.c[2] = p[5];
+ u.c[3] = p[4];
+ u.c[4] = p[3];
+ u.c[5] = p[2];
+ u.c[6] = p[1];
+ u.c[7] = p[0];
+
+ return u.i;
+#else
+ return *(int64*)p;
+#endif
+}
+
+
+uint64 ToUInt64( const char *p )
+{
+#ifdef OSC_HOST_LITTLE_ENDIAN
+ union{
+ osc::uint64 i;
+ char c[8];
+ } u;
+
+ u.c[0] = p[7];
+ u.c[1] = p[6];
+ u.c[2] = p[5];
+ u.c[3] = p[4];
+ u.c[4] = p[3];
+ u.c[5] = p[2];
+ u.c[6] = p[1];
+ u.c[7] = p[0];
+
+ return u.i;
+#else
+ return *(uint64*)p;
+#endif
+}
+
+//------------------------------------------------------------------------------
+
+bool ReceivedPacket::IsBundle() const
+{
+ return (Size() > 0 && Contents()[0] == '#');
+}
+
+//------------------------------------------------------------------------------
+
+bool ReceivedBundleElement::IsBundle() const
+{
+ return (Size() > 0 && Contents()[0] == '#');
+}
+
+
+int32 ReceivedBundleElement::Size() const
+{
+ return ToUInt32( size_ );
+}
+
+//------------------------------------------------------------------------------
+
+bool ReceivedMessageArgument::AsBool() const
+{
+ if( !typeTag_ )
+ throw MissingArgumentException();
+ else if( *typeTag_ == TRUE_TYPE_TAG )
+ return true;
+ else if( *typeTag_ == FALSE_TYPE_TAG )
+ return false;
+ else
+ throw WrongArgumentTypeException();
+}
+
+
+bool ReceivedMessageArgument::AsBoolUnchecked() const
+{
+ if( !typeTag_ )
+ throw MissingArgumentException();
+ else if( *typeTag_ == TRUE_TYPE_TAG )
+ return true;
+ else
+ return false;
+}
+
+
+int32 ReceivedMessageArgument::AsInt32() const
+{
+ if( !typeTag_ )
+ throw MissingArgumentException();
+ else if( *typeTag_ == INT32_TYPE_TAG )
+ return AsInt32Unchecked();
+ else
+ throw WrongArgumentTypeException();
+}
+
+
+int32 ReceivedMessageArgument::AsInt32Unchecked() const
+{
+#ifdef OSC_HOST_LITTLE_ENDIAN
+ union{
+ osc::int32 i;
+ char c[4];
+ } u;
+
+ u.c[0] = argument_[3];
+ u.c[1] = argument_[2];
+ u.c[2] = argument_[1];
+ u.c[3] = argument_[0];
+
+ return u.i;
+#else
+ return *(int32*)argument_;
+#endif
+}
+
+
+float ReceivedMessageArgument::AsFloat() const
+{
+ if( !typeTag_ )
+ throw MissingArgumentException();
+ else if( *typeTag_ == FLOAT_TYPE_TAG )
+ return AsFloatUnchecked();
+ else
+ throw WrongArgumentTypeException();
+}
+
+
+float ReceivedMessageArgument::AsFloatUnchecked() const
+{
+#ifdef OSC_HOST_LITTLE_ENDIAN
+ union{
+ float f;
+ char c[4];
+ } u;
+
+ u.c[0] = argument_[3];
+ u.c[1] = argument_[2];
+ u.c[2] = argument_[1];
+ u.c[3] = argument_[0];
+
+ return u.f;
+#else
+ return *(float*)argument_;
+#endif
+}
+
+
+char ReceivedMessageArgument::AsChar() const
+{
+ if( !typeTag_ )
+ throw MissingArgumentException();
+ else if( *typeTag_ == CHAR_TYPE_TAG )
+ return AsCharUnchecked();
+ else
+ throw WrongArgumentTypeException();
+}
+
+
+char ReceivedMessageArgument::AsCharUnchecked() const
+{
+ return (char)ToInt32( argument_ );
+}
+
+
+uint32 ReceivedMessageArgument::AsRgbaColor() const
+{
+ if( !typeTag_ )
+ throw MissingArgumentException();
+ else if( *typeTag_ == RGBA_COLOR_TYPE_TAG )
+ return AsRgbaColorUnchecked();
+ else
+ throw WrongArgumentTypeException();
+}
+
+
+uint32 ReceivedMessageArgument::AsRgbaColorUnchecked() const
+{
+ return ToUInt32( argument_ );
+}
+
+
+uint32 ReceivedMessageArgument::AsMidiMessage() const
+{
+ if( !typeTag_ )
+ throw MissingArgumentException();
+ else if( *typeTag_ == MIDI_MESSAGE_TYPE_TAG )
+ return AsMidiMessageUnchecked();
+ else
+ throw WrongArgumentTypeException();
+}
+
+
+uint32 ReceivedMessageArgument::AsMidiMessageUnchecked() const
+{
+ return ToUInt32( argument_ );
+}
+
+
+int64 ReceivedMessageArgument::AsInt64() const
+{
+ if( !typeTag_ )
+ throw MissingArgumentException();
+ else if( *typeTag_ == INT64_TYPE_TAG )
+ return AsInt64Unchecked();
+ else
+ throw WrongArgumentTypeException();
+}
+
+
+int64 ReceivedMessageArgument::AsInt64Unchecked() const
+{
+ return ToInt64( argument_ );
+}
+
+
+uint64 ReceivedMessageArgument::AsTimeTag() const
+{
+ if( !typeTag_ )
+ throw MissingArgumentException();
+ else if( *typeTag_ == TIME_TAG_TYPE_TAG )
+ return AsTimeTagUnchecked();
+ else
+ throw WrongArgumentTypeException();
+}
+
+
+uint64 ReceivedMessageArgument::AsTimeTagUnchecked() const
+{
+ return ToUInt64( argument_ );
+}
+
+
+double ReceivedMessageArgument::AsDouble() const
+{
+ if( !typeTag_ )
+ throw MissingArgumentException();
+ else if( *typeTag_ == DOUBLE_TYPE_TAG )
+ return AsDoubleUnchecked();
+ else
+ throw WrongArgumentTypeException();
+}
+
+
+double ReceivedMessageArgument::AsDoubleUnchecked() const
+{
+#ifdef OSC_HOST_LITTLE_ENDIAN
+ union{
+ double d;
+ char c[8];
+ } u;
+
+ u.c[0] = argument_[7];
+ u.c[1] = argument_[6];
+ u.c[2] = argument_[5];
+ u.c[3] = argument_[4];
+ u.c[4] = argument_[3];
+ u.c[5] = argument_[2];
+ u.c[6] = argument_[1];
+ u.c[7] = argument_[0];
+
+ return u.d;
+#else
+ return *(double*)argument_;
+#endif
+}
+
+
+const char* ReceivedMessageArgument::AsString() const
+{
+ if( !typeTag_ )
+ throw MissingArgumentException();
+ else if( *typeTag_ == STRING_TYPE_TAG )
+ return argument_;
+ else
+ throw WrongArgumentTypeException();
+}
+
+
+const char* ReceivedMessageArgument::AsSymbol() const
+{
+ if( !typeTag_ )
+ throw MissingArgumentException();
+ else if( *typeTag_ == SYMBOL_TYPE_TAG )
+ return argument_;
+ else
+ throw WrongArgumentTypeException();
+}
+
+
+void ReceivedMessageArgument::AsBlob( const void*& data, unsigned long& size ) const
+{
+ if( !typeTag_ )
+ throw MissingArgumentException();
+ else if( *typeTag_ == BLOB_TYPE_TAG )
+ AsBlobUnchecked( data, size );
+ else
+ throw WrongArgumentTypeException();
+}
+
+
+void ReceivedMessageArgument::AsBlobUnchecked( const void*& data, unsigned long& size ) const
+{
+ size = ToUInt32( argument_ );
+ data = (void*)(argument_+4);
+}
+
+//------------------------------------------------------------------------------
+
+void ReceivedMessageArgumentIterator::Advance()
+{
+ if( !value_.typeTag_ )
+ return;
+
+ switch( *value_.typeTag_++ ){
+ case '\0':
+ // don't advance past end
+ --value_.typeTag_;
+ break;
+
+ case TRUE_TYPE_TAG:
+ case FALSE_TYPE_TAG:
+ case NIL_TYPE_TAG:
+ case INFINITUM_TYPE_TAG:
+
+ // zero length
+ break;
+
+ case INT32_TYPE_TAG:
+ case FLOAT_TYPE_TAG:
+ case CHAR_TYPE_TAG:
+ case RGBA_COLOR_TYPE_TAG:
+ case MIDI_MESSAGE_TYPE_TAG:
+
+ value_.argument_ += 4;
+ break;
+
+ case INT64_TYPE_TAG:
+ case TIME_TAG_TYPE_TAG:
+ case DOUBLE_TYPE_TAG:
+
+ value_.argument_ += 8;
+ break;
+
+ case STRING_TYPE_TAG:
+ case SYMBOL_TYPE_TAG:
+
+ // we use the unsafe function FindStr4End(char*) here because all of
+ // the arguments have already been validated in
+ // ReceivedMessage::Init() below.
+
+ value_.argument_ = FindStr4End( value_.argument_ );
+ break;
+
+ case BLOB_TYPE_TAG:
+ {
+ uint32 blobSize = ToUInt32( value_.argument_ );
+ value_.argument_ = value_.argument_ + 4 + RoundUp4( (unsigned long)blobSize );
+ }
+ break;
+
+ default: // unknown type tag
+ // don't advance
+ --value_.typeTag_;
+ break;
+
+
+ // not handled:
+ // [ Indicates the beginning of an array. The tags following are for
+ // data in the Array until a close brace tag is reached.
+ // ] Indicates the end of an array.
+ }
+}
+
+//------------------------------------------------------------------------------
+
+ReceivedMessage::ReceivedMessage( const ReceivedPacket& packet )
+ : addressPattern_( packet.Contents() )
+{
+ Init( packet.Contents(), packet.Size() );
+}
+
+
+ReceivedMessage::ReceivedMessage( const ReceivedBundleElement& bundleElement )
+ : addressPattern_( bundleElement.Contents() )
+{
+ Init( bundleElement.Contents(), bundleElement.Size() );
+}
+
+
+bool ReceivedMessage::AddressPatternIsUInt32() const
+{
+ return (addressPattern_[0] == '\0');
+}
+
+
+uint32 ReceivedMessage::AddressPatternAsUInt32() const
+{
+ return ToUInt32( addressPattern_ );
+}
+
+
+void ReceivedMessage::Init( const char *message, unsigned long size )
+{
+ if( size == 0 )
+ throw MalformedMessageException( "zero length messages not permitted" );
+
+ if( (size & 0x03L) != 0 )
+ throw MalformedMessageException( "message size must be multiple of four" );
+
+ const char *end = message + size;
+
+ typeTagsBegin_ = FindStr4End( addressPattern_, end );
+ if( typeTagsBegin_ == 0 ){
+ // address pattern was not terminated before end
+ throw MalformedMessageException( "unterminated address pattern" );
+ }
+
+ if( typeTagsBegin_ == end ){
+ // message consists of only the address pattern - no arguments or type tags.
+ typeTagsBegin_ = 0;
+ typeTagsEnd_ = 0;
+ arguments_ = 0;
+
+ }else{
+ if( *typeTagsBegin_ != ',' )
+ throw MalformedMessageException( "type tags not present" );
+
+ if( *(typeTagsBegin_ + 1) == '\0' ){
+ // zero length type tags
+ typeTagsBegin_ = 0;
+ typeTagsEnd_ = 0;
+ arguments_ = 0;
+
+ }else{
+ // check that all arguments are present and well formed
+
+ arguments_ = FindStr4End( typeTagsBegin_, end );
+ if( arguments_ == 0 ){
+ throw MalformedMessageException( "type tags were not terminated before end of message" );
+ }
+
+ ++typeTagsBegin_; // advance past initial ','
+
+ const char *typeTag = typeTagsBegin_;
+ const char *argument = arguments_;
+
+ do{
+ switch( *typeTag ){
+ case TRUE_TYPE_TAG:
+ case FALSE_TYPE_TAG:
+ case NIL_TYPE_TAG:
+ case INFINITUM_TYPE_TAG:
+
+ // zero length
+ break;
+
+ case INT32_TYPE_TAG:
+ case FLOAT_TYPE_TAG:
+ case CHAR_TYPE_TAG:
+ case RGBA_COLOR_TYPE_TAG:
+ case MIDI_MESSAGE_TYPE_TAG:
+
+ if( argument == end )
+ throw MalformedMessageException( "arguments exceed message size" );
+ argument += 4;
+ if( argument > end )
+ throw MalformedMessageException( "arguments exceed message size" );
+ break;
+
+ case INT64_TYPE_TAG:
+ case TIME_TAG_TYPE_TAG:
+ case DOUBLE_TYPE_TAG:
+
+ if( argument == end )
+ throw MalformedMessageException( "arguments exceed message size" );
+ argument += 8;
+ if( argument > end )
+ throw MalformedMessageException( "arguments exceed message size" );
+ break;
+
+ case STRING_TYPE_TAG:
+ case SYMBOL_TYPE_TAG:
+
+ if( argument == end )
+ throw MalformedMessageException( "arguments exceed message size" );
+ argument = FindStr4End( argument, end );
+ if( argument == 0 )
+ throw MalformedMessageException( "unterminated string argument" );
+ break;
+
+ case BLOB_TYPE_TAG:
+ {
+ if( argument + 4 > end )
+ MalformedMessageException( "arguments exceed message size" );
+
+ uint32 blobSize = ToUInt32( argument );
+ argument = argument + 4 + RoundUp4( (unsigned long)blobSize );
+ if( argument > end )
+ MalformedMessageException( "arguments exceed message size" );
+ }
+ break;
+
+ default:
+ throw MalformedMessageException( "unknown type tag" );
+
+ // not handled:
+ // [ Indicates the beginning of an array. The tags following are for
+ // data in the Array until a close brace tag is reached.
+ // ] Indicates the end of an array.
+ }
+
+ }while( *++typeTag != '\0' );
+ typeTagsEnd_ = typeTag;
+ }
+ }
+}
+
+//------------------------------------------------------------------------------
+
+ReceivedBundle::ReceivedBundle( const ReceivedPacket& packet )
+ : elementCount_( 0 )
+{
+ Init( packet.Contents(), packet.Size() );
+}
+
+
+ReceivedBundle::ReceivedBundle( const ReceivedBundleElement& bundleElement )
+ : elementCount_( 0 )
+{
+ Init( bundleElement.Contents(), bundleElement.Size() );
+}
+
+
+void ReceivedBundle::Init( const char *bundle, unsigned long size )
+{
+ if( size < 16 )
+ throw MalformedBundleException( "packet too short for bundle" );
+
+ if( (size & 0x03L) != 0 )
+ throw MalformedBundleException( "bundle size must be multiple of four" );
+
+ if( bundle[0] != '#'
+ || bundle[1] != 'b'
+ || bundle[2] != 'u'
+ || bundle[3] != 'n'
+ || bundle[4] != 'd'
+ || bundle[5] != 'l'
+ || bundle[6] != 'e'
+ || bundle[7] != '\0' )
+ throw MalformedBundleException( "bad bundle address pattern" );
+
+ end_ = bundle + size;
+
+ timeTag_ = bundle + 8;
+
+ const char *p = timeTag_ + 8;
+
+ while( p < end_ ){
+ if( p + 4 > end_ )
+ throw MalformedBundleException( "packet too short for elementSize" );
+
+ uint32 elementSize = ToUInt32( p );
+ if( (elementSize & 0x03L) != 0 )
+ throw MalformedBundleException( "bundle element size must be multiple of four" );
+
+ p += 4 + elementSize;
+ if( p > end_ )
+ throw MalformedBundleException( "packet too short for bundle element" );
+
+ ++elementCount_;
+ }
+
+ if( p != end_ )
+ throw MalformedBundleException( "bundle contents " );
+}
+
+
+uint64 ReceivedBundle::TimeTag() const
+{
+ return ToUInt64( timeTag_ );
+}
+
+
+} // namespace osc
+
--- /dev/null
+/*
+ oscpack -- Open Sound Control packet manipulation library
+ http://www.audiomulch.com/~rossb/oscpack
+
+ Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files
+ (the "Software"), to deal in the Software without restriction,
+ including without limitation the rights to use, copy, modify, merge,
+ publish, distribute, sublicense, and/or sell copies of the Software,
+ and to permit persons to whom the Software is furnished to do so,
+ subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ Any person wishing to distribute modifications to the Software is
+ requested to send the modifications to the original developer so that
+ they can be incorporated into the canonical version.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+#ifndef INCLUDED_OSCRECEIVEDELEMENTS_H
+#define INCLUDED_OSCRECEIVEDELEMENTS_H
+
+#include <cstddef>
+
+#include "OscTypes.h"
+#include "OscException.h"
+
+
+namespace osc{
+
+
+class MalformedMessageException : public Exception{
+public:
+ MalformedMessageException( const char *w="malformed message" )
+ : Exception( w ) {}
+};
+
+class MalformedBundleException : public Exception{
+public:
+ MalformedBundleException( const char *w="malformed bundle" )
+ : Exception( w ) {}
+};
+
+class WrongArgumentTypeException : public Exception{
+public:
+ WrongArgumentTypeException( const char *w="wrong argument type" )
+ : Exception( w ) {}
+};
+
+class MissingArgumentException : public Exception{
+public:
+ MissingArgumentException( const char *w="missing argument" )
+ : Exception( w ) {}
+};
+
+class ExcessArgumentException : public Exception{
+public:
+ ExcessArgumentException( const char *w="too many arguments" )
+ : Exception( w ) {}
+};
+
+
+class ReceivedPacket{
+public:
+ ReceivedPacket( const char *contents, int32 size )
+ : contents_( contents )
+ , size_( size ) {}
+
+ bool IsMessage() const { return !IsBundle(); }
+ bool IsBundle() const;
+
+ int32 Size() const { return size_; }
+ const char *Contents() const { return contents_; }
+
+private:
+ const char *contents_;
+ int32 size_;
+};
+
+
+class ReceivedBundleElement{
+public:
+ ReceivedBundleElement( const char *size )
+ : size_( size ) {}
+
+ friend class ReceivedBundleElementIterator;
+
+ bool IsMessage() const { return !IsBundle(); }
+ bool IsBundle() const;
+
+ int32 Size() const;
+ const char *Contents() const { return size_ + 4; }
+
+private:
+ const char *size_;
+};
+
+
+class ReceivedBundleElementIterator{
+public:
+ ReceivedBundleElementIterator( const char *sizePtr )
+ : value_( sizePtr ) {}
+
+ ReceivedBundleElementIterator operator++()
+ {
+ Advance();
+ return *this;
+ }
+
+ ReceivedBundleElementIterator operator++(int)
+ {
+ ReceivedBundleElementIterator old( *this );
+ Advance();
+ return old;
+ }
+
+ const ReceivedBundleElement& operator*() const { return value_; }
+
+ const ReceivedBundleElement* operator->() const { return &value_; }
+
+ friend bool operator==(const ReceivedBundleElementIterator& lhs,
+ const ReceivedBundleElementIterator& rhs );
+
+private:
+ ReceivedBundleElement value_;
+
+ void Advance() { value_.size_ = value_.Contents() + value_.Size(); }
+
+ bool IsEqualTo( const ReceivedBundleElementIterator& rhs ) const
+ {
+ return value_.size_ == rhs.value_.size_;
+ }
+};
+
+inline bool operator==(const ReceivedBundleElementIterator& lhs,
+ const ReceivedBundleElementIterator& rhs )
+{
+ return lhs.IsEqualTo( rhs );
+}
+
+inline bool operator!=(const ReceivedBundleElementIterator& lhs,
+ const ReceivedBundleElementIterator& rhs )
+{
+ return !( lhs == rhs );
+}
+
+
+class ReceivedMessageArgument{
+public:
+ ReceivedMessageArgument( const char *typeTag, const char *argument )
+ : typeTag_( typeTag )
+ , argument_( argument ) {}
+
+ friend class ReceivedMessageArgumentIterator;
+
+ const char TypeTag() const { return *typeTag_; }
+
+ // the unchecked methods below don't check whether the argument actually
+ // is of the specified type. they should only be used if you've already
+ // checked the type tag or the associated IsType() method.
+
+ bool IsBool() const
+ { return *typeTag_ == TRUE_TYPE_TAG || *typeTag_ == FALSE_TYPE_TAG; }
+ bool AsBool() const;
+ bool AsBoolUnchecked() const;
+
+ bool IsNil() const { return *typeTag_ == NIL_TYPE_TAG; }
+ bool IsInfinitum() const { return *typeTag_ == INFINITUM_TYPE_TAG; }
+
+ bool IsInt32() const { return *typeTag_ == INT32_TYPE_TAG; }
+ int32 AsInt32() const;
+ int32 AsInt32Unchecked() const;
+
+ bool IsFloat() const { return *typeTag_ == FLOAT_TYPE_TAG; }
+ float AsFloat() const;
+ float AsFloatUnchecked() const;
+
+ bool IsChar() const { return *typeTag_ == CHAR_TYPE_TAG; }
+ char AsChar() const;
+ char AsCharUnchecked() const;
+
+ bool IsRgbaColor() const { return *typeTag_ == RGBA_COLOR_TYPE_TAG; }
+ uint32 AsRgbaColor() const;
+ uint32 AsRgbaColorUnchecked() const;
+
+ bool IsMidiMessage() const { return *typeTag_ == MIDI_MESSAGE_TYPE_TAG; }
+ uint32 AsMidiMessage() const;
+ uint32 AsMidiMessageUnchecked() const;
+
+ bool IsInt64() const { return *typeTag_ == INT64_TYPE_TAG; }
+ int64 AsInt64() const;
+ int64 AsInt64Unchecked() const;
+
+ bool IsTimeTag() const { return *typeTag_ == TIME_TAG_TYPE_TAG; }
+ uint64 AsTimeTag() const;
+ uint64 AsTimeTagUnchecked() const;
+
+ bool IsDouble() const { return *typeTag_ == DOUBLE_TYPE_TAG; }
+ double AsDouble() const;
+ double AsDoubleUnchecked() const;
+
+ bool IsString() const { return *typeTag_ == STRING_TYPE_TAG; }
+ const char* AsString() const;
+ const char* AsStringUnchecked() const { return argument_; }
+
+ bool IsSymbol() const { return *typeTag_ == SYMBOL_TYPE_TAG; }
+ const char* AsSymbol() const;
+ const char* AsSymbolUnchecked() const { return argument_; }
+
+ bool IsBlob() const { return *typeTag_ == BLOB_TYPE_TAG; }
+ void AsBlob( const void*& data, unsigned long& size ) const;
+ void AsBlobUnchecked( const void*& data, unsigned long& size ) const;
+
+private:
+ const char *typeTag_;
+ const char *argument_;
+};
+
+
+class ReceivedMessageArgumentIterator{
+public:
+ ReceivedMessageArgumentIterator( const char *typeTags, const char *arguments )
+ : value_( typeTags, arguments ) {}
+
+ ReceivedMessageArgumentIterator operator++()
+ {
+ Advance();
+ return *this;
+ }
+
+ ReceivedMessageArgumentIterator operator++(int)
+ {
+ ReceivedMessageArgumentIterator old( *this );
+ Advance();
+ return old;
+ }
+
+ const ReceivedMessageArgument& operator*() const { return value_; }
+
+ const ReceivedMessageArgument* operator->() const { return &value_; }
+
+ friend bool operator==(const ReceivedMessageArgumentIterator& lhs,
+ const ReceivedMessageArgumentIterator& rhs );
+
+private:
+ ReceivedMessageArgument value_;
+
+ void Advance();
+
+ bool IsEqualTo( const ReceivedMessageArgumentIterator& rhs ) const
+ {
+ return value_.typeTag_ == rhs.value_.typeTag_;
+ }
+};
+
+inline bool operator==(const ReceivedMessageArgumentIterator& lhs,
+ const ReceivedMessageArgumentIterator& rhs )
+{
+ return lhs.IsEqualTo( rhs );
+}
+
+inline bool operator!=(const ReceivedMessageArgumentIterator& lhs,
+ const ReceivedMessageArgumentIterator& rhs )
+{
+ return !( lhs == rhs );
+}
+
+
+class ReceivedMessageArgumentStream{
+ friend class ReceivedMessage;
+ ReceivedMessageArgumentStream( const ReceivedMessageArgumentIterator& begin,
+ const ReceivedMessageArgumentIterator& end )
+ : p_( begin )
+ , end_( end ) {}
+
+ ReceivedMessageArgumentIterator p_, end_;
+
+public:
+
+ // end of stream
+ bool Eos() const { return p_ == end_; }
+
+ ReceivedMessageArgumentStream& operator>>( bool& rhs )
+ {
+ if( Eos() )
+ throw MissingArgumentException();
+
+ rhs = (*p_++).AsBool();
+ return *this;
+ }
+
+ // not sure if it would be useful to stream Nil and Infinitum
+ // for now it's not possible
+
+ ReceivedMessageArgumentStream& operator>>( int32& rhs )
+ {
+ if( Eos() )
+ throw MissingArgumentException();
+
+ rhs = (*p_++).AsInt32();
+ return *this;
+ }
+
+ ReceivedMessageArgumentStream& operator>>( float& rhs )
+ {
+ if( Eos() )
+ throw MissingArgumentException();
+
+ rhs = (*p_++).AsFloat();
+ return *this;
+ }
+
+ ReceivedMessageArgumentStream& operator>>( char& rhs )
+ {
+ if( Eos() )
+ throw MissingArgumentException();
+
+ rhs = (*p_++).AsChar();
+ return *this;
+ }
+
+ ReceivedMessageArgumentStream& operator>>( RgbaColor& rhs )
+ {
+ if( Eos() )
+ throw MissingArgumentException();
+
+ rhs.value = (*p_++).AsRgbaColor();
+ return *this;
+ }
+
+ ReceivedMessageArgumentStream& operator>>( MidiMessage& rhs )
+ {
+ if( Eos() )
+ throw MissingArgumentException();
+
+ rhs.value = (*p_++).AsMidiMessage();
+ return *this;
+ }
+
+ ReceivedMessageArgumentStream& operator>>( int64& rhs )
+ {
+ if( Eos() )
+ throw MissingArgumentException();
+
+ rhs = (*p_++).AsInt64();
+ return *this;
+ }
+
+ ReceivedMessageArgumentStream& operator>>( TimeTag& rhs )
+ {
+ if( Eos() )
+ throw MissingArgumentException();
+
+ rhs.value = (*p_++).AsTimeTag();
+ return *this;
+ }
+
+ ReceivedMessageArgumentStream& operator>>( double& rhs )
+ {
+ if( Eos() )
+ throw MissingArgumentException();
+
+ rhs = (*p_++).AsDouble();
+ return *this;
+ }
+
+ ReceivedMessageArgumentStream& operator>>( Blob& rhs )
+ {
+ if( Eos() )
+ throw MissingArgumentException();
+
+ (*p_++).AsBlob( rhs.data, rhs.size );
+ return *this;
+ }
+
+ ReceivedMessageArgumentStream& operator>>( const char*& rhs )
+ {
+ if( Eos() )
+ throw MissingArgumentException();
+
+ rhs = (*p_++).AsString();
+ return *this;
+ }
+
+ ReceivedMessageArgumentStream& operator>>( Symbol& rhs )
+ {
+ if( Eos() )
+ throw MissingArgumentException();
+
+ rhs.value = (*p_++).AsSymbol();
+ return *this;
+ }
+
+ ReceivedMessageArgumentStream& operator>>( MessageTerminator& rhs )
+ {
+ if( !Eos() )
+ throw ExcessArgumentException();
+
+ return *this;
+ }
+};
+
+
+class ReceivedMessage{
+ void Init( const char *bundle, unsigned long size );
+public:
+ explicit ReceivedMessage( const ReceivedPacket& packet );
+ explicit ReceivedMessage( const ReceivedBundleElement& bundleElement );
+
+ const char *AddressPattern() const { return addressPattern_; }
+
+ // Support for non-standad SuperCollider integer address patterns:
+ bool AddressPatternIsUInt32() const;
+ uint32 AddressPatternAsUInt32() const;
+
+ unsigned long ArgumentCount() const { return static_cast<unsigned long>(typeTagsEnd_ - typeTagsBegin_); }
+
+ const char *TypeTags() const { return typeTagsBegin_; }
+
+
+ typedef ReceivedMessageArgumentIterator const_iterator;
+
+ ReceivedMessageArgumentIterator ArgumentsBegin() const
+ {
+ return ReceivedMessageArgumentIterator( typeTagsBegin_, arguments_ );
+ }
+
+ ReceivedMessageArgumentIterator ArgumentsEnd() const
+ {
+ return ReceivedMessageArgumentIterator( typeTagsEnd_, 0 );
+ }
+
+ ReceivedMessageArgumentStream ArgumentStream() const
+ {
+ return ReceivedMessageArgumentStream( ArgumentsBegin(), ArgumentsEnd() );
+ }
+
+private:
+ const char *addressPattern_;
+ const char *typeTagsBegin_;
+ const char *typeTagsEnd_;
+ const char *arguments_;
+};
+
+
+class ReceivedBundle{
+ void Init( const char *message, unsigned long size );
+public:
+ explicit ReceivedBundle( const ReceivedPacket& packet );
+ explicit ReceivedBundle( const ReceivedBundleElement& bundleElement );
+
+ uint64 TimeTag() const;
+
+ unsigned long ElementCount() const { return elementCount_; }
+
+ typedef ReceivedBundleElementIterator const_iterator;
+
+ ReceivedBundleElementIterator ElementsBegin() const
+ {
+ return ReceivedBundleElementIterator( timeTag_ + 8 );
+ }
+
+ ReceivedBundleElementIterator ElementsEnd() const
+ {
+ return ReceivedBundleElementIterator( end_ );
+ }
+
+private:
+ const char *timeTag_;
+ const char *end_;
+ unsigned long elementCount_;
+};
+
+
+} // namespace osc
+
+
+#endif /* INCLUDED_OSCRECEIVEDELEMENTS_H */
--- /dev/null
+/*
+ oscpack -- Open Sound Control packet manipulation library
+ http://www.audiomulch.com/~rossb/oscpack
+
+ Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files
+ (the "Software"), to deal in the Software without restriction,
+ including without limitation the rights to use, copy, modify, merge,
+ publish, distribute, sublicense, and/or sell copies of the Software,
+ and to permit persons to whom the Software is furnished to do so,
+ subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ Any person wishing to distribute modifications to the Software is
+ requested to send the modifications to the original developer so that
+ they can be incorporated into the canonical version.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+#include "OscTypes.h"
+
+namespace osc{
+
+BundleInitiator BeginBundleImmediate(1);
+BundleTerminator EndBundle;
+MessageTerminator EndMessage;
+NilType Nil;
+InfinitumType Infinitum;
+
+} // namespace osc
--- /dev/null
+/*
+ oscpack -- Open Sound Control packet manipulation library
+ http://www.audiomulch.com/~rossb/oscpack
+
+ Copyright (c) 2004-2005 Ross Bencina <rossb@audiomulch.com>
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files
+ (the "Software"), to deal in the Software without restriction,
+ including without limitation the rights to use, copy, modify, merge,
+ publish, distribute, sublicense, and/or sell copies of the Software,
+ and to permit persons to whom the Software is furnished to do so,
+ subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ Any person wishing to distribute modifications to the Software is
+ requested to send the modifications to the original developer so that
+ they can be incorporated into the canonical version.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+#ifndef INCLUDED_OSCTYPES_H
+#define INCLUDED_OSCTYPES_H
+
+
+namespace osc{
+
+// basic types
+
+#if defined(__BORLANDC__) || defined(_MSC_VER)
+
+typedef __int64 int64;
+typedef unsigned __int64 uint64;
+
+#elif defined(__x86_64__) || defined(_M_X64)
+
+typedef long int64;
+typedef unsigned long uint64;
+
+#else
+
+typedef long long int64;
+typedef unsigned long long uint64;
+
+#endif
+
+
+
+#if defined(__x86_64__) || defined(_M_X64)
+
+typedef signed int int32;
+typedef unsigned int uint32;
+
+#else
+
+typedef signed long int32;
+typedef unsigned long uint32;
+
+#endif
+
+
+
+enum TypeTagValues {
+ TRUE_TYPE_TAG = 'T',
+ FALSE_TYPE_TAG = 'F',
+ NIL_TYPE_TAG = 'N',
+ INFINITUM_TYPE_TAG = 'I',
+ INT32_TYPE_TAG = 'i',
+ FLOAT_TYPE_TAG = 'f',
+ CHAR_TYPE_TAG = 'c',
+ RGBA_COLOR_TYPE_TAG = 'r',
+ MIDI_MESSAGE_TYPE_TAG = 'm',
+ INT64_TYPE_TAG = 'h',
+ TIME_TAG_TYPE_TAG = 't',
+ DOUBLE_TYPE_TAG = 'd',
+ STRING_TYPE_TAG = 's',
+ SYMBOL_TYPE_TAG = 'S',
+ BLOB_TYPE_TAG = 'b'
+};
+
+
+
+// i/o manipulators used for streaming interfaces
+
+struct BundleInitiator{
+ explicit BundleInitiator( uint64 timeTag_ ) : timeTag( timeTag_ ) {}
+ uint64 timeTag;
+};
+
+extern BundleInitiator BeginBundleImmediate;
+
+inline BundleInitiator BeginBundle( uint64 timeTag=1 )
+{
+ return BundleInitiator(timeTag);
+}
+
+
+struct BundleTerminator{
+};
+
+extern BundleTerminator EndBundle;
+
+struct BeginMessage{
+ explicit BeginMessage( const char *addressPattern_ ) : addressPattern( addressPattern_ ) {}
+ const char *addressPattern;
+};
+
+struct MessageTerminator{
+};
+
+extern MessageTerminator EndMessage;
+
+
+// osc specific types. they are defined as structs so they can be used
+// as separately identifiable types with the streaming operators.
+
+struct NilType{
+};
+
+extern NilType Nil;
+
+
+struct InfinitumType{
+};
+
+extern InfinitumType Infinitum;
+
+struct RgbaColor{
+ RgbaColor() {}
+ explicit RgbaColor( uint32 value_ ) : value( value_ ) {}
+ uint32 value;
+
+ operator uint32() const { return value; }
+};
+
+
+struct MidiMessage{
+ MidiMessage() {}
+ explicit MidiMessage( uint32 value_ ) : value( value_ ) {}
+ uint32 value;
+
+ operator uint32() const { return value; }
+};
+
+
+struct TimeTag{
+ TimeTag() {}
+ explicit TimeTag( uint64 value_ ) : value( value_ ) {}
+ uint64 value;
+
+ operator uint64() const { return value; }
+};
+
+
+struct Symbol{
+ Symbol() {}
+ explicit Symbol( const char* value_ ) : value( value_ ) {}
+ const char* value;
+
+ operator const char *() const { return value; }
+};
+
+
+struct Blob{
+ Blob() {}
+ explicit Blob( const void* data_, unsigned long size_ )
+ : data( data_ ), size( size_ ) {}
+ const void* data;
+ unsigned long size;
+};
+
+} // namespace osc
+
+
+#endif /* INCLUDED_OSCTYPES_H */
--- /dev/null
+#include "..\stdafx.h"
+
+#include "server.h"
+
+#include "oscpack/oscOutboundPacketStream.h"
+
+#include <common/utility/string.h>
+
+#include <functional>
+#include <vector>
+
+#include <boost/asio.hpp>
+#include <boost/foreach.hpp>
+#include <boost/thread.hpp>
+
+using namespace boost::asio::ip;
+
+namespace caspar { namespace protocol { namespace osc {
+
+template<typename T>
+struct param_visitor : public boost::static_visitor<void>
+{
+ T& o;
+
+ param_visitor(T& o)
+ : o(o)
+ {
+ }
+
+ void operator()(const bool value) {o << value;}
+ void operator()(const int32_t value) {o << static_cast<int64_t>(value);}
+ void operator()(const uint32_t value) {o << static_cast<int64_t>(value);}
+ void operator()(const int64_t value) {o << static_cast<int64_t>(value);}
+ void operator()(const uint64_t value) {o << static_cast<int64_t>(value);}
+ void operator()(const float value) {o << value;}
+ void operator()(const double value) {o << static_cast<float>(value);}
+ void operator()(const std::string& value) {o << value.c_str();}
+ void operator()(const std::wstring& value) {o << narrow(value).c_str();}
+ void operator()(const std::vector<int8_t>& value) {o << ::osc::Blob(value.data(), static_cast<unsigned long>(value.size()));}
+};
+
+std::vector<char> write_osc_event(const core::monitor::message& e)
+{
+ std::array<char, 4096> buffer;
+ ::osc::OutboundPacketStream o(buffer.data(), static_cast<unsigned long>(buffer.size()));
+
+ o << ::osc::BeginMessage(e.path().c_str());
+
+ param_visitor<decltype(o)> pd_visitor(o);
+ BOOST_FOREACH(auto data, e.data())
+ boost::apply_visitor(pd_visitor, data);
+
+ o << ::osc::EndMessage;
+
+ return std::vector<char>(o.Data(), o.Data() + o.Size());
+}
+
+struct server::impl
+{
+ boost::asio::io_service service_;
+
+ udp::endpoint endpoint_;
+ udp::socket socket_;
+
+ boost::thread thread_;
+
+ Concurrency::call<core::monitor::message> on_next_;
+
+public:
+ impl(udp::endpoint endpoint,
+ Concurrency::ISource<core::monitor::message>& source)
+ : endpoint_(endpoint)
+ , socket_(service_, endpoint_.protocol())
+ , thread_(std::bind(&boost::asio::io_service::run, &service_))
+ , on_next_([this](const core::monitor::message& msg){ on_next(msg); })
+ {
+ source.link_target(&on_next_);
+ }
+
+ ~impl()
+ {
+ thread_.join();
+ }
+
+ void on_next(const core::monitor::message& msg)
+ {
+ auto data_ptr = make_safe<std::vector<char>>(write_osc_event(msg));
+
+ socket_.async_send_to(boost::asio::buffer(*data_ptr),
+ endpoint_,
+ boost::bind(&impl::handle_send_to, this,
+ boost::asio::placeholders::error,
+ boost::asio::placeholders::bytes_transferred));
+ }
+
+ void handle_send_to(const boost::system::error_code& /*error*/, size_t /*bytes_sent*/)
+ {
+ }
+};
+
+server::server(udp::endpoint endpoint,
+ Concurrency::ISource<core::monitor::message>& source)
+ : impl_(new impl(endpoint, source))
+{
+}
+
+server::server(server&& other)
+ : impl_(std::move(other.impl_))
+{
+}
+
+server& server::operator=(server&& other)
+{
+ impl_ = std::move(other.impl_);
+ return *this;
+}
+
+server::~server()
+{
+}
+
+}}}
\ No newline at end of file
--- /dev/null
+#pragma once
+
+#include <common/memory/safe_ptr.h>
+
+#include <core/monitor/monitor.h>
+#include <boost/asio/ip/udp.hpp>
+
+namespace caspar { namespace protocol { namespace osc {
+
+class server
+{
+ server(const server&);
+ server& operator=(const server&);
+public:
+
+ // Static Members
+
+ // Constructors
+
+ server(boost::asio::ip::udp::endpoint endpoint,
+ Concurrency::ISource<core::monitor::message>& source);
+
+ server(server&&);
+
+ ~server();
+
+ // Methods
+
+ server& operator=(server&&);
+
+ // Properties
+
+private:
+ struct impl;
+ std::unique_ptr<impl> impl_;
+};
+
+}}}
\ No newline at end of file
<ClInclude Include="clk\CLKProtocolStrategy.h" />\r
<ClInclude Include="clk\clk_commands.h" />\r
<ClInclude Include="clk\clk_command_processor.h" />\r
+ <ClInclude Include="osc\oscpack\MessageMappingOscPacketListener.h" />\r
+ <ClInclude Include="osc\oscpack\OscException.h" />\r
+ <ClInclude Include="osc\oscpack\OscHostEndianness.h" />\r
+ <ClInclude Include="osc\oscpack\OscOutboundPacketStream.h" />\r
+ <ClInclude Include="osc\oscpack\OscPacketListener.h" />\r
+ <ClInclude Include="osc\oscpack\OscPrintReceivedElements.h" />\r
+ <ClInclude Include="osc\oscpack\OscReceivedElements.h" />\r
+ <ClInclude Include="osc\oscpack\OscTypes.h" />\r
+ <ClInclude Include="osc\server.h" />\r
<ClInclude Include="StdAfx.h" />\r
<ClInclude Include="util\AsyncEventServer.h" />\r
<ClInclude Include="util\ClientInfo.h" />\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Develop|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
</ClCompile>\r
+ <ClCompile Include="osc\oscpack\OscOutboundPacketStream.cpp">\r
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'">NotUsing</PrecompiledHeader>\r
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Develop|Win32'">NotUsing</PrecompiledHeader>\r
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>\r
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">NotUsing</PrecompiledHeader>\r
+ </ClCompile>\r
+ <ClCompile Include="osc\oscpack\OscPrintReceivedElements.cpp">\r
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'">NotUsing</PrecompiledHeader>\r
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Develop|Win32'">NotUsing</PrecompiledHeader>\r
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>\r
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">NotUsing</PrecompiledHeader>\r
+ </ClCompile>\r
+ <ClCompile Include="osc\oscpack\OscReceivedElements.cpp">\r
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'">NotUsing</PrecompiledHeader>\r
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Develop|Win32'">NotUsing</PrecompiledHeader>\r
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>\r
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">NotUsing</PrecompiledHeader>\r
+ </ClCompile>\r
+ <ClCompile Include="osc\oscpack\OscTypes.cpp">\r
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'">NotUsing</PrecompiledHeader>\r
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Develop|Win32'">NotUsing</PrecompiledHeader>\r
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>\r
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">NotUsing</PrecompiledHeader>\r
+ </ClCompile>\r
+ <ClCompile Include="osc\server.cpp">\r
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Develop|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
+ </ClCompile>\r
<ClCompile Include="StdAfx.cpp">\r
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>\r
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'">Create</PrecompiledHeader>\r
<Filter Include="source\amcp">\r
<UniqueIdentifier>{93331f26-581b-4d15-81a6-0aae31ad3958}</UniqueIdentifier>\r
</Filter>\r
+ <Filter Include="source\osc">\r
+ <UniqueIdentifier>{b2150993-f000-4bf8-bb4f-e97d2b54a479}</UniqueIdentifier>\r
+ </Filter>\r
+ <Filter Include="source\osc\oscpack">\r
+ <UniqueIdentifier>{6d9a82d4-6805-4de0-b400-6212fac06109}</UniqueIdentifier>\r
+ </Filter>\r
</ItemGroup>\r
<ItemGroup>\r
<ClInclude Include="amcp\AMCPCommand.h">\r
<ClInclude Include="util\stateful_protocol_strategy_wrapper.h">\r
<Filter>source\util</Filter>\r
</ClInclude>\r
+ <ClInclude Include="osc\oscpack\OscPacketListener.h">\r
+ <Filter>source\osc\oscpack</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="osc\oscpack\OscPrintReceivedElements.h">\r
+ <Filter>source\osc\oscpack</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="osc\oscpack\OscReceivedElements.h">\r
+ <Filter>source\osc\oscpack</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="osc\oscpack\OscTypes.h">\r
+ <Filter>source\osc\oscpack</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="osc\oscpack\MessageMappingOscPacketListener.h">\r
+ <Filter>source\osc\oscpack</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="osc\oscpack\OscException.h">\r
+ <Filter>source\osc\oscpack</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="osc\oscpack\OscHostEndianness.h">\r
+ <Filter>source\osc\oscpack</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="osc\oscpack\OscOutboundPacketStream.h">\r
+ <Filter>source\osc\oscpack</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="osc\server.h">\r
+ <Filter>source\osc</Filter>\r
+ </ClInclude>\r
</ItemGroup>\r
<ItemGroup>\r
<ClCompile Include="amcp\AMCPCommandQueue.cpp">\r
<ClCompile Include="util\stateful_protocol_strategy_wrapper.cpp">\r
<Filter>source\util</Filter>\r
</ClCompile>\r
+ <ClCompile Include="osc\oscpack\OscPrintReceivedElements.cpp">\r
+ <Filter>source\osc\oscpack</Filter>\r
+ </ClCompile>\r
+ <ClCompile Include="osc\oscpack\OscReceivedElements.cpp">\r
+ <Filter>source\osc\oscpack</Filter>\r
+ </ClCompile>\r
+ <ClCompile Include="osc\oscpack\OscTypes.cpp">\r
+ <Filter>source\osc\oscpack</Filter>\r
+ </ClCompile>\r
+ <ClCompile Include="osc\oscpack\OscOutboundPacketStream.cpp">\r
+ <Filter>source\osc\oscpack</Filter>\r
+ </ClCompile>\r
+ <ClCompile Include="osc\server.cpp">\r
+ <Filter>source\osc</Filter>\r
+ </ClCompile>\r
</ItemGroup>\r
</Project>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>\r
<configuration>\r
<paths>\r
- <media-path>media\</media-path>\r
- <log-path>log\</log-path>\r
- <data-path>data\</data-path>\r
- <template-path>templates\</template-path>\r
- <thumbnails-path>thumbnails\</thumbnails-path>\r
+ <media-path>M:\\_media\\</media-path>\r
+ <log-path>M:\\_log\\</log-path>\r
+ <data-path>M:\\_data\\</data-path>\r
+ <template-path>M:\\_template\\</template-path>\r
+ <thumbnails-path>M:\\_thumbnails\\</thumbnails-path>\r
</paths>\r
<channels>\r
<channel>\r
<port>5250</port>\r
<protocol>AMCP</protocol>\r
</tcp>\r
+ <udp>\r
+ <address>127.0.0.1</address>\r
+ <port>5253</port>\r
+ <protocol>OSC</protocol>\r
+ </udp>\r
</controllers>\r
</configuration>\r
\r
#include <atlbase.h>\r
\r
#include <protocol/amcp/AMCPProtocolStrategy.h>\r
+#include <protocol/osc/server.h>\r
\r
#include <modules/bluefish/bluefish.h>\r
#include <modules/decklink/decklink.h>\r
\r
// Create server object which initializes channels, protocols and controllers.\r
caspar::server caspar_server(shutdown_server_now);\r
+ \r
\r
// Use separate thread for the blocking console input, will be terminated \r
// anyway when the main thread terminates.\r
#include <protocol/CLK/CLKProtocolStrategy.h>\r
#include <protocol/util/AsyncEventServer.h>\r
#include <protocol/util/stateful_protocol_strategy_wrapper.h>\r
+#include <protocol/osc/server.h>\r
\r
#include <boost/algorithm/string.hpp>\r
#include <boost/lexical_cast.hpp>\r
\r
struct server::implementation : boost::noncopyable\r
{\r
+ core::monitor::subject monitor_subject_;\r
boost::promise<bool>& shutdown_server_now_;\r
safe_ptr<ogl_device> ogl_;\r
std::vector<safe_ptr<IO::AsyncEventServer>> async_servers_; \r
+ std::vector<osc::server> osc_servers_;\r
std::vector<safe_ptr<video_channel>> channels_;\r
std::shared_ptr<thumbnail_generator> thumbnail_generator_;\r
\r
\r
channels_.push_back(make_safe<video_channel>(channels_.size()+1, format_desc, ogl_));\r
\r
+ channels_.back()->monitor_output().link_target(&monitor_subject_);\r
+\r
BOOST_FOREACH(auto& xml_consumer, xml_channel.second.get_child(L"consumers"))\r
{\r
try\r
asyncbootstrapper->Start();\r
async_servers_.push_back(asyncbootstrapper);\r
}\r
+ else if(name == L"udp")\r
+ { \r
+ const auto address = xml_controller.second.get(L"address", L"127.0.0.1");\r
+ const auto port = xml_controller.second.get<unsigned short>(L"port", 5253);\r
+\r
+ osc_servers_.push_back(osc::server(boost::asio::ip::udp::endpoint(boost::asio::ip::address_v4::from_string(narrow(address)), port), monitor_subject_));\r
+ }\r
else\r
CASPAR_LOG(warning) << "Invalid controller: " << widen(name); \r
}\r
return impl_->thumbnail_generator_;\r
}\r
\r
+core::monitor::source& server::monitor_output()\r
+{\r
+ return impl_->monitor_subject_;\r
+}\r
+\r
}
\ No newline at end of file
\r
#include <common/memory/safe_ptr.h>\r
\r
+#include <core/monitor/monitor.h>\r
+\r
#include <boost/noncopyable.hpp>\r
#include <boost/thread/future.hpp>\r
\r
server(boost::promise<bool>& shutdown_server_now);\r
const std::vector<safe_ptr<core::video_channel>> get_channels() const;\r
std::shared_ptr<core::thumbnail_generator> get_thumbnail_generator() const;\r
+\r
+ core::monitor::source& monitor_output();\r
+\r
private:\r
struct implementation;\r
safe_ptr<implementation> impl_;\r