]> git.sesse.net Git - casparcg/blobdiff - protocol/amcp/AMCPCommandsImpl.cpp
Removed a parameter from the "data retrieve" documentation. [data:string] is never...
[casparcg] / protocol / amcp / AMCPCommandsImpl.cpp
index ec2151f1ea289584a6232a592b7cbfcb74ba4f6a..710977ec666156b916071f7e65ccd74a8f44b4ad 100644 (file)
@@ -38,6 +38,7 @@
 #include <common/os/filesystem.h>
 #include <common/base64.h>
 #include <common/thread_info.h>
+#include <common/filesystem.h>
 
 #include <core/producer/cg_proxy.h>
 #include <core/producer/frame_producer.h>
@@ -46,7 +47,9 @@
 #include <core/help/util.h>
 #include <core/video_format.h>
 #include <core/producer/transition/transition_producer.h>
+#include <core/frame/audio_channel_layout.h>
 #include <core/frame/frame_transform.h>
+#include <core/producer/text/text_producer.h>
 #include <core/producer/stage.h>
 #include <core/producer/layer.h>
 #include <core/mixer/mixer.h>
@@ -206,8 +209,6 @@ std::wstring MediaInfo(const boost::filesystem::path& path, const spl::shared_pt
 
        auto is_not_digit = [](char c){ return std::isdigit(c) == 0; };
 
-       auto relativePath = boost::filesystem::path(path.wstring().substr(env::media_folder().size() - 1, path.wstring().size()));
-
        auto writeTimeStr = boost::posix_time::to_iso_string(boost::posix_time::from_time_t(boost::filesystem::last_write_time(path)));
        writeTimeStr.erase(std::remove_if(writeTimeStr.begin(), writeTimeStr.end(), is_not_digit), writeTimeStr.end());
        auto writeTimeWStr = std::wstring(writeTimeStr.begin(), writeTimeStr.end());
@@ -216,7 +217,9 @@ std::wstring MediaInfo(const boost::filesystem::path& path, const spl::shared_pt
        sizeStr.erase(std::remove_if(sizeStr.begin(), sizeStr.end(), is_not_digit), sizeStr.end());
        auto sizeWStr = std::wstring(sizeStr.begin(), sizeStr.end());
 
-       auto str = relativePath.replace_extension(L"").generic_wstring();
+       auto relativePath = get_relative_without_extension(path, env::media_folder());
+       auto str = relativePath.generic_wstring();
+
        if (str[0] == '\\' || str[0] == '/')
                str = std::wstring(str.begin() + 1, str.end());
 
@@ -247,7 +250,7 @@ std::wstring ListTemplates(const spl::shared_ptr<core::cg_producer_registry>& cg
        {               
                if(boost::filesystem::is_regular_file(itr->path()) && cg_registry->is_cg_extension(itr->path().extension().wstring()))
                {
-                       auto relativePath = boost::filesystem::path(itr->path().wstring().substr(env::template_folder().size()-1, itr->path().wstring().size()));
+                       auto relativePath = get_relative_without_extension(itr->path(), env::template_folder());
 
                        auto writeTimeStr = boost::posix_time::to_iso_string(boost::posix_time::from_time_t(boost::filesystem::last_write_time(itr->path())));
                        writeTimeStr.erase(std::remove_if(writeTimeStr.begin(), writeTimeStr.end(), [](char c){ return std::isdigit(c) == 0;}), writeTimeStr.end());
@@ -262,12 +265,15 @@ std::wstring ListTemplates(const spl::shared_ptr<core::cg_producer_registry>& cg
                        auto file = boost::to_upper_copy(relativePath.filename().wstring());
                        relativePath = dir / file;
                                                
-                       auto str = relativePath.replace_extension(L"").generic_wstring();
+                       auto str = relativePath.generic_wstring();
                        boost::trim_if(str, boost::is_any_of("\\/"));
 
+                       auto template_type = cg_registry->get_cg_producer_name(str);
+
                        replyString << L"\"" << str
                                                << L"\" " << sizeWStr
                                                << L" " << writeTimeWStr
+                                               << L" " << template_type
                                                << L"\r\n";
                }
        }
@@ -530,7 +536,7 @@ void call_describer(core::help_sink& sink, const core::help_repository& repo)
 
 std::wstring call_command(command_context& ctx)
 {
-       auto result = ctx.channel.channel->stage().call(ctx.layer_index(), ctx.parameters);
+       auto result = ctx.channel.channel->stage().call(ctx.layer_index(), ctx.parameters).get();
 
        // TODO: because of std::async deferred timed waiting does not work
 
@@ -539,10 +545,10 @@ std::wstring call_command(command_context& ctx)
        CASPAR_THROW_EXCEPTION(timed_out());*/
 
        std::wstringstream replyString;
-       if (result.get().empty())
+       if (result.empty())
                replyString << L"202 CALL OK\r\n";
        else
-               replyString << L"201 CALL OK\r\n" << result.get() << L"\r\n";
+               replyString << L"201 CALL OK\r\n" << result << L"\r\n";
 
        return replyString.str();
 }
@@ -592,7 +598,7 @@ std::wstring swap_command(command_context& ctx)
 void add_describer(core::help_sink& sink, const core::help_repository& repo)
 {
        sink.short_description(L"Add a consumer to a video channel.");
-       sink.syntax(L"ADD [video_channel:int] [consumer:string] [parameters:string]");
+       sink.syntax(L"ADD [video_channel:int]{-[consumer_index:int]} [consumer:string] [parameters:string]");
        sink.para()
                ->text(L"Adds a consumer to the specified video channel. The string ")
                ->code(L"consumer")->text(L" will be parsed by the available consumer factories. ")
@@ -600,6 +606,10 @@ void add_describer(core::help_sink& sink, const core::help_repository& repo)
                ->code(L"video_channel")->text(L". Different consumers require different parameters, ")
                ->text(L"some examples are below. Consumers can alternatively be specified by adding them to ")
                ->see(L"the CasparCG config file")->text(L".");
+       sink.para()
+               ->text(L"Specifying ")->code(L"consumer_index")
+               ->text(L" overrides the index that the consumer itself decides and can later be used with the ")
+               ->see(L"REMOVE")->text(L" command to remove the consumer.");
        sink.para()->text(L"Examples:");
        sink.example(L">> ADD 1 DECKLINK 1");
        sink.example(L">> ADD 1 BLUEFISH 2");
@@ -608,6 +618,9 @@ void add_describer(core::help_sink& sink, const core::help_repository& repo)
        sink.example(L">> ADD 1 IMAGE filename");
        sink.example(L">> ADD 1 FILE filename.mov");
        sink.example(L">> ADD 1 FILE filename.mov SEPARATE_KEY");
+       sink.example(
+               L">> ADD 1-700 FILE filename.mov SEPARATE_KEY\n"
+               L">> REMOVE 1-700", L"overriding the consumer index to easier remove later.");
        sink.para()->text(L"The streaming consumer is an implementation of the ffmpeg_consumer and supports many of the same arguments:");
        sink.example(L">> ADD 1 STREAM udp://localhost:5004 -vcodec libx264 -tune zerolatency -preset ultrafast -crf 25 -format mpegts -vf scale=240:180");
 }
@@ -698,15 +711,34 @@ std::wstring log_level_command(command_context& ctx)
        return L"202 LOG OK\r\n";
 }
 
+void log_category_describer(core::help_sink& sink, const core::help_repository& repo)
+{
+       sink.short_description(L"Enable/disable a logging category in the server.");
+       sink.syntax(L"LOG CATEGORY [category:calltrace,communication] [enable:0,1]");
+       sink.para()->text(L"Enables or disables the specified logging category.");
+       sink.para()->text(L"Examples:");
+       sink.example(L">> LOG CATEGORY calltrace 1", L"to enable call trace");
+       sink.example(L">> LOG CATEGORY calltrace 0", L"to disable call trace");
+}
+
+std::wstring log_category_command(command_context& ctx)
+{
+       log::set_log_category(ctx.parameters.at(0), ctx.parameters.at(1) == L"1");
+
+       return L"202 LOG OK\r\n";
+}
+
 void set_describer(core::help_sink& sink, const core::help_repository& repo)
 {
        sink.short_description(L"Change the value of a channel variable.");
        sink.syntax(L"SET [video_channel:int] [variable:string] [value:string]");
        sink.para()->text(L"Changes the value of a channel variable. Available variables to set:");
        sink.definitions()
-               ->item(L"MODE", L"Changes the video format of the channel.");
+               ->item(L"MODE", L"Changes the video format of the channel.")
+               ->item(L"CHANNEL_LAYOUT", L"Changes the audio channel layout of the video channel channel.");
        sink.para()->text(L"Examples:");
-       sink.example(L">> SET 1 MODE PAL", L"changes the video mode on channel 1 to PAL");
+       sink.example(L">> SET 1 MODE PAL", L"changes the video mode on channel 1 to PAL.");
+       sink.example(L">> SET 1 CHANNEL_LAYOUT smpte", L"changes the audio channel layout on channel 1 to smpte.");
 }
 
 std::wstring set_command(command_context& ctx)
@@ -723,10 +755,22 @@ std::wstring set_command(command_context& ctx)
                        return L"202 SET MODE OK\r\n";
                }
 
-               CASPAR_THROW_EXCEPTION(invalid_argument() << msg_info(L"Invalid video mode"));
+               CASPAR_THROW_EXCEPTION(user_error() << msg_info(L"Invalid video mode"));
+       }
+       else if (name == L"CHANNEL_LAYOUT")
+       {
+               auto channel_layout = core::audio_channel_layout_repository::get_default()->get_layout(value);
+
+               if (channel_layout)
+               {
+                       ctx.channel.channel->audio_channel_layout(*channel_layout);
+                       return L"202 SET CHANNEL_LAYOUT OK\r\n";
+               }
+
+               CASPAR_THROW_EXCEPTION(user_error() << msg_info(L"Invalid audio channel layout"));
        }
 
-       CASPAR_THROW_EXCEPTION(invalid_argument() << msg_info(L"Invalid channel variable"));
+       CASPAR_THROW_EXCEPTION(user_error() << msg_info(L"Invalid channel variable"));
 }
 
 void data_store_describer(core::help_sink& sink, const core::help_repository& repo)
