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