-
Notifications
You must be signed in to change notification settings - Fork 1.7k
/
AUBuffer.h
166 lines (134 loc) · 5.27 KB
/
AUBuffer.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
/*!
@file AudioUnitSDK/AUBuffer.h
@copyright © 2000-2021 Apple Inc. All rights reserved.
*/
#ifndef AudioUnitSDK_AUBuffer_h
#define AudioUnitSDK_AUBuffer_h
#include <AudioUnitSDK/AUUtility.h>
#include <AudioToolbox/AudioUnit.h>
#include <cstddef>
#include <optional>
namespace ausdk {
/// struct created/destroyed by allocator. Do not attempt to manually create/destroy.
struct AllocatedBuffer {
const UInt32 mMaximumNumberBuffers;
const UInt32 mMaximumBytesPerBuffer;
const UInt32 mReservedA[2]; // NOLINT C-style array
const UInt32 mHeaderSize;
const UInt32 mBufferDataSize;
const UInt32 mReservedB[2]; // NOLINT C-style array
void* const mBufferData;
void* const mReservedC;
AudioBufferList mAudioBufferList;
// opaque variable-length data may follow the AudioBufferList
AudioBufferList& Prepare(UInt32 channelsPerBuffer, UInt32 bytesPerBuffer);
AudioBufferList& PrepareNull(UInt32 channelsPerBuffer, UInt32 bytesPerBuffer);
};
/*!
@class BufferAllocator
@brief Class which allocates memory for internal audio buffers.
To customize, create a subclass and install an instance into the global via set_instance().
*/
class BufferAllocator {
public:
/// Obtain the global instance, creating it if necessary.
static BufferAllocator& instance();
/// A client may install a custom global instance via this method. Throws an exception if
/// a default instance has already been created.
static void set_instance(BufferAllocator& instance);
BufferAllocator() = default;
virtual ~BufferAllocator() = default;
// Rule of 5
BufferAllocator(const BufferAllocator&) = delete;
BufferAllocator(BufferAllocator&&) = delete;
BufferAllocator& operator=(const BufferAllocator&) = delete;
BufferAllocator& operator=(BufferAllocator&&) = delete;
// N.B. Must return zeroed memory aligned to at least 16 bytes.
virtual AllocatedBuffer* Allocate(
UInt32 numberBuffers, UInt32 maxBytesPerBuffer, UInt32 reservedFlags);
virtual void Deallocate(AllocatedBuffer* allocatedBuffer);
};
/*!
@class AUBufferList
@brief Manages an `AudioBufferList` backed by allocated memory buffers.
*/
class AUBufferList {
enum class EPtrState { Invalid, ToMyMemory, ToExternalMemory };
public:
AUBufferList() = default;
~AUBufferList() { Deallocate(); }
AUBufferList(const AUBufferList&) = delete;
AUBufferList(AUBufferList&&) = delete;
AUBufferList& operator=(const AUBufferList&) = delete;
AUBufferList& operator=(AUBufferList&&) = delete;
AudioBufferList& PrepareBuffer(const AudioStreamBasicDescription& format, UInt32 nFrames);
AudioBufferList& PrepareNullBuffer(const AudioStreamBasicDescription& format, UInt32 nFrames);
AudioBufferList& SetBufferList(const AudioBufferList& abl)
{
ausdk::ThrowExceptionIf(mAllocatedStreams < abl.mNumberBuffers, -1);
mPtrState = EPtrState::ToExternalMemory;
auto& myabl = mBuffers->mAudioBufferList;
memcpy(&myabl, &abl,
static_cast<size_t>(
reinterpret_cast<const std::byte*>(&abl.mBuffers[abl.mNumberBuffers]) - // NOLINT
reinterpret_cast<const std::byte*>(&abl))); // NOLINT
return myabl;
}
void SetBuffer(UInt32 index, const AudioBuffer& ab)
{
auto& myabl = mBuffers->mAudioBufferList;
ausdk::ThrowExceptionIf(
mPtrState == EPtrState::Invalid || index >= myabl.mNumberBuffers, -1);
mPtrState = EPtrState::ToExternalMemory;
myabl.mBuffers[index] = ab; // NOLINT
}
void InvalidateBufferList() noexcept { mPtrState = EPtrState::Invalid; }
[[nodiscard]] AudioBufferList& GetBufferList() const
{
ausdk::ThrowExceptionIf(mPtrState == EPtrState::Invalid, -1);
return mBuffers->mAudioBufferList;
}
void CopyBufferListTo(AudioBufferList& abl) const
{
ausdk::ThrowExceptionIf(mPtrState == EPtrState::Invalid, -1);
memcpy(&abl, &mBuffers->mAudioBufferList,
static_cast<size_t>(
reinterpret_cast<std::byte*>(&abl.mBuffers[abl.mNumberBuffers]) - // NOLINT
reinterpret_cast<std::byte*>(&abl))); // NOLINT
}
void CopyBufferContentsTo(AudioBufferList& destabl) const
{
ausdk::ThrowExceptionIf(mPtrState == EPtrState::Invalid, -1);
const auto& srcabl = mBuffers->mAudioBufferList;
const AudioBuffer* srcbuf = srcabl.mBuffers; // NOLINT
AudioBuffer* destbuf = destabl.mBuffers; // NOLINT
for (UInt32 i = 0; i < destabl.mNumberBuffers; ++i, ++srcbuf, ++destbuf) { // NOLINT
if (i >=
srcabl.mNumberBuffers) { // duplicate last source to additional outputs [4341137]
--srcbuf; // NOLINT
}
if (destbuf->mData != srcbuf->mData) {
memmove(destbuf->mData, srcbuf->mData, srcbuf->mDataByteSize);
}
destbuf->mDataByteSize = srcbuf->mDataByteSize;
}
}
void Allocate(const AudioStreamBasicDescription& format, UInt32 nFrames);
void Deallocate();
// AudioBufferList utilities
static void ZeroBuffer(AudioBufferList& abl)
{
AudioBuffer* buf = abl.mBuffers; // NOLINT
for (UInt32 i = 0; i < abl.mNumberBuffers; ++i, ++buf) { // NOLINT
memset(buf->mData, 0, buf->mDataByteSize);
}
}
[[nodiscard]] UInt32 GetAllocatedFrames() const noexcept { return mAllocatedFrames; }
private:
EPtrState mPtrState{ EPtrState::Invalid };
AllocatedBuffer* mBuffers = nullptr; // only valid between Allocate and Deallocate
UInt32 mAllocatedStreams{ 0 };
UInt32 mAllocatedFrames{ 0 };
};
} // namespace ausdk
#endif // AudioUnitSDK_AUBuffer_h