@@ -774,7 +818,7 @@ std::wstring data_store_command(command_context& ctx)
 void data_retrieve_describer(core::help_sink& sink, const core::help_repository& repo)
 {
        sink.short_description(L"Retrieve a dataset.");
-       sink.syntax(L"DATA RETRIEVE [name:string] [data:string]");
+       sink.syntax(L"DATA RETRIEVE [name:string]");
        sink.para()->text(L"Returns the data saved under the name ")->code(L"name")->text(L".");
        sink.para()->text(L"Examples:");
        sink.example(L">> DATA RETRIEVE my_data");
@@ -837,9 +881,9 @@ std::wstring data_list_command(command_context& ctx)
                        if (!boost::iequals(itr->path().extension().wstring(), L".ftd"))
                                continue;
 
-                       auto relativePath = boost::filesystem::path(itr->path().wstring().substr(env::data_folder().size() - 1, itr->path().wstring().size()));
+                       auto relativePath = get_relative_without_extension(itr->path(), env::data_folder());
+                       auto str = relativePath.generic_wstring();
 
-                       auto str = relativePath.replace_extension(L"").generic_wstring();
                        if (str[0] == L'\\' || str[0] == L'/')
                                str = std::wstring(str.begin() + 1, str.end());
 
@@ -874,22 +918,11 @@ std::wstring data_remove_command(command_context& ctx)
        if (!boost::filesystem::remove(filename))
                CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info(filename + L" could not be removed"));
 
-       return L"201 DATA REMOVE OK\r\n";
+       return L"202 DATA REMOVE OK\r\n";
 }
 
 // Template Graphics Commands
 
