]> git.sesse.net Git - casparcg/commitdiff
2.0.0.2: Added audio support to decklink producer.
authorronag <ronag@362d55ac-95cf-4e76-9f9a-cbaa9c17b72d>
Sat, 5 Feb 2011 23:45:40 +0000 (23:45 +0000)
committerronag <ronag@362d55ac-95cf-4e76-9f9a-cbaa9c17b72d>
Sat, 5 Feb 2011 23:45:40 +0000 (23:45 +0000)
git-svn-id: https://casparcg.svn.sourceforge.net/svnroot/casparcg/server/branches/2.0.0.2@454 362d55ac-95cf-4e76-9f9a-cbaa9c17b72d

14 files changed:
common/diagnostics/graph.cpp
common/diagnostics/graph.h
core/consumer/bluefish/bluefish_consumer.cpp
core/consumer/decklink/decklink_consumer.cpp
core/consumer/frame_consumer_device.cpp
core/consumer/oal/oal_consumer.cpp
core/consumer/ogl/ogl_consumer.cpp
core/core.vcxproj
core/producer/decklink/decklink_producer.cpp
core/producer/flash/flash_producer.cpp
core/video_format.cpp
mixer/frame_mixer_device.cpp
protocol/media.cpp
shell/caspar.config

index 2f163840eb847828a2182cf470605254620ef17e..0bdadf23f7e476fa5b1092367d88400c47fd6db2 100644 (file)
@@ -163,6 +163,12 @@ public:
        {\r
                tick_data_.push_back(value);\r
        }\r
+\r
+       void set(float value)\r
+       {\r
+               tick_data_.clear();\r
+               tick_data_.push_back(value);\r
+       }\r
        \r
        void tag()\r
        {\r
@@ -244,6 +250,14 @@ struct graph::implementation : public drawable
                });\r
        }\r
 \r
+       void set(const std::string& name, float value)\r
+       {\r
+               context::begin_invoke([=]\r
+               {\r
+                       lines_[name].set(value);\r
+               });\r
+       }\r
+\r
        void tag(const std::string& name)\r
        {\r
                context::begin_invoke([=]\r
@@ -327,6 +341,7 @@ graph::graph(const std::string& name) : impl_(new implementation(name))
 }\r
 \r
 void graph::update(const std::string& name, float value){impl_->update(name, value);}\r
+void graph::set(const std::string& name, float value){impl_->set(name, value);}\r
 void graph::tag(const std::string& name){impl_->tag(name);}\r
 void graph::guide(const std::string& name, float value){impl_->guide(name, value);}\r
 void graph::set_color(const std::string& name, color c){impl_->set_color(name, c);}\r
index 26c10d1fc9f852b434998fcd22b7018925bb1a6a..9ada47b222b0ead224759f15364972d997da52a6 100644 (file)
@@ -26,6 +26,7 @@ class graph
        graph(const std::string& name);\r
 public:\r
        void update(const std::string& name, float value);\r
+       void set(const std::string& name, float value);\r
        void tag(const std::string& name);\r
        void guide(const std::string& name, float value);\r
        void set_color(const std::string& name, color c);\r
index 0b757f25f775051ee00f34e0621e0221144db4a8..52b0fd227c262fab109b31e95d2c4d8c4152a389 100644 (file)
@@ -150,7 +150,7 @@ public:
 \r
                graph_ = diagnostics::create_graph(narrow(print()));\r
                graph_->guide("tick-time", 0.5);\r
-               graph_->set_color("tick-time", diagnostics::color(0.4f, 0.7f, 0.7f));   \r
+               graph_->set_color("tick-time", diagnostics::color(0.1f, 0.7f, 0.8f));\r
                        \r
                //void* pBlueDevice = blue_attach_to_device(1);\r
                //EBlueConnectorPropertySetting video_routing[1];\r
@@ -341,7 +341,7 @@ public:
        \r
        std::wstring print() const\r
        {\r
-               return model_name_ + L"[" + boost::lexical_cast<std::wstring>(device_index_) + L"]";\r
+               return model_name_ + L" [output-" + boost::lexical_cast<std::wstring>(device_index_) + L"]";\r
        }\r
 };\r
 \r
