alternative new version of the AppleUtility library
[ardour.git] / libs / appleutility / CoreAudio / PublicUtility / CAExtAudioFile.h
1 /*
2      File: CAExtAudioFile.h
3  Abstract: Part of CoreAudio Utility Classes
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 #ifndef __CAExtAudioFile_h__
48 #define __CAExtAudioFile_h__
49
50 #include <TargetConditionals.h>
51
52 #if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
53         #include <AudioToolbox/ExtendedAudioFile.h>
54         #include <AudioToolbox/AudioConverter.h>
55 #else
56         #include "ExtendedAudioFile.h"
57         #include "AudioConverter.h"
58 #endif
59 #include "CAXException.h"
60 //#include "CAAutoDisposer.h"
61 #include "CAStreamBasicDescription.h"
62 #include "CAAudioChannelLayout.h"
63 #include "CACFObject.h"
64
65 // A C++ wrapper for ExtAudioFile
66 // Error returns throw CAXExceptions.
67 class CAExtAudioFile {
68 public:
69         // instances are not automatically associated with open files.
70         CAExtAudioFile() :
71                 mExtAudioFile(NULL) { }
72
73         virtual ~CAExtAudioFile()
74         {
75                 Close();
76         }
77         
78         bool IsValid() const { return mExtAudioFile != NULL; }
79         
80         void    Open(const char* filename)
81         {
82                 Close();
83                 CFURLRef url = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, (const UInt8*)filename, strlen(filename), false);
84                 XThrowIf(!url, -1, "couldn't convert path to CFURLRef");
85                 OSStatus res = ExtAudioFileOpenURL(url, &mExtAudioFile);
86                 if (res)
87                         CFRelease(url);
88                 Check(res, "ExtAudioFileOpenURL");
89                 CFRelease (url);
90         }
91         
92         // this group of methods maps directly to the API other than OSStatus results translating into exceptions.
93         // you must explicitly open, wrap or create a file.
94         void    OpenURL(CFURLRef url)
95         {
96                 Close();
97                 Check(ExtAudioFileOpenURL(url, &mExtAudioFile), "ExtAudioFileOpenURL");
98         }
99                 
100         void    WrapAudioFileID(AudioFileID inFileID, Boolean forWriting)
101         {
102                 Close();
103                 Check(ExtAudioFileWrapAudioFileID(inFileID, forWriting, &mExtAudioFile), "ExtAudioFileWrapAudioFileID");
104         }
105
106         void    Create(const char *filePath, AudioFileTypeID filetype, const AudioStreamBasicDescription &streamDesc, const AudioChannelLayout *channelLayout, UInt32 flags)
107         {
108                 CFURLRef url = CFURLCreateFromFileSystemRepresentation(NULL, (const UInt8 *)filePath, strlen(filePath), false);
109                 XThrowIf(!url, -1, "couldn't convert path to CFURLRef");
110                 Close();
111                 OSStatus res = ExtAudioFileCreateWithURL(url, filetype, &streamDesc, channelLayout, flags, &mExtAudioFile);
112                 if (res)
113                         CFRelease(url);
114                 Check(res, "ExtAudioFileCreateWithURL");
115                 CFRelease(url);
116         }
117         
118         void    CreateWithURL(CFURLRef url, AudioFileTypeID filetype, const AudioStreamBasicDescription &streamDesc, const AudioChannelLayout *channelLayout, UInt32 flags)
119         {
120                 Close();
121                 Check(ExtAudioFileCreateWithURL(url, filetype, &streamDesc, channelLayout, flags, &mExtAudioFile), "ExtAudioFileCreateWithURL");
122         }
123
124         // you may explicitly close a file, or have it closed automatically by the destructor.
125         void    Close()
126         {
127                 if (mExtAudioFile != NULL) {
128                         Check(ExtAudioFileDispose(mExtAudioFile), "ExtAudioFileClose");
129                         mExtAudioFile = NULL;
130                 }
131         }
132         
133         void    Read(UInt32 &ioNumberFrames, AudioBufferList *ioData)
134         {
135                 Check(ExtAudioFileRead(mExtAudioFile, &ioNumberFrames, ioData), "ExtAudioFileRead");
136         }
137         
138         OSStatus        Write(UInt32 inNumberFrames, const AudioBufferList *ioData)
139         {
140                 OSStatus err = ExtAudioFileWrite(mExtAudioFile, inNumberFrames, ioData);
141                 switch (err) {
142                         // noErr and certain special errors are returned without an exception
143                 case noErr:
144                         break;
145         #if TARGET_OS_IPHONE
146                 case kExtAudioFileError_CodecUnavailableInputConsumed:
147                 case kExtAudioFileError_CodecUnavailableInputNotConsumed:
148                         break;
149         #endif
150                 default:
151                         // throw an exception
152                         Check(err, "ExtAudioFileWrite");
153                         break;
154                 }
155                 return err;
156         }
157         
158         void    WriteAsync(UInt32 inNumberFrames, const AudioBufferList *ioData)
159         {
160                 Check(ExtAudioFileWriteAsync(mExtAudioFile, inNumberFrames, ioData), "ExtAudioFileWriteAsync");
161         }
162         
163         void    Seek(SInt64 inFrameOffset)
164         {
165                 Check(ExtAudioFileSeek(mExtAudioFile, inFrameOffset), "ExtAudioFileSeek");
166         }
167         
168         SInt64  Tell() const
169         {
170                 SInt64 pos;
171                 Check(ExtAudioFileTell(mExtAudioFile, &pos), "ExtAudioFileTell");
172                 return pos;
173         }
174         
175         UInt32  GetPropertyInfo(ExtAudioFilePropertyID propid, Boolean *outWritable) const
176         {
177                 UInt32 size;
178                 CheckProperty(ExtAudioFileGetPropertyInfo(mExtAudioFile, propid, &size, outWritable), "ExtAudioFileGetPropertyInfo", propid);
179                 return size;
180         }
181         
182         void    GetProperty(ExtAudioFilePropertyID propid, UInt32 &ioSize, void *outData) const
183         {
184                 CheckProperty(ExtAudioFileGetProperty(mExtAudioFile, propid, &ioSize, outData), "ExtAudioFileGetProperty", propid);
185         }
186         
187         void    SetProperty(ExtAudioFilePropertyID propid, UInt32 size, const void *inData)
188         {
189                 CheckProperty(ExtAudioFileSetProperty(mExtAudioFile, propid, size, inData), "ExtAudioFileSetProperty", propid);
190         }
191         
192         const CAAudioChannelLayout &GetFileChannelLayout()
193         {
194                 return FetchChannelLayout(mFileChannelLayout, kExtAudioFileProperty_FileChannelLayout);
195         }
196
197         void    SetFileChannelLayout(const CAAudioChannelLayout &layout) {
198                 SetProperty(kExtAudioFileProperty_FileChannelLayout, layout.Size(), &layout.Layout());
199         }
200
201         const CAStreamBasicDescription &GetFileDataFormat()
202         {
203                 UInt32 size = sizeof(mFileDataFormat);
204                 GetProperty(kExtAudioFileProperty_FileDataFormat, size, &mFileDataFormat);
205                 return mFileDataFormat;
206         }
207         
208         const CAStreamBasicDescription &GetClientDataFormat() {
209                 UInt32 size = sizeof(mClientDataFormat);
210                 GetProperty(kExtAudioFileProperty_ClientDataFormat, size, &mClientDataFormat);
211                 return mClientDataFormat;
212         }
213         
214
215         void    SetClientFormat(const CAStreamBasicDescription &dataFormat, const CAAudioChannelLayout *layout=NULL, UInt32 codecManuf=0) {
216                 if (codecManuf != 0)
217                         SetProperty('cman' /*kExtAudioFileProperty_CodecManufacturer*/, sizeof(codecManuf), &codecManuf);
218                 SetProperty(kExtAudioFileProperty_ClientDataFormat, sizeof(dataFormat), &dataFormat);
219                 if (layout)
220                         SetClientChannelLayout(*layout);
221         }
222         
223         void    SetClientChannelLayout(const CAAudioChannelLayout &layout) {
224                 SetProperty(kExtAudioFileProperty_ClientChannelLayout, layout.Size(), &layout.Layout());
225         }
226         
227         AudioConverterRef                               GetConverter() const {
228                 UInt32 size = sizeof(AudioConverterRef);
229                 AudioConverterRef converter = NULL;
230                 GetProperty(kExtAudioFileProperty_AudioConverter, size, &converter);
231                 return converter;
232         }
233
234         bool    HasConverter() const { return GetConverter() != NULL; }
235         
236         OSStatus        SetConverterProperty(AudioConverterPropertyID inPropertyID,     UInt32 inPropertyDataSize, const void *inPropertyData, bool inCanFail=false)
237         {
238                 OSStatus err = AudioConverterSetProperty(GetConverter(), inPropertyID, inPropertyDataSize, inPropertyData);
239                 if (!inCanFail)
240                         XThrowIfError(err, "Couldn't set audio converter property");
241                 if (!err) {
242                         // must tell the file that we have changed the converter; a NULL converter config is sufficient
243                         CFPropertyListRef config = NULL;
244                         SetProperty(kExtAudioFileProperty_ConverterConfig, sizeof(CFPropertyListRef), &config);
245                 }
246                 return err;
247         }
248         
249         SInt64          GetNumberFrames() {
250                 SInt64 length;
251                 UInt32 size = sizeof(SInt64);
252                 GetProperty(kExtAudioFileProperty_FileLengthFrames, size, &length);
253                 return length;
254         }
255         
256
257 protected:
258         virtual void Check(OSStatus err, const char *func) const
259         {
260                 if (err) {
261                         char txt[128];
262                         snprintf(txt, sizeof(txt), "%s failed", func);
263                         throw CAXException(txt, err);
264                 }
265         }
266         
267         virtual void CheckProperty(OSStatus err, const char *func, UInt32 propid) const
268         {
269                 if (err) {
270                         char txt[128];
271                         char propstr[] = CA4CCToCString(propid);
272                         snprintf(txt, sizeof(txt), "%s ('%s') failed", func, propstr);
273                         throw CAXException(txt, err);
274                 }
275         }
276
277         const CAAudioChannelLayout &    FetchChannelLayout(CAAudioChannelLayout &layoutObj, ExtAudioFilePropertyID propID) {
278                 UInt32 size = GetPropertyInfo(propID, NULL);
279                 CAAutoFree<AudioChannelLayout> layout;
280                 layout.allocBytes(size);
281                 GetProperty(propID, size, layout);
282                 layoutObj = layout;
283                 return layoutObj;
284         }
285
286 private:
287         CAExtAudioFile(const CAExtAudioFile &) { }      // prohibit
288         CAExtAudioFile & operator = (const CAExtAudioFile &) { return *this; } // prohibit
289
290 private:
291         ExtAudioFileRef                         mExtAudioFile;
292         
293         // for convenience to the client, it helps if we hold onto some storage for these
294         CAStreamBasicDescription        mFileDataFormat;
295         CAAudioChannelLayout            mFileChannelLayout;
296         CAStreamBasicDescription        mClientDataFormat;
297 };
298
299
300 #endif // __CAExtAudioFile_h__