]> git.sesse.net Git - casparcg/blob - core/frame/audio_channel_layout.cpp
Merge pull request #493 from dimitry-ishenko-casparcg/2.1.0
[casparcg] / core / frame / audio_channel_layout.cpp
1 /*
2 * Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
3 *
4 * This file is part of CasparCG (www.casparcg.com).
5 *
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.
10 *
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.
15 *
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/>.
18 *
19 * Author: Helge Norberg, helge.norberg@svt.se
20 */
21
22 #include "../StdAfx.h"
23
24 #include "audio_channel_layout.h"
25
26 #include <common/ptree.h>
27
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>
34
35 #include <map>
36
37 namespace caspar { namespace core {
38
39 audio_channel_layout::audio_channel_layout()
40         : num_channels(0)
41 {
42 }
43
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_))
47 {
48         if (num_channels < 1)
49                 CASPAR_THROW_EXCEPTION(invalid_argument() << msg_info(L"num_channels cannot be less than 1"));
50
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"|"))
56         {
57                 CASPAR_THROW_EXCEPTION(invalid_argument() << msg_info(
58                         channel_order_ + L" contains illegal characters =<+*| reserved for mix config syntax"));
59         }
60
61         boost::to_upper(type);
62         boost::split(channel_order, channel_order_, boost::is_any_of(L" "), boost::algorithm::token_compress_on);
63
64         if (channel_order.size() == 1 && channel_order.front().empty())
65                 channel_order.clear();
66
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)));
70 }
71
72 std::vector<int> audio_channel_layout::indexes_of(const std::wstring& channel_name) const
73 {
74         std::vector<int> result;
75         for (int i = 0; i < channel_order.size(); ++i)
76                 if (channel_name == channel_order.at(i))
77                         result.push_back(i);
78
79         return result;
80 }
81
82 std::wstring audio_channel_layout::print() const
83 {
84         auto channels = boost::join(channel_order, L" ");
85
86         return L"[audio_channel_layout] num_channels=" + boost::lexical_cast<std::wstring>(num_channels) + L" type=" + type + L" channel_order=" + channels;
87 }
88
89 const audio_channel_layout& audio_channel_layout::invalid()
90 {
91         static const audio_channel_layout instance;
92
93         return instance;
94 }
95
96 bool operator==(const audio_channel_layout& lhs, const audio_channel_layout& rhs)
97 {
98         return lhs.num_channels == rhs.num_channels
99                 && boost::equal(lhs.channel_order, rhs.channel_order)
100                 && lhs.type == rhs.type;
101 }
102
103 bool operator!=(const audio_channel_layout& lhs, const audio_channel_layout& rhs)
104 {
105         return !(lhs == rhs);
106 }
107
108 struct audio_channel_layout_repository::impl
109 {
110         mutable boost::mutex                                                    mutex_;
111         std::map<std::wstring, audio_channel_layout>    layouts_;
112 };
113
114 audio_channel_layout_repository::audio_channel_layout_repository()
115         : impl_(new impl)
116 {
117 }
118
119 void audio_channel_layout_repository::register_layout(std::wstring name, audio_channel_layout layout)
120 {
121         auto& self = *impl_;
122         boost::lock_guard<boost::mutex> lock(self.mutex_);
123
124         boost::to_upper(name);
125         self.layouts_.insert(std::make_pair(std::move(name), std::move(layout)));
126 }
127
128 void audio_channel_layout_repository::register_all_layouts(const boost::property_tree::wptree& layouts)
129 {
130         auto& self = *impl_;
131         boost::lock_guard<boost::mutex> lock(self.mutex_);
132
133         for (auto& layout : layouts | welement_context_iteration)
134         {
135                 ptree_verify_element_name(layout, L"channel-layout");
136
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"");
141
142                 boost::to_upper(name);
143                 self.layouts_.insert(std::make_pair(
144                                 std::move(name),
145                                 audio_channel_layout(num_channels, std::move(type), channel_order)));
146         }
147 }
148
149 boost::optional<audio_channel_layout> audio_channel_layout_repository::get_layout(const std::wstring& name) const
150 {
151         auto& self = *impl_;
152         boost::lock_guard<boost::mutex> lock(self.mutex_);
153
154         auto found = self.layouts_.find(boost::to_upper_copy(name));
155
156         if (found == self.layouts_.end())
157                 return boost::none;
158
159         return found->second;
160 }
161
162 spl::shared_ptr<audio_channel_layout_repository> audio_channel_layout_repository::get_default()
163 {
164         static spl::shared_ptr<audio_channel_layout_repository> instance;
165
166         return instance;
167 }
168
169 struct audio_mix_config_repository::impl
170 {
171         mutable boost::mutex                                                                                    mutex_;
172         std::map<std::wstring, std::map<std::wstring, std::wstring>>    from_to_configs_;
173 };
174
175 audio_mix_config_repository::audio_mix_config_repository()
176         : impl_(new impl)
177 {
178 }
179
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)
184 {
185         auto& self = *impl_;
186         boost::lock_guard<boost::mutex> lock(self.mutex_);
187         
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;
190 }
191
192 void audio_mix_config_repository::register_all_configs(const boost::property_tree::wptree& configs)
193 {
194         auto& self = *impl_;
195         boost::lock_guard<boost::mutex> lock(self.mutex_);
196
197         for (auto& config : configs | welement_context_iteration)
198         {
199                 ptree_verify_element_name(config, L"mix-config");
200
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");
204
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);
208
209                 for (auto& to_type : to_types)
210                 {
211                         boost::trim(to_type);
212
213                         if (to_type.empty())
214                                 continue;
215
216                         boost::to_upper(to_type);
217                         self.from_to_configs_[from_type][to_type] = mix_config;
218                 }
219         }
220 }
221
222 boost::optional<std::wstring> audio_mix_config_repository::get_config(
223                 const std::wstring& from_type,
224                 const std::wstring& to_type) const
225 {
226         auto& self = *impl_;
227         boost::lock_guard<boost::mutex> lock(self.mutex_);
228
229         auto from_found = self.from_to_configs_.find(boost::to_upper_copy(from_type));
230
231         if (from_found == self.from_to_configs_.end())
232                 return boost::none;
233
234         auto to_found = from_found->second.find(boost::to_upper_copy(to_type));
235
236         if (to_found == from_found->second.end())
237                 return boost::none;
238
239         return to_found->second;
240 }
241
242 spl::shared_ptr<audio_mix_config_repository> audio_mix_config_repository::get_default()
243 {
244         static spl::shared_ptr<audio_mix_config_repository> instance;
245
246         return instance;
247 }
248
249 }}