Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qpipewire_spa_pod_parser_support_p.h
Go to the documentation of this file.
1// Copyright (C) 2025 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#ifndef QPIPEWIRE_SPA_POD_PARSER_SUPPORT_P_H
5#define QPIPEWIRE_SPA_POD_PARSER_SUPPORT_P_H
6
7//
8// W A R N I N G
9// -------------
10//
11// This file is not part of the Qt API. It exists purely as an
12// implementation detail. This header file may change from version to
13// version without notice, or even be removed.
14//
15// We mean it.
16//
17
18#include <QtMultimedia/private/qaudio_qspan_support_p.h>
19#include <QtMultimedia/private/qpipewire_support_p.h>
20#include <QtCore/qdebug.h>
21#include <QtCore/qspan.h>
22#include <QtCore/qtconfigmacros.h>
23
24#include <spa/pod/pod.h>
25#include <spa/pod/parser.h>
26#include <spa/utils/defs.h>
27
28#include <optional>
29#include <vector>
30
31QT_BEGIN_NAMESPACE
32
33namespace QtPipeWire {
34
36
37////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
38
39template <typename T>
40bool spaChoiceHoldsElementsOfSize(const struct spa_pod *value)
41{
42 return SPA_POD_CHOICE_VALUE_SIZE(value) == sizeof(T);
43}
44
45template <typename T>
47{
48 static std::optional<SpaRange> parse(const struct spa_pod *value)
49 {
50 if (SPA_POD_CHOICE_N_VALUES(value) != 3)
51 return std::nullopt;
52
53 if (!spaChoiceHoldsElementsOfSize<T>(value))
54 return std::nullopt;
55
56 T *v = reinterpret_cast<T *>(SPA_POD_CHOICE_VALUES(value));
57
58 return SpaRange{
59 .defaultValue = v[0],
60 .minValue = v[1],
61 .maxValue = v[2],
62 };
63 }
64
68};
69
70template <typename T>
71struct SpaEnum
72{
73 static std::optional<SpaEnum> parse(const struct spa_pod *value)
74 {
75 int numberOfChoices = SPA_POD_CHOICE_N_VALUES(value);
76
77 if (SPA_POD_CHOICE_N_VALUES(value) < 1)
78 return std::nullopt;
79
80 if (!spaChoiceHoldsElementsOfSize<T>(value))
81 return std::nullopt;
82
83 QSpan<const T> values{
84 reinterpret_cast<const T *>(SPA_POD_CHOICE_VALUES(value)),
85 numberOfChoices,
86 };
87
88 return SpaEnum{ values };
89 }
90
91 const T &defaultValue() const
92 {
93 Q_ASSERT(!m_values.empty());
94 return m_values.front();
95 }
96
97 QSpan<const T> alternativeValues() const
98 {
99 Q_ASSERT(m_values.size() > 1);
100 return drop(QSpan{ m_values }, 1);
101 }
102
103 QSpan<const T> allValues() const { return m_values; }
104
105 size_t size() const { return m_values.size(); }
106
107private:
108 explicit SpaEnum(QSpan<const T> args)
109 : m_values{
110 args.begin(),
111 args.end(),
112 }
113 {
114 }
115
117};
118
119////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
120
121template <typename T>
122std::optional<T> spaParsePodPropertyScalar(const spa_pod &pod, unsigned spaObjectType,
123 unsigned objectProperty)
124{
125 T value{};
126 int status = [&] {
127 if constexpr (std::is_enum_v<T>) {
128 return spa_pod_parse_object(&pod, spaObjectType, nullptr, objectProperty,
129 SPA_POD_Id(&value));
130 } else if constexpr (std::is_same_v<T, int>) {
131 return spa_pod_parse_object(&pod, spaObjectType, nullptr, objectProperty,
132 SPA_POD_Int(&value));
133 } else if constexpr (std::is_same_v<T, spa_rectangle>) {
134 return spa_pod_parse_object(&pod, spaObjectType, nullptr, objectProperty,
135 SPA_POD_Rectangle(&value));
136 } else if constexpr (std::is_same_v<T, spa_fraction>) {
137 return spa_pod_parse_object(&pod, spaObjectType, nullptr, objectProperty,
138 SPA_POD_Fraction(&value));
139 } else {
140#if !(Q_CC_GNU_ONLY && Q_CC_GNU < 1300) // P2593R1
141 static_assert(false);
142#endif
143 Q_UNREACHABLE_RETURN(-1);
144 }
145 }();
146
147 if (status < 0)
148 return std::nullopt;
149 return value;
150}
151
152template <typename Visitor>
153auto spaVisitChoice(const spa_pod &pod, unsigned spaObjectType, unsigned objectProperty, Visitor v)
154 -> decltype(v(std::declval<const spa_pod &>()))
155{
156 const spa_pod *format_pod = nullptr;
157 int res = spa_pod_parse_object(&pod, spaObjectType, nullptr, objectProperty,
158 SPA_POD_PodChoice(&format_pod));
159 if (res < 0)
160 return std::nullopt;
161
162 if (!format_pod)
163 return std::nullopt;
164
165 return v(*format_pod);
166}
167
168template <typename T, spa_choice_type... Choices>
169auto spaParsePodPropertyChoice(const spa_pod &pod, unsigned spaObjectType, unsigned objectProperty)
170{
171 constexpr bool has_choices = sizeof...(Choices) != 0;
172 constexpr bool has_single_choice = sizeof...(Choices) == 1;
173 constexpr bool has_enum = ((Choices == SPA_CHOICE_Enum) || ...);
174 constexpr bool has_range = ((Choices == SPA_CHOICE_Range) || ...);
175
176 // clang-format off
177 using ReturnType = std::conditional_t<has_choices,
178 std::conditional_t<has_single_choice,
179 std::conditional_t<has_enum,
180 SpaEnum<T>,
181 SpaRange<T>
182 >,
183 std::variant<SpaEnum<T>, SpaRange<T>>
184 >,
185 std::variant<SpaEnum<T>, SpaRange<T>>>;
186 // clang-format on
187
188 return spaVisitChoice(pod, spaObjectType, objectProperty,
189 [](const spa_pod &format_pod) -> std::optional<ReturnType> {
190 spa_choice_type choice_type = spa_choice_type(SPA_POD_CHOICE_TYPE(&format_pod));
191 if constexpr (has_enum || !has_choices) {
192 if (choice_type == SPA_CHOICE_Enum)
193 return SpaEnum<T>::parse(&format_pod);
194 }
195
196 if constexpr (has_range || !has_choices) {
197 if (choice_type == SPA_CHOICE_Range)
198 return SpaRange<T>::parse(&format_pod);
199 }
200
201 // LATER: Step/Flags
202 return std::nullopt;
203 });
204}
205
206////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
207
208} // namespace QtPipeWire
209
210QT_END_NAMESPACE
211
212#endif // QPIPEWIRE_SPA_POD_PARSER_SUPPORT_P_H
auto spaParsePodPropertyChoice(const spa_pod &pod, unsigned spaObjectType, unsigned objectProperty)
bool spaChoiceHoldsElementsOfSize(const struct spa_pod *value)
std::optional< T > spaParsePodPropertyScalar(const spa_pod &pod, unsigned spaObjectType, unsigned objectProperty)
auto spaVisitChoice(const spa_pod &pod, unsigned spaObjectType, unsigned objectProperty, Visitor v) -> decltype(v(std::declval< const spa_pod & >()))
static std::optional< SpaEnum > parse(const struct spa_pod *value)
QSpan< const T > alternativeValues() const
static std::optional< SpaRange > parse(const struct spa_pod *value)