X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=shell%2Fmain.cpp;h=b90bd40018219abba98dc17097a27fa220b08756;hb=06bdd05d8ec7da072de717d5e1fcb462a1d8ee56;hp=0fa28cdcbdf42e3d3083b9493172db71f170e8c4;hpb=7ac3f4419d79e81b111b1b3d068528f4a618351d;p=casparcg diff --git a/shell/main.cpp b/shell/main.cpp index 0fa28cdcb..b90bd4001 100644 --- a/shell/main.cpp +++ b/shell/main.cpp @@ -19,9 +19,9 @@ * Author: Robert Nagy, ronag89@gmail.com */ -// tbbmalloc_proxy: -// Replace the standard memory allocation routines in Microsoft* C/C++ RTL -// (malloc/free, global new/delete, etc.) with the TBB memory allocator. +// tbbmalloc_proxy: +// Replace the standard memory allocation routines in Microsoft* C/C++ RTL +// (malloc/free, global new/delete, etc.) with the TBB memory allocator. #include "stdafx.h" @@ -33,7 +33,8 @@ #include #include #else - #include + // Reenable when tbb gets official support for vc14 + //#include #endif #include "server.h" @@ -60,19 +61,28 @@ #include #include #include +#include +#include + +#include #include +#include #include +#include using namespace caspar; - + void setup_global_locale() { boost::locale::generator gen; gen.categories(boost::locale::codepage_facet); std::locale::global(gen("")); + + // sscanf is used in for example FFmpeg where we want decimals to be parsed as . + std::setlocale(LC_ALL, "C"); } void print_info() @@ -89,18 +99,6 @@ void print_info() CASPAR_LOG(info) << system_product_name(); } -void print_child(const std::wstring& indent, const std::wstring& elem, const boost::property_tree::wptree& tree) -{ - auto data = tree.data(); - - if (data.empty()) - CASPAR_LOG(info) << indent << elem; - else - CASPAR_LOG(info) << indent << elem << L" " << tree.data(); - - for (auto& child : tree) - print_child(indent + L" ", child.first, child.second); -} void print_system_info(const spl::shared_ptr& repo) { @@ -108,21 +106,26 @@ void print_system_info(const spl::shared_ptrfill_information(info); for (auto& elem : info.get_child(L"system")) - print_child(L"", elem.first, elem.second); + log::print_child(boost::log::trivial::info, L"", elem.first, elem.second); } -void do_run(std::weak_ptr> amcp, std::promise& shutdown_server_now) +void do_run( + std::weak_ptr> amcp, + std::promise& shutdown_server_now, + tbb::atomic& should_wait_for_keypress) { + ensure_gpf_handler_installed_for_thread("Console thread"); std::wstring wcmd; while(true) { - std::getline(std::wcin, wcmd); // TODO: It's blocking... - - //boost::to_upper(wcmd); + if (!std::getline(std::wcin, wcmd)) // TODO: It's blocking... + wcmd = L"EXIT"; // EOF, handle as EXIT if(boost::iequals(wcmd, L"EXIT") || boost::iequals(wcmd, L"Q") || boost::iequals(wcmd, L"QUIT") || boost::iequals(wcmd, L"BYE")) { - shutdown_server_now.set_value(true); //true to wait for keypress + CASPAR_LOG(info) << L"Received message from Console: " << wcmd << L"\\r\\n"; + should_wait_for_keypress = true; + shutdown_server_now.set_value(false); //false to not restart break; } @@ -140,11 +143,11 @@ void do_run(std::weak_ptr> amcp, std::pro else if(wcmd.substr(0, 1) == L"5") { auto file = wcmd.substr(2, wcmd.length()-1); - wcmd = L"PLAY 1-1 " + file + L" LOOP\r\n" - L"PLAY 1-2 " + file + L" LOOP\r\n" + wcmd = L"PLAY 1-1 " + file + L" LOOP\r\n" + L"PLAY 1-2 " + file + L" LOOP\r\n" L"PLAY 1-3 " + file + L" LOOP\r\n" - L"PLAY 2-1 " + file + L" LOOP\r\n" - L"PLAY 2-2 " + file + L" LOOP\r\n" + L"PLAY 2-1 " + file + L" LOOP\r\n" + L"PLAY 2-2 " + file + L" LOOP\r\n" L"PLAY 2-3 " + file + L" LOOP\r\n"; } else if(wcmd.substr(0, 1) == L"7") @@ -208,7 +211,7 @@ void do_run(std::weak_ptr> amcp, std::pro } }; -bool run() +bool run(const std::wstring& config_file_name, tbb::atomic& should_wait_for_keypress) { std::promise shutdown_server_now; std::future shutdown_server = shutdown_server_now.get_future(); @@ -216,33 +219,46 @@ bool run() print_info(); // Create server object which initializes channels, protocols and controllers. - server caspar_server(shutdown_server_now); - + std::unique_ptr caspar_server(new server(shutdown_server_now)); + + // For example CEF resets the global locale, so this is to reset it back to "our" preference. + setup_global_locale(); + // Print environment information. - print_system_info(caspar_server.get_system_info_provider_repo()); + print_system_info(caspar_server->get_system_info_provider_repo()); std::wstringstream str; boost::property_tree::xml_writer_settings w(' ', 3); boost::property_tree::write_xml(str, env::properties(), w); - CASPAR_LOG(info) << L"casparcg.config:\n-----------------------------------------\n" << str.str() << L"-----------------------------------------"; - - caspar_server.start(); + CASPAR_LOG(info) << config_file_name << L":\n-----------------------------------------\n" << str.str() << L"-----------------------------------------"; + + { + CASPAR_SCOPED_CONTEXT_MSG(config_file_name + L": ") + caspar_server->start(); + } // Create a dummy client which prints amcp responses to console. auto console_client = spl::make_shared(); // Create a amcp parser for console commands. - auto amcp = spl::make_shared>( + std::shared_ptr> amcp = spl::make_shared>( L"\r\n", spl::make_shared( spl::make_shared( - caspar_server.get_amcp_command_repository())))->create(console_client); + L"Console", + caspar_server->get_amcp_command_repository())))->create(console_client); + std::weak_ptr> weak_amcp = amcp; - // Use separate thread for the blocking console input, will be terminated + // Use separate thread for the blocking console input, will be terminated // anyway when the main thread terminates. - boost::thread stdin_thread(std::bind(do_run, amcp, std::ref(shutdown_server_now))); //compiler didn't like lambda here... + boost::thread stdin_thread(std::bind(do_run, weak_amcp, std::ref(shutdown_server_now), std::ref(should_wait_for_keypress))); //compiler didn't like lambda here... stdin_thread.detach(); - return shutdown_server.get(); + bool should_restart = shutdown_server.get(); + amcp.reset(); + + while (weak_amcp.lock()); + + return should_restart; } void on_abort(int) @@ -262,7 +278,7 @@ int main(int argc, char** argv) setup_global_locale(); std::wcout << L"Type \"q\" to close application." << std::endl; - + // Set debug mode. auto debugging_environment = setup_debugging_environment(); @@ -276,41 +292,68 @@ int main(int argc, char** argv) struct tbb_thread_installer : public tbb::task_scheduler_observer { tbb_thread_installer(){observe(true);} - void on_scheduler_entry(bool is_worker) + void on_scheduler_entry(bool is_worker) override { ensure_gpf_handler_installed_for_thread("tbb-worker-thread"); } } tbb_thread_installer; tbb::task_scheduler_init init; - - try + std::wstring config_file_name(L"casparcg.config"); + + try { // Configure environment properties from configuration. - env::configure(L"casparcg.config"); + if (argc >= 2) + config_file_name = caspar::u16(argv[1]); - log::set_log_level(env::properties().get(L"configuration.log-level", L"debug")); + env::configure(config_file_name); + + log::set_log_level(env::properties().get(L"configuration.log-level", L"info")); + auto log_categories_str = env::properties().get(L"configuration.log-categories", L"communication"); + std::set log_categories; + boost::split(log_categories, log_categories_str, boost::is_any_of(L", ")); + for (auto& log_category : { L"calltrace", L"communication" }) + log::set_log_category(log_category, log_categories.find(log_category) != log_categories.end()); if (env::properties().get(L"configuration.debugging.remote", false)) wait_for_remote_debugging(); // Start logging to file. - log::add_file_sink(env::log_folder()); + log::add_file_sink(env::log_folder() + L"caspar", caspar::log::category != caspar::log::log_category::calltrace); + log::add_file_sink(env::log_folder() + L"calltrace", caspar::log::category == caspar::log::log_category::calltrace); std::wcout << L"Logging [info] or higher severity to " << env::log_folder() << std::endl << std::endl; - + + // Once logging to file, log configuration warnings. + env::log_configuration_warnings(); + // Setup console window. setup_console_window(); - return_code = run() ? 5 : 0; - - boost::this_thread::sleep_for(boost::chrono::milliseconds(500)); + tbb::atomic should_wait_for_keypress; + should_wait_for_keypress = false; + auto should_restart = run(config_file_name, should_wait_for_keypress); + return_code = should_restart ? 5 : 0; + + for (auto& thread : get_thread_infos()) + { + if (thread->name != "main thread" && thread->name != "tbb-worker-thread") + CASPAR_LOG(warning) << L"Thread left running: " << thread->name << L" (" << thread->native_id << L")"; + } CASPAR_LOG(info) << "Successfully shutdown CasparCG Server."; + + if (should_wait_for_keypress) + wait_for_keypress(); } - catch(boost::property_tree::file_parser_error&) + catch(const boost::property_tree::file_parser_error& e) { - CASPAR_LOG_CURRENT_EXCEPTION(); - CASPAR_LOG(fatal) << L"Unhandled configuration error in main thread. Please check the configuration file (casparcg.config) for errors."; + CASPAR_LOG(fatal) << "At " << u8(config_file_name) << ":" << e.line() << ": " << e.message() << ". Please check the configuration file (" << u8(config_file_name) << ") for errors."; + wait_for_keypress(); + } + catch (const user_error& e) + { + CASPAR_LOG(fatal) << get_message_and_context(e) << " Please check the configuration file (" << u8(config_file_name) << ") for errors."; wait_for_keypress(); } catch(...) @@ -321,6 +364,6 @@ int main(int argc, char** argv) std::wcout << L"\n\nCasparCG will automatically shutdown. See the log file located at the configured log-file folder for more information.\n\n"; boost::this_thread::sleep_for(boost::chrono::milliseconds(4000)); } - + return return_code; }