-int get_and_validate_layer(const std::wstring& layerstring) {
-       int length = layerstring.length();
-       for (int i = 0; i < length; ++i) {
-               if (!std::isdigit(layerstring[i])) {
-                       CASPAR_THROW_EXCEPTION(invalid_argument() << msg_info(layerstring + L" is not a layer"));
-               }
-       }
-
-       return boost::lexical_cast<int>(layerstring);
-}
-
 void cg_add_describer(core::help_sink& sink, const core::help_repository& repo)
 {
        sink.short_description(L"Prepare a template for displaying.");
@@ -905,7 +938,7 @@ std::wstring cg_add_command(command_context& ctx)
 {
        //CG 1 ADD 0 "template_folder/templatename" [STARTLABEL] 0/1 [DATA]
 
-       int layer = get_and_validate_layer(ctx.parameters.at(0));
+       int layer = boost::lexical_cast<int>(ctx.parameters.at(0));
        std::wstring label;             //_parameters[2]
        bool bDoStart = false;          //_parameters[2] alt. _parameters[3]
        unsigned int dataIndex = 3;
@@ -974,12 +1007,22 @@ void cg_play_describer(core::help_sink& sink, const core::help_repository& repo)
 
 std::wstring cg_play_command(command_context& ctx)
 {
-       int layer = get_and_validate_layer(ctx.parameters.at(0));
+       int layer = boost::lexical_cast<int>(ctx.parameters.at(0));
        ctx.cg_registry->get_proxy(spl::make_shared_ptr(ctx.channel.channel), ctx.layer_index(core::cg_proxy::DEFAULT_LAYER))->play(layer);
 
        return L"202 CG OK\r\n";
 }
 
+spl::shared_ptr<core::cg_proxy> get_expected_cg_proxy(command_context& ctx)
+{
+       auto proxy = ctx.cg_registry->get_proxy(spl::make_shared_ptr(ctx.channel.channel), ctx.layer_index(core::cg_proxy::DEFAULT_LAYER));
+
+       if (proxy == cg_proxy::empty())
+               CASPAR_THROW_EXCEPTION(expected_user_error() << msg_info(L"No CG proxy running on layer"));
+
+       return proxy;
+}
+
 void cg_stop_describer(core::help_sink& sink, const core::help_repository& repo)
 {
        sink.short_description(L"Stop and remove a template.");
@@ -993,8 +1036,8 @@ void cg_stop_describer(core::help_sink& sink, const core::help_repository& repo)
 
 std::wstring cg_stop_command(command_context& ctx)
 {
-       int layer = get_and_validate_layer(ctx.parameters.at(0));
-       ctx.cg_registry->get_proxy(spl::make_shared_ptr(ctx.channel.channel), ctx.layer_index(core::cg_proxy::DEFAULT_LAYER))->stop(layer, 0);
+       int layer = boost::lexical_cast<int>(ctx.parameters.at(0));
+       get_expected_cg_proxy(ctx)->stop(layer, 0);
 
        return L"202 CG OK\r\n";
 }
@@ -1012,8 +1055,8 @@ void cg_next_describer(core::help_sink& sink, const core::help_repository& repo)
 
 std::wstring cg_next_command(command_context& ctx)
 {
-       int layer = get_and_validate_layer(ctx.parameters.at(0));
-       ctx.cg_registry->get_proxy(spl::make_shared_ptr(ctx.channel.channel), ctx.layer_index(core::cg_proxy::DEFAULT_LAYER))->next(layer);
+       int layer = boost::lexical_cast<int>(ctx.parameters.at(0));
+       get_expected_cg_proxy(ctx)->next(layer);
 
        return L"202 CG OK\r\n";
 }
@@ -1029,8 +1072,8 @@ void cg_remove_describer(core::help_sink& sink, const core::help_repository& rep
 
 std::wstring cg_remove_command(command_context& ctx)
 {
-       int layer = get_and_validate_layer(ctx.parameters.at(0));
-       ctx.cg_registry->get_proxy(spl::make_shared_ptr(ctx.channel.channel), ctx.layer_index(core::cg_proxy::DEFAULT_LAYER))->remove(layer);
+       int layer = boost::lexical_cast<int>(ctx.parameters.at(0));
+       get_expected_cg_proxy(ctx)->remove(layer);
 
        return L"202 CG OK\r\n";
 }
@@ -1060,7 +1103,7 @@ void cg_update_describer(core::help_sink& sink, const core::help_repository& rep
 
 std::wstring cg_update_command(command_context& ctx)
 {
-       int layer = get_and_validate_layer(ctx.parameters.at(0));
+       int layer = boost::lexical_cast<int>(ctx.parameters.at(0));
 
        std::wstring dataString = ctx.parameters.at(1);
        if (dataString.at(0) != L'<' && dataString.at(0) != L'{')
@@ -1073,10 +1116,7 @@ std::wstring cg_update_command(command_context& ctx)
                dataString = read_file(boost::filesystem::path(filename));
        }
 
-       ctx.cg_registry->get_proxy(
-               spl::make_shared_ptr(ctx.channel.channel),
-               ctx.layer_index(core::cg_proxy::DEFAULT_LAYER))
-               ->update(layer, dataString);
+       get_expected_cg_proxy(ctx)->update(layer, dataString);
 
        return L"202 CG OK\r\n";
 }
@@ -1093,11 +1133,8 @@ std::wstring cg_invoke_command(command_context& ctx)
 {
        std::wstringstream replyString;
        replyString << L"201 CG OK\r\n";
-       int layer = get_and_validate_layer(ctx.parameters.at(0));
-       auto result = ctx.cg_registry->get_proxy(
-               spl::make_shared_ptr(ctx.channel.channel),
-               ctx.layer_index(core::cg_proxy::DEFAULT_LAYER))
-               ->invoke(layer, ctx.parameters.at(1));
+       int layer = boost::lexical_cast<int>(ctx.parameters.at(0));
+       auto result = get_expected_cg_proxy(ctx)->invoke(layer, ctx.parameters.at(1));
        replyString << result << L"\r\n";
 
        return replyString.str();
@@ -1118,19 +1155,13 @@ std::wstring cg_info_command(command_context& ctx)
 
        if (ctx.parameters.empty())
        {
-               auto info = ctx.cg_registry->get_proxy(
-                       spl::make_shared_ptr(ctx.channel.channel),
-                       ctx.layer_index(core::cg_proxy::DEFAULT_LAYER))
-                       ->template_host_info();
+               auto info = get_expected_cg_proxy(ctx)->template_host_info();
                replyString << info << L"\r\n";
        }
        else
        {
-               int layer = get_and_validate_layer(ctx.parameters.at(0));
-               auto desc = ctx.cg_registry->get_proxy(
-                       spl::make_shared_ptr(ctx.channel.channel),
-                       ctx.layer_index(core::cg_proxy::DEFAULT_LAYER))
-                       ->description(layer);
+               int layer = boost::lexical_cast<int>(ctx.parameters.at(0));
+               auto desc = get_expected_cg_proxy(ctx)->description(layer);
 
                replyString << desc << L"\r\n";
        }
@@ -1177,8 +1208,9 @@ public:
 
        void commit_deferred()
        {
-               ctx_.channel.channel->stage().apply_transforms(
-                               std::move(deferred_transforms_[ctx_.channel_index]));
+               auto& transforms = deferred_transforms_[ctx_.channel_index];
+               ctx_.channel.channel->stage().apply_transforms(transforms).get();
+               transforms.clear();
        }
 
        void apply()
@@ -1223,7 +1255,7 @@ std::wstring mixer_keyer_command(command_context& ctx)
        {
                transform.image_transform.is_key = value;
                return transform;
-       }, 0, L"linear"));
+       }, 0, tweener(L"linear")));
        transforms.apply();
 
        return L"202 MIXER OK\r\n";