index 3d227834fcc919cd22283cacc00088504bad90d3..3811a141c44dc70a9768eca910f5efbf5a0bb618 100644 (file)
@@ -126,7 +126,7 @@ public:
                while(n < device_index_ && pDecklinkIterator->Next(&decklink_) == S_OK){++n;}   \r
 \r
                if(n != device_index_ || !decklink_)\r
-                       BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(narrow(print()) + " No Decklink card found."));\r
+                       BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(narrow(print()) + " Decklink card not found.") << arg_name_info("device_index") << arg_value_info(boost::lexical_cast<std::string>(device_index_)));\r
 \r
                output_ = decklink_;\r
                keyer_ = decklink_;\r
@@ -137,7 +137,7 @@ public:
                                \r
                graph_ = diagnostics::create_graph(narrow(print()));\r
                graph_->guide("tick-time", 0.5);\r
-               graph_->set_color("tick-time", diagnostics::color(0.4f, 0.7f, 0.7f));   \r
+               graph_->set_color("tick-time", diagnostics::color(0.1f, 0.7f, 0.8f));\r
                \r
                auto display_mode = get_display_mode(output_.p, format_desc_.format);\r
                if(display_mode == nullptr) \r
@@ -272,7 +272,7 @@ public:
 \r
        std::wstring print() const\r
        {\r
-               return model_name_ + L"[" + boost::lexical_cast<std::wstring>(device_index_) + L"]";\r
+               return model_name_ + L" [output-" + boost::lexical_cast<std::wstring>(device_index_) + L"]";\r
        }\r
 };\r
 \r
index 3ca5896232889592e30c2dfa59fd13bae60b01d8..cbff69a9ebe7676c8b21ce3c6de74a20fad2820e 100644 (file)
@@ -42,7 +42,11 @@ public:
        ~implementation()\r
        {\r
                executor_.clear();\r
-               CASPAR_LOG(info) << "Shutting down consumer-device.";\r
+               CASPAR_LOG(info) << "Removing consumers from consumer-device.";\r
+               executor_.invoke([this]{consumers_.clear();});\r
+               CASPAR_LOG(info) << "Stopping consumer-device.";\r
+               executor_.stop();\r
+               CASPAR_LOG(info) << "Releasing consumer-device.";\r
        }\r
 \r
        void add(int index, safe_ptr<frame_consumer>&& consumer)\r
index e88ef8e68f190e240f8654644c279bc8a4e6872a..bcb41bf07822da3d7c6b367c2abd30e55e97b78b 100644 (file)
@@ -50,7 +50,7 @@ public:
                , container_(5)\r
        {\r
                graph_->guide("tick-time", 0.5);\r
-               graph_->set_color("tick-time", diagnostics::color(0.4f, 0.7f, 0.7f));   \r
+               graph_->set_color("tick-time", diagnostics::color(0.1f, 0.7f, 0.8f));\r
                is_running_ = true;\r
        }\r
 \r
@@ -100,7 +100,7 @@ public:
 \r
        std::wstring print() const\r
        {\r
-               return L"Default Audio Device";\r
+               return L"Default Audio Device [output]";\r
        }\r
 };\r
 \r
index 1b84c4c15f09aa87fdf862d1b756cfe7eb4c60f9..b114db880b73a605edd2ce32fc8cb24c82bcfc94 100644 (file)
@@ -263,7 +263,7 @@ public:
 \r
        std::wstring print() const\r
        {\r
-               return L"OpenGL Device[" + boost::lexical_cast<std::wstring>(screen_index_) + L"]";\r
+               return L"OpenGL Device [output-" + boost::lexical_cast<std::wstring>(screen_index_) + L"]";\r
        }\r
 \r
        size_t buffer_depth() const{return 2;}\r
