1 /* Copyright © 2007 Apple Inc. All Rights Reserved.
3 Disclaimer: IMPORTANT: This Apple software is supplied to you by
4 Apple Inc. ("Apple") in consideration of your agreement to the
5 following terms, and your use, installation, modification or
6 redistribution of this Apple software constitutes acceptance of these
7 terms. If you do not agree with these terms, please do not use,
8 install, modify or redistribute this Apple software.
10 In consideration of your agreement to abide by the following terms, and
11 subject to these terms, Apple grants you a personal, non-exclusive
12 license, under Apple's copyrights in this original Apple software (the
13 "Apple Software"), to use, reproduce, modify and redistribute the Apple
14 Software, with or without modifications, in source and/or binary forms;
15 provided that if you redistribute the Apple Software in its entirety and
16 without modifications, you must retain this notice and the following
17 text and disclaimers in all such redistributions of the Apple Software.
18 Neither the name, trademarks, service marks or logos of Apple Inc.
19 may be used to endorse or promote products derived from the Apple
20 Software without specific prior written permission from Apple. Except
21 as expressly stated in this notice, no other rights or licenses, express
22 or implied, are granted by Apple herein, including but not limited to
23 any patent rights that may be infringed by your derivative works or by
24 other works in which the Apple Software may be incorporated.
26 The Apple Software is provided by Apple on an "AS IS" basis. APPLE
27 MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
28 THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
29 FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
30 OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
32 IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
33 OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
34 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
35 INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
36 MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
37 AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
38 STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
39 POSSIBILITY OF SUCH DAMAGE.
41 /*=============================================================================
42 CAStreamBasicDescription.cpp
44 =============================================================================*/
46 #include "CAStreamBasicDescription.h"
49 #if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
50 #include <CoreFoundation/CFByteOrder.h>
52 #include <CFByteOrder.h>
59 #pragma mark This file needs to compile on earlier versions of the OS, so please keep that in mind when editing it
61 const AudioStreamBasicDescription
CAStreamBasicDescription::sEmpty
= { 0.0, 0, 0, 0, 0, 0, 0, 0, 0 };
63 CAStreamBasicDescription::CAStreamBasicDescription(double inSampleRate
, UInt32 inFormatID
,
64 UInt32 inBytesPerPacket
, UInt32 inFramesPerPacket
,
65 UInt32 inBytesPerFrame
, UInt32 inChannelsPerFrame
,
66 UInt32 inBitsPerChannel
, UInt32 inFormatFlags
)
68 mSampleRate
= inSampleRate
;
69 mFormatID
= inFormatID
;
70 mBytesPerPacket
= inBytesPerPacket
;
71 mFramesPerPacket
= inFramesPerPacket
;
72 mBytesPerFrame
= inBytesPerFrame
;
73 mChannelsPerFrame
= inChannelsPerFrame
;
74 mBitsPerChannel
= inBitsPerChannel
;
75 mFormatFlags
= inFormatFlags
;
79 void CAStreamBasicDescription::PrintFormat2(FILE *f
, const char *indent
, const char *name
) const
81 fprintf(f
, "%s%s ", indent
, name
);
83 *(UInt32
*)formatID
= CFSwapInt32HostToBig(mFormatID
);
85 fprintf(f
, "%2d ch, %6.0f Hz, '%-4.4s' (0x%08X) ",
86 (int)NumberChannels(), mSampleRate
, formatID
,
88 if (mFormatID
== kAudioFormatLinearPCM
) {
89 bool isInt
= !(mFormatFlags
& kLinearPCMFormatFlagIsFloat
);
90 int wordSize
= SampleWordSize();
91 const char *endian
= (wordSize
> 1) ?
92 ((mFormatFlags
& kLinearPCMFormatFlagIsBigEndian
) ? " big-endian" : " little-endian" ) : "";
93 const char *sign
= isInt
?
94 ((mFormatFlags
& kLinearPCMFormatFlagIsSignedInteger
) ? " signed" : " unsigned") : "";
95 const char *floatInt
= isInt
? "integer" : "float";
97 if (wordSize
> 0 && PackednessIsSignificant()) {
98 if (mFormatFlags
& kLinearPCMFormatFlagIsPacked
)
99 sprintf(packed
, "packed in %d bytes", wordSize
);
101 sprintf(packed
, "unpacked in %d bytes", wordSize
);
104 const char *align
= (wordSize
> 0 && AlignmentIsSignificant()) ?
105 ((mFormatFlags
& kLinearPCMFormatFlagIsAlignedHigh
) ? " high-aligned" : " low-aligned") : "";
106 const char *deinter
= (mFormatFlags
& kAudioFormatFlagIsNonInterleaved
) ? ", deinterleaved" : "";
107 const char *commaSpace
= (packed
[0]!='\0') || (align
[0]!='\0') ? ", " : "";
109 fprintf(f
, "%d-bit%s%s %s%s%s%s%s",
110 (int)mBitsPerChannel
, endian
, sign
, floatInt
,
111 commaSpace
, packed
, align
, deinter
);
112 } else if (mFormatID
== 'alac') { // kAudioFormatAppleLossless
114 switch (mFormatFlags
)
116 case 1: // kAppleLosslessFormatFlag_16BitSourceData
119 case 2: // kAppleLosslessFormatFlag_20BitSourceData
122 case 3: // kAppleLosslessFormatFlag_24BitSourceData
125 case 4: // kAppleLosslessFormatFlag_32BitSourceData
130 fprintf(f
, "from %d-bit source, ", sourceBits
);
132 fprintf(f
, "from UNKNOWN source bit depth, ");
134 fprintf(f
, "%d frames/packet", (int)mFramesPerPacket
);
137 fprintf(f
, "%d bits/channel, %d bytes/packet, %d frames/packet, %d bytes/frame",
138 (int)mBitsPerChannel
, (int)mBytesPerPacket
, (int)mFramesPerPacket
, (int)mBytesPerFrame
);
141 void CAStreamBasicDescription::NormalizeLinearPCMFormat(AudioStreamBasicDescription
& ioDescription
)
143 // the only thing that changes is to make mixable linear PCM into the canonical linear PCM format
144 if((ioDescription
.mFormatID
== kAudioFormatLinearPCM
) && ((ioDescription
.mFormatFlags
& kIsNonMixableFlag
) == 0))
146 // the canonical linear PCM format
147 ioDescription
.mFormatFlags
= kAudioFormatFlagsCanonical
;
148 ioDescription
.mBytesPerPacket
= sizeof(AudioSampleType
) * ioDescription
.mChannelsPerFrame
;
149 ioDescription
.mFramesPerPacket
= 1;
150 ioDescription
.mBytesPerFrame
= sizeof(AudioSampleType
) * ioDescription
.mChannelsPerFrame
;
151 ioDescription
.mBitsPerChannel
= 8 * sizeof(AudioSampleType
);
155 void CAStreamBasicDescription::ResetFormat(AudioStreamBasicDescription
& ioDescription
)
157 ioDescription
.mSampleRate
= 0;
158 ioDescription
.mFormatID
= 0;
159 ioDescription
.mBytesPerPacket
= 0;
160 ioDescription
.mFramesPerPacket
= 0;
161 ioDescription
.mBytesPerFrame
= 0;
162 ioDescription
.mChannelsPerFrame
= 0;
163 ioDescription
.mBitsPerChannel
= 0;
164 ioDescription
.mFormatFlags
= 0;
167 void CAStreamBasicDescription::FillOutFormat(AudioStreamBasicDescription
& ioDescription
, const AudioStreamBasicDescription
& inTemplateDescription
)
169 if(fiszero(ioDescription
.mSampleRate
))
171 ioDescription
.mSampleRate
= inTemplateDescription
.mSampleRate
;
173 if(ioDescription
.mFormatID
== 0)
175 ioDescription
.mFormatID
= inTemplateDescription
.mFormatID
;
177 if(ioDescription
.mFormatFlags
== 0)
179 ioDescription
.mFormatFlags
= inTemplateDescription
.mFormatFlags
;
181 if(ioDescription
.mBytesPerPacket
== 0)
183 ioDescription
.mBytesPerPacket
= inTemplateDescription
.mBytesPerPacket
;
185 if(ioDescription
.mFramesPerPacket
== 0)
187 ioDescription
.mFramesPerPacket
= inTemplateDescription
.mFramesPerPacket
;
189 if(ioDescription
.mBytesPerFrame
== 0)
191 ioDescription
.mBytesPerFrame
= inTemplateDescription
.mBytesPerFrame
;
193 if(ioDescription
.mChannelsPerFrame
== 0)
195 ioDescription
.mChannelsPerFrame
= inTemplateDescription
.mChannelsPerFrame
;
197 if(ioDescription
.mBitsPerChannel
== 0)
199 ioDescription
.mBitsPerChannel
= inTemplateDescription
.mBitsPerChannel
;
203 void CAStreamBasicDescription::GetSimpleName(const AudioStreamBasicDescription
& inDescription
, char* outName
, bool inAbbreviate
)
205 switch(inDescription
.mFormatID
)
207 case kAudioFormatLinearPCM
:
209 const char* theEndianString
= NULL
;
210 if((inDescription
.mFormatFlags
& kAudioFormatFlagIsBigEndian
) != 0)
212 #if TARGET_RT_LITTLE_ENDIAN
213 theEndianString
= "Big Endian";
218 #if TARGET_RT_BIG_ENDIAN
219 theEndianString
= "Little Endian";
223 const char* theKindString
= NULL
;
224 if((inDescription
.mFormatFlags
& kAudioFormatFlagIsFloat
) != 0)
226 theKindString
= (inAbbreviate
? "Float" : "Floating Point");
228 else if((inDescription
.mFormatFlags
& kAudioFormatFlagIsSignedInteger
) != 0)
230 theKindString
= (inAbbreviate
? "SInt" : "Signed Integer");
234 theKindString
= (inAbbreviate
? "UInt" : "Unsigned Integer");
237 const char* thePackingString
= NULL
;
238 if((inDescription
.mFormatFlags
& kAudioFormatFlagIsPacked
) == 0)
240 if((inDescription
.mFormatFlags
& kAudioFormatFlagIsAlignedHigh
) != 0)
242 thePackingString
= "High";
246 thePackingString
= "Low";
250 const char* theMixabilityString
= NULL
;
251 if((inDescription
.mFormatFlags
& kIsNonMixableFlag
) == 0)
253 theMixabilityString
= "Mixable";
257 theMixabilityString
= "Unmixable";
262 if(theEndianString
!= NULL
)
264 if(thePackingString
!= NULL
)
266 sprintf(outName
, "%s %d Ch %s %s %s%d/%s%d", theMixabilityString
, (int)inDescription
.mChannelsPerFrame
, theEndianString
, thePackingString
, theKindString
, (int)inDescription
.mBitsPerChannel
, theKindString
, (int)(inDescription
.mBytesPerFrame
/ inDescription
.mChannelsPerFrame
) * 8);
270 sprintf(outName
, "%s %d Ch %s %s%d", theMixabilityString
, (int)inDescription
.mChannelsPerFrame
, theEndianString
, theKindString
, (int)inDescription
.mBitsPerChannel
);
275 if(thePackingString
!= NULL
)
277 sprintf(outName
, "%s %d Ch %s %s%d/%s%d", theMixabilityString
, (int)inDescription
.mChannelsPerFrame
, thePackingString
, theKindString
, (int)inDescription
.mBitsPerChannel
, theKindString
, (int)((inDescription
.mBytesPerFrame
/ inDescription
.mChannelsPerFrame
) * 8));
281 sprintf(outName
, "%s %d Ch %s%d", theMixabilityString
, (int)inDescription
.mChannelsPerFrame
, theKindString
, (int)inDescription
.mBitsPerChannel
);
287 if(theEndianString
!= NULL
)
289 if(thePackingString
!= NULL
)
291 sprintf(outName
, "%s %d Channel %d Bit %s %s Aligned %s in %d Bits", theMixabilityString
, (int)inDescription
.mChannelsPerFrame
, (int)inDescription
.mBitsPerChannel
, theEndianString
, theKindString
, thePackingString
, (int)(inDescription
.mBytesPerFrame
/ inDescription
.mChannelsPerFrame
) * 8);
295 sprintf(outName
, "%s %d Channel %d Bit %s %s", theMixabilityString
, (int)inDescription
.mChannelsPerFrame
, (int)inDescription
.mBitsPerChannel
, theEndianString
, theKindString
);
300 if(thePackingString
!= NULL
)
302 sprintf(outName
, "%s %d Channel %d Bit %s Aligned %s in %d Bits", theMixabilityString
, (int)inDescription
.mChannelsPerFrame
, (int)inDescription
.mBitsPerChannel
, theKindString
, thePackingString
, (int)(inDescription
.mBytesPerFrame
/ inDescription
.mChannelsPerFrame
) * 8);
306 sprintf(outName
, "%s %d Channel %d Bit %s", theMixabilityString
, (int)inDescription
.mChannelsPerFrame
, (int)inDescription
.mBitsPerChannel
, theKindString
);
313 case kAudioFormatAC3
:
314 strcpy(outName
, "AC-3");
317 case kAudioFormat60958AC3
:
318 strcpy(outName
, "AC-3 for SPDIF");
322 CACopy4CCToCString(outName
, inDescription
.mFormatID
);
328 #include "CALogMacros.h"
330 void CAStreamBasicDescription::PrintToLog(const AudioStreamBasicDescription
& inDesc
)
332 PrintFloat (" Sample Rate: ", inDesc
.mSampleRate
);
333 Print4CharCode (" Format ID: ", inDesc
.mFormatID
);
334 PrintHex (" Format Flags: ", inDesc
.mFormatFlags
);
335 PrintInt (" Bytes per Packet: ", inDesc
.mBytesPerPacket
);
336 PrintInt (" Frames per Packet: ", inDesc
.mFramesPerPacket
);
337 PrintInt (" Bytes per Frame: ", inDesc
.mBytesPerFrame
);
338 PrintInt (" Channels per Frame: ", inDesc
.mChannelsPerFrame
);
339 PrintInt (" Bits per Channel: ", inDesc
.mBitsPerChannel
);
343 bool operator<(const AudioStreamBasicDescription
& x
, const AudioStreamBasicDescription
& y
)
345 bool theAnswer
= false;
348 // note that if either side is 0, that field is skipped
350 // format ID is the first order sort
351 if((!isDone
) && ((x
.mFormatID
!= 0) && (y
.mFormatID
!= 0)))
353 if(x
.mFormatID
!= y
.mFormatID
)
355 // formats are sorted numerically except that linear
356 // PCM is always first
357 if(x
.mFormatID
== kAudioFormatLinearPCM
)
361 else if(y
.mFormatID
== kAudioFormatLinearPCM
)
367 theAnswer
= x
.mFormatID
< y
.mFormatID
;
374 // mixable is always better than non-mixable for linear PCM and should be the second order sort item
375 if((!isDone
) && ((x
.mFormatID
== kAudioFormatLinearPCM
) && (y
.mFormatID
== kAudioFormatLinearPCM
)))
377 if(((x
.mFormatFlags
& kIsNonMixableFlag
) == 0) && ((y
.mFormatFlags
& kIsNonMixableFlag
) != 0))
382 else if(((x
.mFormatFlags
& kIsNonMixableFlag
) != 0) && ((y
.mFormatFlags
& kIsNonMixableFlag
) == 0))
389 // floating point vs integer for linear PCM only
390 if((!isDone
) && ((x
.mFormatID
== kAudioFormatLinearPCM
) && (y
.mFormatID
== kAudioFormatLinearPCM
)))
392 if((x
.mFormatFlags
& kAudioFormatFlagIsFloat
) != (y
.mFormatFlags
& kAudioFormatFlagIsFloat
))
394 // floating point is better than integer
395 theAnswer
= y
.mFormatFlags
& kAudioFormatFlagIsFloat
;
401 if((!isDone
) && ((x
.mBitsPerChannel
!= 0) && (y
.mBitsPerChannel
!= 0)))
403 if(x
.mBitsPerChannel
!= y
.mBitsPerChannel
)
405 // deeper bit depths are higher quality
406 theAnswer
= x
.mBitsPerChannel
< y
.mBitsPerChannel
;
412 if((!isDone
) && fnonzero(x
.mSampleRate
) && fnonzero(y
.mSampleRate
))
414 if(fnotequal(x
.mSampleRate
, y
.mSampleRate
))
416 // higher sample rates are higher quality
417 theAnswer
= x
.mSampleRate
< y
.mSampleRate
;
422 // number of channels
423 if((!isDone
) && ((x
.mChannelsPerFrame
!= 0) && (y
.mChannelsPerFrame
!= 0)))
425 if(x
.mChannelsPerFrame
!= y
.mChannelsPerFrame
)
427 // more channels is higher quality
428 theAnswer
= x
.mChannelsPerFrame
< y
.mChannelsPerFrame
;
436 static bool MatchFormatFlags(const AudioStreamBasicDescription
& x
, const AudioStreamBasicDescription
& y
)
438 UInt32 xFlags
= x
.mFormatFlags
;
439 UInt32 yFlags
= y
.mFormatFlags
;
442 if (x
.mFormatID
== 0 || y
.mFormatID
== 0 || xFlags
== 0 || yFlags
== 0)
445 if (x
.mFormatID
== kAudioFormatLinearPCM
)
447 // knock off the all clear flag
448 xFlags
= xFlags
& ~kAudioFormatFlagsAreAllClear
;
449 yFlags
= yFlags
& ~kAudioFormatFlagsAreAllClear
;
451 // if both kAudioFormatFlagIsPacked bits are set, then we don't care about the kAudioFormatFlagIsAlignedHigh bit.
452 if (xFlags
& yFlags
& kAudioFormatFlagIsPacked
) {
453 xFlags
= xFlags
& ~kAudioFormatFlagIsAlignedHigh
;
454 yFlags
= yFlags
& ~kAudioFormatFlagIsAlignedHigh
;
457 // if both kAudioFormatFlagIsFloat bits are set, then we don't care about the kAudioFormatFlagIsSignedInteger bit.
458 if (xFlags
& yFlags
& kAudioFormatFlagIsFloat
) {
459 xFlags
= xFlags
& ~kAudioFormatFlagIsSignedInteger
;
460 yFlags
= yFlags
& ~kAudioFormatFlagIsSignedInteger
;
463 // if the bit depth is 8 bits or less and the format is packed, we don't care about endianness
464 if((x
.mBitsPerChannel
<= 8) && ((xFlags
& kAudioFormatFlagIsPacked
) == kAudioFormatFlagIsPacked
))
466 xFlags
= xFlags
& ~kAudioFormatFlagIsBigEndian
;
468 if((y
.mBitsPerChannel
<= 8) && ((yFlags
& kAudioFormatFlagIsPacked
) == kAudioFormatFlagIsPacked
))
470 yFlags
= yFlags
& ~kAudioFormatFlagIsBigEndian
;
473 // if the number of channels is 0 or 1, we don't care about non-interleavedness
474 if (x
.mChannelsPerFrame
<= 1 && y
.mChannelsPerFrame
<= 1) {
475 xFlags
&= ~kLinearPCMFormatFlagIsNonInterleaved
;
476 yFlags
&= ~kLinearPCMFormatFlagIsNonInterleaved
;
479 return xFlags
== yFlags
;
482 bool operator==(const AudioStreamBasicDescription
& x
, const AudioStreamBasicDescription
& y
)
484 // the semantics for equality are:
485 // 1) Values must match exactly
486 // 2) wildcard's are ignored in the comparison
488 #define MATCH(name) ((x.name) == 0 || (y.name) == 0 || (x.name) == (y.name))
491 // check the sample rate
492 (fiszero(x
.mSampleRate
) || fiszero(y
.mSampleRate
) || fequal(x
.mSampleRate
, y
.mSampleRate
))
494 // check the format ids
497 // check the format flags
498 && MatchFormatFlags(x
, y
)
500 // check the bytes per packet
501 && MATCH(mBytesPerPacket
)
503 // check the frames per packet
504 && MATCH(mFramesPerPacket
)
506 // check the bytes per frame
507 && MATCH(mBytesPerFrame
)
509 // check the channels per frame
510 && MATCH(mChannelsPerFrame
)
512 // check the channels per frame
513 && MATCH(mBitsPerChannel
) ;
516 bool CAStreamBasicDescription::IsEqual(const AudioStreamBasicDescription
&other
, bool interpretingWildcards
) const
518 if (interpretingWildcards
)
519 return *this == other
;
520 return memcmp(this, &other
, offsetof(AudioStreamBasicDescription
, mReserved
)) == 0;
523 bool SanityCheck(const AudioStreamBasicDescription
& x
)
525 return (x
.mSampleRate
>= 0.);