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
27#include <optional>
28#include <vector>
29
30QT_BEGIN_NAMESPACE
31
32namespace QtPipeWire {
33
35
36////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
37
38template <typename T>
39bool spaChoiceHoldsElementsOfSize(const struct spa_pod *value)
40{
41 return SPA_POD_CHOICE_VALUE_SIZE(value) == sizeof(T);
42}
43
44template <typename T>
46{
47 static std::optional<SpaRange> parse(const struct spa_pod *value)
48 {
49 if (SPA_POD_CHOICE_N_VALUES(value) != 3)
50 return std::nullopt;
51
52 if (!spaChoiceHoldsElementsOfSize<T>(value))
53 return std::nullopt;
54
55 T *v = reinterpret_cast<T *>(SPA_POD_CHOICE_VALUES(value));
56
57 return SpaRange{
58 .defaultValue = v[0],
59 .minValue = v[1],
60 .maxValue = v[2],
61 };
62 }
63
67};
68
69template <typename T>
70struct SpaEnum
71{
72 static std::optional<SpaEnum> parse(const struct spa_pod *value)
73 {
74 int numberOfChoices = SPA_POD_CHOICE_N_VALUES(value);
75
76 if (SPA_POD_CHOICE_N_VALUES(value) < 1)
77 return std::nullopt;
78
79 if (!spaChoiceHoldsElementsOfSize<T>(value))
80 return std::nullopt;
81
82 QSpan<const T> values{
83 reinterpret_cast<const T *>(SPA_POD_CHOICE_VALUES(value)),
84 numberOfChoices,
85 };
86
87 return SpaEnum{ values };
88 }
89
90 const T &defaultValue() const
91 {
92 Q_ASSERT(!m_values.empty());
93 return m_values.front();
94 }
95
96 QSpan<const T> values() const
97 {
98 Q_ASSERT(m_values.size() > 1);
99 return drop(QSpan{ m_values }, 1);
100 }
101
102private:
103 explicit SpaEnum(QSpan<const T> args)
104 : m_values{
105 args.begin(),
106 args.end(),
107 }
108 {
109 }
110
112};
113
114////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
115
116template <typename T>
117std::optional<T> spaParsePodPropertyScalar(const spa_pod &pod, unsigned spaObjectType,
118 unsigned objectProperty)
119{
120 T value{};
121 int status = [&] {
122 if constexpr (std::is_enum_v<T>) {
123 return spa_pod_parse_object(&pod, spaObjectType, nullptr, objectProperty,
124 SPA_POD_Id(&value));
125 } else if constexpr (std::is_same_v<T, int>) {
126 return spa_pod_parse_object(&pod, spaObjectType, nullptr, objectProperty,
127 SPA_POD_Int(&value));
128 } else {
129#if !(Q_CC_GNU_ONLY && Q_CC_GNU < 1300) // P2593R1
130 static_assert(false);
131#endif
132 Q_UNREACHABLE_RETURN(-1);
133 }
134 }();
135
136 if (status < 0)
137 return std::nullopt;
138 return value;
139}
140
141template <typename Visitor>
142auto spaVisitChoice(const spa_pod &pod, unsigned spaObjectType, unsigned objectProperty, Visitor v)
143 -> decltype(v(std::declval<const spa_pod &>()))
144{
145 const spa_pod *format_pod = nullptr;
146 int res = spa_pod_parse_object(&pod, spaObjectType, nullptr, objectProperty,
147 SPA_POD_PodChoice(&format_pod));
148 if (res < 0)
149 return std::nullopt;
150
151 if (!format_pod)
152 return std::nullopt;
153
154 return v(*format_pod);
155}
156
157template <typename T, spa_choice_type... Choices>
158auto spaParsePodPropertyChoice(const spa_pod &pod, unsigned spaObjectType, unsigned objectProperty)
159{
160 constexpr bool has_choices = sizeof...(Choices) != 0;
161 constexpr bool has_single_choice = sizeof...(Choices) == 1;
162 constexpr bool has_enum = ((Choices == SPA_CHOICE_Enum) || ...);
163 constexpr bool has_range = ((Choices == SPA_CHOICE_Range) || ...);
164
165 // clang-format off
166 using ReturnType = std::conditional_t<has_choices,
167 std::conditional_t<has_single_choice,
168 std::conditional_t<has_enum,
169 SpaEnum<T>,
170 SpaRange<T>
171 >,
172 std::variant<SpaEnum<T>, SpaRange<T>>
173 >,
174 std::variant<SpaEnum<T>, SpaRange<T>>>;
175 // clang-format on
176
177 return spaVisitChoice(pod, spaObjectType, objectProperty,
178 [](const spa_pod &format_pod) -> std::optional<ReturnType> {
179 spa_choice_type choice_type = spa_choice_type(SPA_POD_CHOICE_TYPE(&format_pod));
180 if constexpr (has_enum || !has_choices) {
181 if (choice_type == SPA_CHOICE_Enum)
182 return SpaEnum<T>::parse(&format_pod);
183 }
184
185 if constexpr (has_range || !has_choices) {
186 if (choice_type == SPA_CHOICE_Range)
187 return SpaRange<T>::parse(&format_pod);
188 }
189
190 // LATER: Step/Flags
191 return std::nullopt;
192 });
193}
194
195////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
196
197} // namespace QtPipeWire
198
199QT_END_NAMESPACE
200
201#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)
static std::optional< SpaRange > parse(const struct spa_pod *value)