index 7f7c1b41ca99ebdfd52ea4595e22faec3611597e..a2716389361d0695f898475b2e56b08ad01c6779 100644 (file)
       <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../../StdAfx.h</PrecompiledHeaderFile>\r
       <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../../StdAfx.h</PrecompiledHeaderFile>\r
       <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Develop|Win32'">../../StdAfx.h</PrecompiledHeaderFile>\r
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>\r
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Develop|Win32'">true</ExcludedFromBuild>\r
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>\r
     </ClCompile>\r
     <ClCompile Include="producer\silverlight\XcpControlHost.cpp">\r
       <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../../StdAfx.h</PrecompiledHeaderFile>\r
index 8a31e6ec1bb83af78a4dff61f4afee1a6a871340..7642f7c8cfc5f128e1c0a5091f468bfce4608611 100644 (file)
 #include "../../consumer/decklink/DeckLinkAPI_h.h" // TODO: Change this\r
 #include "../../consumer/decklink/util.h" // TODO: Change this\r
 \r
+#include <common/diagnostics/graph.h>\r
 #include <common/concurrency/executor.h>\r
 #include <common/exception/exceptions.h>\r
+#include <common/utility/timer.h>\r
 \r
 #include <tbb/concurrent_queue.h>\r
 #include <tbb/atomic.h>\r
@@ -55,68 +57,80 @@ class decklink_input : public IDeckLinkInputCallback
        } co_;\r
 \r
        const video_format_desc format_desc_;\r
+       std::wstring model_name_;\r
        const size_t device_index_;\r
 \r
+       std::shared_ptr<diagnostics::graph> graph_;\r
+       timer perf_timer_;\r
+\r
        CComPtr<IDeckLink>                      decklink_;\r
        CComQIPtr<IDeckLinkInput>       input_;\r
        IDeckLinkDisplayMode*           d_mode_;\r
 \r
+       std::vector<short>                      audio_data_;\r
+\r
        std::shared_ptr<frame_factory> frame_factory_;\r
 \r
        tbb::concurrent_bounded_queue<safe_ptr<draw_frame>> frame_buffer_;\r
-       safe_ptr<draw_frame> head_;\r
        safe_ptr<draw_frame> tail_;\r
 \r
 public:\r
 \r
        decklink_input(const video_format_desc& format_desc, size_t device_index, const std::shared_ptr<frame_factory>& frame_factory)\r
-               : device_index_(device_index)\r
+               : format_desc_(format_desc)\r
+               , device_index_(device_index)\r
+               , model_name_(L"DECKLINK")\r
                , frame_factory_(frame_factory)\r
-               , head_(draw_frame::empty())\r
                , tail_(draw_frame::empty())\r
        {\r
                frame_buffer_.set_capacity(4);\r
                \r
                CComPtr<IDeckLinkIterator> pDecklinkIterator;\r
                if(FAILED(pDecklinkIterator.CoCreateInstance(CLSID_CDeckLinkIterator)))\r
-                       BOOST_THROW_EXCEPTION(caspar_exception() << msg_info("decklink_producer: No Decklink drivers installed."));\r
+                       BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(narrow(print()) + " No Decklink drivers installed."));\r
 \r
                size_t n = 0;\r
                while(n < device_index_ && pDecklinkIterator->Next(&decklink_) == S_OK){++n;}   \r
 \r
                if(n != device_index_ || !decklink_)\r
-                       BOOST_THROW_EXCEPTION(caspar_exception() << msg_info("decklink_producer: No Decklink card found.") << arg_name_info("device_index") << arg_value_info(boost::lexical_cast<std::string>(device_index_)));\r
+                       BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(narrow(print()) + " Decklink card not found.") << arg_name_info("device_index") << arg_value_info(boost::lexical_cast<std::string>(device_index_)));\r
 \r
                input_ = decklink_;\r
 \r
                BSTR pModelName;\r
                decklink_->GetModelName(&pModelName);\r
-               if(pModelName != nullptr)\r
-                       CASPAR_LOG(info) << "decklink_producer: Modelname: " << pModelName;\r
+               model_name_ = std::wstring(pModelName);\r
+\r
+               graph_ = diagnostics::create_graph(narrow(print()));\r
+               graph_->guide("tick-time", 0.5);\r
+               graph_->set_color("tick-time", diagnostics::color(0.1f, 0.7f, 0.8f));\r
                \r
                unsigned long decklinkVideoFormat = GetDecklinkVideoFormat(format_desc.format);\r
                if(decklinkVideoFormat == ULONG_MAX) \r
