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