libASPL
Loading...
Searching...
No Matches
Object.hpp
Go to the documentation of this file.
1// Copyright (c) libASPL authors
2// Licensed under MIT
3
4//! @file aspl/Object.hpp
5//! @brief Basic audio object.
6
7#pragma once
8
9#include <aspl/Compat.hpp>
10#include <aspl/Context.hpp>
11#include <aspl/DoubleBuffer.hpp>
12
13#include <CoreAudio/AudioServerPlugIn.h>
14
15#include <functional>
16#include <map>
17#include <memory>
18#include <mutex>
19#include <type_traits>
20#include <vector>
21
22namespace aspl {
23
24//! Base class for audio objects.
25//!
26//! CoreAudio uses property-based object model to communicate with plugins.
27//! This class is the base class for various audio objects which implement
28//! property dispatch protocol required by HAL.
29//!
30//! This class provides the following services:
31//!
32//! - **Common context.** Each object belongs to Context, a common environment
33//! shared between objects of the same plugin / driver.
34//!
35//! - **Identification.** Each object has a unique numeric identifier.
36//! ID is unique only within the same Context.
37//!
38//! - **Classification.** Each object belongs to one of the predefined classes.
39//! The class defines a set of the properties and probably other
40//! operations which should be supported by object.
41//!
42//! - **Ownership.** All objects of the plugin forms a tree hierarchy,
43//! with the Plugin object in the root.
44//!
45//! - **Property dispatch protocol.** Every object implements a set
46//! of methods allowing to introspect, get, and set its properties.
47//!
48//! - **Notification**. Object automatically notifies HAL when
49//! some of its properties is changed.
50//!
51//! - **Registration of custom properties.** Object allows to register
52//! custom user-defined properties in addition to builtin properties
53//! defined by CoreAudio.
54class Object : public std::enable_shared_from_this<Object>
55{
56public:
57 //! Construct object.
58 //! Class name is used for logging. It should be the name of the derived class.
59 //! If objectID is @c kAudioObjectUnknown (zero), allocates new object ID.
60 //! Otherwise uses given object ID.
61 explicit Object(std::shared_ptr<const Context> context,
62 const char* className = "Object",
63 AudioObjectID objectID = kAudioObjectUnknown);
64
65 Object(const Object&) = delete;
66 Object& operator=(const Object&) = delete;
67
68 virtual ~Object();
69
70 //! Get object context.
71 std::shared_ptr<const Context> GetContext() const;
72
73 //! @name Class and ID
74 //! @{
75
76 //! Get class ID.
77 //! Each subclass overrides this method.
78 //! @note
79 //! Backs @c kAudioObjectPropertyClass property.
80 virtual AudioClassID GetClass() const;
81
82 //! Get base class ID.
83 //! Each subclass overrides this method.
84 //! @note
85 //! Backs @c kAudioObjectPropertyBaseClass property.
86 virtual AudioClassID GetBaseClass() const;
87
88 //! Check if this object is instance of given base class.
89 //! Returns true if any of the base classes matches given class ID.
90 //! Each subclass overrides this method.
91 virtual bool IsInstance(AudioClassID classID) const;
92
93 //! Get object ID.
94 //! Returns objectID selected at construction time.
95 AudioObjectID GetID() const;
96
97 //! @}
98
99 //! @name Ownership
100 //! @{
101
102 //! Get object owner.
103 //! If the object has an owner, returns its ID.
104 //! Otherwise, returns @c kAudioObjectUnknown (zero).
105 //! @note
106 //! Backs @c kAudioObjectPropertyOwner property.
107 AudioObjectID GetOwnerID() const;
108
109 //! Check if the object is part of the hierarchy.
110 //! Returns true if GetOwnerID() is not equal to kAudioObjectUnknown.
111 //! @remarks
112 //! By default, object does not have an owner. Until the object is
113 //! attached to an owner, it is not part of the plugin object
114 //! hierarchy and is not visible to HAL.
115 bool HasOwner() const;
116
117 //! Get owned objects.
118 //! Returns the list of objects to which this object is the owner.
119 //! @remarks
120 //! Filters the returned list by scope and class.
121 //! Global scope or zero class will match any object.
122 //! Class, if non-zero, is matched using IsInstance() method, so
123 //! parent classes will match derived classes too.
124 //! @note
125 //! Backs @c kAudioObjectPropertyOwnedObjects property.
126 std::vector<AudioObjectID> GetOwnedObjectIDs(
127 AudioObjectPropertyScope scope = kAudioObjectPropertyScopeGlobal,
128 AudioClassID classID = 0) const;
129
130 //! Add object to the list of owned objects.
131 //! Also invokes SetOwner() on the added object.
132 void AddOwnedObject(std::shared_ptr<Object> object,
133 AudioObjectPropertyScope scope = kAudioObjectPropertyScopeGlobal);
134
135 //! Remove object to the list of owned objects.
136 //! Also invokes SetOwner() on the removed object.
137 void RemoveOwnedObject(AudioObjectID objectID);
138
139 //! @}
140
141 //! @name Notification
142 //! @{
143
144 //! Notify HAL that a property was changed.
145 //! This is automatically called by all setters.
146 void NotifyPropertyChanged(AudioObjectPropertySelector selector,
147 AudioObjectPropertyScope scope = kAudioObjectPropertyScopeGlobal,
148 AudioObjectPropertyElement element = kAudioObjectPropertyElementMain) const
149 {
150 NotifyPropertiesChanged({selector}, scope, element);
151 }
152
153 //! Notify HAL that some properties were changed.
154 //! This is automatically called by all setters.
155 void NotifyPropertiesChanged(std::vector<AudioObjectPropertySelector> selectors,
156 AudioObjectPropertyScope scope = kAudioObjectPropertyScopeGlobal,
157 AudioObjectPropertyElement element = kAudioObjectPropertyElementMain) const;
158
159 //! @}
160
161 //! @name Custom properties
162 //! @{
163
164 //! Get info about registered custom properties.
165 //! Returns list of properties added using RegisterCustomProperty().
166 //! @note
167 //! Backs @c kAudioObjectPropertyCustomPropertyInfoList property.
168 virtual std::vector<AudioServerPlugInCustomPropertyInfo> GetCustomProperties() const;
169
170 //! Pointer to custom property getter method.
171 //! Used in RegisterCustomProperty().
172 template <typename ObjectType, typename ValueType>
173 using GetterMethod = ValueType (ObjectType::*)() const;
174
175 //! Pointer to custom property setter method.
176 //! Used in RegisterCustomProperty().
177 template <typename ObjectType, typename ValueType>
178 using SetterMethod = void (ObjectType::*)(ValueType);
179
180 //! Register custom property with getter and optional setter.
181 //!
182 //! This overload allows to use methods as getter and setter:
183 //! @code
184 //! class MyObject : public aspl::Object
185 //! {
186 //! public:
187 //! CFStringRef GetMyProperty() const { ... }
188 //! void SetMyProperty(CFStringRef value) { ... }
189 //!
190 //! MyObject(...)
191 //! : Object(...)
192 //! {
193 //! RegisterCustomProperty(
194 //! MyPropertySelector, *this, &MyObject::GetMyProperty,
195 //! &MyObject::SetMyProperty);
196 //! }
197 //! };
198 //! @endcode
199 //!
200 //! Value type should be either CFStringRef or CFPropertyListRef because
201 //! they are the only types allowed by CoreAudio.
202 //!
203 //! Getter transfers ownership to the caller; the caller will call CFRelease().
204 //! Setter does not transfer ownership; the setter should call CFRetain() if
205 //! it wants to store the value.
206 template <typename ObjectType, typename ValueType>
207 void RegisterCustomProperty(AudioObjectPropertySelector selector,
208 ObjectType& object,
211 {
212 static_assert(std::is_same<ValueType, CFStringRef>::value ||
213 std::is_same<ValueType, CFPropertyListRef>::value,
214 "ValueType should be CFStringRef or CFPropertyListRef");
215
216 RegisterCustomProperty(selector,
217 std::bind(getter, &object),
218 setter ? std::bind(setter, &object, std::placeholders::_1)
219 : std::function<void(ValueType)>{});
220 }
221
222 //! Register custom property with getter and optional setter.
223 //!
224 //! This overload is for read-only properties (without setter).
225 //!
226 //! GetterFunc should be convertible to std::function<ValueType()>, where
227 //! value type should be either CFStringRef or CFPropertyListRef (because
228 //! they are the only types allowed by CoreAudio).
229 //!
230 //! Getter transfers ownership to the caller; the caller will call CFRelease().
231 template <typename GetterFunc>
232 void RegisterCustomProperty(AudioObjectPropertySelector selector, GetterFunc getter)
233 {
234 using ValueType = decltype(getter());
235
236 static_assert(std::is_same<ValueType, CFStringRef>::value ||
237 std::is_same<ValueType, CFPropertyListRef>::value,
238 "GetterFunc() should return CFStringRef or CFPropertyListRef");
239
240 RegisterCustomProperty(selector,
241 std::function<ValueType()>(getter),
242 std::function<void(ValueType)>{});
243 }
244
245 //! Register custom property with getter and optional setter.
246 //!
247 //! This overload is for properties of type CFStringRef.
248 //!
249 //! Setter may be null function if the property is read-only.
250 //!
251 //! Getter transfers ownership to the caller; the caller will call CFRelease().
252 //! Setter does not transfer ownership; the setter should call CFRetain() if
253 //! it wants to store the value.
254 void RegisterCustomProperty(AudioObjectPropertySelector selector,
255 std::function<CFStringRef()> getter,
256 std::function<void(CFStringRef)> setter);
257
258 //! Register custom property with getter and optional setter.
259 //!
260 //! This overload is for properties of type CFPropertyListRef.
261 //!
262 //! Setter may be null function if the property is read-only.
263 //!
264 //! Getter transfers ownership to the caller; the caller will call CFRelease().
265 //! Setter does not transfer ownership; the setter should call CFRetain() if
266 //! it wants to store the value.
267 void RegisterCustomProperty(AudioObjectPropertySelector selector,
268 std::function<CFPropertyListRef()> getter,
269 std::function<void(CFPropertyListRef)> setter);
270
271 //! @}
272
273 //! @name Property dispatch
274 //! @{
275
276 //! Check whether given property is present.
277 //! @note
278 //! Invoked by HAL on non-realtime thread.
279 virtual Boolean HasProperty(AudioObjectID objectID,
280 pid_t clientPID,
281 const AudioObjectPropertyAddress* address) const;
282
283 //! Check whether given property can be changed.
284 //! @note
285 //! Invoked by HAL on non-realtime thread.
286 virtual OSStatus IsPropertySettable(AudioObjectID objectID,
287 pid_t clientPID,
288 const AudioObjectPropertyAddress* address,
289 Boolean* outIsSettable) const;
290
291 //! Get size of property value in bytes.
292 //! @note
293 //! Invoked by HAL on non-realtime thread.
294 virtual OSStatus GetPropertyDataSize(AudioObjectID objectID,
295 pid_t clientPID,
296 const AudioObjectPropertyAddress* address,
297 UInt32 qualifierDataSize,
298 const void* qualifierData,
299 UInt32* outDataSize) const;
300
301 //! Get property value.
302 //! @note
303 //! Invoked by HAL on non-realtime thread.
304 virtual OSStatus GetPropertyData(AudioObjectID objectID,
305 pid_t clientPID,
306 const AudioObjectPropertyAddress* address,
307 UInt32 qualifierDataSize,
308 const void* qualifierData,
309 UInt32 inDataSize,
310 UInt32* outDataSize,
311 void* outData) const;
312
313 //! Change property value.
314 //! @note
315 //! Invoked by HAL on non-realtime thread.
316 virtual OSStatus SetPropertyData(AudioObjectID objectID,
317 pid_t clientPID,
318 const AudioObjectPropertyAddress* address,
319 UInt32 qualifierDataSize,
320 const void* qualifierData,
321 UInt32 inDataSize,
322 const void* inData);
323
324 //! @}
325
326private:
327 struct CustomProperty;
328
329 void AttachOwner(Object& owner);
330 void DetachOwner();
331
332 Boolean HasPropertyFallback(AudioObjectID objectID,
333 pid_t clientPID,
334 const AudioObjectPropertyAddress* address) const;
335
336 OSStatus IsPropertySettableFallback(AudioObjectID objectID,
337 pid_t clientPID,
338 const AudioObjectPropertyAddress* address,
339 Boolean* outIsSettable) const;
340
341 OSStatus GetPropertyDataSizeFallback(AudioObjectID objectID,
342 pid_t clientPID,
343 const AudioObjectPropertyAddress* address,
344 UInt32 qualifierDataSize,
345 const void* qualifierData,
346 UInt32* outDataSize) const;
347
348 OSStatus GetPropertyDataFallback(AudioObjectID objectID,
349 pid_t clientPID,
350 const AudioObjectPropertyAddress* address,
351 UInt32 qualifierDataSize,
352 const void* qualifierData,
353 UInt32 inDataSize,
354 UInt32* outDataSize,
355 void* outData) const;
356
357 OSStatus SetPropertyDataFallback(AudioObjectID objectID,
358 pid_t clientPID,
359 const AudioObjectPropertyAddress* address,
360 UInt32 qualifierDataSize,
361 const void* qualifierData,
362 UInt32 inDataSize,
363 const void* inData);
364
365 mutable std::mutex writeMutex_;
366
367 const std::shared_ptr<const Context> context_;
368
369 const char* const className_;
370
371 const AudioObjectID objectID_;
372
373 Object* ownerObject_ = nullptr;
374 std::atomic<AudioObjectID> ownerObjectID_ = kAudioObjectUnknown;
375
376 DoubleBuffer<std::map<AudioObjectPropertyScope,
377 std::map<AudioObjectID, std::shared_ptr<Object>>>>
378 ownedObjects_;
379
381 customProps_;
382};
383
384} // namespace aspl
Compatibility definitions.
Context.
Double buffer.
Doubly-buffered value with non-blocking read and blocking write.
Base class for audio objects.
Definition Object.hpp:55
virtual OSStatus GetPropertyDataSize(AudioObjectID objectID, pid_t clientPID, const AudioObjectPropertyAddress *address, UInt32 qualifierDataSize, const void *qualifierData, UInt32 *outDataSize) const
Get size of property value in bytes.
AudioObjectID GetOwnerID() const
Get object owner. If the object has an owner, returns its ID. Otherwise, returns kAudioObjectUnknown ...
ValueType(ObjectType::*)() const GetterMethod
Pointer to custom property getter method. Used in RegisterCustomProperty().
Definition Object.hpp:173
std::vector< AudioObjectID > GetOwnedObjectIDs(AudioObjectPropertyScope scope=kAudioObjectPropertyScopeGlobal, AudioClassID classID=0) const
Get owned objects. Returns the list of objects to which this object is the owner.
virtual Boolean HasProperty(AudioObjectID objectID, pid_t clientPID, const AudioObjectPropertyAddress *address) const
Check whether given property is present.
void NotifyPropertyChanged(AudioObjectPropertySelector selector, AudioObjectPropertyScope scope=kAudioObjectPropertyScopeGlobal, AudioObjectPropertyElement element=kAudioObjectPropertyElementMain) const
Notify HAL that a property was changed. This is automatically called by all setters.
Definition Object.hpp:146
void RegisterCustomProperty(AudioObjectPropertySelector selector, ObjectType &object, GetterMethod< ObjectType, ValueType > getter, SetterMethod< ObjectType, ValueType > setter=nullptr)
Register custom property with getter and optional setter.
Definition Object.hpp:207
bool HasOwner() const
Check if the object is part of the hierarchy. Returns true if GetOwnerID() is not equal to kAudioObje...
virtual bool IsInstance(AudioClassID classID) const
Check if this object is instance of given base class. Returns true if any of the base classes matches...
virtual AudioClassID GetClass() const
Get class ID. Each subclass overrides this method.
virtual AudioClassID GetBaseClass() const
Get base class ID. Each subclass overrides this method.
AudioObjectID GetID() const
Get object ID. Returns objectID selected at construction time.
void NotifyPropertiesChanged(std::vector< AudioObjectPropertySelector > selectors, AudioObjectPropertyScope scope=kAudioObjectPropertyScopeGlobal, AudioObjectPropertyElement element=kAudioObjectPropertyElementMain) const
Notify HAL that some properties were changed. This is automatically called by all setters.
virtual std::vector< AudioServerPlugInCustomPropertyInfo > GetCustomProperties() const
Get info about registered custom properties. Returns list of properties added using RegisterCustomPro...
void RegisterCustomProperty(AudioObjectPropertySelector selector, GetterFunc getter)
Register custom property with getter and optional setter.
Definition Object.hpp:232
void RegisterCustomProperty(AudioObjectPropertySelector selector, std::function< CFStringRef()> getter, std::function< void(CFStringRef)> setter)
Register custom property with getter and optional setter.
std::shared_ptr< const Context > GetContext() const
Get object context.
void(ObjectType::*)(ValueType) SetterMethod
Pointer to custom property setter method. Used in RegisterCustomProperty().
Definition Object.hpp:178
void AddOwnedObject(std::shared_ptr< Object > object, AudioObjectPropertyScope scope=kAudioObjectPropertyScopeGlobal)
Add object to the list of owned objects. Also invokes SetOwner() on the added object.
virtual OSStatus IsPropertySettable(AudioObjectID objectID, pid_t clientPID, const AudioObjectPropertyAddress *address, Boolean *outIsSettable) const
Check whether given property can be changed.
Object(std::shared_ptr< const Context > context, const char *className="Object", AudioObjectID objectID=kAudioObjectUnknown)
Construct object. Class name is used for logging. It should be the name of the derived class....
virtual OSStatus GetPropertyData(AudioObjectID objectID, pid_t clientPID, const AudioObjectPropertyAddress *address, UInt32 qualifierDataSize, const void *qualifierData, UInt32 inDataSize, UInt32 *outDataSize, void *outData) const
Get property value.
void RegisterCustomProperty(AudioObjectPropertySelector selector, std::function< CFPropertyListRef()> getter, std::function< void(CFPropertyListRef)> setter)
Register custom property with getter and optional setter.
virtual OSStatus SetPropertyData(AudioObjectID objectID, pid_t clientPID, const AudioObjectPropertyAddress *address, UInt32 qualifierDataSize, const void *qualifierData, UInt32 inDataSize, const void *inData)
Change property value.
void RemoveOwnedObject(AudioObjectID objectID)
Remove object to the list of owned objects. Also invokes SetOwner() on the removed object.