-                       BOOST_THROW_EXCEPTION(caspar_exception() << msg_info("decklink_producer: Card does not support requested videoformat."));\r
+                       BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(narrow(print()) + " Card does not support requested videoformat."));\r
 \r
                d_mode_ = get_display_mode((BMDDisplayMode)decklinkVideoFormat);\r
                if(d_mode_ == nullptr) \r
-                       BOOST_THROW_EXCEPTION(caspar_exception() << msg_info("decklink_producer: Card does not support requested videoformat."));\r
+                       BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(narrow(print()) + " Card does not support requested videoformat."));\r
 \r
                BMDDisplayModeSupport displayModeSupport;\r
                if(FAILED(input_->DoesSupportVideoMode((BMDDisplayMode)decklinkVideoFormat, bmdFormat8BitYUV, &displayModeSupport)))\r
-                       BOOST_THROW_EXCEPTION(caspar_exception() << msg_info("decklink_producer: Card does not support requested videoformat."));\r
+                       BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(narrow(print()) + " Card does not support requested videoformat."));\r
 \r
                // NOTE: bmdFormat8BitABGR does not seem to work with Decklink HD Extreme 3D\r
                if(FAILED(input_->EnableVideoInput((BMDDisplayMode)decklinkVideoFormat, bmdFormat8BitYUV, 0))) \r
-                       BOOST_THROW_EXCEPTION(caspar_exception() << msg_info("DECKLINK: Could not enable video input."));\r
+                       BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(narrow(print()) + " Could not enable video input."));\r
+\r
+               if(FAILED(input_->EnableAudioInput(bmdAudioSampleRate48kHz, bmdAudioSampleType16bitInteger, 2))) \r
+                       BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(narrow(print()) + " Could not enable audio input."));\r
                        \r
                if (FAILED(input_->SetCallback(this)) != S_OK)\r
-                       BOOST_THROW_EXCEPTION(caspar_exception() << msg_info("decklink_producer: Failed to set input callback."));\r
+                       BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(narrow(print()) + " Failed to set input callback."));\r
                        \r
                if(FAILED(input_->StartStreams()))\r
-                       BOOST_THROW_EXCEPTION(caspar_exception() << msg_info("DECKLINK: Failed to start input stream."));\r
+                       BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(narrow(print()) + " Failed to start input stream."));\r
 \r
-               CASPAR_LOG(info) << "decklink_producer: Successfully initialized decklink for " << format_desc_.name;\r
+               CASPAR_LOG(info) << print() << " Successfully initialized decklink for " << format_desc_.name;\r
        }\r
 \r
        ~decklink_input()\r
@@ -139,9 +153,12 @@ public:
        }\r
 \r
        // TODO: Enable audio input\r
-       virtual HRESULT STDMETHODCALLTYPE VideoInputFrameArrived(IDeckLinkVideoInputFrame* video, IDeckLinkAudioInputPacket* /*audio*/)\r
-       {               \r
-               if(!frame_buffer_.try_push(head_) || video == nullptr)\r
+       virtual HRESULT STDMETHODCALLTYPE VideoInputFrameArrived(IDeckLinkVideoInputFrame* video, IDeckLinkAudioInputPacket* audio)\r
+       {       \r
+               graph_->update("tick-time", static_cast<float>(perf_timer_.elapsed()/format_desc_.interval*0.5));\r
+               perf_timer_.reset();\r
+\r
+               if(!video)\r
                        return S_OK;            \r
                                \r
                void* bytes = nullptr;\r
@@ -175,7 +192,21 @@ public:
                        }\r
                });\r
 \r
