Jamoma API  0.6.0.a19
CAStreamBasicDescription.cpp
1 /* Copyright 2007 Apple Inc. All Rights Reserved.
2 
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.
9 
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.
25 
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.
31 
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.
40 */
41 #include "CAStreamBasicDescription.h"
42 #include "CAMath.h"
43 
44 #if !defined(__COREAUDIO_USE_FLAT_INCLUDES__)
45  #include <CoreFoundation/CFByteOrder.h>
46 #else
47  #include <CFByteOrder.h>
48 #endif
49 
50 #pragma mark This file needs to compile on earlier versions of the OS, so please keep that in mind when editing it
51 
52 char *CAStringForOSType (OSType t, char *writeLocation)
53 {
54  char *p = writeLocation;
55  unsigned char str[4], *q = str;
56  *(UInt32 *)str = CFSwapInt32HostToBig(t);
57 
58  bool hasNonPrint = false;
59  for (int i = 0; i < 4; ++i) {
60  if (!(isprint(*q) && *q != '\\')) {
61  hasNonPrint = true;
62  break;
63  }
64  }
65 
66  if (hasNonPrint)
67  p += sprintf (p, "0x");
68  else
69  *p++ = '\'';
70 
71  for (int i = 0; i < 4; ++i) {
72  if (hasNonPrint) {
73  p += sprintf(p, "%02X", *q++);
74  } else {
75  *p++ = *q++;
76  }
77  }
78  if (!hasNonPrint)
79  *p++ = '\'';
80  *p = '\0';
81  return writeLocation;
82 }
83 
84 
85 const AudioStreamBasicDescription CAStreamBasicDescription::sEmpty = { 0.0, 0, 0, 0, 0, 0, 0, 0, 0 };
86 
87 CAStreamBasicDescription::CAStreamBasicDescription(double inSampleRate, UInt32 inFormatID,
88  UInt32 inBytesPerPacket, UInt32 inFramesPerPacket,
89  UInt32 inBytesPerFrame, UInt32 inChannelsPerFrame,
90  UInt32 inBitsPerChannel, UInt32 inFormatFlags)
91 {
92  mSampleRate = inSampleRate;
93  mFormatID = inFormatID;
94  mBytesPerPacket = inBytesPerPacket;
95  mFramesPerPacket = inFramesPerPacket;
96  mBytesPerFrame = inBytesPerFrame;
97  mChannelsPerFrame = inChannelsPerFrame;
98  mBitsPerChannel = inBitsPerChannel;
99  mFormatFlags = inFormatFlags;
100  mReserved = 0;
101 }
102 
103 char *CAStreamBasicDescription::AsString(char *buf, size_t _bufsize) const
104 {
105  int bufsize = (int)_bufsize; // must be signed to protect against overflow
106  char *theBuffer = buf;
107  int nc;
108  char formatID[24];
109  CAStringForOSType (mFormatID, formatID);
110  nc = snprintf(buf, bufsize, "%2d ch, %6.0f Hz, %s (0x%08X) ", (int)NumberChannels(), mSampleRate, formatID, (int)mFormatFlags);
111  buf += nc; if ((bufsize -= nc) <= 0) goto exit;
112  if (mFormatID == kAudioFormatLinearPCM) {
113  bool isInt = !(mFormatFlags & kLinearPCMFormatFlagIsFloat);
114  int wordSize = SampleWordSize();
115  const char *endian = (wordSize > 1) ?
116  ((mFormatFlags & kLinearPCMFormatFlagIsBigEndian) ? " big-endian" : " little-endian" ) : "";
117  const char *sign = isInt ?
118  ((mFormatFlags & kLinearPCMFormatFlagIsSignedInteger) ? " signed" : " unsigned") : "";
119  const char *floatInt = isInt ? "integer" : "float";
120  char packed[32];
121  if (wordSize > 0 && PackednessIsSignificant()) {
122  if (mFormatFlags & kLinearPCMFormatFlagIsPacked)
123  snprintf(packed, sizeof(packed), "packed in %d bytes", wordSize);
124  else
125  snprintf(packed, sizeof(packed), "unpacked in %d bytes", wordSize);
126  } else
127  packed[0] = '\0';
128  const char *align = (wordSize > 0 && AlignmentIsSignificant()) ?
129  ((mFormatFlags & kLinearPCMFormatFlagIsAlignedHigh) ? " high-aligned" : " low-aligned") : "";
130  const char *deinter = (mFormatFlags & kAudioFormatFlagIsNonInterleaved) ? ", deinterleaved" : "";
131  const char *commaSpace = (packed[0]!='\0') || (align[0]!='\0') ? ", " : "";
132  char bitdepth[20];
133 
134  int fracbits = (mFormatFlags & kLinearPCMFormatFlagsSampleFractionMask) >> kLinearPCMFormatFlagsSampleFractionShift;
135  if (fracbits > 0)
136  snprintf(bitdepth, sizeof(bitdepth), "%d.%d", (int)mBitsPerChannel - fracbits, fracbits);
137  else
138  snprintf(bitdepth, sizeof(bitdepth), "%d", (int)mBitsPerChannel);
139 
140  nc = snprintf(buf, bufsize, "%s-bit%s%s %s%s%s%s%s",
141  bitdepth, endian, sign, floatInt,
142  commaSpace, packed, align, deinter);
143  // buf += nc; if ((bufsize -= nc) <= 0) goto exit;
144  } else if (mFormatID == 'alac') { // kAudioFormatAppleLossless
145  int sourceBits = 0;
146  switch (mFormatFlags)
147  {
148  case 1: // kAppleLosslessFormatFlag_16BitSourceData
149  sourceBits = 16;
150  break;
151  case 2: // kAppleLosslessFormatFlag_20BitSourceData
152  sourceBits = 20;
153  break;
154  case 3: // kAppleLosslessFormatFlag_24BitSourceData
155  sourceBits = 24;
156  break;
157  case 4: // kAppleLosslessFormatFlag_32BitSourceData
158  sourceBits = 32;
159  break;
160  }
161  if (sourceBits)
162  nc = snprintf(buf, bufsize, "from %d-bit source, ", sourceBits);
163  else
164  nc = snprintf(buf, bufsize, "from UNKNOWN source bit depth, ");
165  buf += nc; if ((bufsize -= nc) <= 0) goto exit;
166  nc = snprintf(buf, bufsize, "%d frames/packet", (int)mFramesPerPacket);
167  // buf += nc; if ((bufsize -= nc) <= 0) goto exit;
168  }
169  else
170  nc = snprintf(buf, bufsize, "%d bits/channel, %d bytes/packet, %d frames/packet, %d bytes/frame",
171  (int)mBitsPerChannel, (int)mBytesPerPacket, (int)mFramesPerPacket, (int)mBytesPerFrame);
172 exit:
173  return theBuffer;
174 }
175 
176 void CAStreamBasicDescription::NormalizeLinearPCMFormat(AudioStreamBasicDescription& ioDescription)
177 {
178  // the only thing that changes is to make mixable linear PCM into the canonical linear PCM format
179  if((ioDescription.mFormatID == kAudioFormatLinearPCM) && ((ioDescription.mFormatFlags & kIsNonMixableFlag) == 0))
180  {
181  // the canonical linear PCM format
182  ioDescription.mFormatFlags = kAudioFormatFlagsCanonical;
183  ioDescription.mBytesPerPacket = SizeOf32(AudioSampleType) * ioDescription.mChannelsPerFrame;
184  ioDescription.mFramesPerPacket = 1;
185  ioDescription.mBytesPerFrame = SizeOf32(AudioSampleType) * ioDescription.mChannelsPerFrame;
186  ioDescription.mBitsPerChannel = 8 * SizeOf32(AudioSampleType);
187  }
188 }
189 
190 void CAStreamBasicDescription::ResetFormat(AudioStreamBasicDescription& ioDescription)
191 {
192  ioDescription.mSampleRate = 0;
193  ioDescription.mFormatID = 0;
194  ioDescription.mBytesPerPacket = 0;
195  ioDescription.mFramesPerPacket = 0;
196  ioDescription.mBytesPerFrame = 0;
197  ioDescription.mChannelsPerFrame = 0;
198  ioDescription.mBitsPerChannel = 0;
199  ioDescription.mFormatFlags = 0;
200 }
201 
202 void CAStreamBasicDescription::FillOutFormat(AudioStreamBasicDescription& ioDescription, const AudioStreamBasicDescription& inTemplateDescription)
203 {
204  if(fiszero(ioDescription.mSampleRate))
205  {
206  ioDescription.mSampleRate = inTemplateDescription.mSampleRate;
207  }
208  if(ioDescription.mFormatID == 0)
209  {
210  ioDescription.mFormatID = inTemplateDescription.mFormatID;
211  }
212  if(ioDescription.mFormatFlags == 0)
213  {
214  ioDescription.mFormatFlags = inTemplateDescription.mFormatFlags;
215  }
216  if(ioDescription.mBytesPerPacket == 0)
217  {
218  ioDescription.mBytesPerPacket = inTemplateDescription.mBytesPerPacket;
219  }
220  if(ioDescription.mFramesPerPacket == 0)
221  {
222  ioDescription.mFramesPerPacket = inTemplateDescription.mFramesPerPacket;
223  }
224  if(ioDescription.mBytesPerFrame == 0)
225  {
226  ioDescription.mBytesPerFrame = inTemplateDescription.mBytesPerFrame;
227  }
228  if(ioDescription.mChannelsPerFrame == 0)
229  {
230  ioDescription.mChannelsPerFrame = inTemplateDescription.mChannelsPerFrame;
231  }
232  if(ioDescription.mBitsPerChannel == 0)
233  {
234  ioDescription.mBitsPerChannel = inTemplateDescription.mBitsPerChannel;
235  }
236 }
237 
238 void CAStreamBasicDescription::GetSimpleName(const AudioStreamBasicDescription& inDescription, char* outName, UInt32 inMaxNameLength, bool inAbbreviate)
239 {
240  switch(inDescription.mFormatID)
241  {
242  case kAudioFormatLinearPCM:
243  {
244  const char* theEndianString = NULL;
245  if((inDescription.mFormatFlags & kAudioFormatFlagIsBigEndian) != 0)
246  {
247  #if TARGET_RT_LITTLE_ENDIAN
248  theEndianString = "Big Endian";
249  #endif
250  }
251  else
252  {
253  #if TARGET_RT_BIG_ENDIAN
254  theEndianString = "Little Endian";
255  #endif
256  }
257 
258  const char* theKindString = NULL;
259  if((inDescription.mFormatFlags & kAudioFormatFlagIsFloat) != 0)
260  {
261  theKindString = (inAbbreviate ? "Float" : "Floating Point");
262  }
263  else if((inDescription.mFormatFlags & kAudioFormatFlagIsSignedInteger) != 0)
264  {
265  theKindString = (inAbbreviate ? "SInt" : "Signed Integer");
266  }
267  else
268  {
269  theKindString = (inAbbreviate ? "UInt" : "Unsigned Integer");
270  }
271 
272  const char* thePackingString = NULL;
273  if((inDescription.mFormatFlags & kAudioFormatFlagIsPacked) == 0)
274  {
275  if((inDescription.mFormatFlags & kAudioFormatFlagIsAlignedHigh) != 0)
276  {
277  thePackingString = "High";
278  }
279  else
280  {
281  thePackingString = "Low";
282  }
283  }
284 
285  const char* theMixabilityString = NULL;
286  if((inDescription.mFormatFlags & kIsNonMixableFlag) == 0)
287  {
288  theMixabilityString = "Mixable";
289  }
290  else
291  {
292  theMixabilityString = "Unmixable";
293  }
294 
295  if(inAbbreviate)
296  {
297  if(theEndianString != NULL)
298  {
299  if(thePackingString != NULL)
300  {
301  snprintf(outName, inMaxNameLength, "%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);
302  }
303  else
304  {
305  snprintf(outName, inMaxNameLength, "%s %d Ch %s %s%d", theMixabilityString, (int)inDescription.mChannelsPerFrame, theEndianString, theKindString, (int)inDescription.mBitsPerChannel);
306  }
307  }
308  else
309  {
310  if(thePackingString != NULL)
311  {
312  snprintf(outName, inMaxNameLength, "%s %d Ch %s %s%d/%s%d", theMixabilityString, (int)inDescription.mChannelsPerFrame, thePackingString, theKindString, (int)inDescription.mBitsPerChannel, theKindString, (int)((inDescription.mBytesPerFrame / inDescription.mChannelsPerFrame) * 8));
313  }
314  else
315  {
316  snprintf(outName, inMaxNameLength, "%s %d Ch %s%d", theMixabilityString, (int)inDescription.mChannelsPerFrame, theKindString, (int)inDescription.mBitsPerChannel);
317  }
318  }
319  }
320  else
321  {
322  if(theEndianString != NULL)
323  {
324  if(thePackingString != NULL)
325  {
326  snprintf(outName, inMaxNameLength, "%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);
327  }
328  else
329  {
330  snprintf(outName, inMaxNameLength, "%s %d Channel %d Bit %s %s", theMixabilityString, (int)inDescription.mChannelsPerFrame, (int)inDescription.mBitsPerChannel, theEndianString, theKindString);
331  }
332  }
333  else
334  {
335  if(thePackingString != NULL)
336  {
337  snprintf(outName, inMaxNameLength, "%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);
338  }
339  else
340  {
341  snprintf(outName, inMaxNameLength, "%s %d Channel %d Bit %s", theMixabilityString, (int)inDescription.mChannelsPerFrame, (int)inDescription.mBitsPerChannel, theKindString);
342  }
343  }
344  }
345  }
346  break;
347 
348  case kAudioFormatAC3:
349  strlcpy(outName, "AC-3", sizeof(outName));
350  break;
351 
352  case kAudioFormat60958AC3:
353  strlcpy(outName, "AC-3 for SPDIF", sizeof(outName));
354  break;
355 
356  default:
357  CACopy4CCToCString(outName, inDescription.mFormatID);
358  break;
359  };
360 }
361 
362 #if CoreAudio_Debug
363 #include "CALogMacros.h"
364 
365 void CAStreamBasicDescription::PrintToLog(const AudioStreamBasicDescription& inDesc)
366 {
367  PrintFloat (" Sample Rate: ", inDesc.mSampleRate);
368  Print4CharCode (" Format ID: ", inDesc.mFormatID);
369  PrintHex (" Format Flags: ", inDesc.mFormatFlags);
370  PrintInt (" Bytes per Packet: ", inDesc.mBytesPerPacket);
371  PrintInt (" Frames per Packet: ", inDesc.mFramesPerPacket);
372  PrintInt (" Bytes per Frame: ", inDesc.mBytesPerFrame);
373  PrintInt (" Channels per Frame: ", inDesc.mChannelsPerFrame);
374  PrintInt (" Bits per Channel: ", inDesc.mBitsPerChannel);
375 }
376 #endif
377 
378 bool operator<(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y)
379 {
380  bool theAnswer = false;
381  bool isDone = false;
382 
383  // note that if either side is 0, that field is skipped
384 
385  // format ID is the first order sort
386  if((!isDone) && ((x.mFormatID != 0) && (y.mFormatID != 0)))
387  {
388  if(x.mFormatID != y.mFormatID)
389  {
390  // formats are sorted numerically except that linear
391  // PCM is always first
392  if(x.mFormatID == kAudioFormatLinearPCM)
393  {
394  theAnswer = true;
395  }
396  else if(y.mFormatID == kAudioFormatLinearPCM)
397  {
398  theAnswer = false;
399  }
400  else
401  {
402  theAnswer = x.mFormatID < y.mFormatID;
403  }
404  isDone = true;
405  }
406  }
407 
408 
409  // mixable is always better than non-mixable for linear PCM and should be the second order sort item
410  if((!isDone) && ((x.mFormatID == kAudioFormatLinearPCM) && (y.mFormatID == kAudioFormatLinearPCM)))
411  {
412  if(((x.mFormatFlags & kIsNonMixableFlag) == 0) && ((y.mFormatFlags & kIsNonMixableFlag) != 0))
413  {
414  theAnswer = true;
415  isDone = true;
416  }
417  else if(((x.mFormatFlags & kIsNonMixableFlag) != 0) && ((y.mFormatFlags & kIsNonMixableFlag) == 0))
418  {
419  theAnswer = false;
420  isDone = true;
421  }
422  }
423 
424  // floating point vs integer for linear PCM only
425  if((!isDone) && ((x.mFormatID == kAudioFormatLinearPCM) && (y.mFormatID == kAudioFormatLinearPCM)))
426  {
427  if((x.mFormatFlags & kAudioFormatFlagIsFloat) != (y.mFormatFlags & kAudioFormatFlagIsFloat))
428  {
429  // floating point is better than integer
430  theAnswer = y.mFormatFlags & kAudioFormatFlagIsFloat;
431  isDone = true;
432  }
433  }
434 
435  // bit depth
436  if((!isDone) && ((x.mBitsPerChannel != 0) && (y.mBitsPerChannel != 0)))
437  {
438  if(x.mBitsPerChannel != y.mBitsPerChannel)
439  {
440  // deeper bit depths are higher quality
441  theAnswer = x.mBitsPerChannel < y.mBitsPerChannel;
442  isDone = true;
443  }
444  }
445 
446  // sample rate
447  if((!isDone) && fnonzero(x.mSampleRate) && fnonzero(y.mSampleRate))
448  {
449  if(fnotequal(x.mSampleRate, y.mSampleRate))
450  {
451  // higher sample rates are higher quality
452  theAnswer = x.mSampleRate < y.mSampleRate;
453  isDone = true;
454  }
455  }
456 
457  // number of channels
458  if((!isDone) && ((x.mChannelsPerFrame != 0) && (y.mChannelsPerFrame != 0)))
459  {
460  if(x.mChannelsPerFrame != y.mChannelsPerFrame)
461  {
462  // more channels is higher quality
463  theAnswer = x.mChannelsPerFrame < y.mChannelsPerFrame;
464  isDone = true;
465  }
466  }
467 
468  return theAnswer;
469 }
470 
471 static bool MatchFormatFlags(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y)
472 {
473  UInt32 xFlags = x.mFormatFlags;
474  UInt32 yFlags = y.mFormatFlags;
475 
476  // match wildcards
477  if (x.mFormatID == 0 || y.mFormatID == 0 || xFlags == 0 || yFlags == 0)
478  return true;
479 
480  if (x.mFormatID == kAudioFormatLinearPCM)
481  {
482  // knock off the all clear flag
483  xFlags = xFlags & ~kAudioFormatFlagsAreAllClear;
484  yFlags = yFlags & ~kAudioFormatFlagsAreAllClear;
485 
486  // if both kAudioFormatFlagIsPacked bits are set, then we don't care about the kAudioFormatFlagIsAlignedHigh bit.
487  if (xFlags & yFlags & kAudioFormatFlagIsPacked) {
488  xFlags = xFlags & ~kAudioFormatFlagIsAlignedHigh;
489  yFlags = yFlags & ~kAudioFormatFlagIsAlignedHigh;
490  }
491 
492  // if both kAudioFormatFlagIsFloat bits are set, then we don't care about the kAudioFormatFlagIsSignedInteger bit.
493  if (xFlags & yFlags & kAudioFormatFlagIsFloat) {
494  xFlags = xFlags & ~kAudioFormatFlagIsSignedInteger;
495  yFlags = yFlags & ~kAudioFormatFlagIsSignedInteger;
496  }
497 
498  // if the bit depth is 8 bits or less and the format is packed, we don't care about endianness
499  if((x.mBitsPerChannel <= 8) && ((xFlags & kAudioFormatFlagIsPacked) == kAudioFormatFlagIsPacked))
500  {
501  xFlags = xFlags & ~kAudioFormatFlagIsBigEndian;
502  }
503  if((y.mBitsPerChannel <= 8) && ((yFlags & kAudioFormatFlagIsPacked) == kAudioFormatFlagIsPacked))
504  {
505  yFlags = yFlags & ~kAudioFormatFlagIsBigEndian;
506  }
507 
508  // if the number of channels is 0 or 1, we don't care about non-interleavedness
509  if (x.mChannelsPerFrame <= 1 && y.mChannelsPerFrame <= 1) {
510  xFlags &= ~kLinearPCMFormatFlagIsNonInterleaved;
511  yFlags &= ~kLinearPCMFormatFlagIsNonInterleaved;
512  }
513  }
514  return xFlags == yFlags;
515 }
516 
517 bool operator==(const AudioStreamBasicDescription& x, const AudioStreamBasicDescription& y)
518 {
519  // the semantics for equality are:
520  // 1) Values must match exactly
521  // 2) wildcard's are ignored in the comparison
522 
523 #define MATCH(name) ((x.name) == 0 || (y.name) == 0 || (x.name) == (y.name))
524 
525  return
526  // check the sample rate
527  (fiszero(x.mSampleRate) || fiszero(y.mSampleRate) || fequal(x.mSampleRate, y.mSampleRate))
528 
529  // check the format ids
530  && MATCH(mFormatID)
531 
532  // check the format flags
533  && MatchFormatFlags(x, y)
534 
535  // check the bytes per packet
536  && MATCH(mBytesPerPacket)
537 
538  // check the frames per packet
539  && MATCH(mFramesPerPacket)
540 
541  // check the bytes per frame
542  && MATCH(mBytesPerFrame)
543 
544  // check the channels per frame
545  && MATCH(mChannelsPerFrame)
546 
547  // check the channels per frame
548  && MATCH(mBitsPerChannel) ;
549 }
550 
551 bool CAStreamBasicDescription::IsEqual(const AudioStreamBasicDescription &other, bool interpretingWildcards) const
552 {
553  if (interpretingWildcards)
554  return *this == other;
555  return memcmp(this, &other, offsetof(AudioStreamBasicDescription, mReserved)) == 0;
556 }
557 
558 bool SanityCheck(const AudioStreamBasicDescription& x)
559 {
560  // This function returns false if there are sufficiently insane values in any field.
561  // It is very conservative so even some very unlikely values will pass.
562  // This is just meant to catch the case where the data from a file is corrupted.
563 
564  return
565  (x.mSampleRate >= 0.)
566  && (x.mBytesPerPacket < 1000000)
567  && (x.mFramesPerPacket < 1000000)
568  && (x.mBytesPerFrame < 1000000)
569  && (x.mChannelsPerFrame <= 1024)
570  && (x.mBitsPerChannel <= 1024)
571  && (x.mFormatID != 0)
572  && !(x.mFormatID == kAudioFormatLinearPCM && (x.mFramesPerPacket != 1 || x.mBytesPerPacket != x.mBytesPerFrame));
573 }
bool TTFOUNDATION_EXPORT operator==(const TTObject &anObject, const TTObject &anotherObject)
Compare two objects for equality.
Definition: TTObject.cpp:167