]> git.sesse.net Git - casparcg/commitdiff
- Implemented real-time state notification using OSC-UDP.
authorRobert Nagy <ronag89@gmail.com>
Sun, 14 Apr 2013 17:12:40 +0000 (19:12 +0200)
committerRobert Nagy <ronag89@gmail.com>
Sun, 14 Apr 2013 20:27:55 +0000 (22:27 +0200)
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.

45 files changed:
core/core.vcxproj
core/core.vcxproj.filters
core/monitor/monitor.cpp [new file with mode: 0644]
core/monitor/monitor.h [new file with mode: 0644]
core/producer/channel/channel_producer.cpp
core/producer/color/color_producer.cpp
core/producer/frame_producer.cpp
core/producer/frame_producer.h
core/producer/layer.cpp
core/producer/layer.h
core/producer/playlist/playlist_producer.cpp [deleted file]
core/producer/playlist/playlist_producer.h [deleted file]
core/producer/separated/separated_producer.cpp
core/producer/stage.cpp
core/producer/stage.h
core/producer/transition/transition_producer.cpp
core/video_channel.cpp
core/video_channel.h
modules/decklink/producer/decklink_producer.cpp
modules/ffmpeg/producer/ffmpeg_producer.cpp
modules/flash/producer/cg_producer.cpp
modules/flash/producer/cg_producer.h
modules/flash/producer/flash_producer.cpp
modules/image/producer/image_producer.cpp
modules/image/producer/image_scroll_producer.cpp
protocol/osc/oscpack/MessageMappingOscPacketListener.h [new file with mode: 0644]
protocol/osc/oscpack/OscException.h [new file with mode: 0644]
protocol/osc/oscpack/OscHostEndianness.h [new file with mode: 0644]
protocol/osc/oscpack/OscOutboundPacketStream.cpp [new file with mode: 0644]
protocol/osc/oscpack/OscOutboundPacketStream.h [new file with mode: 0644]
protocol/osc/oscpack/OscPacketListener.h [new file with mode: 0644]
protocol/osc/oscpack/OscPrintReceivedElements.cpp [new file with mode: 0644]
protocol/osc/oscpack/OscPrintReceivedElements.h [new file with mode: 0644]
protocol/osc/oscpack/OscReceivedElements.cpp [new file with mode: 0644]
protocol/osc/oscpack/OscReceivedElements.h [new file with mode: 0644]
protocol/osc/oscpack/OscTypes.cpp [new file with mode: 0644]
protocol/osc/oscpack/OscTypes.h [new file with mode: 0644]
protocol/osc/server.cpp [new file with mode: 0644]
protocol/osc/server.h [new file with mode: 0644]
protocol/protocol.vcxproj
protocol/protocol.vcxproj.filters
shell/casparcg.config
shell/main.cpp
shell/server.cpp
shell/server.h

index 872801ac6289965692d706f22862b95a71d35e56..fbd0729d95570fff53c4b4ad2215b77d6849dabd 100644 (file)
     <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
index 1a7f733e3c2b47b1e3cc49164a33a1c7ba2fab17..0fb5e67d1d3cc86c70c8d72c282d8a5d1d0731fa 100644 (file)
     <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
diff --git a/core/monitor/monitor.cpp b/core/monitor/monitor.cpp
new file mode 100644 (file)
index 0000000..cab17c1
--- /dev/null
@@ -0,0 +1,7 @@
+#include "../StdAfx.h"
+
+#include "monitor.h"
+
+namespace caspar { namespace core {
+       
+}}
\ No newline at end of file
diff --git a/core/monitor/monitor.h b/core/monitor/monitor.h
new file mode 100644 (file)
index 0000000..1e1e504
--- /dev/null
@@ -0,0 +1,94 @@
+#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
index 6d3bdb2636b2ba760ed53434cd3e98f5c426c677..2c52d88bfe414a05fd15c154c4d9904c977e3bf5 100644 (file)
@@ -23,6 +23,7 @@
 \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
@@ -34,7 +35,8 @@
 \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
@@ -125,6 +127,8 @@ public:
        \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
@@ -206,6 +210,11 @@ public:
                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
index 8582a27417dd87de1e79d1987cd10aac924b9071..a6e16a6a106700c2c9f7520f962c60f1857569c5 100644 (file)
@@ -23,6 +23,8 @@
 \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
