11#include <promeki/config.h>
12#if PROMEKI_ENABLE_PROAV
24PROMEKI_NAMESPACE_BEGIN
83class AudioChannelMap {
84 PROMEKI_SHARED_FINAL(AudioChannelMap)
86 PROMEKI_DATATYPE(AudioChannelMap, DataTypeAudioChannelMap, 1)
89 using Entry = Pair<AudioStreamDesc, ChannelRole>;
92 using EntryList = ::promeki::List<Entry>;
95 using List = ::promeki::List<AudioChannelMap>;
98 using Ptr = SharedPtr<AudioChannelMap>;
101 using PtrList = ::promeki::List<Ptr>;
104 using ChannelRoleList = ::promeki::List<ChannelRole>;
117 struct WellKnownLayout {
119 ChannelRoleList roles;
123 using WellKnownLayoutList = ::promeki::List<WellKnownLayout>;
126 static WellKnownLayoutList wellKnownLayouts();
150 static Result<AudioChannelMap> fromString(
const String &str);
185 static AudioChannelMap defaultForChannels(
size_t channels);
195 static AudioChannelMap defaultForChannels(
size_t channels,
const AudioStreamDesc &stream);
198 AudioChannelMap() =
default;
204 explicit AudioChannelMap(ChannelRoleList roles) {
205 _entries.reserve(roles.size());
206 for (
const ChannelRole &r : roles) _entries.pushToBack(Entry(AudioStreamDesc(), r));
213 AudioChannelMap(std::initializer_list<ChannelRole> roles) {
214 _entries.reserve(roles.size());
215 for (
const ChannelRole &r : roles) _entries.pushToBack(Entry(AudioStreamDesc(), r));
223 AudioChannelMap(
const AudioStreamDesc &stream, ChannelRoleList roles) {
224 _entries.reserve(roles.size());
225 for (
const ChannelRole &r : roles) _entries.pushToBack(Entry(stream, r));
231 AudioChannelMap(
const AudioStreamDesc &stream, std::initializer_list<ChannelRole> roles) {
232 _entries.reserve(roles.size());
233 for (
const ChannelRole &r : roles) _entries.pushToBack(Entry(stream, r));
244 explicit AudioChannelMap(EntryList entries) : _entries(std::move(entries)) {}
247 AudioChannelMap(std::initializer_list<Entry> entries) : _entries(entries) {}
250 bool isValid()
const {
return !_entries.isEmpty(); }
253 size_t channels()
const {
return _entries.size(); }
256 const EntryList &entries()
const {
return _entries; }
259 ChannelRole role(
size_t index)
const {
260 if (index >= _entries.size())
return ChannelRole::Unused;
261 return _entries[index].second();
265 AudioStreamDesc stream(
size_t index)
const {
266 if (index >= _entries.size())
return AudioStreamDesc();
267 return _entries[index].first();
271 Entry entry(
size_t index)
const {
272 if (index >= _entries.size())
return Entry(AudioStreamDesc(), ChannelRole::Unused);
273 return _entries[index];
282 void setRole(
size_t index,
const ChannelRole &role);
290 void setStream(
size_t index,
const AudioStreamDesc &stream);
293 void setEntry(
size_t index,
const AudioStreamDesc &stream,
const ChannelRole &role);
300 int indexOf(
const ChannelRole &role)
const;
306 int indexOf(
const AudioStreamDesc &stream,
const ChannelRole &role)
const;
309 bool contains(
const ChannelRole &role)
const {
return indexOf(role) >= 0; }
318 bool isSingleStream()
const;
326 AudioStreamDesc commonStream()
const;
337 String wellKnownName()
const;
340 bool isWellKnown()
const {
return !wellKnownName().isEmpty(); }
349 String toString()
const;
352 bool operator==(
const AudioChannelMap &o)
const {
return _entries == o._entries; }
353 bool operator!=(
const AudioChannelMap &o)
const {
return !(*
this == o); }
363 Error writeToStream(DataStream &s)
const;
369 template <u
int32_t V>
static Result<AudioChannelMap> readFromStream(DataStream &s);
375inline Error AudioChannelMap::writeToStream(DataStream &s)
const {
376 s << static_cast<uint32_t>(channels());
377 for (
const auto &entry : entries()) {
378 s << entry.first().name();
379 s << static_cast<int32_t>(entry.second().value());
381 return s.status() == DataStream::Ok ? Error::Ok : s.toError();
385inline Result<AudioChannelMap> AudioChannelMap::readFromStream<1>(DataStream &s) {
388 if (s.status() != DataStream::Ok)
return makeError<AudioChannelMap>(s.toError());
389 AudioChannelMap::EntryList entries;
390 entries.reserve(count);
391 for (uint32_t i = 0; i < count; ++i) {
393 int32_t roleValue = 0;
394 s >> streamName >> roleValue;
395 AudioStreamDesc stream = (streamName.isEmpty() || streamName ==
"Undefined")
397 : AudioStreamDesc(streamName);
398 entries.pushToBack(AudioChannelMap::Entry(stream, ChannelRole(roleValue)));
400 if (s.status() != DataStream::Ok)
return makeError<AudioChannelMap>(s.toError());
401 return makeResult(AudioChannelMap(std::move(entries)));
406PROMEKI_FORMAT_VIA_TOSTRING(promeki::AudioChannelMap);
416template <>
struct std::hash<promeki::AudioChannelMap> {
417 size_t operator()(
const promeki::AudioChannelMap &v)
const noexcept {
419 for (
const auto &entry : v.entries()) {
420 size_t s = std::hash<promeki::AudioStreamDesc>()(entry.first());
421 size_t r = std::hash<promeki::ChannelRole>()(entry.second());
422 size_t combined = s ^ (r + 0x9e3779b97f4a7c15ULL + (s << 6) + (s >> 2));
423 h = h ^ (combined + 0x9e3779b97f4a7c15ULL + (h << 6) + (h >> 2));