@@ -1314,7 +1346,7 @@ std::wstring mixer_blend_command(command_context& ctx)
        {
                transform.image_transform.blend_mode = value;
                return transform;
-       }, 0, L"linear"));
+       }, 0, tweener(L"linear")));
        transforms.apply();
 
        return L"202 MIXER OK\r\n";
@@ -1823,7 +1855,7 @@ std::wstring mixer_mipmap_command(command_context& ctx)
        {
                transform.image_transform.use_mipmap = value;
                return transform;
-       }, 0, L"linear"));
+       }, 0, tweener(L"linear")));
        transforms.apply();
 
        return L"202 MIXER OK\r\n";
@@ -1877,6 +1909,35 @@ std::wstring mixer_mastervolume_command(command_context& ctx)
        return L"202 MIXER OK\r\n";
 }
 
+void mixer_straight_alpha_describer(core::help_sink& sink, const core::help_repository& repo)
+{
+       sink.short_description(L"Turn straight alpha output on or off for a channel.");
+       sink.syntax(L"MIXER [video_channel:int] STRAIGHT_ALPHA_OUTPUT {[straight_alpha:0,1|0]}");
+       sink.para()->text(L"Turn straight alpha output on or off for the specified channel.");
+       sink.para()->code(L"casparcg.config")->text(L" needs to be configured to enable the feature.");
+       sink.para()->text(L"Examples:");
+       sink.example(L">> MIXER 1 STRAIGHT_ALPHA_OUTPUT 0");
+       sink.example(L">> MIXER 1 STRAIGHT_ALPHA_OUTPUT 1");
+       sink.example(
+                       L">> MIXER 1 STRAIGHT_ALPHA_OUTPUT\n"
+                       L"<< 201 MIXER OK\n"
+                       L"<< 1");
+}
+
+std::wstring mixer_straight_alpha_command(command_context& ctx)
+{
+       if (ctx.parameters.empty())
+       {
+               bool state = ctx.channel.channel->mixer().get_straight_alpha_output();
+               return L"201 MIXER OK\r\n" + boost::lexical_cast<std::wstring>(state) + L"\r\n";
+       }
+
+       bool state = boost::lexical_cast<bool>(ctx.parameters.at(0));
+       ctx.channel.channel->mixer().set_straight_alpha_output(state);
+
+       return L"202 MIXER OK\r\n";
+}
+
 void mixer_grid_describer(core::help_sink& sink, const core::help_repository& repo)
 {
        sink.short_description(L"Create a grid of video layers.");
@@ -1993,7 +2054,7 @@ std::wstring channel_grid_command(command_context& ctx)
                if (channel.channel != self.channel)
                {
                        core::diagnostics::call_context::for_thread().layer = index;
-                       auto producer = ctx.producer_registry->create_producer(get_producer_dependencies(channel.channel, ctx), L"route://" + boost::lexical_cast<std::wstring>(channel.channel->index()));
+                       auto producer = ctx.producer_registry->create_producer(get_producer_dependencies(self.channel, ctx), L"route://" + boost::lexical_cast<std::wstring>(channel.channel->index()));
                        self.channel->stage().load(index, producer, false);
                        self.channel->stage().play(index);
                        index++;
@@ -2039,9 +2100,9 @@ std::wstring thumbnail_list_command(command_context& ctx)
                        if (!boost::iequals(itr->path().extension().wstring(), L".png"))
                                continue;
 
-                       auto relativePath = boost::filesystem::path(itr->path().wstring().substr(env::thumbnails_folder().size() - 1, itr->path().wstring().size()));
+                       auto relativePath = get_relative_without_extension(itr->path(), env::thumbnails_folder());
+                       auto str = relativePath.generic_wstring();
 
-                       auto str = relativePath.replace_extension(L"").generic_wstring();
                        if (str[0] == '\\' || str[0] == '/')
                                str = std::wstring(str.begin() + 1, str.end());
 
@@ -2109,7 +2170,7 @@ std::wstring thumbnail_generate_command(command_context& ctx)
                return L"202 THUMBNAIL GENERATE OK\r\n";
        }
        else
-               CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info(L"Thumbnail generation turned off"));
+               CASPAR_THROW_EXCEPTION(not_supported() << msg_info(L"Thumbnail generation turned off"));
 }
 
 void thumbnail_generateall_describer(core::help_sink& sink, const core::help_repository& repo)
@@ -2127,7 +2188,7 @@ std::wstring thumbnail_generateall_command(command_context& ctx)
                return L"202 THUMBNAIL GENERATE_ALL OK\r\n";
        }
        else
-               CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info(L"Thumbnail generation turned off"));
+               CASPAR_THROW_EXCEPTION(not_supported() << msg_info(L"Thumbnail generation turned off"));
 }
 
 // Query Commands
@@ -2147,7 +2208,7 @@ std::wstring cinf_command(command_context& ctx)
                auto path = itr->path();
                auto file = path.replace_extension(L"").filename().wstring();
                if (boost::iequals(file, ctx.parameters.at(0)))
-                       info += MediaInfo(itr->path(), ctx.media_info_repo) + L"\r\n";
+                       info += MediaInfo(itr->path(), ctx.media_info_repo);
        }
 
        if (info.empty())
@@ -2178,6 +2239,29 @@ std::wstring cls_command(command_context& ctx)
        return boost::to_upper_copy(replyString.str());
 }
 
+void fls_describer(core::help_sink& sink, const core::help_repository& repo)
+{
+       sink.short_description(L"List all fonts.");
+       sink.syntax(L"FLS");
+       sink.para()
+               ->text(L"Lists all font files in the ")->code(L"fonts")->text(L" folder. Use the command ")
+               ->see(L"INFO PATHS")->text(L" to get the path to the ")->code(L"fonts")->text(L" folder.");
+       sink.para()->text(L"Columns in order from left to right are: Font name and font path.");
+}
+
+std::wstring fls_command(command_context& ctx)
+{
+       std::wstringstream replyString;
+       replyString << L"200 FLS OK\r\n";
+
+       for (auto& font : core::text::list_fonts())
+               replyString << L"\"" << font.first << L"\" \"" << get_relative(font.second, env::font_folder()).wstring() << L"\"\r\n";
+
+       replyString << L"\r\n";
+
+       return replyString.str();
+}
+
 void tls_describer(core::help_sink& sink, const core::help_repository& repo)
 {
        sink.short_description(L"List all templates.");
@@ -2216,6 +2300,14 @@ void version_describer(core::help_sink& sink, const core::help_repository& repo)
                L">> VERSION FLASH\n"
                L"<< 201 VERSION OK\n"
                L"<< 11.8.800.94");
