1 /*
2 File: CAPersistence.cpp
3 Abstract: CAPersistence.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 #include "CACFArray.h"
48 #include "CACFDictionary.h"
49
50 #include "CAAudioUnit.h"
51 #include "CACFString.h"
52 #include "CAAudioChannelLayout.h"
53 #include "CAAUParameter.h"
54 #include "CAAUMIDIMap.h"
55
56 #include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
57
58 #pragma mark __CAStreamBasicDescription
59
60 static const CFStringRef kSampleRate = CFSTR("sample rate");
61 static const CFStringRef kFormat = CFSTR("format");
62 static const CFStringRef kFormatFlags = CFSTR("format flags");
63 static const CFStringRef kPacketBytes = CFSTR("packet bytes");
64 static const CFStringRef kFramePackets = CFSTR("frame packets");
65 static const CFStringRef kFrameBytes = CFSTR("frame bytes");
66 static const CFStringRef kFrameChannels = CFSTR("frame channels");
67 static const CFStringRef kChannelBits = CFSTR("channel bits");
68
69 // This will return a value that should be used as the key for this struct
70 // and a CFData object that contains the current state of this object
Save(CFPropertyListRef * outData) const71 OSStatus CAStreamBasicDescription::Save (CFPropertyListRef *outData) const
72 {
73 CACFDictionary dict(false);
74
75 if (!dict.AddFloat64 (kSampleRate, mSampleRate)) goto error;
76 if (!dict.AddUInt32 (kFormat, mFormatID)) goto error;
77 if (!dict.AddUInt32 (kFormatFlags, mFormatFlags)) goto error;
78 if (!dict.AddUInt32 (kPacketBytes, mBytesPerPacket)) goto error;
79 if (!dict.AddUInt32 (kFramePackets, mFramesPerPacket)) goto error;
80 if (!dict.AddUInt32 (kFrameBytes, mBytesPerFrame)) goto error;
81 if (!dict.AddUInt32 (kFrameChannels, mChannelsPerFrame)) goto error;
82 if (!dict.AddUInt32 (kChannelBits, mBitsPerChannel)) goto error;
83
84 *outData = dict.GetDict();
85
86 return noErr;
87
88 error:
89 dict.ShouldRelease (true);
90 return paramErr;
91 }
92
93
94 // Given a CFData object generated by the save command, this will re-establish
95 // the CAStreamBasicDescription
Restore(CFPropertyListRef & inData)96 OSStatus CAStreamBasicDescription::Restore (CFPropertyListRef& inData)
97 {
98 if (CFGetTypeID (inData) != CFDictionaryGetTypeID()) return paramErr;
99 CACFDictionary dict(static_cast<CFDictionaryRef>(inData), false);
100
101 if (!dict.GetFloat64 (kSampleRate, mSampleRate)) return paramErr;
102 if (!dict.GetUInt32 (kFormat, mFormatID)) return paramErr;
103 if (!dict.GetUInt32 (kFormatFlags, mFormatFlags)) return paramErr;
104 if (!dict.GetUInt32 (kPacketBytes, mBytesPerPacket)) return paramErr;
105 if (!dict.GetUInt32 (kFramePackets, mFramesPerPacket)) return paramErr;
106 if (!dict.GetUInt32 (kFrameBytes, mBytesPerFrame)) return paramErr;
107 if (!dict.GetUInt32 (kFrameChannels, mChannelsPerFrame)) return paramErr;
108 if (!dict.GetUInt32 (kChannelBits, mBitsPerChannel)) return paramErr;
109
110 return noErr;
111 }
112
113 #pragma mark __CAComponentDescription
114
115 static const CFStringRef kType = CFSTR("type");
116 static const CFStringRef kSubType = CFSTR("subtype");
117 static const CFStringRef kManu = CFSTR("manufacturer");
118
Save(CFPropertyListRef * outData) const119 OSStatus CAComponentDescription::Save (CFPropertyListRef *outData) const
120 {
121 CACFDictionary dict(false);
122 if (!dict.AddUInt32 (kType, componentType)) goto error;
123 if (!dict.AddUInt32 (kSubType, componentSubType)) goto error;
124 if (!dict.AddUInt32 (kManu, componentManufacturer)) goto error;
125
126 *outData = dict.GetDict();
127
128 return 0;
129 error:
130 dict.ShouldRelease (true);
131 return paramErr;
132 }
133
Restore(CFPropertyListRef & inData)134 OSStatus CAComponentDescription::Restore (CFPropertyListRef &inData)
135 {
136 if (CFGetTypeID (inData) != CFDictionaryGetTypeID()) return paramErr;
137 CACFDictionary dict(static_cast<CFDictionaryRef>(inData), false);
138
139 if (!dict.GetUInt32 (kType, componentType)) return paramErr;
140 if (!dict.GetUInt32 (kSubType, componentSubType)) return paramErr;
141 if (!dict.GetUInt32 (kManu, componentManufacturer)) return paramErr;
142
143 componentFlags = 0;
144 componentFlagsMask = 0;
145
146 return 0;
147 }
148
149 #pragma mark __CAComponent
150
Save(CFPropertyListRef * outData) const151 OSStatus CAComponent::Save (CFPropertyListRef *outData) const
152 {
153 OSStatus result = mDesc.Save (outData);
154 if (result) return result;
155
156 //add the name string of the component for a human readable name...
157 // this name string is *not* restored when restoring the component
158 CFStringRef name = GetCompName ();
159 if (name && *outData)
160 CFDictionarySetValue ((CFMutableDictionaryRef)(*outData), CFSTR("name"), name);
161
162 return noErr;
163 }
164
Restore(CFPropertyListRef & inData)165 OSStatus CAComponent::Restore (CFPropertyListRef &inData)
166 {
167 if (mDesc.Restore (inData)) return paramErr;
168
169 Clear();
170
171 mComp = AudioComponentFindNext (NULL, &mDesc);
172 // this will restore the current flags...
173 if (mComp)
174 AudioComponentGetDescription (Comp(), &mDesc);
175
176 return noErr;
177 }
178
179
180 #pragma mark __CAAudioChannelLayout
181
182 static const CFStringRef kACLTagKey = CFSTR("acl tag");
183 static const CFStringRef kACLBitmapKey = CFSTR("chan bitmap");
184 static const CFStringRef kACLLabelKey = CFSTR("label");
185 static const CFStringRef kACLFlagsKey = CFSTR("flags");
186 static const CFStringRef kACLCoords0Key = CFSTR("coords 0");
187 static const CFStringRef kACLCoords1Key = CFSTR("coords 1");
188 static const CFStringRef kACLCoords2Key = CFSTR("coords 2");
189 static const CFStringRef kACLDescsKey = CFSTR("descriptions");
190
Save(CFPropertyListRef * outData) const191 OSStatus CAAudioChannelLayout::Save (CFPropertyListRef *outData) const
192 {
193 const AudioChannelLayout& layout = Layout();
194
195 CACFDictionary dict (false);
196 if (!dict.AddUInt32 (kACLTagKey, layout.mChannelLayoutTag))
197 goto badadd;
198 if (layout.mChannelBitmap && !dict.AddUInt32 (kACLBitmapKey, layout.mChannelBitmap))
199 goto badadd;
200
201 if (layout.mNumberChannelDescriptions)
202 {
203 CFMutableArrayRef descs = CFArrayCreateMutable (NULL, layout.mNumberChannelDescriptions, &kCFTypeArrayCallBacks);
204
205 const AudioChannelDescription *desc = layout.mChannelDescriptions;
206 for (unsigned int i = 0; i < layout.mNumberChannelDescriptions; ++i, ++desc)
207 {
208 CACFDictionary descDict (true);
209 if (!descDict.AddUInt32 (kACLLabelKey, desc->mChannelLabel))
210 { CFRelease (descs); goto badadd; }
211 if (!descDict.AddUInt32 (kACLFlagsKey, desc->mChannelFlags))
212 { CFRelease (descs); goto badadd; }
213 if (!descDict.AddFloat32 (kACLCoords0Key, desc->mCoordinates[0]))
214 { CFRelease (descs); goto badadd; }
215 if (!descDict.AddFloat32 (kACLCoords1Key, desc->mCoordinates[1]))
216 { CFRelease (descs); goto badadd; }
217 if (!descDict.AddFloat32 (kACLCoords2Key, desc->mCoordinates[2]))
218 { CFRelease (descs); goto badadd; }
219
220 CFArrayAppendValue (descs, descDict.AsPropertyList());
221 }
222 dict.AddArray (kACLDescsKey, descs);
223
224 CFRelease (descs);
225 }
226
227 *outData = dict.GetDict();
228
229 return noErr;
230
231 badadd:
232 dict.ShouldRelease(true);
233 return paramErr;
234 }
235
Restore(CFPropertyListRef & inData)236 OSStatus CAAudioChannelLayout::Restore (CFPropertyListRef &inData)
237 {
238 if (CFGetTypeID (inData) != CFDictionaryGetTypeID()) return paramErr;
239 CACFDictionary dict(static_cast<CFDictionaryRef>(inData), false);
240
241 RefCountedLayout *temp = NULL;
242 AudioChannelLayout* layout;
243
244 CFArrayRef descs = NULL;
245 UInt32 numDescs = 0;
246
247 if (dict.GetArray (kACLDescsKey, descs)) {
248 numDescs = static_cast<OSStatus>(CFArrayGetCount (descs));
249 }
250
251 temp = RefCountedLayout::CreateWithNumberChannelDescriptions(numDescs);
252 layout = temp->GetLayout();
253
254 if (!dict.GetUInt32 (kACLTagKey, layout->mChannelLayoutTag))
255 goto badget;
256 if (dict.HasKey (kACLBitmapKey)) {
257 if (!dict.GetUInt32 (kACLBitmapKey, layout->mChannelBitmap))
258 goto badget;
259 } else
260 layout->mChannelBitmap = 0;
261
262 layout->mNumberChannelDescriptions = numDescs;
263
264 if (numDescs)
265 {
266 AudioChannelDescription *desc = layout->mChannelDescriptions;
267 for (unsigned int i = 0; i < numDescs; ++i, ++desc)
268 {
269 CFDictionaryRef descDict = (CFDictionaryRef)CFArrayGetValueAtIndex (descs, i);
270 CACFDictionary theDesc (descDict, false);
271
272 if (!theDesc.GetUInt32 (kACLLabelKey, desc->mChannelLabel))
273 goto badget;
274 if (!theDesc.GetUInt32 (kACLFlagsKey, desc->mChannelFlags))
275 goto badget;
276 if (!theDesc.GetFloat32 (kACLCoords0Key, desc->mCoordinates[0]))
277 goto badget;
278 if (!theDesc.GetFloat32 (kACLCoords1Key, desc->mCoordinates[1]))
279 goto badget;
280 if (!theDesc.GetFloat32 (kACLCoords2Key, desc->mCoordinates[2]))
281 goto badget;
282 }
283 }
284 if (mLayout)
285 mLayout->release();
286
287 mLayout = temp;
288
289 return noErr;
290
291 badget:
292 delete temp;
293 return paramErr;
294 }
295
296 #pragma mark __AudioUnitParameter
297
298 static const CFStringRef kAUScopeStr = CFSTR("scope");
299 static const CFStringRef kAUElementIDStr = CFSTR("element ID");
300 static const CFStringRef kAUParameterIDStr = CFSTR("paramID");
301
Save(CFPropertyListRef & outData) const302 void CAAUParameter::Save (CFPropertyListRef &outData) const
303 {
304 return CAAUParameter::Save (*this, outData);
305 }
306
307 // static functions to save/restore AudioUnitParameter
Save(const AudioUnitParameter & inParam,CFPropertyListRef & outData)308 void CAAUParameter::Save (const AudioUnitParameter &inParam, CFPropertyListRef &outData)
309 {
310 CACFDictionary dict(false);
311 dict.AddUInt32 (kAUScopeStr, inParam.mScope);
312 dict.AddUInt32 (kAUElementIDStr, inParam.mElement);
313 dict.AddUInt32 (kAUParameterIDStr, inParam.mParameterID);
314
315 outData = dict.AsPropertyList();
316 }
317
Restore(const CFPropertyListRef inData,AudioUnitParameter & outParam)318 OSStatus CAAUParameter::Restore (const CFPropertyListRef inData, AudioUnitParameter &outParam)
319 {
320 if (CFGetTypeID (inData) != CFDictionaryGetTypeID()) return paramErr;
321 CACFDictionary dict(static_cast<CFDictionaryRef>(inData), false);
322
323 if (!dict.GetUInt32 (kAUScopeStr, outParam.mScope)) return paramErr;
324 if (!dict.GetUInt32 (kAUElementIDStr, outParam.mElement)) return paramErr;
325 if (!dict.GetUInt32 (kAUParameterIDStr, outParam.mParameterID)) return paramErr;
326 return noErr;
327 }
328
329
330 #pragma mark __MIDIMap
331
332 const CFStringRef kParamMIDIStr = CFSTR("param maps");
333
334 const CFStringRef kMIDIFlagsStr = CFSTR("flags");
335 const CFStringRef kMIDISubMinStr = CFSTR("sub min");
336 const CFStringRef kMIDISubMaxStr = CFSTR("sub max");
337 const CFStringRef kMIDIStatusStr = CFSTR("midi status byte");
338 const CFStringRef kMIDIDataByteStr = CFSTR("midi data1 byte");
339 const CFStringRef kAUStr = CFSTR("unit");
340
341 static const CFStringRef kLocalElementIDStr = CFSTR("element ID");
342 static const CFStringRef kLocalScopeStr = CFSTR("scope");
343 static const CFStringRef kLocalParameterIDStr = CFSTR("paramID");
344
Save(CFPropertyListRef & outData) const345 void CAAUMIDIMap::Save(CFPropertyListRef &outData) const
346 {
347 CACFDictionary paramDict(false);
348
349 paramDict.AddUInt32 (kLocalScopeStr, mScope);
350 paramDict.AddUInt32 (kLocalElementIDStr, mElement);
351 paramDict.AddUInt32 (kLocalParameterIDStr, mParameterID);
352 paramDict.AddUInt32 (kMIDIFlagsStr, mFlags);
353 paramDict.AddFloat32 (kMIDISubMinStr, mSubRangeMin);
354 paramDict.AddFloat32 (kMIDISubMaxStr, mSubRangeMax);
355
356 UInt32 data = mStatus;
357 paramDict.AddUInt32 (kMIDIStatusStr, data);
358
359 data = mData1;
360 paramDict.AddUInt32 (kMIDIDataByteStr, data);
361
362 outData = paramDict.GetCFDictionary();
363 }
364
Restore(CFDictionaryRef inData)365 void CAAUMIDIMap::Restore(CFDictionaryRef inData)
366 {
367 CACFDictionary paramDict (inData, false);
368
369 if (!paramDict.GetUInt32 (kLocalScopeStr, mScope)) return;
370 if (!paramDict.GetUInt32 (kLocalElementIDStr, mElement)) return;
371 if (!paramDict.GetUInt32 (kLocalParameterIDStr, mParameterID)) return;
372 if (!paramDict.GetUInt32 (kMIDIFlagsStr, mFlags)) return;
373 if (!paramDict.GetFloat32 (kMIDISubMinStr, mSubRangeMin)) return;
374 if (!paramDict.GetFloat32 (kMIDISubMaxStr, mSubRangeMax)) return;
375 UInt32 data;
376 if (!paramDict.GetUInt32 (kMIDIStatusStr, data)) return;
377 mStatus = data;
378 if (!paramDict.GetUInt32 (kMIDIDataByteStr, data)) return;
379 mData1 = data;
380 }
381
SaveAsMapPList(AudioUnit inUnit,const AUParameterMIDIMapping * inMappings,UInt32 inNumMappings,CFPropertyListRef & outData,CFStringRef inName)382 void CAAUMIDIMap::SaveAsMapPList (AudioUnit inUnit, const AUParameterMIDIMapping* inMappings, UInt32 inNumMappings, CFPropertyListRef &outData, CFStringRef inName)
383 {
384
385 CACFDictionary mappingDict (false);
386 CACFArray maps (true);
387
388 for (UInt32 i = 0; i< inNumMappings; ++i)
389 {
390 CFPropertyListRef data;
391 CAAUMIDIMap paramMap(inMappings[i]);
392 paramMap.Save (data);
393 if (data)
394 {
395 maps.AppendCFType (data);
396 CFRelease(data);
397 }
398 }
399
400 if (maps.GetNumberItems()) {
401 mappingDict.AddCFType (kParamMIDIStr, maps.GetCFArray());
402
403 // Add the AU info here - where this map came from
404 CAAudioUnit au (inUnit);
405 CFPropertyListRef data;
406 au.Comp().Save (&data);
407
408 mappingDict.AddCFType (kAUStr, data);
409 CFRelease(data);
410
411 if (!inName) inName = CFSTR("Untitled");
412 mappingDict.AddString (CFSTR("name"), inName);
413
414 mappingDict.AddUInt32 (CFSTR("version"), 1);
415
416 outData = mappingDict.AsPropertyList();
417 } else {
418 mappingDict.ShouldRelease(true);
419 outData = NULL;
420 }
421 }
422
NumberOfMaps(const CFDictionaryRef inData)423 UInt32 CAAUMIDIMap::NumberOfMaps (const CFDictionaryRef inData)
424 {
425 CACFDictionary dict (inData, false);
426
427 if (dict.HasKey (kParamMIDIStr))
428 {
429 CFArrayRef cfArray;
430 dict.GetArray (kParamMIDIStr, cfArray);
431
432 CACFArray array (cfArray, false);
433
434 return array.GetNumberItems();
435 }
436 return 0;
437 }
438
RestoreFromMapPList(const CFDictionaryRef inData,AUParameterMIDIMapping * outMappings,UInt32 inNumMappings)439 void CAAUMIDIMap::RestoreFromMapPList (const CFDictionaryRef inData, AUParameterMIDIMapping* outMappings, UInt32 inNumMappings)
440 {
441
442 CACFDictionary dict (inData, false);
443
444 if (dict.HasKey (kParamMIDIStr))
445 {
446 CFArrayRef cfArray;
447 dict.GetArray (kParamMIDIStr, cfArray);
448
449 CACFArray array (cfArray, false);
450
451 UInt32 count = array.GetNumberItems();
452 if (count > inNumMappings)
453 count = inNumMappings;
454
455 for (unsigned int i = 0; i < count; ++i)
456 {
457 CFDictionaryRef paramsDictRef;
458 if (!array.GetDictionary(i, paramsDictRef))
459 return;
460
461 CAAUMIDIMap parameterMap;
462 parameterMap.Restore(paramsDictRef);
463 outMappings[i] = parameterMap;
464 }
465 }
466 }
467
468
469