-               head_ = frame;\r
+               if(audio && SUCCEEDED(audio->GetBytes(&bytes)))\r
+               {\r
+                       auto sample_frame_count = audio->GetSampleFrameCount();\r
+                       auto audio_data = reinterpret_cast<short*>(bytes);\r
+                       audio_data_.insert(audio_data_.end(), audio_data, audio_data + sample_frame_count*2);\r
+\r
+                       if(audio_data_.size() > 3840)\r
+                       {\r
+                               frame->audio_data() = std::vector<short>(audio_data_.begin(), audio_data_.begin() + 3840);\r
+                               audio_data_.erase(audio_data_.begin(), audio_data_.begin() + 3840);\r
+                               frame_buffer_.try_push(frame);\r
+                       }\r
+               }\r
+               else\r
+                       frame_buffer_.try_push(frame);\r
 \r
                return S_OK;\r
        }\r
@@ -201,6 +232,11 @@ public:
                frame_buffer_.try_pop(tail_);\r
                return tail_;\r
        }\r
+\r
+       std::wstring print() const\r
+       {\r
+               return model_name_ + L" [input-" + boost::lexical_cast<std::wstring>(device_index_) + L"]";\r
+       }\r
 };\r
        \r
 class decklink_producer : public frame_producer\r
@@ -240,7 +276,10 @@ public:
                return input_->get_frame();\r
        }\r
        \r
-       virtual std::wstring print() const { return + L"decklink"; }\r
+       std::wstring print() const\r
+       {\r
+               return input_ ? input_->print() : L"Unknown Decklink [input-" + boost::lexical_cast<std::wstring>(device_index_) + L"]";\r
+       }\r
 };\r
 \r
 safe_ptr<frame_producer> create_decklink_producer(const std::vector<std::wstring>& params)\r
