replicate the remove-all-trailing whitespace commit(s) in master
[ardour.git] / libs / appleutility / CoreAudio / AudioCodecs / ACPublic / ACSimpleCodec.cpp
1 /*
2      File: ACSimpleCodec.cpp
3  Abstract: ACSimpleCodec.h
4   Version: 1.1
5
6  Disclaimer: IMPORTANT:  This Apple software is supplied to you by Apple
7  Inc. ("Apple") in consideration of your agreement to the following
8  terms, and your use, installation, modification or redistribution of
9  this Apple software constitutes acceptance of these terms.  If you do
10  not agree with these terms, please do not use, install, modify or
11  redistribute this Apple software.
12
13  In consideration of your agreement to abide by the following terms, and
14  subject to these terms, Apple grants you a personal, non-exclusive
15  license, under Apple's copyrights in this original Apple software (the
16  "Apple Software"), to use, reproduce, modify and redistribute the Apple
17  Software, with or without modifications, in source and/or binary forms;
18  provided that if you redistribute the Apple Software in its entirety and
19  without modifications, you must retain this notice and the following
20  text and disclaimers in all such redistributions of the Apple Software.
21  Neither the name, trademarks, service marks or logos of Apple Inc. may
22  be used to endorse or promote products derived from the Apple Software
23  without specific prior written permission from Apple.  Except as
24  expressly stated in this notice, no other rights or licenses, express or
25  implied, are granted by Apple herein, including but not limited to any
26  patent rights that may be infringed by your derivative works or by other
27  works in which the Apple Software may be incorporated.
28
29  The Apple Software is provided by Apple on an "AS IS" basis.  APPLE
30  MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
31  THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
32  FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
33  OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
34
35  IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
36  OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
37  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
38  INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
39  MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
40  AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
41  STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
42  POSSIBILITY OF SUCH DAMAGE.
43
44  Copyright (C) 2014 Apple Inc. All Rights Reserved.
45
46 */
47 //=============================================================================
48 //      Includes
49 //=============================================================================
50
51 #include "ACSimpleCodec.h"
52 #include <string.h>
53
54 //=============================================================================
55 //      ACSimpleCodec
56 //=============================================================================
57
58 static const UInt32 kBufferPad = 64; // this is used to prevent end from passing start.
59
60 ACSimpleCodec::ACSimpleCodec(UInt32 inInputBufferByteSize, AudioComponentInstance inInstance)
61 :
62         ACBaseCodec(inInstance),
63         mInputBuffer(NULL),
64         mInputBufferByteSize(inInputBufferByteSize+kBufferPad),
65         mInputBufferStart(0),
66         mInputBufferEnd(0)
67 {
68 }
69
70 ACSimpleCodec::~ACSimpleCodec()
71 {
72         delete[] mInputBuffer;
73 }
74
75 void    ACSimpleCodec::Initialize(const AudioStreamBasicDescription* inInputFormat, const AudioStreamBasicDescription* inOutputFormat, const void* inMagicCookie, UInt32 inMagicCookieByteSize)
76 {
77         ReallocateInputBuffer(mInputBufferByteSize - kBufferPad);
78
79         // By definition CBR has this greater than 0. We must avoid a div by 0 error in AppendInputData()
80         // Note this will cause us to fail initialization which is intended
81         if (mInputFormat.mBytesPerPacket == 0)
82         {
83                 CODEC_THROW(kAudioCodecUnsupportedFormatError);
84         }
85
86         ACBaseCodec::Initialize(inInputFormat, inOutputFormat, inMagicCookie, inMagicCookieByteSize);
87 }
88
89 void    ACSimpleCodec::Uninitialize()
90 {
91         //      get rid of the buffer
92         delete[] mInputBuffer;
93         mInputBuffer = NULL;
94
95         //      reset the ring buffer state
96         mInputBufferStart = 0;
97         mInputBufferEnd = 0;
98
99         ACBaseCodec::Uninitialize();
100 }
101
102 void    ACSimpleCodec::Reset()
103 {
104         //      clear the entire input buffer
105         if (mInputBuffer) { // could be called before allocated.
106                 memset(mInputBuffer, 0, mInputBufferByteSize);
107         }
108
109         //      reset the ring buffer state
110         mInputBufferStart = 0;
111         mInputBufferEnd = 0;
112
113         ACBaseCodec::Reset();
114 }
115
116 UInt32  ACSimpleCodec::GetInputBufferByteSize() const
117 {
118         return mInputBufferByteSize - kBufferPad; // minus kBufferPad to prevent end moving past start
119 }
120
121 UInt32  ACSimpleCodec::GetUsedInputBufferByteSize() const
122 {
123         UInt32 theAnswer = 0;
124
125         //      this object uses a ring buffer
126         if(mInputBufferStart <= mInputBufferEnd)
127         {
128                 //      the active region is contiguous
129                 theAnswer = mInputBufferEnd - mInputBufferStart;
130         }
131         else
132         {
133                 //      the active region wraps around
134                 theAnswer = (mInputBufferByteSize - mInputBufferStart) + mInputBufferEnd;
135         }
136
137         return theAnswer;
138 }
139
140
141 void    ACSimpleCodec::AppendInputData(const void* inInputData, UInt32& ioInputDataByteSize, UInt32& ioNumberPackets, const AudioStreamPacketDescription* inPacketDescription)
142 {
143         //      this buffer handling code doesn't care about such things as the packet descriptions
144         if(!mIsInitialized) CODEC_THROW(kAudioCodecStateError);
145
146         //      this is a ring buffer we're dealing with, so we need to set up a few things
147         UInt32 theUsedByteSize = GetUsedInputBufferByteSize();
148         UInt32 theAvailableByteSize = GetInputBufferByteSize() - theUsedByteSize;
149
150         UInt32 theMaxAvailableInputBytes = ioInputDataByteSize; // we can't consume more than we get
151
152         const Byte* theInputData = static_cast<const Byte*>(inInputData);
153
154         // >>jamesmcc: added this because ioNumberPackets was not being updated if less was taken than given.
155         // THIS ASSUMES CBR!
156         UInt32 bytesPerPacketOfInput = mInputFormat.mBytesPerPacket;
157         UInt32 theAvailablePacketSize = theAvailableByteSize / bytesPerPacketOfInput;
158
159         UInt32 minPacketSize = ioNumberPackets < theAvailablePacketSize ? ioNumberPackets : theAvailablePacketSize;
160         UInt32 minByteSize = minPacketSize * bytesPerPacketOfInput;
161
162         //      we can copy only as much data as there is or up to how much space is availiable
163         ioNumberPackets = minPacketSize;
164         ioInputDataByteSize = minByteSize;
165
166         // ioInputDataByteSize had better be <= to theMaxAvailableInputBytes or we're screwed
167         if (ioInputDataByteSize > theMaxAvailableInputBytes)
168         {
169                 CODEC_THROW(kAudioCodecStateError);
170         }
171         // <<jamesmcc
172
173         //      now we have to copy the data taking into account the wrap around and where the start is
174         if(mInputBufferEnd + ioInputDataByteSize < mInputBufferByteSize)
175         {
176                 //      no wrap around here
177                 memcpy(mInputBuffer + mInputBufferEnd, theInputData, ioInputDataByteSize);
178
179                 //      adjust the end point
180                 mInputBufferEnd += ioInputDataByteSize;
181         }
182         else
183         {
184                 //      the copy will wrap
185
186                 //      copy the first part
187                 UInt32 theBeforeWrapByteSize = mInputBufferByteSize - mInputBufferEnd;
188                 memcpy(mInputBuffer + mInputBufferEnd, theInputData, theBeforeWrapByteSize);
189
190                 //      and the rest
191                 UInt32 theAfterWrapByteSize = ioInputDataByteSize - theBeforeWrapByteSize;
192                 memcpy(mInputBuffer, theInputData + theBeforeWrapByteSize, theAfterWrapByteSize);
193
194                 //      adjust the end point
195                 mInputBufferEnd = theAfterWrapByteSize;
196         }
197
198 }
199
200
201 void    ACSimpleCodec::ZeroPadInputData(UInt32& ioNumberPackets, const AudioStreamPacketDescription* inPacketDescription)
202 {
203         //      this buffer handling code doesn't care about such things as the packet descriptions
204         if(!mIsInitialized) CODEC_THROW(kAudioCodecStateError);
205
206
207         //      this is a ring buffer we're dealing with, so we need to set up a few things
208         UInt32 theUsedByteSize = GetUsedInputBufferByteSize();
209         UInt32 theAvailableByteSize = GetInputBufferByteSize() - theUsedByteSize;
210
211         // >>jamesmcc: added this because ioNumberPackets was not being updated if less was taken than given.
212         // THIS ASSUMES CBR!
213         UInt32 bytesPerPacketOfInput = mInputFormat.mBytesPerPacket;
214         UInt32 theAvailablePacketSize = theAvailableByteSize / bytesPerPacketOfInput;
215
216         UInt32 minPacketSize = ioNumberPackets < theAvailablePacketSize ? ioNumberPackets : theAvailablePacketSize;
217         UInt32 minByteSize = minPacketSize * bytesPerPacketOfInput;
218
219         //      we can copy only as much data as there is or up to how much space is availiable
220         ioNumberPackets = minPacketSize;
221
222         // <<jamesmcc
223
224         //      now we have to copy the data taking into account the wrap around and where the start is
225         if(mInputBufferEnd + minByteSize < mInputBufferByteSize)
226         {
227                 //      no wrap around here
228                 memset(mInputBuffer + mInputBufferEnd, 0, minByteSize);
229
230                 //      adjust the end point
231                 mInputBufferEnd += minByteSize;
232         }
233         else
234         {
235                 //      the copy will wrap
236
237                 //      copy the first part
238                 UInt32 theBeforeWrapByteSize = mInputBufferByteSize - mInputBufferEnd;
239                 memset(mInputBuffer + mInputBufferEnd, 0, theBeforeWrapByteSize);
240
241                 //      and the rest
242                 UInt32 theAfterWrapByteSize = minByteSize - theBeforeWrapByteSize;
243                 memset(mInputBuffer, 0, theAfterWrapByteSize);
244
245                 //      adjust the end point
246                 mInputBufferEnd = theAfterWrapByteSize;
247         }
248 }
249
250
251 void    ACSimpleCodec::ConsumeInputData(UInt32 inConsumedByteSize)
252 {
253         //      this is a convenience routine to make maintaining the ring buffer state easy
254         UInt32 theContiguousRange = GetInputBufferContiguousByteSize();
255
256         if(inConsumedByteSize > GetUsedInputBufferByteSize()) CODEC_THROW(kAudioCodecUnspecifiedError);
257
258         if(inConsumedByteSize <= theContiguousRange)
259         {
260                 //      the region to consume doesn't wrap
261
262                 //      figure out how much to consume
263                 inConsumedByteSize = (theContiguousRange < inConsumedByteSize) ? theContiguousRange : inConsumedByteSize;
264
265                 //      clear the consumed bits
266                 memset(mInputBuffer + mInputBufferStart, 0, inConsumedByteSize);
267
268                 //      adjust the start
269                 mInputBufferStart += inConsumedByteSize;
270         }
271         else
272         {
273                 //      the region to consume will wrap
274
275                 //      clear the bits to the end of the buffer
276                 memset(mInputBuffer + mInputBufferStart, 0, theContiguousRange);
277
278                 //      now clear the bits left from the start
279                 memset(mInputBuffer, 0, inConsumedByteSize - theContiguousRange);
280
281                 //      adjust the start
282                 mInputBufferStart = inConsumedByteSize - theContiguousRange;
283         }
284 }
285
286
287 Byte* ACSimpleCodec::GetBytes(UInt32& ioNumberBytes) const
288 {
289         // if a client's algorithm has to have contiguous data and mInputBuffer wraps, then someone has to make a copy.
290         // I can do it more efficiently than the client.
291
292         if(!mIsInitialized) CODEC_THROW(kAudioCodecStateError);
293
294         UInt32 theUsedByteSize = GetUsedInputBufferByteSize();
295         //UInt32 theAvailableByteSize = GetInputBufferByteSize() - theUsedByteSize;
296
297         if (ioNumberBytes > theUsedByteSize) ioNumberBytes = theUsedByteSize;
298
299         SInt32 leftOver = mInputBufferStart + ioNumberBytes - mInputBufferByteSize;
300
301         if(leftOver > 0)
302         {
303                 // need to copy beginning of buffer to the end.
304                 // We cleverly over allocated our buffer space to make this possible.
305                 memmove(mInputBuffer + mInputBufferByteSize, mInputBuffer, leftOver);
306         }
307
308         return GetInputBufferStart();
309 }
310
311
312 void    ACSimpleCodec::ReallocateInputBuffer(UInt32 inInputBufferByteSize)
313 {
314         mInputBufferByteSize = inInputBufferByteSize + kBufferPad;
315
316         //      toss the old buffer
317         delete[] mInputBuffer;
318         mInputBuffer = NULL;
319
320         //      allocate the new one
321         // allocate extra in order to allow making contiguous data.
322         UInt32 allocSize = 2*inInputBufferByteSize + kBufferPad;
323         mInputBuffer = new Byte[allocSize];
324         memset(mInputBuffer, 0, allocSize);
325
326         //      reset the ring buffer state
327         mInputBufferStart = 0;
328         mInputBufferEnd = 0;
329 }
330
331 void    ACSimpleCodec::GetPropertyInfo(AudioCodecPropertyID inPropertyID, UInt32& outPropertyDataSize, Boolean& outWritable)
332 {
333         switch(inPropertyID)
334         {
335                 case kAudioCodecPropertyInputBufferSize:
336                         outPropertyDataSize = SizeOf32(UInt32);
337                         outWritable = true;
338                         break;
339                 default:
340                         ACBaseCodec::GetPropertyInfo(inPropertyID, outPropertyDataSize, outWritable);
341                         break;
342         }
343
344 }
345
346 void    ACSimpleCodec::SetProperty(AudioCodecPropertyID inPropertyID, UInt32 inPropertyDataSize, const void* inPropertyData)
347 {
348         switch(inPropertyID)
349         {
350                 case kAudioCodecPropertyInputBufferSize:
351                         if(inPropertyDataSize == sizeof(UInt32))
352                         {
353                                 ReallocateInputBuffer(*reinterpret_cast<const UInt32*>(inPropertyData));
354                         }
355                         else
356                         {
357                                 CODEC_THROW(kAudioCodecBadPropertySizeError);
358                         }
359                         break;
360                 default:
361             ACBaseCodec::SetProperty(inPropertyID, inPropertyDataSize, inPropertyData);
362             break;
363     }
364 }