2 * Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
4 * This file is part of CasparCG (www.casparcg.com).
6 * CasparCG is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * CasparCG is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
19 * Author: Helge Norberg, helge.norberg@svt.se
22 #include "../StdAfx.h"
24 #include "audio_channel_layout.h"
26 #include <common/ptree.h>
28 #include <boost/algorithm/string/split.hpp>
29 #include <boost/algorithm/string/join.hpp>
30 #include <boost/range/algorithm/equal.hpp>
31 #include <boost/lexical_cast.hpp>
32 #include <boost/thread/mutex.hpp>
33 #include <boost/property_tree/ptree.hpp>
37 namespace caspar { namespace core {
39 audio_channel_layout::audio_channel_layout()
44 audio_channel_layout::audio_channel_layout(int num_channels, std::wstring type_, const std::wstring& channel_order_)
45 : num_channels(num_channels)
46 , type(std::move(type_))
49 CASPAR_THROW_EXCEPTION(invalid_argument() << msg_info(L"num_channels cannot be less than 1"));
51 if (boost::contains(channel_order_, L"=") ||
52 boost::contains(channel_order_, L"<") ||
53 boost::contains(channel_order_, L"+") ||
54 boost::contains(channel_order_, L"*") ||
55 boost::contains(channel_order_, L"|"))
57 CASPAR_THROW_EXCEPTION(invalid_argument() << msg_info(
58 channel_order_ + L" contains illegal characters =<+*| reserved for mix config syntax"));
61 boost::to_upper(type);
62 boost::split(channel_order, channel_order_, boost::is_any_of(L" "), boost::algorithm::token_compress_on);
64 if (channel_order.size() == 1 && channel_order.front().empty())
65 channel_order.clear();
67 if (channel_order.size() > num_channels)
68 CASPAR_THROW_EXCEPTION(invalid_argument() << msg_info(
69 channel_order_ + L" contains more than " + boost::lexical_cast<std::wstring>(num_channels)));
72 std::vector<int> audio_channel_layout::indexes_of(const std::wstring& channel_name) const
74 std::vector<int> result;
75 for (int i = 0; i < channel_order.size(); ++i)
76 if (channel_name == channel_order.at(i))
82 std::wstring audio_channel_layout::print() const
84 auto channels = boost::join(channel_order, L" ");
86 return L"[audio_channel_layout] num_channels=" + boost::lexical_cast<std::wstring>(num_channels) + L" type=" + type + L" channel_order=" + channels;
89 const audio_channel_layout& audio_channel_layout::invalid()
91 static const audio_channel_layout instance;
96 bool operator==(const audio_channel_layout& lhs, const audio_channel_layout& rhs)
98 return lhs.num_channels == rhs.num_channels
99 && boost::equal(lhs.channel_order, rhs.channel_order)
100 && lhs.type == rhs.type;
103 bool operator!=(const audio_channel_layout& lhs, const audio_channel_layout& rhs)
105 return !(lhs == rhs);
108 struct audio_channel_layout_repository::impl
110 mutable boost::mutex mutex_;
111 std::map<std::wstring, audio_channel_layout> layouts_;
114 audio_channel_layout_repository::audio_channel_layout_repository()
119 void audio_channel_layout_repository::register_layout(std::wstring name, audio_channel_layout layout)
122 boost::lock_guard<boost::mutex> lock(self.mutex_);
124 boost::to_upper(name);
125 self.layouts_.insert(std::make_pair(std::move(name), std::move(layout)));
128 void audio_channel_layout_repository::register_all_layouts(const boost::property_tree::wptree& layouts)
131 boost::lock_guard<boost::mutex> lock(self.mutex_);
133 for (auto& layout : layouts | welement_context_iteration)
135 ptree_verify_element_name(layout, L"channel-layout");
137 auto name = ptree_get<std::wstring>(layout.second, L"<xmlattr>.name");
138 auto type = ptree_get<std::wstring>(layout.second, L"<xmlattr>.type");
139 auto num_channels = ptree_get<int>(layout.second, L"<xmlattr>.num-channels");
140 auto channel_order = layout.second.get<std::wstring>(L"<xmlattr>.channel-order", L"");
142 boost::to_upper(name);
143 self.layouts_.insert(std::make_pair(
145 audio_channel_layout(num_channels, std::move(type), channel_order)));
149 boost::optional<audio_channel_layout> audio_channel_layout_repository::get_layout(const std::wstring& name) const
152 boost::lock_guard<boost::mutex> lock(self.mutex_);
154 auto found = self.layouts_.find(boost::to_upper_copy(name));
156 if (found == self.layouts_.end())
159 return found->second;
162 spl::shared_ptr<audio_channel_layout_repository> audio_channel_layout_repository::get_default()
164 static spl::shared_ptr<audio_channel_layout_repository> instance;
169 struct audio_mix_config_repository::impl
171 mutable boost::mutex mutex_;
172 std::map<std::wstring, std::map<std::wstring, std::wstring>> from_to_configs_;
175 audio_mix_config_repository::audio_mix_config_repository()
180 void audio_mix_config_repository::register_config(
181 const std::wstring& from_type,
182 const std::vector<std::wstring>& to_types,
183 const std::wstring& mix_config)
186 boost::lock_guard<boost::mutex> lock(self.mutex_);
188 for (auto& to_type : to_types)
189 self.from_to_configs_[boost::to_upper_copy(from_type)][boost::to_upper_copy(to_type)] = mix_config;
192 void audio_mix_config_repository::register_all_configs(const boost::property_tree::wptree& configs)
195 boost::lock_guard<boost::mutex> lock(self.mutex_);
197 for (auto& config : configs | welement_context_iteration)
199 ptree_verify_element_name(config, L"mix-config");
201 auto from_type = ptree_get<std::wstring>(config.second, L"<xmlattr>.from-type");
202 auto to_types_str = ptree_get<std::wstring>(config.second, L"<xmlattr>.to-types");
203 auto mix_config = ptree_get<std::wstring>(config.second, L"<xmlattr>.mix");
205 boost::to_upper(from_type);
206 std::vector<std::wstring> to_types;
207 boost::split(to_types, to_types_str, boost::is_any_of(L","), boost::algorithm::token_compress_off);
209 for (auto& to_type : to_types)
211 boost::trim(to_type);
216 boost::to_upper(to_type);
217 self.from_to_configs_[from_type][to_type] = mix_config;
222 boost::optional<std::wstring> audio_mix_config_repository::get_config(
223 const std::wstring& from_type,
224 const std::wstring& to_type) const
227 boost::lock_guard<boost::mutex> lock(self.mutex_);
229 auto from_found = self.from_to_configs_.find(boost::to_upper_copy(from_type));
231 if (from_found == self.from_to_configs_.end())
234 auto to_found = from_found->second.find(boost::to_upper_copy(to_type));
236 if (to_found == from_found->second.end())
239 return to_found->second;
242 spl::shared_ptr<audio_mix_config_repository> audio_mix_config_repository::get_default()
244 static spl::shared_ptr<audio_mix_config_repository> instance;