2 * Copyright (C) 2010-2021 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
9 #include "PipewireNode.h"
11 #include "PipewireContext.h"
12 #include "PipewireCore.h"
13 #include "PipewireRegistry.h"
14 #include "PipewireThreadLoop.h"
15 #include "utils/StringUtils.h"
16 #include "utils/log.h"
18 #include <spa/param/format.h>
19 #include <spa/pod/iter.h>
22 using namespace PIPEWIRE
;
24 CPipewireNode::CPipewireNode(CPipewireRegistry
& registry
, uint32_t id
, const char* type
)
25 : CPipewireProxy(registry
, id
, type
, PW_VERSION_NODE
), m_nodeEvents(CreateNodeEvents())
27 pw_proxy_add_object_listener(m_proxy
.get(), &m_objectListener
, &m_nodeEvents
, this);
30 CPipewireNode::~CPipewireNode()
32 spa_hook_remove(&m_objectListener
);
35 void CPipewireNode::EnumerateFormats()
40 for (uint32_t param
= 0; param
< m_info
->n_params
; param
++)
42 if (m_info
->params
[param
].id
== SPA_PARAM_EnumFormat
)
43 pw_node_enum_params(m_proxy
.get(), 0, m_info
->params
[param
].id
, 0, 0, NULL
);
47 void CPipewireNode::Info(void* userdata
, const struct pw_node_info
* info
)
49 auto& node
= *reinterpret_cast<CPipewireNode
*>(userdata
);
53 CLog::Log(LOGDEBUG
, "CPipewireNode::{} - node {} changed", __FUNCTION__
, info
->id
);
54 pw_node_info
* m_info
= node
.m_info
.get();
55 m_info
= pw_node_info_update(m_info
, info
);
59 node
.m_info
.reset(pw_node_info_update(node
.m_info
.get(), info
));
64 static T
Parse(uint32_t type
, void* body
, uint32_t size
)
70 return *reinterpret_cast<T
*>(body
);
73 throw std::runtime_error(StringUtils::Format("unhandled type: {}", type
));
78 static std::set
<T
> ParseArray(uint32_t type
, void* body
, uint32_t size
)
86 values
.emplace(Parse
<T
>(type
, body
, size
));
92 auto array
= reinterpret_cast<spa_pod_array_body
*>(body
);
95 SPA_POD_ARRAY_BODY_FOREACH(array
, size
, p
)
96 values
.emplace(Parse
<T
>(array
->child
.type
, p
, array
->child
.size
));
100 case SPA_TYPE_Choice
:
102 auto choice
= reinterpret_cast<spa_pod_choice_body
*>(body
);
105 SPA_POD_CHOICE_BODY_FOREACH(choice
, size
, p
)
106 values
.emplace(Parse
<T
>(choice
->child
.type
, p
, choice
->child
.size
));
111 throw std::runtime_error(StringUtils::Format("unhandled array: {}", type
));
115 void CPipewireNode::Parse(uint32_t type
, void* body
, uint32_t size
)
119 case SPA_TYPE_Object
:
121 auto object
= reinterpret_cast<spa_pod_object_body
*>(body
);
123 switch (object
->type
)
125 case SPA_TYPE_OBJECT_Format
:
128 SPA_POD_OBJECT_BODY_FOREACH(object
, size
, prop
)
130 spa_format format
= static_cast<spa_format
>(prop
->key
);
134 case SPA_FORMAT_AUDIO_format
:
136 m_formats
= ParseArray
<spa_audio_format
>(
137 prop
->value
.type
, SPA_POD_CONTENTS(spa_pod_prop
, prop
), prop
->value
.size
);
140 case SPA_FORMAT_AUDIO_rate
:
142 m_rates
= ParseArray
<uint32_t>(
143 prop
->value
.type
, SPA_POD_CONTENTS(spa_pod_prop
, prop
), prop
->value
.size
);
146 case SPA_FORMAT_AUDIO_position
:
148 m_channels
= ParseArray
<spa_audio_channel
>(
149 prop
->value
.type
, SPA_POD_CONTENTS(spa_pod_prop
, prop
), prop
->value
.size
);
152 case SPA_FORMAT_AUDIO_iec958Codec
:
154 m_iec958Codecs
= ParseArray
<spa_audio_iec958_codec
>(
155 prop
->value
.type
, SPA_POD_CONTENTS(spa_pod_prop
, prop
), prop
->value
.size
);
176 void CPipewireNode::Param(void* userdata
,
181 const struct spa_pod
* param
)
183 auto& node
= *reinterpret_cast<CPipewireNode
*>(userdata
);
184 auto& loop
= node
.GetRegistry().GetCore().GetContext().GetThreadLoop();
186 node
.Parse(SPA_POD_TYPE(param
), SPA_POD_BODY(param
), SPA_POD_BODY_SIZE(param
));
191 pw_node_events
CPipewireNode::CreateNodeEvents()
193 pw_node_events nodeEvents
= {};
194 nodeEvents
.version
= PW_VERSION_NODE_EVENTS
;
195 nodeEvents
.info
= Info
;
196 nodeEvents
.param
= Param
;