1/**********************************************************************************************************************************
2 *
3 *   OpenAL cross platform audio library
4 *	Copyright (c) 2004, Apple Computer, Inc., Copyright (c) 2012, Apple Inc. All rights reserved.
5 *
6 *   Redistribution and use in source and binary forms, with or without modification, are permitted provided
7 *   that the following conditions are met:
8 *
9 *   1.  Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
10 *   2.  Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
11 *       disclaimer in the documentation and/or other materials provided with the distribution.
12 *   3.  Neither the name of Apple Inc. ("Apple") nor the names of its contributors may be used to endorse or promote
13 *       products derived from this software without specific prior written permission.
14 *
15 *   THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16 *   THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS
17 *   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
18 *   TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
19 *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
20 *   USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
21 *
22 **********************************************************************************************************************************/
23
24#include <libkern/OSAtomic.h>
25
26// Local includes
27#include "oalImp.h"
28#include "oalCaptureMixer.h"
29
30// Public Utility includes
31#include  "CAXException.h"
32
33const UInt32 kMaxFramesPerSlice = 4096;
34
35// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
36// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
37#pragma mark ***** OALCaptureMixers *****
38// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
39// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
40OALCaptureMixer::OALCaptureMixer (AudioUnit inMixerUnit, Float64 inSampleRate, UInt32 inOALFormat, UInt32 inBufferSize)
41: mMixerUnit(inMixerUnit),
42mRingBuffer(NULL),
43mRequestedRingFrames(inBufferSize),
44mStoreSampleTime(0),
45mFetchSampleTime(0),
46mCaptureOn(false),
47mAudioConverter(0),
48mConvertedDataABL(NULL)
49{
50	try {
51        // translate the sample rate and data format parameters into an ASBD - this method throws
52		FillInASBD(mRequestedFormat, inOALFormat, inSampleRate);
53
54		// inBufferSize must be at least as big as one packet of the requested output format
55		if (inBufferSize < mRequestedFormat.mBytesPerPacket)
56            throw ((OSStatus) AL_INVALID_VALUE);
57
58        // get the output format of the 3DMixer
59        CAStreamBasicDescription mixerOutFormat;
60        UInt32 propSize = sizeof(mixerOutFormat);
61        XThrowIfErr(AudioUnitGetProperty(mMixerUnit, kAudioUnitProperty_StreamFormat, 0, 0, &mixerOutFormat, &propSize));
62
63        mRingBuffer =  new OALRingBuffer();
64		mRingBuffer->Allocate(mRequestedFormat.mBytesPerFrame, kMaxFramesPerSlice);
65
66        //create a new converter to convert the mixer output data to the requested format
67        XThrowIfErr(AudioConverterNew(&mixerOutFormat, &mRequestedFormat, &mAudioConverter));
68
69        mConvertedDataABL = CABufferList::New("converted data", mRequestedFormat);
70        mConvertedDataABL->AllocateBuffers(mRequestedFormat.mBytesPerFrame * kMaxFramesPerSlice);
71
72	}
73	catch (OSStatus	result) {
74        if (mRingBuffer) {
75            delete (mRingBuffer);
76            mRingBuffer = NULL;
77        }
78        throw result;
79	}
80	catch (...) {
81        if (mRingBuffer) {
82            delete (mRingBuffer);
83            mRingBuffer = NULL;
84        }
85        throw static_cast<OSStatus>(-1);
86	}
87}
88
89// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
90OALCaptureMixer::~OALCaptureMixer()
91{
92    if (mCaptureOn)
93        StopCapture();
94
95    if (mRingBuffer) {
96        delete (mRingBuffer);
97        mRingBuffer = NULL;
98    }
99    if (mConvertedDataABL) {
100        delete (mConvertedDataABL);
101        mConvertedDataABL = NULL;
102    }
103    if (mAudioConverter) {
104        AudioConverterDispose(mAudioConverter);
105        mAudioConverter = NULL;
106    }
107}
108
109// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
110void OALCaptureMixer::StartCapture()
111{
112    if (!mCaptureOn)
113    {
114        SetCaptureFlag();
115        AudioUnitAddRenderNotify(mMixerUnit, RenderCallback, this);
116        mRingBuffer->Clear();
117    }
118}
119
120// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
121void OALCaptureMixer::StopCapture()
122{
123    if (mCaptureOn)
124    {
125        ClearCaptureFlag();
126        AudioUnitRemoveRenderNotify(mMixerUnit, RenderCallback, this);
127        mRingBuffer->Clear();
128    }
129}
130
131// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
132OSStatus OALCaptureMixer::RenderCallback(      void *							inRefCon,
133                                               AudioUnitRenderActionFlags *	ioActionFlags,
134                                               const AudioTimeStamp *			inTimeStamp,
135                                               UInt32							inBusNumber,
136                                               UInt32							inNumberFrames,
137                                               AudioBufferList *				ioData)
138{
139    OALCaptureMixer* THIS = (OALCaptureMixer*) inRefCon;
140
141    if (!THIS->mCaptureOn)
142        return noErr;
143
144    try {
145        if (*ioActionFlags & kAudioUnitRenderAction_PostRender)
146        {
147            static int TEMP_kAudioUnitRenderAction_PostRenderError	= (1 << 8);
148            if (inBusNumber == 0 && !(*ioActionFlags & TEMP_kAudioUnitRenderAction_PostRenderError))
149            {
150                // convert the data from the mixer to the requested format
151                UInt32 packetCount = inNumberFrames;
152                AudioBufferList* abl = &THIS->mConvertedDataABL->GetModifiableBufferList();
153                XThrowIfErr(AudioConverterFillComplexBuffer(THIS->mAudioConverter, ConverterProc, ioData, &packetCount, abl, NULL));
154
155                // store the converted data in the ring buffer
156                if(THIS->mRingBuffer->Store((const Byte*)abl->mBuffers[0].mData, inNumberFrames, THIS->mStoreSampleTime))
157                    THIS->mStoreSampleTime += inNumberFrames;
158            }
159        }
160    }
161
162    catch (OSStatus	result) {
163        return result;
164	}
165	catch (...) {
166        return -1;
167	}
168
169    return noErr;
170}
171
172// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
173OSStatus OALCaptureMixer::ConverterProc(       AudioConverterRef               /*inAudioConverter*/,
174                                               UInt32*                           ioNumberDataPackets,
175                                               AudioBufferList*                  ioData,
176                                               AudioStreamPacketDescription**    /*outDataPacketDescription*/,
177                                               void*                             inUserData)
178{
179    AudioBufferList* inputData = (AudioBufferList*) inUserData;
180    for (int i=0; i<inputData->mNumberBuffers; ++i)
181    {
182        //tell the converter where the data is and how much there is
183        ioData->mBuffers[i].mData = inputData->mBuffers[i].mData;
184        ioData->mBuffers[i].mDataByteSize = inputData->mBuffers[i].mDataByteSize;
185    }
186
187    return noErr;
188}
189
190
191// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
192OSStatus	OALCaptureMixer::GetFrames(UInt32 inFrameCount, UInt8*	inBuffer)
193{
194	OSStatus	result = noErr;
195
196	if (!mCaptureOn)
197    {
198		throw ((OSStatus) AL_INVALID_OPERATION);  // error condition, device not currently capturing
199    }
200
201	if (inFrameCount > AvailableFrames())
202	{
203		return -1; // error condition, there aren't enough valid frames to satisfy request
204	}
205
206	result = mRingBuffer->Fetch((Byte*)inBuffer, inFrameCount, mFetchSampleTime);
207
208	if (result)
209	{
210		return result;
211	}
212
213	if (result == noErr)
214		mFetchSampleTime += inFrameCount;
215
216	return result;
217}
218
219// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
220UInt32	OALCaptureMixer::AvailableFrames()
221{
222	SInt64	start, end;
223	mRingBuffer->GetTimeBounds(start, end);
224
225	if (mFetchSampleTime < start)
226		mFetchSampleTime = start;	// move up our fetch starting point, we have fallen too far behind
227
228	UInt32	availableFrames = static_cast<UInt32>(end - mFetchSampleTime);
229
230	if (availableFrames > mRequestedRingFrames)
231		availableFrames = mRequestedRingFrames;
232
233	return availableFrames;
234}
235
236// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
237void	OALCaptureMixer::SetCaptureFlag()
238{
239    int32_t one = 1;    int32_t zero = 0;
240    OSAtomicCompareAndSwap32Barrier(zero, one, &mCaptureOn);
241}
242
243// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
244void	OALCaptureMixer::ClearCaptureFlag()
245{
246    int32_t one = 1;    int32_t zero = 0;
247    OSAtomicCompareAndSwap32Barrier(one, zero, &mCaptureOn);
248}
249
250// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
251
252
253
254
255