+       sink.example(
+               L">> VERSION TEMPLATEHOST\n"
+               L"<< 201 VERSION OK\n"
+               L"<< unknown");
+       sink.example(
+               L">> VERSION CEF\n"
+               L"<< 201 VERSION OK\n"
+               L"<< 3.1750.1805");
 }
 
 std::wstring version_command(command_context& ctx)
@@ -2416,13 +2508,34 @@ std::wstring info_threads_command(command_context& ctx)
 
        for (auto& thread : get_thread_infos())
        {
-               replyString << thread->native_id << L"\t" << u16(thread->name) << L"\r\n";
+               replyString << thread->native_id << L" " << u16(thread->name) << L"\r\n";
        }
 
        replyString << L"\r\n";
        return replyString.str();
 }
 
+void info_delay_describer(core::help_sink& sink, const core::help_repository& repo)
+{
+       sink.short_description(L"Get the current delay on a channel or a layer.");
+       sink.syntax(L"INFO [video_channel:int]{-[layer:int]} DELAY");
+       sink.para()->text(L"Get the current delay on the specified channel or layer.");
+}
+
+std::wstring info_delay_command(command_context& ctx)
+{
+       boost::property_tree::wptree info;
+       auto layer = ctx.layer_index(std::numeric_limits<int>::min());
+
+       if (layer == std::numeric_limits<int>::min())
+               info.add_child(L"channel-delay", ctx.channel.channel->delay_info());
+       else
+               info.add_child(L"layer-delay", ctx.channel.channel->stage().delay_info(layer).get())
+                       .add(L"index", layer);
+
+       return create_info_xml_reply(info, L"DELAY");
+}
+
 void diag_describer(core::help_sink& sink, const core::help_repository& repo)
 {
        sink.short_description(L"Open the diagnostics window.");
@@ -2437,6 +2550,50 @@ std::wstring diag_command(command_context& ctx)
        return L"202 DIAG OK\r\n";
 }
 
+void gl_info_describer(core::help_sink& sink, const core::help_repository& repo)
+{
+       sink.short_description(L"Get information about the allocated and pooled OpenGL resources.");
+       sink.syntax(L"GL INFO");
+       sink.para()->text(L"Retrieves information about the allocated and pooled OpenGL resources.");
+}
+
+std::wstring gl_info_command(command_context& ctx)
+{
+       auto device = ctx.ogl_device;
+
+       if (!device)
+               CASPAR_THROW_EXCEPTION(not_supported() << msg_info("GL command only supported with OpenGL accelerator."));
+
+       std::wstringstream result;
+       result << L"201 GL INFO OK\r\n";
+
+       boost::property_tree::xml_writer_settings<std::wstring> w(' ', 3);
+       auto info = device->info();
+       boost::property_tree::write_xml(result, info, w);
+       result << L"\r\n";
+
+       return result.str();
+}
+
+void gl_gc_describer(core::help_sink& sink, const core::help_repository& repo)
+{
+       sink.short_description(L"Release pooled OpenGL resources.");
+       sink.syntax(L"GL GC");
+       sink.para()->text(L"Releases all the pooled OpenGL resources. ")->strong(L"May cause a pause on all video channels.");
+}
+
+std::wstring gl_gc_command(command_context& ctx)
+{
+       auto device = ctx.ogl_device;
+
+       if (!device)
+               CASPAR_THROW_EXCEPTION(not_supported() << msg_info("GL command only supported with OpenGL accelerator."));
+
+       device->gc().wait();
+
+       return L"202 GL GC OK\r\n";
+}
+
 static const int WIDTH = 80;
 
 struct max_width_sink : public core::help_sink
@@ -2483,6 +2640,7 @@ struct simple_paragraph_builder : core::paragraph_builder
                return shared_from_this();
        }
        spl::shared_ptr<paragraph_builder> code(std::wstring txt) override { return text(std::move(txt)); }
+       spl::shared_ptr<paragraph_builder> strong(std::wstring item) override { return text(L"*" + std::move(item) + L"*"); }
        spl::shared_ptr<paragraph_builder> see(std::wstring item) override { return text(std::move(item)); }
        spl::shared_ptr<paragraph_builder> url(std::wstring url, std::wstring name)  override { return text(std::move(url)); }
 };
