libASPL
Loading...
Searching...
No Matches
Driver.hpp
Go to the documentation of this file.
1// Copyright (c) libASPL authors
2// Licensed under MIT
3
4//! @file aspl/Driver.hpp
5//! @brief Plugin driver.
6
7#pragma once
8
9#include <aspl/Context.hpp>
10#include <aspl/DoubleBuffer.hpp>
12#include <aspl/Plugin.hpp>
13#include <aspl/Storage.hpp>
14
15#include <CoreAudio/AudioServerPlugIn.h>
16
17#include <atomic>
18#include <memory>
19#include <variant>
20
21namespace aspl {
22
23//! Plugin driver.
24//!
25//! Driver is the top-level object of AudioServer plugin. It contains Plugin
26//! object, which is the root of the whole object hierarchy. The driver's job
27//! is to receive requests from HAL and redirect them to appropriate objects.
28//!
29//! Driver is exposed to HAL as "driver reference" (@c AudioServerPlugInDriverRef).
30//! The driver reference is actually a pointer to pointer to "plugin driver interface"
31//! (@c AudioServerPlugInDriverInterface), which is a struct with a bunch of function
32//! pointers for various operations (mostly for property dispatch and I/O).
33//!
34//! Driver fills this struct with its private functions. Each of them just finds
35//! the registered object by ID and redirects operation to it. Objects are searched
36//! in Context::Dispatcher. Every object requires Context as constructor argument
37//! and automatically registers and unregisters itself in Dispatcher.
38//!
39//! Driver also provides Storage object, which provides API for persistent storage
40//! associated with plugin, and managed by CoreAudio daemon.
41//!
42//! By default driver creates its own Context, Plugin, and Storage objects, but you
43//! can provide your own if desired.
44//!
45//! After constructing driver, you need to use GetReference() method to obtain
46//! the "driver reference" and return it from the plugin entry point, like:
47//!
48//! @code
49//! extern "C" void* MyEntryPoint(CFAllocatorRef, CFUUIDRef typeUUID)
50//! {
51//! if (!CFEqual(typeUUID, kAudioServerPlugInTypeUUID)) {
52//! return nullptr;
53//! }
54//! static auto driver = std::make_shared<aspl::Driver>();
55//! return driver->GetReference();
56//! }
57//! @endcode
58//!
59//! Don't forget do declare your entry point in Info.plist of the plugin.
60//!
61//! Right after the Driver object is created, it is not fully initialized yet. The
62//! final initialization is performed by HAL asynchronously, after returning from
63//! plugin entry point.
64//!
65//! Until asynchronous initialization is done, most driver services are not really
66//! functioning yet: devices don't appear in system, persistent storage returns
67//! errors for all requests, etc.
68//!
69//! The user can be notified when the initialization is done by providing custom
70//! DriverRequestHandler, or by inheriting Driver and overriding appropriate method.
71class Driver
72{
73public:
74 //! Construct driver.
75 //! If context, plugin, or storage is not set, it is created automatically.
76 explicit Driver(std::shared_ptr<Context> context = {},
77 std::shared_ptr<Plugin> plugin = {},
78 std::shared_ptr<Storage> storage = {});
79
80 Driver(const Driver&) = delete;
81 Driver& operator=(const Driver&) = delete;
82
83 virtual ~Driver();
84
85 //! Get context.
86 //! Context contains data shared among all driver objects.
87 std::shared_ptr<const Context> GetContext() const;
88
89 //! Get plugin.
90 //! Plugin is the root of driver's object tree.
91 std::shared_ptr<Plugin> GetPlugin() const;
92
93 //! Get storage.
94 //! Storage provides API for persistent key-value database.
95 std::shared_ptr<Storage> GetStorage() const;
96
97 //! Get plugin interface.
98 //! Plugin interface is a table with function pointers which implement
99 //! various plugin operations.
100 const AudioServerPlugInDriverInterface& GetPluginInterface() const;
101
102 //! Get driver reference.
103 //! This is what should be returned from plugin entry point.
104 AudioServerPlugInDriverRef GetReference();
105
106 //! Cast driver reference back to driver.
107 static Driver* GetDriver(AudioServerPlugInDriverRef driverRef);
108
109 //! Set handler for HAL requests to driver.
110 //! Optional. Use when you need to do custom handling.
111 void SetDriverHandler(std::shared_ptr<DriverRequestHandler> handler);
112
113 //! Set handler for HAL requests to driver (raw pointer overload).
114 //! This overload uses raw pointer instead of shared_ptr, and the user
115 //! is responsible for keeping handler object alive until it's reset
116 //! or Driver is destroyed.
118
119protected:
120 //! Initialize driver.
121 //! Default implementation invokes DriverRequestHandler::OnInitialize().
122 virtual OSStatus Initialize();
123
124 //! Create device.
125 //! Default implementation returns kAudioHardwareUnsupportedOperationError.
126 virtual OSStatus CreateDevice(CFDictionaryRef description,
127 const AudioServerPlugInClientInfo* clientInfo,
128 AudioObjectID* outDeviceObjectID);
129
130 //! Destroy device.
131 //! Default implementation returns kAudioHardwareUnsupportedOperationError.
132 virtual OSStatus DestroyDevice(AudioObjectID objectID);
133
134private:
135 // COM methods
136 static HRESULT QueryInterface(void* driverRef, REFIID iid, LPVOID* outInterface);
137
138 static ULONG AddRef(void* driverRef);
139 static ULONG Release(void* driverRef);
140
141 // Driver methods
142 static OSStatus InitializeJumper(AudioServerPlugInDriverRef driverRef,
143 AudioServerPlugInHostRef hostRef);
144
145 static OSStatus CreateDeviceJumper(AudioServerPlugInDriverRef driverRef,
146 CFDictionaryRef description,
147 const AudioServerPlugInClientInfo* clientInfo,
148 AudioObjectID* outDeviceObjectID);
149
150 static OSStatus DestroyDeviceJumper(AudioServerPlugInDriverRef driverRef,
151 AudioObjectID objectID);
152
153 const std::shared_ptr<Context> context_;
154 const std::shared_ptr<Plugin> plugin_;
155 const std::shared_ptr<Storage> storage_;
156
157 // User-provided handler
159 std::variant<std::shared_ptr<DriverRequestHandler>, DriverRequestHandler*>>
160 driverHandler_;
161
162 // Method table
163 AudioServerPlugInDriverInterface driverInterface_;
164 AudioServerPlugInDriverInterface* driverInterfacePointer_;
165
166 // Reference counter
167 std::atomic<ULONG> refCounter_ = 0;
168};
169
170} // namespace aspl
Context.
Double buffer.
Handler for HAL requests to driver.
Plugin object.
Plugin persistent storage.
Doubly-buffered value with non-blocking read and blocking write.
Plugin driver.
Definition Driver.hpp:72
virtual OSStatus DestroyDevice(AudioObjectID objectID)
Destroy device. Default implementation returns kAudioHardwareUnsupportedOperationError.
virtual OSStatus CreateDevice(CFDictionaryRef description, const AudioServerPlugInClientInfo *clientInfo, AudioObjectID *outDeviceObjectID)
Create device. Default implementation returns kAudioHardwareUnsupportedOperationError.
virtual OSStatus Initialize()
Initialize driver. Default implementation invokes DriverRequestHandler::OnInitialize().
Driver(std::shared_ptr< Context > context={}, std::shared_ptr< Plugin > plugin={}, std::shared_ptr< Storage > storage={})
Construct driver. If context, plugin, or storage is not set, it is created automatically.
void SetDriverHandler(std::shared_ptr< DriverRequestHandler > handler)
Set handler for HAL requests to driver. Optional. Use when you need to do custom handling.
std::shared_ptr< Plugin > GetPlugin() const
Get plugin. Plugin is the root of driver's object tree.
AudioServerPlugInDriverRef GetReference()
Get driver reference. This is what should be returned from plugin entry point.
void SetDriverHandler(DriverRequestHandler *handler)
Set handler for HAL requests to driver (raw pointer overload). This overload uses raw pointer instead...
std::shared_ptr< const Context > GetContext() const
Get context. Context contains data shared among all driver objects.
std::shared_ptr< Storage > GetStorage() const
Get storage. Storage provides API for persistent key-value database.
static Driver * GetDriver(AudioServerPlugInDriverRef driverRef)
Cast driver reference back to driver.
const AudioServerPlugInDriverInterface & GetPluginInterface() const
Get plugin interface. Plugin interface is a table with function pointers which implement various plug...
Handler for HAL requests to driver.