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",
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.
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.
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(
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,
134
135 //! Remove object to the list of owned objects.
136 //! Also invokes SetOwner() on the removed object.
138
139 //! @}
140
141 //! @name Notification
142 //! @{
143
144 //! Notify HAL that a property was changed.
145 //! This is automatically called by all setters.
152
153 //! Notify HAL that some properties were changed.
154 //! This is automatically called by all setters.
155 void NotifyPropertiesChanged(std::vector<AudioObjectPropertySelector> selectors,
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>
174
175 //! Pointer to custom property setter method.
176 //! Used in RegisterCustomProperty().
177 template <typename ObjectType, typename 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>
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
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>
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
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.
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.
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.
282
283 //! Check whether given property can be changed.
284 //! @note
285 //! Invoked by HAL on non-realtime thread.
289 Boolean* outIsSettable) const;
290
291 //! Get size of property value in bytes.
292 //! @note
293 //! Invoked by HAL on non-realtime thread.
298 const void* qualifierData,
299 UInt32* outDataSize) const;
300
301 //! Get property value.
302 //! @note
303 //! Invoked by HAL on non-realtime thread.
308 const void* qualifierData,
311 void* outData) const;
312
313 //! Change property value.
314 //! @note
315 //! Invoked by HAL on non-realtime thread.
320 const void* qualifierData,
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,
335
336 OSStatus IsPropertySettableFallback(AudioObjectID objectID,
339 Boolean* outIsSettable) const;
340
341 OSStatus GetPropertyDataSizeFallback(AudioObjectID objectID,
345 const void* qualifierData,
346 UInt32* outDataSize) const;
347
348 OSStatus GetPropertyDataFallback(AudioObjectID objectID,
352 const void* qualifierData,
355 void* outData) const;
356
357 OSStatus SetPropertyDataFallback(AudioObjectID objectID,
361 const void* qualifierData,
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
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.