@@ -2717,84 +2875,90 @@ std::wstring lock_command(command_context& ctx)
 
 void register_commands(amcp_command_repository& repo)
 {
-       repo.register_channel_command(  L"Basic Commands",              L"LOADBG",                                      loadbg_describer,                                       loadbg_command,                                 1);
-       repo.register_channel_command(  L"Basic Commands",              L"LOAD",                                        load_describer,                                         load_command,                                   1);
-       repo.register_channel_command(  L"Basic Commands",              L"PLAY",                                        play_describer,                                         play_command,                                   0);
-       repo.register_channel_command(  L"Basic Commands",              L"PAUSE",                                       pause_describer,                                        pause_command,                                  0);
-       repo.register_channel_command(  L"Basic Commands",              L"RESUME",                                      resume_describer,                                       resume_command,                                 0);
-       repo.register_channel_command(  L"Basic Commands",              L"STOP",                                        stop_describer,                                         stop_command,                                   0);
-       repo.register_channel_command(  L"Basic Commands",              L"CLEAR",                                       clear_describer,                                        clear_command,                                  0);
-       repo.register_channel_command(  L"Basic Commands",              L"CALL",                                        call_describer,                                         call_command,                                   1);
-       repo.register_channel_command(  L"Basic Commands",              L"SWAP",                                        swap_describer,                                         swap_command,                                   1);
-       repo.register_channel_command(  L"Basic Commands",              L"ADD",                                         add_describer,                                          add_command,                                    1);
-       repo.register_channel_command(  L"Basic Commands",              L"REMOVE",                                      remove_describer,                                       remove_command,                                 0);
-       repo.register_channel_command(  L"Basic Commands",              L"PRINT",                                       print_describer,                                        print_command,                                  0);
-       repo.register_command(                  L"Basic Commands",              L"LOG LEVEL",                           log_level_describer,                            log_level_command,                              1);
-       repo.register_channel_command(  L"Basic Commands",              L"SET",                                         set_describer,                                          set_command,                                    2);
-       repo.register_command(                  L"Basic Commands",              L"LOCK",                                        lock_describer,                                         lock_command,                                   2);
-
-       repo.register_command(                  L"Data Commands",               L"DATA STORE",                          data_store_describer,                           data_store_command,                             2);
-       repo.register_command(                  L"Data Commands",               L"DATA RETRIEVE",                       data_retrieve_describer,                        data_retrieve_command,                  1);
-       repo.register_command(                  L"Data Commands",               L"DATA LIST",                           data_list_describer,                            data_list_command,                              0);
-       repo.register_command(                  L"Data Commands",               L"DATA REMOVE",                         data_remove_describer,                          data_remove_command,                    1);
-
-       repo.register_channel_command(  L"Template Commands",   L"CG ADD",                                      cg_add_describer,                                       cg_add_command,                                 3);
-       repo.register_channel_command(  L"Template Commands",   L"CG PLAY",                                     cg_play_describer,                                      cg_play_command,                                1);
-       repo.register_channel_command(  L"Template Commands",   L"CG STOP",                                     cg_stop_describer,                                      cg_stop_command,                                1);
-       repo.register_channel_command(  L"Template Commands",   L"CG NEXT",                                     cg_next_describer,                                      cg_next_command,                                1);
-       repo.register_channel_command(  L"Template Commands",   L"CG REMOVE",                           cg_remove_describer,                            cg_remove_command,                              1);
-       repo.register_channel_command(  L"Template Commands",   L"CG CLEAR",                            cg_clear_describer,                                     cg_clear_command,                               0);
-       repo.register_channel_command(  L"Template Commands",   L"CG UPDATE",                           cg_update_describer,                            cg_update_command,                              2);
-       repo.register_channel_command(  L"Template Commands",   L"CG INVOKE",                           cg_invoke_describer,                            cg_invoke_command,                              2);
-       repo.register_channel_command(  L"Template Commands",   L"CG INFO",                                     cg_info_describer,                                      cg_info_command,                                0);
-
-       repo.register_channel_command(  L"Mixer Commands",              L"MIXER KEYER",                         mixer_keyer_describer,                          mixer_keyer_command,                    0);
-       repo.register_channel_command(  L"Mixer Commands",              L"MIXER CHROMA",                        mixer_chroma_describer,                         mixer_chroma_command,                   0);
-       repo.register_channel_command(  L"Mixer Commands",              L"MIXER BLEND",                         mixer_blend_describer,                          mixer_blend_command,                    0);
-       repo.register_channel_command(  L"Mixer Commands",              L"MIXER OPACITY",                       mixer_opacity_describer,                        mixer_opacity_command,                  0);
-       repo.register_channel_command(  L"Mixer Commands",              L"MIXER BRIGHTNESS",            mixer_brightness_describer,                     mixer_brightness_command,               0);
-       repo.register_channel_command(  L"Mixer Commands",              L"MIXER SATURATION",            mixer_saturation_describer,                     mixer_saturation_command,               0);
-       repo.register_channel_command(  L"Mixer Commands",              L"MIXER CONTRAST",                      mixer_contrast_describer,                       mixer_contrast_command,                 0);
-       repo.register_channel_command(  L"Mixer Commands",              L"MIXER LEVELS",                        mixer_levels_describer,                         mixer_levels_command,                   0);
-       repo.register_channel_command(  L"Mixer Commands",              L"MIXER FILL",                          mixer_fill_describer,                           mixer_fill_command,                             0);
-       repo.register_channel_command(  L"Mixer Commands",              L"MIXER CLIP",                          mixer_clip_describer,                           mixer_clip_command,                             0);
-       repo.register_channel_command(  L"Mixer Commands",              L"MIXER ANCHOR",                        mixer_anchor_describer,                         mixer_anchor_command,                   0);
-       repo.register_channel_command(  L"Mixer Commands",              L"MIXER CROP",                          mixer_crop_describer,                           mixer_crop_command,                             0);
-       repo.register_channel_command(  L"Mixer Commands",              L"MIXER ROTATION",                      mixer_rotation_describer,                       mixer_rotation_command,                 0);
-       repo.register_channel_command(  L"Mixer Commands",              L"MIXER PERSPECTIVE",           mixer_perspective_describer,            mixer_perspective_command,              0);
-       repo.register_channel_command(  L"Mixer Commands",              L"MIXER MIPMAP",                        mixer_mipmap_describer,                         mixer_mipmap_command,                   0);
-       repo.register_channel_command(  L"Mixer Commands",              L"MIXER VOLUME",                        mixer_volume_describer,                         mixer_volume_command,                   0);
-       repo.register_channel_command(  L"Mixer Commands",              L"MIXER MASTERVOLUME",          mixer_mastervolume_describer,           mixer_mastervolume_command,             0);
-       repo.register_channel_command(  L"Mixer Commands",              L"MIXER GRID",                          mixer_grid_describer,                           mixer_grid_command,                             1);
-       repo.register_channel_command(  L"Mixer Commands",              L"MIXER COMMIT",                        mixer_commit_describer,                         mixer_commit_command,                   0);
-       repo.register_channel_command(  L"Mixer Commands",              L"MIXER CLEAR",                         mixer_clear_describer,                          mixer_clear_command,                    0);
-       repo.register_command(                  L"Mixer Commands",              L"CHANNEL_GRID",                        channel_grid_describer,                         channel_grid_command,                   0);
-
-       repo.register_command(                  L"Thumbnail Commands",  L"THUMBNAIL LIST",                      thumbnail_list_describer,                       thumbnail_list_command,                 0);
-       repo.register_command(                  L"Thumbnail Commands",  L"THUMBNAIL RETRIEVE",          thumbnail_retrieve_describer,           thumbnail_retrieve_command,             1);
-       repo.register_command(                  L"Thumbnail Commands",  L"THUMBNAIL GENERATE",          thumbnail_generate_describer,           thumbnail_generate_command,             1);
-       repo.register_command(                  L"Thumbnail Commands",  L"THUMBNAIL GENERATE_ALL",      thumbnail_generateall_describer,        thumbnail_generateall_command,  0);
-
-       repo.register_command(                  L"Query Commands",              L"CINF",                                        cinf_describer,                                         cinf_command,                                   1);
-       repo.register_command(                  L"Query Commands",              L"CLS",                                         cls_describer,                                          cls_command,                                    0);
-       repo.register_command(                  L"Query Commands",              L"TLS",                                         tls_describer,                                          tls_command,                                    0);
-       repo.register_command(                  L"Query Commands",              L"VERSION",                                     version_describer,                                      version_command,                                0);
-       repo.register_command(                  L"Query Commands",              L"INFO",                                        info_describer,                                         info_command,                                   0);
-       repo.register_channel_command(  L"Query Commands",              L"INFO",                                        info_channel_describer,                         info_channel_command,                   0);
-       repo.register_command(                  L"Query Commands",              L"INFO TEMPLATE",                       info_template_describer,                        info_template_command,                  1);
-       repo.register_command(                  L"Query Commands",              L"INFO CONFIG",                         info_config_describer,                          info_config_command,                    0);
-       repo.register_command(                  L"Query Commands",              L"INFO PATHS",                          info_paths_describer,                           info_paths_command,                             0);
-       repo.register_command(                  L"Query Commands",              L"INFO SYSTEM",                         info_system_describer,                          info_system_command,                    0);
-       repo.register_command(                  L"Query Commands",              L"INFO SERVER",                         info_server_describer,                          info_server_command,                    0);
-       repo.register_command(                  L"Query Commands",              L"INFO QUEUES",                         info_queues_describer,                          info_queues_command,                    0);
-       repo.register_command(                  L"Query Commands",              L"INFO THREADS",                        info_threads_describer,                         info_threads_command,                   0);
-       repo.register_command(                  L"Query Commands",              L"DIAG",                                        diag_describer,                                         diag_command,                                   0);
-       repo.register_command(                  L"Query Commands",              L"BYE",                                         bye_describer,                                          bye_command,                                    0);
-       repo.register_command(                  L"Query Commands",              L"KILL",                                        kill_describer,                                         kill_command,                                   0);
-       repo.register_command(                  L"Query Commands",              L"RESTART",                                     restart_describer,                                      restart_command,                                0);
-       repo.register_command(                  L"Query Commands",              L"HELP",                                        help_describer,                                         help_command,                                   0);
-       repo.register_command(                  L"Query Commands",              L"HELP PRODUCER",                       help_producer_describer,                        help_producer_command,                  0);
-       repo.register_command(                  L"Query Commands",              L"HELP CONSUMER",                       help_consumer_describer,                        help_consumer_command,                  0);
+       repo.register_channel_command(  L"Basic Commands",              L"LOADBG",                                              loadbg_describer,                                       loadbg_command,                                 1);
+       repo.register_channel_command(  L"Basic Commands",              L"LOAD",                                                load_describer,                                         load_command,                                   1);
+       repo.register_channel_command(  L"Basic Commands",              L"PLAY",                                                play_describer,                                         play_command,                                   0);
+       repo.register_channel_command(  L"Basic Commands",              L"PAUSE",                                               pause_describer,                                        pause_command,                                  0);
+       repo.register_channel_command(  L"Basic Commands",              L"RESUME",                                              resume_describer,                                       resume_command,                                 0);
+       repo.register_channel_command(  L"Basic Commands",              L"STOP",                                                stop_describer,                                         stop_command,                                   0);
+       repo.register_channel_command(  L"Basic Commands",              L"CLEAR",                                               clear_describer,                                        clear_command,                                  0);
+       repo.register_channel_command(  L"Basic Commands",              L"CALL",                                                call_describer,                                         call_command,                                   1);
+       repo.register_channel_command(  L"Basic Commands",              L"SWAP",                                                swap_describer,                                         swap_command,                                   1);
+       repo.register_channel_command(  L"Basic Commands",              L"ADD",                                                 add_describer,                                          add_command,                                    1);
+       repo.register_channel_command(  L"Basic Commands",              L"REMOVE",                                              remove_describer,                                       remove_command,                                 0);
+       repo.register_channel_command(  L"Basic Commands",              L"PRINT",                                               print_describer,                                        print_command,                                  0);
+       repo.register_command(                  L"Basic Commands",              L"LOG LEVEL",                                   log_level_describer,                            log_level_command,                              1);
+       repo.register_command(                  L"Basic Commands",              L"LOG CATEGORY",                                log_category_describer,                         log_category_command,                   2);
+       repo.register_channel_command(  L"Basic Commands",              L"SET",                                                 set_describer,                                          set_command,                                    2);
+       repo.register_command(                  L"Basic Commands",              L"LOCK",                                                lock_describer,                                         lock_command,                                   2);
+
+       repo.register_command(                  L"Data Commands",               L"DATA STORE",                                  data_store_describer,                           data_store_command,                             2);
+       repo.register_command(                  L"Data Commands",               L"DATA RETRIEVE",                               data_retrieve_describer,                        data_retrieve_command,                  1);
+       repo.register_command(                  L"Data Commands",               L"DATA LIST",                                   data_list_describer,                            data_list_command,                              0);
+       repo.register_command(                  L"Data Commands",               L"DATA REMOVE",                                 data_remove_describer,                          data_remove_command,                    1);
+
+       repo.register_channel_command(  L"Template Commands",   L"CG ADD",                                              cg_add_describer,                                       cg_add_command,                                 3);
+       repo.register_channel_command(  L"Template Commands",   L"CG PLAY",                                             cg_play_describer,                                      cg_play_command,                                1);
+       repo.register_channel_command(  L"Template Commands",   L"CG STOP",                                             cg_stop_describer,                                      cg_stop_command,                                1);
+       repo.register_channel_command(  L"Template Commands",   L"CG NEXT",                                             cg_next_describer,                                      cg_next_command,                                1);
+       repo.register_channel_command(  L"Template Commands",   L"CG REMOVE",                                   cg_remove_describer,                            cg_remove_command,                              1);
+       repo.register_channel_command(  L"Template Commands",   L"CG CLEAR",                                    cg_clear_describer,                                     cg_clear_command,                               0);
+       repo.register_channel_command(  L"Template Commands",   L"CG UPDATE",                                   cg_update_describer,                            cg_update_command,                              2);
+       repo.register_channel_command(  L"Template Commands",   L"CG INVOKE",                                   cg_invoke_describer,                            cg_invoke_command,                              2);
+       repo.register_channel_command(  L"Template Commands",   L"CG INFO",                                             cg_info_describer,                                      cg_info_command,                                0);
+
+       repo.register_channel_command(  L"Mixer Commands",              L"MIXER KEYER",                                 mixer_keyer_describer,                          mixer_keyer_command,                    0);
+       repo.register_channel_command(  L"Mixer Commands",              L"MIXER CHROMA",                                mixer_chroma_describer,                         mixer_chroma_command,                   0);
+       repo.register_channel_command(  L"Mixer Commands",              L"MIXER BLEND",                                 mixer_blend_describer,                          mixer_blend_command,                    0);
+       repo.register_channel_command(  L"Mixer Commands",              L"MIXER OPACITY",                               mixer_opacity_describer,                        mixer_opacity_command,                  0);
+       repo.register_channel_command(  L"Mixer Commands",              L"MIXER BRIGHTNESS",                    mixer_brightness_describer,                     mixer_brightness_command,               0);
+       repo.register_channel_command(  L"Mixer Commands",              L"MIXER SATURATION",                    mixer_saturation_describer,                     mixer_saturation_command,               0);
+       repo.register_channel_command(  L"Mixer Commands",              L"MIXER CONTRAST",                              mixer_contrast_describer,                       mixer_contrast_command,                 0);
+       repo.register_channel_command(  L"Mixer Commands",              L"MIXER LEVELS",                                mixer_levels_describer,                         mixer_levels_command,                   0);
+       repo.register_channel_command(  L"Mixer Commands",              L"MIXER FILL",                                  mixer_fill_describer,                           mixer_fill_command,                             0);
+       repo.register_channel_command(  L"Mixer Commands",              L"MIXER CLIP",                                  mixer_clip_describer,                           mixer_clip_command,                             0);
+       repo.register_channel_command(  L"Mixer Commands",              L"MIXER ANCHOR",                                mixer_anchor_describer,                         mixer_anchor_command,                   0);
+       repo.register_channel_command(  L"Mixer Commands",              L"MIXER CROP",                                  mixer_crop_describer,                           mixer_crop_command,                             0);
+       repo.register_channel_command(  L"Mixer Commands",              L"MIXER ROTATION",                              mixer_rotation_describer,                       mixer_rotation_command,                 0);
+       repo.register_channel_command(  L"Mixer Commands",              L"MIXER PERSPECTIVE",                   mixer_perspective_describer,            mixer_perspective_command,              0);
+       repo.register_channel_command(  L"Mixer Commands",              L"MIXER MIPMAP",                                mixer_mipmap_describer,                         mixer_mipmap_command,                   0);
+       repo.register_channel_command(  L"Mixer Commands",              L"MIXER VOLUME",                                mixer_volume_describer,                         mixer_volume_command,                   0);
+       repo.register_channel_command(  L"Mixer Commands",              L"MIXER MASTERVOLUME",                  mixer_mastervolume_describer,           mixer_mastervolume_command,             0);
+       repo.register_channel_command(  L"Mixer Commands",              L"MIXER STRAIGHT_ALPHA_OUTPUT", mixer_straight_alpha_describer,         mixer_straight_alpha_command,   0);
+       repo.register_channel_command(  L"Mixer Commands",              L"MIXER GRID",                                  mixer_grid_describer,                           mixer_grid_command,                             1);
+       repo.register_channel_command(  L"Mixer Commands",              L"MIXER COMMIT",                                mixer_commit_describer,                         mixer_commit_command,                   0);
+       repo.register_channel_command(  L"Mixer Commands",              L"MIXER CLEAR",                                 mixer_clear_describer,                          mixer_clear_command,                    0);
+       repo.register_command(                  L"Mixer Commands",              L"CHANNEL_GRID",                                channel_grid_describer,                         channel_grid_command,                   0);
+
+       repo.register_command(                  L"Thumbnail Commands",  L"THUMBNAIL LIST",                              thumbnail_list_describer,                       thumbnail_list_command,                 0);
+       repo.register_command(                  L"Thumbnail Commands",  L"THUMBNAIL RETRIEVE",                  thumbnail_retrieve_describer,           thumbnail_retrieve_command,             1);
+       repo.register_command(                  L"Thumbnail Commands",  L"THUMBNAIL GENERATE",                  thumbnail_generate_describer,           thumbnail_generate_command,             1);
+       repo.register_command(                  L"Thumbnail Commands",  L"THUMBNAIL GENERATE_ALL",              thumbnail_generateall_describer,        thumbnail_generateall_command,  0);
+
+       repo.register_command(                  L"Query Commands",              L"CINF",                                                cinf_describer,                                         cinf_command,                                   1);
+       repo.register_command(                  L"Query Commands",              L"CLS",                                                 cls_describer,                                          cls_command,                                    0);
+       repo.register_command(                  L"Query Commands",              L"FLS",                                                 fls_describer,                                          fls_command,                                    0);
+       repo.register_command(                  L"Query Commands",              L"TLS",                                                 tls_describer,                                          tls_command,                                    0);
+       repo.register_command(                  L"Query Commands",              L"VERSION",                                             version_describer,                                      version_command,                                0);
+       repo.register_command(                  L"Query Commands",              L"INFO",                                                info_describer,                                         info_command,                                   0);
+       repo.register_channel_command(  L"Query Commands",              L"INFO",                                                info_channel_describer,                         info_channel_command,                   0);
+       repo.register_command(                  L"Query Commands",              L"INFO TEMPLATE",                               info_template_describer,                        info_template_command,                  1);
+       repo.register_command(                  L"Query Commands",              L"INFO CONFIG",                                 info_config_describer,                          info_config_command,                    0);
+       repo.register_command(                  L"Query Commands",              L"INFO PATHS",                                  info_paths_describer,                           info_paths_command,                             0);
+       repo.register_command(                  L"Query Commands",              L"INFO SYSTEM",                                 info_system_describer,                          info_system_command,                    0);
+       repo.register_command(                  L"Query Commands",              L"INFO SERVER",                                 info_server_describer,                          info_server_command,                    0);
+       repo.register_command(                  L"Query Commands",              L"INFO QUEUES",                                 info_queues_describer,                          info_queues_command,                    0);
+       repo.register_command(                  L"Query Commands",              L"INFO THREADS",                                info_threads_describer,                         info_threads_command,                   0);
+       repo.register_channel_command(  L"Query Commands",              L"INFO DELAY",                                  info_delay_describer,                           info_delay_command,                             0);
+       repo.register_command(                  L"Query Commands",              L"DIAG",                                                diag_describer,                                         diag_command,                                   0);
+       repo.register_command(                  L"Query Commands",              L"GL INFO",                                             gl_info_describer,                                      gl_info_command,                                0);
+       repo.register_command(                  L"Query Commands",              L"GL GC",                                               gl_gc_describer,                                        gl_gc_command,                                  0);
+       repo.register_command(                  L"Query Commands",              L"BYE",                                                 bye_describer,                                          bye_command,                                    0);
+       repo.register_command(                  L"Query Commands",              L"KILL",                                                kill_describer,                                         kill_command,                                   0);
+       repo.register_command(                  L"Query Commands",              L"RESTART",                                             restart_describer,                                      restart_command,                                0);
+       repo.register_command(                  L"Query Commands",              L"HELP",                                                help_describer,                                         help_command,                                   0);
+       repo.register_command(                  L"Query Commands",              L"HELP PRODUCER",                               help_producer_describer,                        help_producer_command,                  0);
+       repo.register_command(                  L"Query Commands",              L"HELP CONSUMER",                               help_consumer_describer,                        help_consumer_command,                  0);
 }
 
 }      //namespace amcp