@@ -37,19 +39,23 @@ namespace caspar { namespace core {
        \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
@@ -70,6 +76,11 @@ public:
                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
index 02cc30f3a3bf409a33dfd257a64dd97d84cacd92..581ff31fd02e8acd64e13a9e5433fbb1679324fe 100644 (file)
@@ -26,7 +26,6 @@
 #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
@@ -105,6 +104,7 @@ public:
        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
@@ -139,6 +139,7 @@ public:
        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
@@ -170,6 +171,11 @@ public:
                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
@@ -186,6 +192,12 @@ struct empty_frame_producer : public frame_producer
                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
@@ -253,10 +265,7 @@ safe_ptr<core::frame_producer> do_create_producer(const safe_ptr<frame_factory>&
 \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
index a29e78d03a175fe224d5a4a3de7c54c5beef3be8..8198bb8030fba4ff323b0af82aa10a0af7ba5cab 100644 (file)
@@ -21,6 +21,8 @@
 \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
@@ -75,6 +77,8 @@ public:
        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
index 0a0ff51f14f53c29208751c0e3297e1688a0a526..94d74d334b98da88b438e6b63dafdc3b13babdbc 100644 (file)
@@ -37,14 +37,16 @@ struct layer::implementation
        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
@@ -80,7 +82,8 @@ public:
                {\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
@@ -91,7 +94,8 @@ public:
        \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
@@ -111,7 +115,13 @@ public:
                                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
@@ -157,22 +167,22 @@ public:
                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
@@ -189,4 +199,5 @@ safe_ptr<frame_producer> layer::background() const { return impl_->background_;}
 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
index 38ccd43a6651e08c18ce3575f63d502e44da2b55..46e873364e0a6c9dbb25d100f25d3533fa219e3b 100644 (file)
@@ -21,6 +21,8 @@
 \r
 #pragma once\r
 \r
+#include "../monitor/monitor.h"\r
+\r
 #include <common/memory/safe_ptr.h>\r
 \r
 #include <boost/noncopyable.hpp>\r
@@ -36,12 +38,12 @@ class basic_frame;
 \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
@@ -62,6 +64,8 @@ public:
        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
diff --git a/core/producer/playlist/playlist_producer.cpp b/core/producer/playlist/playlist_producer.cpp
deleted file mode 100644 (file)
index 2068e2a..0000000
+++ /dev/null
@@ -1,222 +0,0 @@
-/*\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
diff --git a/core/producer/playlist/playlist_producer.h b/core/producer/playlist/playlist_producer.h
deleted file mode 100644 (file)
index 23c130c..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-/*\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
index 9ef26c6f0e5a8566028cd7a1feeb1a68634bc1fa..6f3ada8f313c5beb843915bec6b3d91fe7410bdd 100644 (file)
@@ -21,6 +21,8 @@
 \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
@@ -31,6 +33,9 @@ namespace caspar { namespace core {
 \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
@@ -38,12 +43,18 @@ struct separated_producer : public frame_producer
        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
@@ -116,6 +127,11 @@ struct separated_producer : public frame_producer
                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
index 3422cf4c2bfcc109f3c92c446c2ec2a56f550644..59fafd065d9ffb70ce8b52f32c504f9a2b6f6aee 100644 (file)
@@ -96,15 +96,18 @@ struct stage::implementation : public std::enable_shared_from_this<implementatio
        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
@@ -125,10 +128,10 @@ public:
 \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
@@ -142,7 +145,7 @@ public:
                                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
@@ -228,11 +231,22 @@ public:
                }, 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
@@ -240,7 +254,7 @@ public:
        {               \r
                executor_.begin_invoke([=]\r
                {\r
-                       layers_[index].pause();\r
+                       get_layer(index).pause();\r
                }, high_priority);\r
        }\r
 \r
@@ -248,7 +262,7 @@ public:
        {               \r
                executor_.begin_invoke([=]\r
                {\r
-                       layers_[index].play();\r
+                       get_layer(index).play();\r
                }, high_priority);\r
        }\r
 \r
@@ -256,7 +270,7 @@ public:
        {               \r
                executor_.begin_invoke([=]\r
                {\r
-                       layers_[index].stop();\r
+                       get_layer(index).stop();\r
                }, high_priority);\r
        }\r
 \r
@@ -280,47 +294,77 @@ public:
        {\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
@@ -328,7 +372,7 @@ public:
        {\r
                return executor_.begin_invoke([=]\r
                {\r
-                       return layers_[index].foreground();\r
+                       return get_layer(index).foreground();\r
                }, high_priority);\r
        }\r
        \r
@@ -336,7 +380,7 @@ public:
        {\r
                return executor_.begin_invoke([=]\r
                {\r
-                       return layers_[index].background();\r
+                       return get_layer(index).background();\r
                }, high_priority);\r
        }\r
        \r
@@ -354,7 +398,7 @@ public:
                {\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
@@ -364,12 +408,13 @@ public:
        {\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
@@ -381,13 +426,14 @@ void stage::play(int index){impl_->play(index);}
 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
index e7178caa0add511115b56203d36eef485860c7e7..403498d9011fe461979382bf5533fd5a3f405c3a 100644 (file)
@@ -23,6 +23,8 @@
 \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
@@ -41,13 +43,18 @@ struct frame_transform;
 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
@@ -67,6 +74,9 @@ public:
        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
@@ -74,6 +84,8 @@ public:
        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
index 88f56b9de2edd603e1f3922fa57a013ec57c016d..1375ed0e6efdba513c0cf617ba4ed5083188de8a 100644 (file)
@@ -38,6 +38,8 @@ namespace caspar { namespace core {
 \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
@@ -54,7 +56,10 @@ struct transition_producer : public frame_producer
                , 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
@@ -95,6 +100,20 @@ struct transition_producer : public frame_producer
                                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
@@ -186,6 +205,11 @@ struct transition_producer : public frame_producer
 \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
index 4cad33609b05123de58318adbce71ce07c1ca503..d8f864ee4aa3d30152ef3652402fcf07f1757163 100644 (file)
@@ -41,6 +41,7 @@ namespace caspar { namespace core {
 \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
@@ -49,15 +50,19 @@ struct video_channel::implementation : boost::noncopyable
        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
@@ -65,6 +70,8 @@ public:
                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
@@ -116,7 +123,8 @@ public:
        }\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
@@ -124,5 +132,5 @@ video_format_desc video_channel::get_video_format_desc() const{return impl_->for
 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
index c69bd636e38190d62b605e4f02fc63d357ee1c4d..89312db1dc8cec638b6d80665cab5d554aa0f8cd 100644 (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
@@ -38,8 +41,17 @@ struct video_format_desc;
 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
@@ -50,6 +62,8 @@ public:
        boost::property_tree::wptree info() const;\r
 \r
        int index() const;\r
+       \r
+       monitor::source& monitor_output();\r
 \r
 private:\r
        struct implementation;\r
index 2723a6489326ce49d75c7749b9cc7671cf89b1f0..b6b28859426d9db4ef3d11d56509d4735d4d6853 100644 (file)
@@ -38,6 +38,7 @@
 #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
@@ -79,6 +80,7 @@ namespace caspar { namespace decklink {
                \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
@@ -272,6 +274,11 @@ public:
        {\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
@@ -320,6 +327,11 @@ public:
                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
index e5b03432121fe83210e2220da6089f57b3ea888f..f3936f14c96c3969401641cb6ca54265c1c216c0 100644 (file)
@@ -37,6 +37,7 @@
 #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
@@ -62,6 +63,7 @@ namespace caspar { namespace ffmpeg {
                                \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
@@ -88,7 +90,7 @@ struct ffmpeg_producer : public core::frame_producer
 \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
@@ -190,10 +192,20 @@ public:
                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
@@ -285,6 +297,11 @@ public:
 \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
@@ -420,6 +437,11 @@ public:
                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
index e49cf2fd7830af256575e95459135588ca66dcfb..2432d955e0e089b6d1a21c5cc631e47044e92186 100644 (file)
@@ -191,6 +191,11 @@ public:
                        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
@@ -263,5 +268,5 @@ std::wstring cg_producer::invoke(int layer, const std::wstring& label){return im
 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
index 875b3cf303d2630832b1311425b824c69024de91..2a6920d48d94544588d43e75c17568e7f45b890b 100644 (file)
@@ -60,6 +60,8 @@ public:
        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
index 7afb1bdfdd1f9d097acfbd241cf7a054e9ab5c44..0294155f8aa863c0c79d33aeba13bf3f4286c418 100644 (file)
@@ -33,6 +33,7 @@
 \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
@@ -320,6 +321,7 @@ public:
 \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
@@ -379,6 +381,12 @@ public:
                        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
@@ -488,6 +496,11 @@ public:
                });\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
index 192a5304a0fcc4cd824fb9b6c8f64979fcf9b2f4..4b240bc3e390ba2f2659074dab5e8c7cab892874 100644 (file)
@@ -25,6 +25,7 @@
 \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
@@ -44,7 +45,8 @@ namespace caspar { namespace image {
 \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
@@ -68,6 +70,8 @@ struct image_producer : public core::frame_producer
 \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
@@ -93,6 +97,11 @@ struct image_producer : public core::frame_producer
                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
index 558900e739d060be17179129ba9e697a8b34de02..c7e365ae7394782610c517b76cd53409f102bf93 100644 (file)
@@ -28,6 +28,7 @@
 \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
@@ -57,6 +58,7 @@ namespace caspar { namespace image {
 \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
@@ -381,6 +383,11 @@ struct image_scroll_producer : public core::frame_producer
                        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
diff --git a/protocol/osc/oscpack/MessageMappingOscPacketListener.h b/protocol/osc/oscpack/MessageMappingOscPacketListener.h
new file mode 100644 (file)
index 0000000..ade00e5
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+       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
diff --git a/protocol/osc/oscpack/OscException.h b/protocol/osc/oscpack/OscException.h
new file mode 100644 (file)
index 0000000..8a2d35e
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+       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 */
diff --git a/protocol/osc/oscpack/OscHostEndianness.h b/protocol/osc/oscpack/OscHostEndianness.h
new file mode 100644 (file)
index 0000000..1ff7bf5
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+        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 */
diff --git a/protocol/osc/oscpack/OscOutboundPacketStream.cpp b/protocol/osc/oscpack/OscOutboundPacketStream.cpp
new file mode 100644 (file)
index 0000000..20bc386
--- /dev/null
@@ -0,0 +1,642 @@
+/*
+       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
+
+
diff --git a/protocol/osc/oscpack/OscOutboundPacketStream.h b/protocol/osc/oscpack/OscOutboundPacketStream.h
new file mode 100644 (file)
index 0000000..5faefb9
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+       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 */
diff --git a/protocol/osc/oscpack/OscPacketListener.h b/protocol/osc/oscpack/OscPacketListener.h
new file mode 100644 (file)
index 0000000..b2d1981
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+       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 */
diff --git a/protocol/osc/oscpack/OscPrintReceivedElements.cpp b/protocol/osc/oscpack/OscPrintReceivedElements.cpp
new file mode 100644 (file)
index 0000000..128cc59
--- /dev/null
@@ -0,0 +1,247 @@
+/*
+       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
diff --git a/protocol/osc/oscpack/OscPrintReceivedElements.h b/protocol/osc/oscpack/OscPrintReceivedElements.h
new file mode 100644 (file)
index 0000000..7ec747c
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+       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 */
diff --git a/protocol/osc/oscpack/OscReceivedElements.cpp b/protocol/osc/oscpack/OscReceivedElements.cpp
new file mode 100644 (file)
index 0000000..cca1e13
--- /dev/null
@@ -0,0 +1,725 @@
+/*
+       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
+
diff --git a/protocol/osc/oscpack/OscReceivedElements.h b/protocol/osc/oscpack/OscReceivedElements.h
new file mode 100644 (file)
index 0000000..4836406
--- /dev/null
@@ -0,0 +1,488 @@
+/*
+       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 */
diff --git a/protocol/osc/oscpack/OscTypes.cpp b/protocol/osc/oscpack/OscTypes.cpp
new file mode 100644 (file)
index 0000000..cf8f698
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+       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
diff --git a/protocol/osc/oscpack/OscTypes.h b/protocol/osc/oscpack/OscTypes.h
new file mode 100644 (file)
index 0000000..b319111
--- /dev/null
@@ -0,0 +1,183 @@
+/*
+       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 */
diff --git a/protocol/osc/server.cpp b/protocol/osc/server.cpp
new file mode 100644 (file)
index 0000000..b444abe
--- /dev/null
@@ -0,0 +1,122 @@
+#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
diff --git a/protocol/osc/server.h b/protocol/osc/server.h
new file mode 100644 (file)
index 0000000..1ca4f30
--- /dev/null
@@ -0,0 +1,38 @@
+#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
index 67fb832e686c3d72f2ba1813886af4c58718d4df..ea2043b97f4d5f20193db85d88443d33a2dabc4b 100644 (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
index 9f2e7d2fa6460335e705ba67b659ced4aa34ab2d..9481cb9152c7d4437ddf590be6317052a6dd4c15 100644 (file)
     <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
index 9f4c5cffc4319f8b5b5721912dff2988dd8be27b..aa5c72bd4cba8a680b5e2db15e97ee8a4d572036 100644 (file)
@@ -1,11 +1,11 @@
 <?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
index a41f3857b28e91b74c528cbdd2af90700e63ffa7..294e4d9ac581fb5e67f101bab6b3a27128acc9ea 100644 (file)
@@ -46,6 +46,7 @@
 #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
@@ -267,6 +268,7 @@ int main(int argc, wchar_t* argv[])
 \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
index e36fda83a9d4eca0e77c49f25df7eac270e16c1d..d9335a6ad10bf0f15863235fd7761bad60835c77 100644 (file)
@@ -56,6 +56,7 @@
 #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
@@ -70,9 +71,11 @@ using namespace protocol;
 \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
@@ -129,6 +132,8 @@ struct server::implementation : boost::noncopyable
                        \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
@@ -176,6 +181,13 @@ struct server::implementation : boost::noncopyable
                                        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
@@ -237,4 +249,9 @@ std::shared_ptr<thumbnail_generator> server::get_thumbnail_generator() const
        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
index 13948ee0bd9adee92b0aa4cc57e39ee62fda9ec1..01ed69b8109f71ad2786977eb1600c08e1266fb5 100644 (file)
@@ -24,6 +24,8 @@
 \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
@@ -42,6 +44,9 @@ public:
        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