1/**********************************************************************************************************************************
2*
3*   OpenAL cross platform audio library
4*   Copyright (c) 2005, Apple Computer, 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 Computer, 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#ifndef __OAL_CAPTURE_DEVICE__
25#define __OAL_CAPTURE_DEVICE__
26
27#include <CoreAudio/AudioHardware.h>
28#include <AudioToolbox/AudioToolbox.h>
29#include <AudioUnit/AudioUnit.h>
30#include <map>
31#include <libkern/OSAtomic.h>
32
33#include "oalImp.h"
34#include "oalRingBuffer.h"
35#include "CAStreamBasicDescription.h"
36#include "CABufferList.h"
37
38#define LOG_CAPTUREDEVICE_VERBOSE         0
39
40// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
41// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
42// OALCaptureDevices
43// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
44// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
45
46#pragma mark _____OALCaptureDevice_____
47class OALCaptureDevice
48{
49#pragma mark __________ Public_Class_Members
50	public:
51
52	OALCaptureDevice(const char* 	 inDeviceName, uintptr_t   inSelfToken, UInt32 inSampleRate, UInt32 inFormat, UInt32 inBufferSize);
53	~OALCaptureDevice();
54
55	void				StartCapture();
56	void				StopCapture();
57
58	OSStatus			GetFrames(UInt32 inFrameCount, UInt8*	inBuffer);
59	UInt32				AvailableFrames();
60	void				SetError(ALenum errorCode);
61	ALenum				GetError();
62
63	// we need to mark the capture device if it is being used to prevent deletion from another thread
64	void				SetInUseFlag()		{ OSAtomicIncrement32Barrier(&mInUseFlag); }
65	void				ClearInUseFlag()	{ OSAtomicDecrement32Barrier(&mInUseFlag); }
66	volatile int32_t	IsInUse()			{ return mInUseFlag; }
67
68#pragma mark __________ Private_Class_Members
69
70	private:
71#if LOG_CAPTUREDEVICE_VERBOSE
72		uintptr_t						mSelfToken;
73#endif
74		ALenum							mCurrentError;
75		bool							mCaptureOn;
76		SInt64							mStoreSampleTime;				// increment on each read in the input proc, and pass to the ring buffer class when writing, reset on each stop
77		SInt64							mFetchSampleTime;				// increment on each read in the input proc, and pass to the ring buffer class when writing, reset on each stop
78		AudioUnit						mInputUnit;
79		CAStreamBasicDescription		mNativeFormat;
80		CAStreamBasicDescription		mRequestedFormat;
81		CAStreamBasicDescription		mOutputFormat;
82		OALRingBuffer*					mRingBuffer;					// the ring buffer
83		UInt8*							mBufferData;
84		AudioConverterRef				mAudioConverter;
85		Float64							mSampleRateRatio;
86		UInt32							mRequestedRingFrames;
87		CABufferList*					mAudioInputPtrs;
88		volatile int32_t				mInUseFlag;						// flag to indicate the device is currently being used by one or more threads
89
90	void				InitializeAU (const char* 	inDeviceName);
91	static OSStatus		InputProc(	void *						inRefCon,
92									AudioUnitRenderActionFlags *ioActionFlags,
93									const AudioTimeStamp *		inTimeStamp,
94									UInt32 						inBusNumber,
95									UInt32 						inNumberFrames,
96									AudioBufferList *			ioData);
97
98	static OSStatus		ACComplexInputDataProc	(AudioConverterRef				inAudioConverter,
99												 UInt32							*ioNumberDataPackets,
100												 AudioBufferList				*ioData,
101												 AudioStreamPacketDescription	**outDataPacketDescription,
102												 void*							inUserData);
103
104};
105
106// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
107#pragma mark _____OALCaptureDeviceMap_____
108// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
109class OALCaptureDeviceMap : std::multimap<uintptr_t, OALCaptureDevice*, std::less<uintptr_t> > {
110public:
111
112    void Add (const	uintptr_t	inDeviceToken, OALCaptureDevice **inDevice)  {
113		iterator it = upper_bound(inDeviceToken);
114		insert(it, value_type (inDeviceToken, *inDevice));
115	}
116
117    OALCaptureDevice* Get(uintptr_t	inDeviceToken) {
118        iterator	it = find(inDeviceToken);
119        if (it != end())
120            return ((*it).second);
121		return (NULL);
122    }
123
124    void Remove (const	uintptr_t	inDeviceToken) {
125        iterator 	it = find(inDeviceToken);
126        if (it != end())
127            erase(it);
128    }
129
130    UInt32 Size () const { return size(); }
131    bool Empty () const { return empty(); }
132};
133
134
135#endif
136