index 08af4bbd8a659bd670ff1d4436dabb6d6bbaacda..8767d95d8136e25375ea6b4aece3eddab1173eb3 100644 (file)
@@ -216,7 +216,7 @@ public:
 \r
        virtual safe_ptr<draw_frame> receive()\r
        {               \r
-               graph_->update("output-buffer", static_cast<float>(frame_buffer_.size())/static_cast<float>(frame_buffer_.capacity()));\r
+               graph_->set("output-buffer", static_cast<float>(frame_buffer_.size())/static_cast<float>(frame_buffer_.capacity()));\r
                if(!frame_buffer_.try_pop(tail_))\r
                        CASPAR_LOG(trace) << print() << " underflow";\r
                else\r
@@ -231,6 +231,7 @@ public:
                                        auto frame = draw_frame::empty();\r
                                        do{frame = renderer_->render_frame(frame_buffer_.size() < frame_buffer_.capacity()-2);}\r
                                        while(frame_buffer_.try_push(frame) && frame == draw_frame::empty());\r
+                                       graph_->set("output-buffer", static_cast<float>(frame_buffer_.size())/static_cast<float>(frame_buffer_.capacity()));\r
                                }\r
                                catch(...)\r
                                {\r
index 519a8f7fc683e2ec1cd7e458d456429fcc984c63..09217a82376d0f5f23f2ae0ccfa9211a636bd480 100644 (file)
@@ -32,8 +32,8 @@ namespace caspar { namespace core {
        \r
 const video_format_desc format_descs[video_format::count] =  \r
 {                                                                         \r
-       DEFINE_VIDEOFORMATDESC(720,  576,  video_mode::upper,                   50,                     TEXT("PAL"),            video_format::pal               ), \r
-       DEFINE_VIDEOFORMATDESC(720,  486,  video_mode::lower,                   60/1.001,       TEXT("NTSC"),           video_format::ntsc              ), \r
+       DEFINE_VIDEOFORMATDESC(720,  576,  video_mode::upper,                   50,                     TEXT("pal"),            video_format::pal               ), \r
+       DEFINE_VIDEOFORMATDESC(720,  486,  video_mode::lower,                   60/1.001,       TEXT("ntsc"),           video_format::ntsc              ), \r
        DEFINE_VIDEOFORMATDESC(720,  576,  video_mode::progressive,             25,                     TEXT("576p2500"),       video_format::x576p2500 ),\r
        DEFINE_VIDEOFORMATDESC(1280, 720,  video_mode::progressive,             25,                     TEXT("720p2500"),       video_format::x720p2500 ), \r
        DEFINE_VIDEOFORMATDESC(1280, 720,  video_mode::progressive,             50,                     TEXT("720p5000"),       video_format::x720p5000 ), \r
index 7b57a0cc765781483c8d50218e928463ce5c5563..2bddca4f0f70139b953c0f0439105af32c02a095 100644 (file)
@@ -53,7 +53,7 @@ public:
        {\r
                graph_->guide("frame-time", 0.5f);      \r
                graph_->set_color("frame-time", diagnostics::color(1.0f, 0.0f, 0.0f));\r
-               graph_->set_color("output-wait", diagnostics::color(0.1f, 0.7f, 0.8f));\r
+               graph_->set_color("tick-time", diagnostics::color(0.1f, 0.7f, 0.8f));\r
                graph_->set_color("output-buffer", diagnostics::color( 0.0f, 1.0f, 0.0f));              \r
                executor_.start();\r
                executor_.set_capacity(2);\r
@@ -89,11 +89,13 @@ public:
                        audio_mixer_.end_pass();\r
                        graph_->update("frame-time", static_cast<float>(perf_timer_.elapsed()/format_desc_.interval*0.5));\r
 \r
-                       wait_perf_timer_.reset();\r
                        output_(make_safe<const read_frame>(std::move(image.get()), std::move(audio)));\r
-                       graph_->update("output-wait", static_cast<float>(wait_perf_timer_.elapsed()/format_desc_.interval*0.5));\r
+                       graph_->update("tick-time", static_cast<float>(wait_perf_timer_.elapsed()/format_desc_.interval*0.5));\r
+                       wait_perf_timer_.reset();\r
+\r
+                       graph_->set("output-buffer", static_cast<float>(executor_.size())/static_cast<float>(executor_.capacity()));\r
                });\r
-               graph_->update("output-buffer", static_cast<float>(executor_.size())/static_cast<float>(executor_.capacity()));\r
+               graph_->set("output-buffer", static_cast<float>(executor_.size())/static_cast<float>(executor_.capacity()));\r
        }\r
                \r
        safe_ptr<write_frame> create_frame(const pixel_format_desc& desc)\r
index d1b7c8b9149e86217c7ee99c7b6e80c486954c46..954248eb6444f286538d6c4bc8b026b1be24cbf3 100644 (file)
@@ -38,7 +38,8 @@ safe_ptr<core::frame_producer> create_producer(const std::vector<std::wstring>&
                (&core::image::create_image_producer)\r
                (&core::create_decklink_producer)\r
                (&core::create_color_producer)\r
-               (&core::create_silverlight_producer);\r
+               //(&core::create_silverlight_producer)\r
+               ;\r
 \r
        if(params.empty())\r
                BOOST_THROW_EXCEPTION(invalid_argument() << arg_name_info("params") << arg_value_info(""));\r
index cf42f4b1c75db4a39b66e4941f100b1c1458ee00..b2ae9bf5a1c737ff4f483cfba48521ad72cb7494 100644 (file)
     <channel>\r
       <videomode>PAL</videomode>\r
       <consumers>\r
-        <ogl>\r
-          <device>1</device>\r
-          <stretch>uniform</stretch>\r
-          <windowed>true</windowed>\r
-        </ogl>\r
-        <audio/>\r
-        <decklink>\r
-          <embedded-audio>true</embedded-audio>\r
-          <device>1</device>\r
-        </decklink>\r
         <bluefish>\r
           <embedded-audio>true</embedded-audio>\r
           <device>1</device>\r
         </decklink-->\r
       </consumers>\r
     </channel>\r
+    <channel>\r
+      <videomode>PAL</videomode>\r
+      <consumers>\r
+        <ogl>\r
+          <device>1</device>\r
+          <stretch>uniform</stretch>\r
+          <windowed>true</windowed>\r
+        </ogl>\r
+        <audio/>\r
+      </consumers>\r
+    </channel>\r
   </channels>\r
   <controllers>\r
     <tcp>\r