libASPL
Loading...
Searching...
No Matches
Stream.hpp
Go to the documentation of this file.
1// Copyright (c) libASPL authors
2// Licensed under MIT
3
4//! @file aspl/Stream.hpp
5//! @brief Audio stream object.
6
7#pragma once
8
9#include <aspl/Direction.hpp>
10#include <aspl/DoubleBuffer.hpp>
11#include <aspl/MuteControl.hpp>
12#include <aspl/Object.hpp>
14
15#include <CoreAudio/AudioServerPlugIn.h>
16
17#include <atomic>
18#include <memory>
19#include <mutex>
20#include <optional>
21#include <vector>
22
23namespace aspl {
24
25class Device;
26
27//! Audio stream parameters.
29{
30 //! Stream direction.
31 //! Used by default implementation of Stream::GetDirection().
32 Direction Direction = Direction::Output;
33
34 //! Absolute channel number for the first channel in the stream.
35 //! Used by default implementation of Stream::GetStartingChannel().
36 UInt32 StartingChannel = 1;
37
38 //! Stream format.
39 //! Used by default implementation of Stream::GetPhysicalFormat().
40 //! Default format is:
41 //! - 44100 Hz
42 //! - 2 channels (stereo)
43 //! - 16-bit native-endian signed integers (Int16)
44 //! - interleaved (L R L R ...)
45 AudioStreamBasicDescription Format = {
46 .mSampleRate = 44100,
47 .mFormatID = kAudioFormatLinearPCM,
48 .mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagsNativeEndian |
49 kAudioFormatFlagIsPacked,
50 .mBitsPerChannel = 16,
51 .mChannelsPerFrame = 2,
52 .mBytesPerFrame = 4,
53 .mFramesPerPacket = 1,
54 .mBytesPerPacket = 4,
55 };
56
57 //! Additional presentation latency the stream has.
58 //! Used by default implementation of Stream::GetLatency().
59 UInt32 Latency = 0;
60};
61
62//! Audio stream object.
63//!
64//! Stream is part of a Device representing a source (input stream) or a destination
65//! (output stream) for samples. Clients connected to the device can read from its
66//! input streams and write to its output streams.
67//!
68//! Each stream can have its own format, latency, and other parameters.
69//!
70//! Stream does not do I/O by its own. Instead, it provides ApplyProcessing() method,
71//! which is invoked by ReaderWriter (in its default implementation).
72//!
73//! Default implementation of Stream::ApplyProcessing() just invokes corresponding
74//! methods on attached VolumeControl and MuteControl objects, which you can set
75//! using AttachVolumeControl() and AttachMuteControl().
76class Stream : public Object
77{
78public:
79 //! Construct stream.
80 explicit Stream(std::shared_ptr<const Context> context,
81 std::shared_ptr<Device> device,
82 const StreamParameters& params = {});
83
84 //! @name Getters and setters
85 //! @{
86
87 //! Tell whether the stream participates in I/O.
88 //! By default returns the last value set by SetIsActive().
89 //! Initial value is true.
90 //! @note
91 //! Backs @c kAudioStreamPropertyIsActive property.
92 virtual bool GetIsActive() const;
93
94 //! Activate or deactivate stream.
95 //! Invokes SetIsActiveImpl() and NotifyPropertyChanged().
96 //! @note
97 //! Backs @c kAudioStreamPropertyIsActive property.
98 OSStatus SetIsActive(bool isActive);
99
100 //! Get stream direction.
101 //! By default returns corresponding field of StreamParameters.
102 //! @see StreamParameters::Direction.
103 //! @note
104 //! Backs @c kAudioStreamPropertyDirection property.
105 virtual Direction GetDirection() const;
106
107 //! Get terminal type.
108 //! By default returns kAudioStreamTerminalTypeMicrophone if GetDirection()
109 //! returns Direction::Input, and kAudioStreamTerminalTypeSpeaker if
110 //! it return Direction::Output.
111 //! @remarks
112 //! Indicates what is at the other end of the stream such as a speaker
113 //! or headphones, or a microphone. Values for this property are defined
114 //! in <CoreAudio/AudioHardwareBase.h>
115 //! @note
116 //! Backs @c kAudioStreamPropertyTerminalType property.
117 virtual UInt32 GetTerminalType() const;
118
119 //! Absolute channel number for the first channel in the stream.
120 //! For example, if a device has two output streams with two channels each, then
121 //! the starting channel number for the first stream is 1 and thus starting
122 //! channel number for the second stream is 3.
123 //! By default returns StreamParameters::StartingChannel.
124 //! @note
125 //! Backs @c kAudioStreamPropertyStartingChannel property.
126 virtual UInt32 GetStartingChannel() const;
127
128 //! Get number of channels in stream.
129 //! Return value is based on GetPhysicalFormat().
130 UInt32 GetChannelCount() const;
131
132 //! Get stream sample rate.
133 //! Return value is based on GetPhysicalFormat().
134 Float64 GetSampleRate() const;
135
136 //! Get any additional presentation latency the stream has.
137 //! This latency is added to the device latency.
138 //! By default returns value last set with SetLatencyAsync().
139 //! Initial value is StreamParameters::Latency.
140 //! @note
141 //! Backs @c kAudioStreamPropertyLatency property.
142 virtual UInt32 GetLatency() const;
143
144 //! Asynchronously set stream presentation latency,
145 //! Requests HAL to asynchronously invoke SetLatencyImpl().
146 OSStatus SetLatencyAsync(UInt32 latency);
147
148 //! Get the current physical format of the stream.
149 //! Physical format defines the underlying format supported natively by hardware.
150 //! By default returns value set by last SetPhysicalFormatAsync() call.
151 //! Initial value is StreamParameters::Format.
152 //! @note
153 //! Backs @c kAudioStreamPropertyPhysicalFormat property.
154 virtual AudioStreamBasicDescription GetPhysicalFormat() const;
155
156 //! Set current format of the stream.
157 //! Requests HAL to asynchronously invoke SetPhysicalFormatImpl().
158 //! Fails if format is not present in GetAvailablePhysicalFormats(), which by
159 //! default returns only one format, provided during initialization.
160 //! If you want to make your stream supporting multiple formats, you typically
161 //! need to override both of these methods.
162 //! @note
163 //! Backs @c kAudioStreamPropertyPhysicalFormat property.
164 OSStatus SetPhysicalFormatAsync(AudioStreamBasicDescription format);
165
166 //! Get list of supported physical formats.
167 //! Empty list means that any format is allowed.
168 //! By default returns the last value set by SetAvailablePhysicalFormatsAsync().
169 //! If nothing was set, return a single-element list with the format returned by
170 //! GetPhysicalFormat().
171 //! @note
172 //! Backs @c kAudioStreamPropertyAvailablePhysicalFormats property.
173 virtual std::vector<AudioStreamRangedDescription> GetAvailablePhysicalFormats() const;
174
175 //! Asynchronously set list of supported physical formats.
176 //! See comments for GetAvailablePhysicalFormats().
177 //! Requests HAL to asynchronously invoke SetAvailablePhysicalFormatsImpl().
179 std::vector<AudioStreamRangedDescription> formats);
180
181 //! Get the current format of the stream.
182 //! Virtual format defines the format used to present the device to the apps.
183 //! For example, physical format may use integers, while virtual format may
184 //! use floating point numbers.
185 //! For devices that don't override the mix operation, the virtual format has
186 //! to be the same as the physical format.
187 //! By default returns value set by last SetVirtualFormatAsync() call.
188 //! Initial value is StreamParameters::Format.
189 //! @note
190 //! Backs @c kAudioStreamPropertyVirtualFormat property.
191 virtual AudioStreamBasicDescription GetVirtualFormat() const;
192
193 //! Set current virtual format of the stream.
194 //! Requests HAL to asynchronously invoke SetVirtualFormatImpl().
195 //! Fails if format is not present in GetAvailableVirtualFormats(), which by
196 //! default returns only one format, provided during initialization.
197 //! If you want to make your stream supporting multiple formats, you typically
198 //! need to override both of these methods.
199 //! @note
200 //! Backs @c kAudioStreamPropertyVirtualFormat property.
201 OSStatus SetVirtualFormatAsync(AudioStreamBasicDescription format);
202
203 //! Get list of supported virtual formats.
204 //! Empty list means that any format is allowed.
205 //! By default returns the last value set by SetAvailableVirtualFormatsAsync().
206 //! If nothing was set, return a single-element list with the format returned by
207 //! GetVirtualFormat().
208 //! @note
209 //! Backs @c kAudioStreamPropertyAvailableVirtualFormats property.
210 virtual std::vector<AudioStreamRangedDescription> GetAvailableVirtualFormats() const;
211
212 //! Asynchronously set list of supported virtual formats.
213 //! See comments for GetAvailableVirtualFormats().
214 //! Requests HAL to asynchronously invoke SetAvailableVirtualFormatsImpl().
216 std::vector<AudioStreamRangedDescription> formats);
217
218 //! @}
219
220 //! @name Processing
221 //! @{
222
223 //! Convert number of frame to the number of bytes.
224 //! Result depends on the value returned by GetPhysicalFormat().
225 virtual UInt32 ConvertFramesToBytes(UInt32 numFrames) const;
226
227 //! Convert number of bytes to the number of frames.
228 //! Result depends on the value returned by GetPhysicalFormat().
229 virtual UInt32 ConvertBytesToFrames(UInt32 numBytes) const;
230
231 //! Attach volume control to the stream.
232 //! ApplyProcessing() will use control to apply volume settings to the stream.
233 void AttachVolumeControl(std::shared_ptr<VolumeControl> control);
234
235 //! Attach mute control to the stream.
236 //! ApplyProcessing() will use control to apply mute settings to the stream.
237 void AttachMuteControl(std::shared_ptr<MuteControl> control);
238
239 //! Apply processing to the stream's data.
240 //! The provided buffer contains exactly @p frameCount * @p channelCount samples.
241 //! Modifies frames in the provided buffer.
242 //! Default implementation invokes ApplyProcessing() on attached volume and mute
243 //! controls, if they are present.
244 //! @note
245 //! Invoked by ReaderWriter on realtime thread.
246 virtual void ApplyProcessing(Float32* frames,
247 UInt32 frameCount,
248 UInt32 channelCount) const;
249
250 //! @}
251
252 //! @name Configuration
253 //! @{
254
255 //! Request HAL to perform configuration update.
256 //! Similar to Device::RequestConfigurationChange().
257 void RequestConfigurationChange(std::function<void()> func = {});
258
259 //! @}
260
261 //! @name Property dispatch
262 //! @{
263
264 //! Get class ID.
265 AudioClassID GetClass() const override;
266
267 //! Get base class ID.
268 AudioClassID GetBaseClass() const override;
269
270 //! Check if this object is instance of given base class.
271 bool IsInstance(AudioClassID classID) const override;
272
273 //! Check whether given property is present.
274 Boolean HasProperty(AudioObjectID objectID,
275 pid_t clientPID,
276 const AudioObjectPropertyAddress* address) const override;
277
278 //! Check whether given property can be changed.
279 OSStatus IsPropertySettable(AudioObjectID objectID,
280 pid_t clientPID,
281 const AudioObjectPropertyAddress* address,
282 Boolean* outIsSettable) const override;
283
284 //! Get size of property value in bytes.
285 OSStatus GetPropertyDataSize(AudioObjectID objectID,
286 pid_t clientPID,
287 const AudioObjectPropertyAddress* address,
288 UInt32 qualifierDataSize,
289 const void* qualifierData,
290 UInt32* outDataSize) const override;
291
292 //! Get property value.
293 OSStatus GetPropertyData(AudioObjectID objectID,
294 pid_t clientPID,
295 const AudioObjectPropertyAddress* address,
296 UInt32 qualifierDataSize,
297 const void* qualifierData,
298 UInt32 inDataSize,
299 UInt32* outDataSize,
300 void* outData) const override;
301
302 //! Change property value.
303 OSStatus SetPropertyData(AudioObjectID objectID,
304 pid_t clientPID,
305 const AudioObjectPropertyAddress* address,
306 UInt32 qualifierDataSize,
307 const void* qualifierData,
308 UInt32 inDataSize,
309 const void* inData) override;
310
311 //! @}
312
313protected:
314 //! @name Setters implementation
315 //! @{
316
317 //! Activate or deactivate stream.
318 //! Should return zero if the state was successfully changed.
319 //! By default just changes the value returned by GetIsActive().
320 //! Invoked by SetIsActive().
321 //! @note
322 //! Backs @c kAudioStreamPropertyIsActive property.
323 virtual OSStatus SetIsActiveImpl(bool isActive);
324
325 //! Set stream presentation latency.
326 //! Invoked by SetLatencyAsync() to actually change the latency.
327 //! Default implementation just changes the value returned by GetLatency().
328 virtual OSStatus SetLatencyImpl(UInt32 latency);
329
330 //! Set current format of the stream.
331 //! Invoked by SetPhysicalFormatAsync() to actually change the format.
332 //! Default behavior is to change the format returned by GetPhysicalFormat() and
333 //! to invoke Device::SetSampleRateAsync() to ensure that device and all its
334 //! streams have the same rate.
335 //! @note
336 //! Backs @c kAudioStreamPropertyPhysicalFormat property.
337 virtual OSStatus SetPhysicalFormatImpl(const AudioStreamBasicDescription& format);
338
339 //! Set list of supported physical formats.
340 //! Invoked by SetAvailablePhysicalFormatsAsync().
341 //! Default implementation just changes the list returned by
342 //! GetAvailablePhysicalFormats().
344 std::vector<AudioStreamRangedDescription> formats);
345
346 //! Set current virtual format of the stream.
347 //! Invoked by SetVirtualFormatAsync() to actually change the format.
348 //! Default behavior is to change the format returned by GetVirtualFormat() and
349 //! to invoke Device::SetSampleRateAsync() to ensure that device and all its
350 //! streams have the same rate.
351 //! @note
352 //! Backs @c kAudioStreamPropertyVirtualFormat property.
353 virtual OSStatus SetVirtualFormatImpl(const AudioStreamBasicDescription& format);
354
355 //! Set list of supported virtual formats.
356 //! Invoked by SetAvailableVirtualFormatsAsync().
357 //! Default implementation just changes the list returned by
358 //! GetAvailableVirtualFormats().
360 std::vector<AudioStreamRangedDescription> formats);
361
362 //! @}
363
364private:
365 // value checkers for async setters
366 OSStatus CheckPhysicalFormat(const AudioStreamBasicDescription&) const;
367 OSStatus CheckVirtualFormat(const AudioStreamBasicDescription&) const;
368
369 // fields
370 const StreamParameters params_;
371
372 const std::weak_ptr<Device> device_;
373
374 std::recursive_mutex writeMutex_;
375
376 std::atomic<bool> isActive_ = true;
377 std::atomic<UInt32> latency_;
378
381
383 availPhysicalFormats_;
384
386 availVirtualFormats_;
387
390};
391
392} // namespace aspl
I/O direction.
Direction
I/O direction.
Definition Direction.hpp:15
Double buffer.
Mute control object.
Basic audio object.
Volume control object.
Doubly-buffered value with non-blocking read and blocking write.
Base class for audio objects.
Definition Object.hpp:55
Audio stream object.
Definition Stream.hpp:77
OSStatus SetLatencyAsync(UInt32 latency)
Asynchronously set stream presentation latency, Requests HAL to asynchronously invoke SetLatencyImpl(...
virtual std::vector< AudioStreamRangedDescription > GetAvailableVirtualFormats() const
Get list of supported virtual formats. Empty list means that any format is allowed....
OSStatus IsPropertySettable(AudioObjectID objectID, pid_t clientPID, const AudioObjectPropertyAddress *address, Boolean *outIsSettable) const override
Check whether given property can be changed.
virtual UInt32 ConvertBytesToFrames(UInt32 numBytes) const
Convert number of bytes to the number of frames. Result depends on the value returned by GetPhysicalF...
virtual std::vector< AudioStreamRangedDescription > GetAvailablePhysicalFormats() const
Get list of supported physical formats. Empty list means that any format is allowed....
void AttachVolumeControl(std::shared_ptr< VolumeControl > control)
Attach volume control to the stream. ApplyProcessing() will use control to apply volume settings to t...
UInt32 GetChannelCount() const
Get number of channels in stream. Return value is based on GetPhysicalFormat().
virtual OSStatus SetPhysicalFormatImpl(const AudioStreamBasicDescription &format)
Set current format of the stream. Invoked by SetPhysicalFormatAsync() to actually change the format....
virtual OSStatus SetIsActiveImpl(bool isActive)
Activate or deactivate stream. Should return zero if the state was successfully changed....
virtual UInt32 GetStartingChannel() const
Absolute channel number for the first channel in the stream. For example, if a device has two output ...
virtual void ApplyProcessing(Float32 *frames, UInt32 frameCount, UInt32 channelCount) const
Apply processing to the stream's data. The provided buffer contains exactly frameCount * channelCount...
virtual Direction GetDirection() const
Get stream direction. By default returns corresponding field of StreamParameters.
virtual AudioStreamBasicDescription GetPhysicalFormat() const
Get the current physical format of the stream. Physical format defines the underlying format supporte...
virtual OSStatus SetLatencyImpl(UInt32 latency)
Set stream presentation latency. Invoked by SetLatencyAsync() to actually change the latency....
OSStatus SetPropertyData(AudioObjectID objectID, pid_t clientPID, const AudioObjectPropertyAddress *address, UInt32 qualifierDataSize, const void *qualifierData, UInt32 inDataSize, const void *inData) override
Change property value.
Stream(std::shared_ptr< const Context > context, std::shared_ptr< Device > device, const StreamParameters &params={})
Construct stream.
virtual bool GetIsActive() const
Tell whether the stream participates in I/O. By default returns the last value set by SetIsActive()....
OSStatus SetAvailablePhysicalFormatsAsync(std::vector< AudioStreamRangedDescription > formats)
Asynchronously set list of supported physical formats. See comments for GetAvailablePhysicalFormats()...
Boolean HasProperty(AudioObjectID objectID, pid_t clientPID, const AudioObjectPropertyAddress *address) const override
Check whether given property is present.
OSStatus SetIsActive(bool isActive)
Activate or deactivate stream. Invokes SetIsActiveImpl() and NotifyPropertyChanged().
OSStatus GetPropertyData(AudioObjectID objectID, pid_t clientPID, const AudioObjectPropertyAddress *address, UInt32 qualifierDataSize, const void *qualifierData, UInt32 inDataSize, UInt32 *outDataSize, void *outData) const override
Get property value.
virtual AudioStreamBasicDescription GetVirtualFormat() const
Get the current format of the stream. Virtual format defines the format used to present the device to...
virtual OSStatus SetAvailablePhysicalFormatsImpl(std::vector< AudioStreamRangedDescription > formats)
Set list of supported physical formats. Invoked by SetAvailablePhysicalFormatsAsync()....
OSStatus SetPhysicalFormatAsync(AudioStreamBasicDescription format)
Set current format of the stream. Requests HAL to asynchronously invoke SetPhysicalFormatImpl()....
OSStatus SetVirtualFormatAsync(AudioStreamBasicDescription format)
Set current virtual format of the stream. Requests HAL to asynchronously invoke SetVirtualFormatImpl(...
virtual UInt32 ConvertFramesToBytes(UInt32 numFrames) const
Convert number of frame to the number of bytes. Result depends on the value returned by GetPhysicalFo...
void AttachMuteControl(std::shared_ptr< MuteControl > control)
Attach mute control to the stream. ApplyProcessing() will use control to apply mute settings to the s...
AudioClassID GetClass() const override
Get class ID.
OSStatus GetPropertyDataSize(AudioObjectID objectID, pid_t clientPID, const AudioObjectPropertyAddress *address, UInt32 qualifierDataSize, const void *qualifierData, UInt32 *outDataSize) const override
Get size of property value in bytes.
OSStatus SetAvailableVirtualFormatsAsync(std::vector< AudioStreamRangedDescription > formats)
Asynchronously set list of supported virtual formats. See comments for GetAvailableVirtualFormats()....
bool IsInstance(AudioClassID classID) const override
Check if this object is instance of given base class.
Float64 GetSampleRate() const
Get stream sample rate. Return value is based on GetPhysicalFormat().
virtual UInt32 GetTerminalType() const
Get terminal type. By default returns kAudioStreamTerminalTypeMicrophone if GetDirection() returns Di...
AudioClassID GetBaseClass() const override
Get base class ID.
virtual OSStatus SetAvailableVirtualFormatsImpl(std::vector< AudioStreamRangedDescription > formats)
Set list of supported virtual formats. Invoked by SetAvailableVirtualFormatsAsync()....
virtual UInt32 GetLatency() const
Get any additional presentation latency the stream has. This latency is added to the device latency....
void RequestConfigurationChange(std::function< void()> func={})
Request HAL to perform configuration update. Similar to Device::RequestConfigurationChange().
virtual OSStatus SetVirtualFormatImpl(const AudioStreamBasicDescription &format)
Set current virtual format of the stream. Invoked by SetVirtualFormatAsync() to actually change the f...
Audio stream parameters.
Definition Stream.hpp:29
UInt32 StartingChannel
Absolute channel number for the first channel in the stream. Used by default implementation of Stream...
Definition Stream.hpp:36
AudioStreamBasicDescription Format
Stream format. Used by default implementation of Stream::GetPhysicalFormat(). Default format is:
Definition Stream.hpp:45
UInt32 Latency
Additional presentation latency the stream has. Used by default implementation of Stream::GetLatency(...
Definition Stream.hpp:59