-
Notifications
You must be signed in to change notification settings - Fork 140
/
TPCircularBuffer+AudioBufferList.h
232 lines (211 loc) · 11.1 KB
/
TPCircularBuffer+AudioBufferList.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
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
//
// TPCircularBuffer+AudioBufferList.h
// Circular/Ring buffer implementation
//
// https://github.com/michaeltyson/TPCircularBuffer
//
// Created by Michael Tyson on 20/03/2012.
//
// Copyright (C) 2012-2013 A Tasty Pixel
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
#ifndef TPCircularBuffer_AudioBufferList_h
#define TPCircularBuffer_AudioBufferList_h
#ifdef __cplusplus
extern "C" {
#endif
#include "TPCircularBuffer.h"
#include <AudioToolbox/AudioToolbox.h>
#define kTPCircularBufferCopyAll UINT32_MAX
typedef struct {
AudioTimeStamp timestamp;
UInt32 totalLength;
AudioBufferList bufferList;
} TPCircularBufferABLBlockHeader;
/*!
* Prepare an empty buffer list, stored on the circular buffer
*
* @param buffer Circular buffer
* @param numberOfBuffers The number of buffers to be contained within the buffer list
* @param bytesPerBuffer The number of bytes to store for each buffer
* @param timestamp The timestamp associated with the buffer, or NULL. Note that you can also pass a timestamp into TPCircularBufferProduceAudioBufferList, to set it there instead.
* @return The empty buffer list, or NULL if circular buffer has insufficient space
*/
AudioBufferList *TPCircularBufferPrepareEmptyAudioBufferList(TPCircularBuffer *buffer, UInt32 numberOfBuffers, UInt32 bytesPerBuffer, const AudioTimeStamp *timestamp);
/*!
* Prepare an empty buffer list, stored on the circular buffer, using an audio description to automatically configure buffer
*
* @param buffer Circular buffer
* @param audioFormat The kind of audio that will be stored
* @param frameCount The number of frames that will be stored
* @param timestamp The timestamp associated with the buffer, or NULL. Note that you can also pass a timestamp into TPCircularBufferProduceAudioBufferList, to set it there instead.
* @return The empty buffer list, or NULL if circular buffer has insufficient space
*/
AudioBufferList *TPCircularBufferPrepareEmptyAudioBufferListWithAudioFormat(TPCircularBuffer *buffer, const AudioStreamBasicDescription *audioFormat, UInt32 frameCount, const AudioTimeStamp *timestamp);
/*!
* Mark next audio buffer list as ready for reading
*
* This marks the audio buffer list prepared using TPCircularBufferPrepareEmptyAudioBufferList
* as ready for reading. You must not call this function without first calling
* TPCircularBufferPrepareEmptyAudioBufferList.
*
* @param buffer Circular buffer
* @param inTimestamp The timestamp associated with the buffer, or NULL to leave as-is. Note that you can also pass a timestamp into TPCircularBufferPrepareEmptyAudioBufferList, to set it there instead.
*/
void TPCircularBufferProduceAudioBufferList(TPCircularBuffer *buffer, const AudioTimeStamp *inTimestamp);
/*!
* Copy the audio buffer list onto the buffer
*
* @param buffer Circular buffer
* @param bufferList Buffer list containing audio to copy to buffer
* @param timestamp The timestamp associated with the buffer, or NULL
* @param frames Length of audio in frames. Specify kTPCircularBufferCopyAll to copy the whole buffer (audioFormat can be NULL, in this case)
* @param audioFormat The AudioStreamBasicDescription describing the audio, or NULL if you specify kTPCircularBufferCopyAll to the `frames` argument
* @return YES if buffer list was successfully copied; NO if there was insufficient space
*/
bool TPCircularBufferCopyAudioBufferList(TPCircularBuffer *buffer, const AudioBufferList *bufferList, const AudioTimeStamp *timestamp, UInt32 frames, const AudioStreamBasicDescription *audioFormat);
/*!
* Get a pointer to the next stored buffer list
*
* @param buffer Circular buffer
* @param outTimestamp On output, if not NULL, the timestamp corresponding to the buffer
* @return Pointer to the next buffer list in the buffer
*/
static __inline__ __attribute__((always_inline)) AudioBufferList *TPCircularBufferNextBufferList(TPCircularBuffer *buffer, AudioTimeStamp *outTimestamp) {
uint32_t dontcare; // Length of segment is contained within buffer list, so we can ignore this
TPCircularBufferABLBlockHeader *block = (TPCircularBufferABLBlockHeader*)TPCircularBufferTail(buffer, &dontcare);
if ( !block ) {
if ( outTimestamp ) {
memset(outTimestamp, 0, sizeof(AudioTimeStamp));
}
return NULL;
}
if ( outTimestamp ) {
memcpy(outTimestamp, &block->timestamp, sizeof(AudioTimeStamp));
}
return &block->bufferList;
}
/*!
* Get a pointer to the next stored buffer list after the given one
*
* @param buffer Circular buffer
* @param bufferList Preceding buffer list
* @param outTimestamp On output, if not NULL, the timestamp corresponding to the buffer
* @return Pointer to the next buffer list in the buffer, or NULL
*/
AudioBufferList *TPCircularBufferNextBufferListAfter(TPCircularBuffer *buffer, const AudioBufferList *bufferList, AudioTimeStamp *outTimestamp);
/*!
* Consume the next buffer list
*
* @param buffer Circular buffer
*/
static __inline__ __attribute__((always_inline)) void TPCircularBufferConsumeNextBufferList(TPCircularBuffer *buffer) {
uint32_t dontcare;
TPCircularBufferABLBlockHeader *block = (TPCircularBufferABLBlockHeader*)TPCircularBufferTail(buffer, &dontcare);
if ( !block ) return;
TPCircularBufferConsume(buffer, block->totalLength);
}
/*!
* Consume a portion of the next buffer list
*
* This will also increment the sample time and host time portions of the timestamp of
* the buffer list, if present.
*
* @param buffer Circular buffer
* @param framesToConsume The number of frames to consume from the buffer list
* @param audioFormat The AudioStreamBasicDescription describing the audio
*/
void TPCircularBufferConsumeNextBufferListPartial(TPCircularBuffer *buffer, UInt32 framesToConsume, const AudioStreamBasicDescription *audioFormat);
/*!
* Consume a certain number of frames from the buffer, possibly from multiple queued buffer lists
*
* Copies the given number of frames from the buffer into outputBufferList, of the
* given audio description, then consumes the audio buffers. If an audio buffer has
* not been entirely consumed, then updates the queued buffer list structure to point
* to the unconsumed data only.
*
* @param buffer Circular buffer
* @param ioLengthInFrames On input, the number of frames in the given audio format to consume; on output, the number of frames provided
* @param outputBufferList The buffer list to copy audio to, or NULL to discard audio. If not NULL, the structure must be initialised properly, and the mData pointers must not be NULL.
* @param outTimestamp On output, if not NULL, the timestamp corresponding to the first audio frame returned
* @param audioFormat The format of the audio stored in the buffer
*/
void TPCircularBufferDequeueBufferListFrames(TPCircularBuffer *buffer, UInt32 *ioLengthInFrames, const AudioBufferList *outputBufferList, AudioTimeStamp *outTimestamp, const AudioStreamBasicDescription *audioFormat);
/*!
* Determine how many frames of audio are buffered
*
* Given the provided audio format, determines the frame count of all queued buffers
*
* Note: This function should only be used on the consumer thread, not the producer thread.
*
* @param buffer Circular buffer
* @param outTimestamp On output, if not NULL, the timestamp corresponding to the first audio frame
* @param audioFormat The format of the audio stored in the buffer
* @return The number of frames in the given audio format that are in the buffer
*/
UInt32 TPCircularBufferPeek(TPCircularBuffer *buffer, AudioTimeStamp *outTimestamp, const AudioStreamBasicDescription *audioFormat);
/*!
* Determine how many contiguous frames of audio are buffered
*
* Given the provided audio format, determines the frame count of all queued buffers that are contiguous,
* given their corresponding timestamps (sample time).
*
* Note: This function should only be used on the consumer thread, not the producer thread.
*
* @param buffer Circular buffer
* @param outTimestamp On output, if not NULL, the timestamp corresponding to the first audio frame
* @param audioFormat The format of the audio stored in the buffer
* @param contiguousToleranceSampleTime The number of samples of discrepancy to tolerate
* @return The number of frames in the given audio format that are in the buffer
*/
UInt32 TPCircularBufferPeekContiguous(TPCircularBuffer *buffer, AudioTimeStamp *outTimestamp, const AudioStreamBasicDescription *audioFormat, UInt32 contiguousToleranceSampleTime);
/*!
* Determine how many contiguous frames of audio are buffered, with wrap around
*
* Like TPCircularBufferPeekContiguous, determines how many contiguous frames are buffered,
* but considers audio that wraps around a region of a given length as also contiguous. This
* is good for audio that loops.
*
* Note: This function should only be used on the consumer thread, not the producer thread.
*
* @param buffer Circular buffer
* @param outTimestamp On output, if not NULL, the timestamp corresponding to the first audio frame
* @param audioFormat The format of the audio stored in the buffer
* @param contiguousToleranceSampleTime The number of samples of discrepancy to tolerate
* @param wrapPoint The point around which the audio may wrap and still be considered contiguous, or 0 to disable
* @return The number of frames in the given audio format that are in the buffer
*/
UInt32 TPCircularBufferPeekContiguousWrapped(TPCircularBuffer *buffer, AudioTimeStamp *outTimestamp, const AudioStreamBasicDescription *audioFormat, UInt32 contiguousToleranceSampleTime, UInt32 wrapPoint);
/*!
* Determine how many much space there is in the buffer
*
* Given the provided audio format, determines the number of frames of audio that can be buffered.
*
* Note: This function should only be used on the producer thread, not the consumer thread.
*
* @param buffer Circular buffer
* @param audioFormat The format of the audio stored in the buffer
* @return The number of frames in the given audio format that can be stored in the buffer
*/
UInt32 TPCircularBufferGetAvailableSpace(TPCircularBuffer *buffer, const AudioStreamBasicDescription *audioFormat);
#ifdef __cplusplus
}
#endif
#endif