1 /*
2 File: AudioFileObject.cpp
3 Abstract: AudioFileObject.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 "AudioFileObject.h"
48 #include "CADebugMacros.h"
49 #include <algorithm>
50 #include <sys/stat.h>
51
52 #define kAudioFileNoCacheMask 0x20
53
54 const SInt64 kScanToEnd = 0x7fffFFFFffffFFFFLL;
55
56 //////////////////////////////////////////////////////////////////////////////////////////////////////////
57
~AudioFileObject()58 AudioFileObject::~AudioFileObject()
59 {
60 delete mDataSource;
61 DeletePacketTable();
62 SetURL(NULL);
63 }
64
65 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
66
DoCreate(CFURLRef inFileRef,const AudioStreamBasicDescription * inFormat,UInt32 inFlags)67 OSStatus AudioFileObject::DoCreate(
68 CFURLRef inFileRef,
69 const AudioStreamBasicDescription *inFormat,
70 UInt32 inFlags)
71 {
72 // common prologue
73 if (!IsDataFormatValid(inFormat))
74 return kAudioFileUnsupportedDataFormatError;
75
76 if (!IsDataFormatSupported(inFormat))
77 return kAudioFileUnsupportedDataFormatError;
78
79 SetPermissions(kAudioFileReadWritePermission);
80
81 SetAlignDataWithFillerChunks(!(inFlags & 2 /* kAudioFileFlags_DontPageAlignAudioData */ ));
82
83 // call virtual method for particular format.
84 return Create(inFileRef, inFormat);
85 }
86
87 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
88
Create(CFURLRef inFileRef,const AudioStreamBasicDescription * inFormat)89 OSStatus AudioFileObject::Create(
90 CFURLRef inFileRef,
91 const AudioStreamBasicDescription *inFormat)
92 {
93 int fileD;
94 OSStatus err = CreateDataFile (inFileRef, fileD);
95 FailIf (err != noErr, Bail, "CreateDataFile failed");
96
97 SetURL (inFileRef);
98
99 err = OpenFile(kAudioFileReadWritePermission, fileD);
100 FailIf (err != noErr, Bail, "OpenFile failed");
101
102 err = SetDataFormat(inFormat);
103 FailIf (err != noErr, Bail, "SetDataFormat failed");
104
105 mIsInitialized = false;
106
107 Bail:
108 return err;
109 }
110
111 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
112
DoOpen(CFURLRef inFileRef,SInt8 inPermissions,int inFD)113 OSStatus AudioFileObject::DoOpen(
114 CFURLRef inFileRef,
115 SInt8 inPermissions,
116 int inFD)
117 {
118 OSStatus err = noErr;
119 SetPermissions(inPermissions);
120
121 err = Open(inFileRef, inPermissions, inFD);
122 FailIf (err != noErr, Bail, "Open failed");
123
124 err = ValidateFormatAndData();
125 FailIf (err != noErr, Bail, "ValidateFormatAndData failed");
126
127 Bail:
128 return err;
129 }
130
131 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
132
Open(CFURLRef inFileRef,SInt8 inPermissions,int inFD)133 OSStatus AudioFileObject::Open(
134 CFURLRef inFileRef,
135 SInt8 inPermissions,
136 int inFD)
137 {
138 if (!(inPermissions & kAudioFileReadPermission))
139 return kAudioFilePermissionsError; // file must have read permissions
140
141 SetURL(inFileRef);
142
143 OSStatus err = OpenFile(inPermissions, inFD);
144 FailIf (err != noErr, Bail, "OpenFile failed");
145
146 err = OpenFromDataSource();
147 FailIf (err != noErr, Bail, "OpenFromDataSource failed");
148
149 Bail:
150 return err;
151 }
152
153 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
154
ValidateFormatAndData()155 OSStatus AudioFileObject::ValidateFormatAndData()
156 {
157
158
159 AudioStreamBasicDescription asbd = GetDataFormat();
160
161 if (!IsDataFormatValid(&asbd))
162 return kAudioFileInvalidFileError;
163
164 if (asbd.mFormatID == kAudioFormatLinearPCM)
165 {
166 SInt64 maxPackets = GetNumBytes() / asbd.mBytesPerPacket;
167 if (GetNumPackets() > maxPackets)
168 return kAudioFileInvalidFileError;
169 }
170 return noErr;
171 }
172
173 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
174
DoOpenWithCallbacks(void * inRefCon,AudioFile_ReadProc inReadFunc,AudioFile_WriteProc inWriteFunc,AudioFile_GetSizeProc inGetSizeFunc,AudioFile_SetSizeProc inSetSizeFunc)175 OSStatus AudioFileObject::DoOpenWithCallbacks(
176 void * inRefCon,
177 AudioFile_ReadProc inReadFunc,
178 AudioFile_WriteProc inWriteFunc,
179 AudioFile_GetSizeProc inGetSizeFunc,
180 AudioFile_SetSizeProc inSetSizeFunc)
181 {
182 SInt8 perms = (inSetSizeFunc || inWriteFunc) ? kAudioFileReadWritePermission : kAudioFileReadPermission;
183 SetPermissions(perms);
184
185 DataSource* dataSource = new Seekable_DataSource(inRefCon, inReadFunc, inWriteFunc, inGetSizeFunc, inSetSizeFunc);
186 SetDataSource(dataSource);
187 return OpenFromDataSource();
188 }
189
190 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
191
OpenFromDataSource(void)192 OSStatus AudioFileObject::OpenFromDataSource(void)
193 {
194 return noErr;
195 }
196
197
198 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
199
DoInitializeWithCallbacks(void * inRefCon,AudioFile_ReadProc inReadFunc,AudioFile_WriteProc inWriteFunc,AudioFile_GetSizeProc inGetSizeFunc,AudioFile_SetSizeProc inSetSizeFunc,UInt32 inFileType,const AudioStreamBasicDescription * inFormat,UInt32 inFlags)200 OSStatus AudioFileObject::DoInitializeWithCallbacks(
201 void * inRefCon,
202 AudioFile_ReadProc inReadFunc,
203 AudioFile_WriteProc inWriteFunc,
204 AudioFile_GetSizeProc inGetSizeFunc,
205 AudioFile_SetSizeProc inSetSizeFunc,
206 UInt32 inFileType,
207 const AudioStreamBasicDescription *inFormat,
208 UInt32 inFlags)
209 {
210 DataSource* dataSource = new Seekable_DataSource(inRefCon, inReadFunc, inWriteFunc, inGetSizeFunc, inSetSizeFunc);
211 if (!dataSource->CanWrite()) return -54/*permErr*/;
212 dataSource->SetSize(0);
213 SetDataSource(dataSource);
214 SetPermissions(kAudioFileReadWritePermission);
215
216 SetAlignDataWithFillerChunks(!(inFlags & 2 /* kAudioFileFlags_DontPageAlignAudioData */ ));
217
218 OSStatus err = SetDataFormat(inFormat);
219 if (err) return err;
220
221 return InitializeDataSource(inFormat, inFlags);
222 }
223
224 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
225
DoInitialize(CFURLRef inFileRef,const AudioStreamBasicDescription * inFormat,UInt32 inFlags)226 OSStatus AudioFileObject::DoInitialize(
227 CFURLRef inFileRef,
228 const AudioStreamBasicDescription *inFormat,
229 UInt32 inFlags)
230 {
231 SetURL (inFileRef);
232 SetPermissions(kAudioFileReadWritePermission);
233
234 SetAlignDataWithFillerChunks(!(inFlags & 2 /* kAudioFileFlags_DontPageAlignAudioData */ ));
235
236 return Initialize(inFileRef, inFormat, inFlags);
237 }
238 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
239
Initialize(CFURLRef inFileRef,const AudioStreamBasicDescription * inFormat,UInt32 inFlags)240 OSStatus AudioFileObject::Initialize(
241 CFURLRef inFileRef,
242 const AudioStreamBasicDescription *inFormat,
243 UInt32 inFlags)
244 {
245 OSStatus err = noErr;
246
247 UInt8 fPath[FILENAME_MAX];
248 if (!CFURLGetFileSystemRepresentation (inFileRef, true, fPath, FILENAME_MAX))
249 return kAudio_FileNotFoundError;
250
251 #if TARGET_OS_WIN32
252 int filePerms = 0;
253 int flags = O_TRUNC | O_RDWR | O_BINARY;
254 #else
255 mode_t filePerms = 0;
256 int flags = O_TRUNC | O_RDWR;
257 #endif
258
259 int fileD = open((const char*)fPath, flags, filePerms);
260 if (fileD < 0)
261 return AudioFileTranslateErrno(errno);
262
263 err = OpenFile(kAudioFileReadWritePermission, fileD);
264 FailIf (err != noErr, Bail, "OpenFile failed");
265
266 // don't need to do this as open has an option to truncate the file
267 // GetDataSource()->SetSize(0);
268
269 err = SetDataFormat(inFormat);
270 FailIf (err != noErr, Bail, "SetDataFormat failed");
271
272 InitializeDataSource(inFormat, inFlags);
273
274 Bail:
275 return err;
276 }
277
278 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
279
InitializeDataSource(const AudioStreamBasicDescription * inFormat,UInt32)280 OSStatus AudioFileObject::InitializeDataSource(const AudioStreamBasicDescription *inFormat, UInt32 /*inFlags*/)
281 {
282 return noErr;
283 }
284
285 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
286
DoClose()287 OSStatus AudioFileObject::DoClose()
288 {
289 OSStatus err = UpdateSizeIfNeeded();
290 if (err) return err;
291
292 return Close();
293 }
294
295 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
296
Close()297 OSStatus AudioFileObject::Close()
298 {
299 try {
300 delete mDataSource;
301 mDataSource = 0;
302 } catch (OSStatus err) {
303 return err;
304 } catch (...) {
305 return kAudioFileUnspecifiedError;
306 }
307 return noErr;
308 }
309
310 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
311
312
Optimize()313 OSStatus AudioFileObject::Optimize()
314 {
315 // default is that nothing needs to be done. This happens to be true for Raw, SD2 and NeXT/Sun types.
316 SetIsOptimized(true);
317 return noErr;
318 }
319
320 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
321
322
DoOptimize()323 OSStatus AudioFileObject::DoOptimize()
324 {
325 if (!CanWrite()) return kAudioFilePermissionsError;
326
327 OSStatus err = UpdateSizeIfNeeded();
328 if (err) return err;
329
330 if (IsOptimized()) return noErr;
331
332 err = Optimize();
333 return err;
334 }
335
336 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
337
UpdateNumBytes(SInt64 inNumBytes)338 OSStatus AudioFileObject::UpdateNumBytes(SInt64 inNumBytes)
339 {
340 OSStatus err = noErr;
341 if (inNumBytes != GetNumBytes()) {
342 SetNumBytes(inNumBytes);
343
344 // #warning " this will not work for vbr formats"
345 SetNumPackets(GetNumBytes() / mDataFormat.mBytesPerPacket);
346 SizeChanged();
347 }
348 return err;
349 }
350
351 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
352
UpdateNumPackets(SInt64 inNumPackets)353 OSStatus AudioFileObject::UpdateNumPackets(SInt64 inNumPackets)
354 {
355 OSStatus err = noErr;
356 if (inNumPackets != GetNumPackets()) {
357 // sync current state.
358 SetNeedsSizeUpdate(true);
359 UpdateSizeIfNeeded();
360 SetNumPackets(inNumPackets);
361
362 // #warning " this will not work for vbr formats"
363 SetNumBytes(GetNumPackets() * mDataFormat.mBytesPerFrame);
364 SizeChanged();
365 }
366 return err;
367 }
368
369
370 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
371
PacketToFrame(SInt64 inPacket,SInt64 & outFirstFrameInPacket)372 OSStatus AudioFileObject::PacketToFrame(SInt64 inPacket, SInt64& outFirstFrameInPacket)
373 {
374 if (mDataFormat.mFramesPerPacket == 0)
375 {
376 OSStatus err = ScanForPackets(inPacket+1); // the packet count must be one greater than the packet index
377 if (err) return err;
378
379 SInt64 packetTableSize = GetPacketTableSize();
380
381 if (mPacketTable && inPacket >= packetTableSize)
382 return kAudioFileEndOfFileError;
383
384 CompressedPacketTable* packetTable = GetPacketTable();
385 if (!packetTable)
386 return kAudioFileInvalidPacketOffsetError;
387
388 if (inPacket < 0 || inPacket >= packetTableSize)
389 return kAudioFileInvalidPacketOffsetError;
390
391 outFirstFrameInPacket = (*packetTable)[(size_t)inPacket].mFrameOffset;
392 }
393 else
394 {
395 outFirstFrameInPacket = inPacket * mDataFormat.mFramesPerPacket;
396 }
397 return noErr;
398 }
399
400 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
401
FrameToPacket(SInt64 inFrame,SInt64 & outPacket,UInt32 & outFrameOffsetInPacket)402 OSStatus AudioFileObject::FrameToPacket(SInt64 inFrame, SInt64& outPacket, UInt32& outFrameOffsetInPacket)
403 {
404 if (mDataFormat.mFramesPerPacket == 0)
405 {
406 CompressedPacketTable* packetTable = GetPacketTable();
407 if (!packetTable)
408 return kAudioFileInvalidPacketOffsetError;
409
410 // search packet table
411 AudioStreamPacketDescriptionExtended pext;
412 memset(&pext, 0, sizeof(pext));
413 pext.mFrameOffset = inFrame;
414 CompressedPacketTable::iterator iter = std::lower_bound(packetTable->begin(), packetTable->end(), pext);
415
416 if (iter == packetTable->end())
417 return kAudioFileInvalidPacketOffsetError;
418
419 if (iter > packetTable->begin()) --iter;
420
421 outPacket = iter - packetTable->begin();
422 outFrameOffsetInPacket = (UInt32)(inFrame - iter->mFrameOffset);
423 }
424 else
425 {
426 outPacket = inFrame / mDataFormat.mFramesPerPacket;
427 outFrameOffsetInPacket = (UInt32)(inFrame % mDataFormat.mFramesPerPacket);
428 }
429 return noErr;
430 }
431
432 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
433
PacketToByte(AudioBytePacketTranslation * abpt)434 OSStatus AudioFileObject::PacketToByte(AudioBytePacketTranslation* abpt)
435 {
436 if (abpt->mPacket < 0)
437 return kAudioFileInvalidPacketOffsetError;
438
439 if (mDataFormat.mBytesPerPacket == 0)
440 {
441 CompressedPacketTable* packetTable = GetPacketTable();
442 if (!packetTable)
443 return kAudioFileInvalidPacketOffsetError;
444
445 if (abpt->mPacket < GetPacketTableSize()) {
446 abpt->mByte = (*packetTable)[(int)abpt->mPacket].mStartOffset;
447 abpt->mFlags = 0;
448 } else {
449 SInt64 numPackets = packetTable->size();
450 if (numPackets < 8)
451 return 'more' /*kAudioFileStreamError_DataUnavailable*/ ;
452
453 const AudioStreamPacketDescriptionExtended lastPacket = (*packetTable)[numPackets - 1];
454 SInt64 bytesReadSoFar = lastPacket.mStartOffset + lastPacket.mDataByteSize;
455 double averageBytesPerPacket = (double)(bytesReadSoFar - GetDataOffset()) / (double)numPackets;
456 abpt->mByte = (SInt64)floor((double)abpt->mPacket * averageBytesPerPacket);
457 abpt->mFlags = kBytePacketTranslationFlag_IsEstimate;
458 }
459 }
460 else
461 {
462 abpt->mByte = abpt->mPacket * mDataFormat.mBytesPerPacket;
463 abpt->mFlags = 0;
464 }
465 return noErr;
466 }
467
468 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
469
byte_less_than(const AudioStreamPacketDescriptionExtended & a,const AudioStreamPacketDescriptionExtended & b)470 inline bool byte_less_than (const AudioStreamPacketDescriptionExtended& a, const AudioStreamPacketDescriptionExtended& b)
471 {
472 return a.mStartOffset < b.mStartOffset;
473 }
474
ByteToPacket(AudioBytePacketTranslation * abpt)475 OSStatus AudioFileObject::ByteToPacket(AudioBytePacketTranslation* abpt)
476 {
477 if (abpt->mByte < 0)
478 return kAudioFileInvalidPacketOffsetError;
479
480 if (mDataFormat.mBytesPerPacket == 0)
481 {
482 CompressedPacketTable* packetTable = GetPacketTable();
483 if (!packetTable)
484 return kAudioFileInvalidPacketOffsetError;
485 // search packet table
486 AudioStreamPacketDescriptionExtended pext;
487 memset(&pext, 0, sizeof(pext));
488 pext.mStartOffset = abpt->mByte;
489 CompressedPacketTable::iterator iter = std::lower_bound(packetTable->begin(), packetTable->end(), pext, byte_less_than);
490
491 if (iter == packetTable->end()) {
492 SInt64 numPackets = packetTable->size();
493 if (numPackets < 8)
494 return 'more' /*kAudioFileStreamError_DataUnavailable*/ ;
495
496 const AudioStreamPacketDescriptionExtended lastPacket = (*packetTable)[numPackets - 1];
497 SInt64 bytesReadSoFar = lastPacket.mStartOffset + lastPacket.mDataByteSize;
498 double averageBytesPerPacket = (double)(bytesReadSoFar - GetDataOffset()) / (double)numPackets;
499
500 double fpacket = (double)abpt->mByte / averageBytesPerPacket;
501 abpt->mPacket = (SInt64)floor(fpacket);
502 abpt->mByteOffsetInPacket = (UInt32)floor((fpacket - (double)abpt->mPacket) * averageBytesPerPacket);
503 abpt->mFlags = kBytePacketTranslationFlag_IsEstimate;
504
505 } else {
506 if (iter > packetTable->begin()) --iter;
507 abpt->mPacket = iter - packetTable->begin();
508 abpt->mByteOffsetInPacket = (UInt32)(abpt->mByte - iter->mStartOffset);
509 abpt->mFlags = 0;
510 }
511 }
512 else
513 {
514 abpt->mPacket = abpt->mByte / mDataFormat.mBytesPerPacket;
515 abpt->mByteOffsetInPacket = (UInt32)(abpt->mByte % mDataFormat.mBytesPerPacket);
516 abpt->mFlags = 0;
517 }
518 return noErr;
519 }
520
521
522 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
523
524 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
525
ReadBytes(Boolean inUseCache,SInt64 inStartingByte,UInt32 * ioNumBytes,void * outBuffer)526 OSStatus AudioFileObject::ReadBytes(
527 Boolean inUseCache,
528 SInt64 inStartingByte,
529 UInt32 *ioNumBytes,
530 void *outBuffer)
531 {
532 OSStatus err = noErr;
533 UInt16 mode = SEEK_SET;
534 SInt64 fileOffset = mDataOffset + inStartingByte;
535 bool readingPastEnd = false;
536
537 FailWithAction((ioNumBytes == NULL) || (outBuffer == NULL), err = kAudio_ParamError,
538 Bail, "invalid num bytes parameter");
539
540 //printf("inStartingByte %lld GetNumBytes %lld\n", inStartingByte, GetNumBytes());
541
542 if (inStartingByte >= GetNumBytes())
543 {
544 *ioNumBytes = 0;
545 return kAudioFileEndOfFileError;
546 }
547
548 if ((fileOffset + *ioNumBytes) > (GetNumBytes() + mDataOffset))
549 {
550 *ioNumBytes = (UInt32)(GetNumBytes() + mDataOffset - fileOffset);
551 readingPastEnd = true;
552 }
553 //printf("fileOffset %lld mDataOffset %lld readingPastEnd %d\n", fileOffset, mDataOffset, readingPastEnd);
554
555 if (!inUseCache)
556 mode |= kAudioFileNoCacheMask;
557
558 err = GetDataSource()->ReadBytes(mode, fileOffset, *ioNumBytes, outBuffer, ioNumBytes);
559
560 if (readingPastEnd && err == noErr)
561 err = kAudioFileEndOfFileError;
562
563 Bail:
564 return err;
565 }
566
567
568 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
569
WriteBytes(Boolean inUseCache,SInt64 inStartingByte,UInt32 * ioNumBytes,const void * inBuffer)570 OSStatus AudioFileObject::WriteBytes(
571 Boolean inUseCache,
572 SInt64 inStartingByte,
573 UInt32 *ioNumBytes,
574 const void *inBuffer)
575 {
576 OSStatus err = noErr;
577 UInt16 mode = SEEK_SET;
578 bool extendingTheAudioData;
579
580 if (!CanWrite()) return kAudioFilePermissionsError;
581
582 FailWithAction((ioNumBytes == NULL) || (inBuffer == NULL), err = kAudioFileUnspecifiedError, Bail, "invalid parameters");
583
584 // Do not try to write to a postion greater than 32 bits for some file types
585 // see if starting byte + ioNumBytes is greater than 32 bits
586 // if so, see if file type supports this and bail if not
587 err = IsValidFilePosition(inStartingByte + *ioNumBytes);
588 FailIf(err != noErr, Bail, "invalid file position");
589
590 extendingTheAudioData = inStartingByte + *ioNumBytes > GetNumBytes();
591
592 // if file is not optimized, then do not write data that would overwrite chunks following the sound data chunk
593 FailWithAction( extendingTheAudioData && !IsOptimized(),
594 err = kAudioFileNotOptimizedError, Bail, "Can't write more data until the file is optimized");
595
596 if (!inUseCache)
597 mode |= kAudioFileNoCacheMask;
598
599 err = GetDataSource()->WriteBytes(mode, mDataOffset + inStartingByte, *ioNumBytes,
600 inBuffer, ioNumBytes);
601
602 FailIf(err != noErr, Bail, "couldn't write new data");
603
604 if (extendingTheAudioData) {
605 SInt64 nuEOF; // Get the total bytes of audio data
606 SInt64 nuByteTotal;
607
608 err = GetDataSource()->GetSize(nuEOF);
609 FailIf(err != noErr, Bail, "GetSize failed");
610
611 nuByteTotal = nuEOF - mDataOffset;
612 err = UpdateNumBytes(nuByteTotal);
613 }
614
615 Bail:
616 return err;
617 }
618
619 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
620
ReadPackets(Boolean inUseCache,UInt32 * outNumBytes,AudioStreamPacketDescription * outPacketDescriptions,SInt64 inStartingPacket,UInt32 * ioNumPackets,void * outBuffer)621 OSStatus AudioFileObject::ReadPackets(
622 Boolean inUseCache,
623 UInt32 *outNumBytes,
624 AudioStreamPacketDescription *outPacketDescriptions,
625 SInt64 inStartingPacket,
626 UInt32 *ioNumPackets,
627 void *outBuffer)
628 {
629 // This only works with CBR. To suppport VBR you must override.
630 OSStatus err = noErr;
631
632 FailWithAction(outBuffer == NULL, err = kAudio_ParamError, Bail, "NULL buffer");
633
634 FailWithAction((ioNumPackets == NULL) || (*ioNumPackets < 1), err = kAudio_ParamError, Bail, "invalid num packets parameter");
635
636 {
637 UInt32 byteCount = *ioNumPackets * mDataFormat.mBytesPerPacket;
638 SInt64 startingByte = inStartingPacket * mDataFormat.mBytesPerPacket;
639
640 err = ReadBytes (inUseCache, startingByte, &byteCount, outBuffer);
641 if ((err == noErr) || (err == kAudioFileEndOfFileError))
642 {
643 if (byteCount != (*ioNumPackets * mDataFormat.mBytesPerPacket))
644 {
645 *ioNumPackets = byteCount / mDataFormat.mBytesPerPacket;
646 byteCount = *ioNumPackets * mDataFormat.mBytesPerPacket;
647 }
648
649 if (outNumBytes)
650 *outNumBytes = byteCount;
651
652 if (err == kAudioFileEndOfFileError)
653 err = noErr;
654 }
655 }
656 Bail:
657 return err;
658 }
659
660
661 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
662 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
663
664
665 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
666
ReadPacketData(Boolean inUseCache,UInt32 * ioNumBytes,AudioStreamPacketDescription * outPacketDescriptions,SInt64 inStartingPacket,UInt32 * ioNumPackets,void * outBuffer)667 OSStatus AudioFileObject::ReadPacketData(
668 Boolean inUseCache,
669 UInt32 *ioNumBytes,
670 AudioStreamPacketDescription *outPacketDescriptions,
671 SInt64 inStartingPacket,
672 UInt32 *ioNumPackets,
673 void *outBuffer)
674 {
675 OSStatus err = noErr;
676 FailWithAction(ioNumPackets == NULL || *ioNumPackets < 1, err = kAudio_ParamError, Bail, "invalid ioNumPackets parameter");
677 FailWithAction(ioNumBytes == NULL || *ioNumBytes < 1, err = kAudio_ParamError, Bail, "invalid ioNumBytes parameter");
678 if (mDataFormat.mBytesPerPacket) {
679 // CBR
680 FailWithAction(outBuffer == NULL, err = kAudio_ParamError, Bail, "NULL buffer");
681 UInt32 maxPackets = *ioNumBytes / mDataFormat.mBytesPerPacket;
682 if (*ioNumPackets > maxPackets) *ioNumPackets = maxPackets;
683
684 if (outBuffer) {
685 UInt32 byteCount = *ioNumPackets * mDataFormat.mBytesPerPacket;
686 SInt64 startingByte = inStartingPacket * mDataFormat.mBytesPerPacket;
687 err = ReadBytes (inUseCache, startingByte, &byteCount, outBuffer);
688 if (err == noErr || err == kAudioFileEndOfFileError) {
689 if (byteCount != (*ioNumPackets * mDataFormat.mBytesPerPacket)) {
690 *ioNumPackets = byteCount / mDataFormat.mBytesPerPacket;
691 byteCount = *ioNumPackets * mDataFormat.mBytesPerPacket;
692 }
693 *ioNumBytes = byteCount;
694 }
695 }
696 } else {
697 FailWithAction(outPacketDescriptions == NULL, err = kAudio_ParamError, Bail, "invalid outPacketDescriptions parameter");
698 err = ReadPacketDataVBR(inUseCache, ioNumBytes, outPacketDescriptions, inStartingPacket, ioNumPackets, outBuffer);
699 }
700 Bail:
701 return err;
702 }
703
704 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
705
ReadPacketDataVBR(Boolean inUseCache,UInt32 * ioNumBytes,AudioStreamPacketDescription * outPacketDescriptions,SInt64 inStartingPacket,UInt32 * ioNumPackets,void * outBuffer)706 OSStatus AudioFileObject::ReadPacketDataVBR(
707 Boolean inUseCache,
708 UInt32 *ioNumBytes,
709 AudioStreamPacketDescription *outPacketDescriptions,
710 SInt64 inStartingPacket,
711 UInt32 *ioNumPackets,
712 void *outBuffer)
713 {
714 OSStatus err = ScanForPackets(inStartingPacket+1); // need to scan packets up to start
715 if (err && err != kAudioFileEndOfFileError)
716 return err;
717
718 SInt64 dataOffset = GetDataOffset();
719
720 CompressedPacketTable* packetTable = GetPacketTable();
721 if (!packetTable)
722 return kAudioFileInvalidFileError;
723
724 SInt64 packetTableSize = GetPacketTableSize();
725
726 if (inStartingPacket >= packetTableSize) {
727 *ioNumBytes = 0;
728 *ioNumPackets = 0;
729 return kAudioFileEndOfFileError;
730 }
731
732 if (inStartingPacket + *ioNumPackets <= packetTableSize) {
733 err = ReadPacketDataVBR_InTable(inUseCache, ioNumBytes, outPacketDescriptions, inStartingPacket, ioNumPackets, outBuffer);
734 } else {
735
736 AudioStreamPacketDescription firstPacket = (*packetTable)[inStartingPacket];
737 SInt64 firstPacketOffset = firstPacket.mStartOffset;
738 UInt32 bytesRead = *ioNumBytes;
739 SInt64 fileSize = 0;
740 GetDataSource()->GetSize(fileSize);
741 SInt64 remainingBytesInFile = fileSize - firstPacketOffset - dataOffset;
742 if (bytesRead > remainingBytesInFile)
743 bytesRead = (UInt32)remainingBytesInFile;
744
745 err = ReadBytes (inUseCache, firstPacketOffset, &bytesRead, outBuffer);
746 if (err && err != kAudioFileEndOfFileError) {
747 *ioNumBytes = 0;
748 *ioNumPackets = 0;
749 return err;
750 }
751
752 Buffer_DataSource bufSrc(bytesRead, outBuffer, dataOffset + firstPacketOffset);
753
754 OSStatus scanErr = ScanForPackets(kScanToEnd, &bufSrc, false);
755 if (scanErr && scanErr != kAudioFileEndOfFileError)
756 return scanErr;
757 packetTableSize = packetTable->size();
758
759 UInt32 numPacketsRead = 0;
760 UInt32 endOfData = 0;
761 SInt64 packetNumber = inStartingPacket;
762 for (; numPacketsRead < *ioNumPackets && packetNumber < packetTableSize; ++numPacketsRead, ++packetNumber) {
763 AudioStreamPacketDescription curPacket = (*packetTable)[numPacketsRead + inStartingPacket];
764 SInt64 curPacketOffset = curPacket.mStartOffset - firstPacketOffset;
765 SInt64 endOfPacket = curPacketOffset + curPacket.mDataByteSize;
766 if (endOfPacket > bytesRead) break;
767 endOfData = (UInt32)endOfPacket;
768 outPacketDescriptions[numPacketsRead] = curPacket;
769 outPacketDescriptions[numPacketsRead].mStartOffset = curPacketOffset;
770 }
771
772 *ioNumBytes = endOfData;
773 *ioNumPackets = numPacketsRead;
774 }
775 return err;
776 }
777
778
779 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
HowManyPacketsCanBeReadIntoBuffer(UInt32 * ioNumBytes,SInt64 inStartingPacket,UInt32 * ioNumPackets)780 OSStatus AudioFileObject::HowManyPacketsCanBeReadIntoBuffer(UInt32* ioNumBytes, SInt64 inStartingPacket, UInt32 *ioNumPackets)
781 {
782 CompressedPacketTable* packetTable = GetPacketTable();
783 SInt64 packetTableSize = GetPacketTableSize();
784
785 if (inStartingPacket + *ioNumPackets > (SInt64)packetTableSize) {
786 *ioNumPackets = (UInt32)(packetTableSize - inStartingPacket);
787 }
788
789 AudioStreamPacketDescription firstPacket = (*packetTable)[inStartingPacket];
790
791 if (*ioNumBytes < firstPacket.mDataByteSize) {
792 *ioNumBytes = 0;
793 *ioNumPackets = 0;
794 return kAudio_ParamError;
795 }
796
797 SInt64 lastPacketIndex = inStartingPacket + *ioNumPackets - 1;
798 if (lastPacketIndex >= packetTableSize)
799 lastPacketIndex = packetTableSize - 1;
800
801 AudioStreamPacketDescription lastPacket = (*packetTable)[lastPacketIndex];
802
803 SInt64 readBytes = lastPacket.mStartOffset + lastPacket.mDataByteSize - firstPacket.mStartOffset;
804 if (readBytes <= *ioNumBytes) {
805 *ioNumBytes = (UInt32)readBytes;
806 return noErr;
807 }
808
809 SInt64 lowBound = inStartingPacket;
810 SInt64 highBound = lastPacketIndex + 1;
811 SInt64 okIndex = lowBound;
812 while (highBound >= lowBound) {
813 SInt64 tryBound = (lowBound + highBound) >> 1;
814 if (tryBound > lastPacketIndex)
815 break;
816 AudioStreamPacketDescription tryPacket = (*packetTable)[tryBound];
817
818 SInt64 readBytes = tryPacket.mStartOffset + tryPacket.mDataByteSize - firstPacket.mStartOffset;
819
820 if (readBytes > (SInt64)*ioNumBytes) {
821 highBound = tryBound - 1;
822 } else if (readBytes < (SInt64)*ioNumBytes) {
823 okIndex = tryBound;
824 lowBound = tryBound + 1;
825 } else {
826 okIndex = tryBound;
827 break;
828 }
829 }
830
831 SInt64 numPackets = okIndex - inStartingPacket + 1;
832 if (numPackets > *ioNumPackets) {
833 numPackets = *ioNumPackets;
834 okIndex = inStartingPacket + numPackets - 1;
835 }
836
837 AudioStreamPacketDescription packet = (*packetTable)[okIndex];
838 *ioNumBytes = (UInt32)(packet.mStartOffset + packet.mDataByteSize - firstPacket.mStartOffset);
839 *ioNumPackets = (UInt32)numPackets;
840 return noErr;
841 }
842
843 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
844
845
846
847 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
848
ReadPacketDataVBR_InTable(Boolean inUseCache,UInt32 * ioNumBytes,AudioStreamPacketDescription * outPacketDescriptions,SInt64 inStartingPacket,UInt32 * ioNumPackets,void * outBuffer)849 OSStatus AudioFileObject::ReadPacketDataVBR_InTable(
850 Boolean inUseCache,
851 UInt32 *ioNumBytes,
852 AudioStreamPacketDescription *outPacketDescriptions,
853 SInt64 inStartingPacket,
854 UInt32 *ioNumPackets,
855 void *outBuffer)
856 {
857 CompressedPacketTable* packetTable = GetPacketTable();
858 if (!packetTable)
859 return kAudioFileInvalidFileError;
860
861 OSStatus err = HowManyPacketsCanBeReadIntoBuffer(ioNumBytes, inStartingPacket, ioNumPackets);
862 if (err) return err;
863
864 AudioStreamPacketDescription firstPacket = (*packetTable)[inStartingPacket];
865 SInt64 firstPacketOffset = firstPacket.mStartOffset;
866 UInt32 bytesRead = *ioNumBytes;
867
868 if (outBuffer) {
869 err = ReadBytes (inUseCache, firstPacketOffset, &bytesRead, outBuffer);
870 if (err && err != kAudioFileEndOfFileError) {
871 *ioNumBytes = 0;
872 *ioNumPackets = 0;
873 return err;
874 }
875 *ioNumBytes = bytesRead;
876 }
877
878 // fill out packet descriptions
879 if (outPacketDescriptions) {
880 for (UInt32 i = 0; i < *ioNumPackets; i++) {
881 AudioStreamPacketDescription curPacket = (*packetTable)[i + inStartingPacket];
882 outPacketDescriptions[i] = curPacket;
883 outPacketDescriptions[i].mStartOffset = curPacket.mStartOffset - firstPacketOffset;
884 }
885 }
886
887 return err;
888 }
889
890
891 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
892
WritePackets(Boolean inUseCache,UInt32 inNumBytes,const AudioStreamPacketDescription * inPacketDescriptions,SInt64 inStartingPacket,UInt32 * ioNumPackets,const void * inBuffer)893 OSStatus AudioFileObject::WritePackets(
894 Boolean inUseCache,
895 UInt32 inNumBytes,
896 const AudioStreamPacketDescription *inPacketDescriptions,
897 SInt64 inStartingPacket,
898 UInt32 *ioNumPackets,
899 const void *inBuffer)
900 {
901 // This only works with CBR. To suppport VBR you must override.
902 OSStatus err = noErr;
903
904 FailWithAction(inStartingPacket > GetNumPackets(), err = kAudioFileInvalidPacketOffsetError, Bail, "write past end");
905 FailWithAction((ioNumPackets == NULL) || (inBuffer == NULL), err = kAudioFileUnspecifiedError, Bail, "invalid parameter");
906
907 {
908 UInt32 byteCount = *ioNumPackets * mDataFormat.mBytesPerPacket;
909 SInt64 startingByte = inStartingPacket * mDataFormat.mBytesPerPacket;
910
911 err = WriteBytes(inUseCache, startingByte, &byteCount, inBuffer);
912 FailIf (err != noErr, Bail, "Write Bytes Failed");
913
914 if (byteCount != (*ioNumPackets * mDataFormat.mBytesPerPacket))
915 *ioNumPackets = byteCount / mDataFormat.mBytesPerPacket;
916 }
917 Bail:
918 return (err);
919 }
920
921 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
922
GetBitRate(UInt32 * outBitRate)923 OSStatus AudioFileObject::GetBitRate( UInt32 *outBitRate)
924 {
925
926 if (!outBitRate) return kAudioFileUnspecifiedError;
927
928 UInt32 bytesPerPacket = GetDataFormat().mBytesPerPacket;
929 UInt32 framesPerPacket = GetDataFormat().mFramesPerPacket;
930 Float64 sampleRate = GetDataFormat().mSampleRate;
931 const Float64 bitsPerByte = 8.;
932
933 if (bytesPerPacket && framesPerPacket) {
934 *outBitRate = (UInt32)(bitsPerByte * (Float64)bytesPerPacket * sampleRate / (Float64)framesPerPacket);
935 } else {
936 SInt64 numPackets = GetNumPackets();
937 SInt64 numBytes = GetNumBytes();
938 SInt64 numFrames = 0;
939
940 if (framesPerPacket) {
941 numFrames = numPackets * framesPerPacket;
942 } else {
943 // count frames
944 CompressedPacketTable* packetTable = GetPacketTable();
945 if (packetTable) {
946 if (packetTable->size() != numPackets) {
947 return kAudioFileInvalidFileError;
948 }
949 #if !TARGET_OS_WIN32
950 for (ssize_t i = 0; i < numPackets; i++)
951 #else
952 for (int i = 0; i < numPackets; i++)
953 #endif
954 {
955 numFrames += (*packetTable)[i].mVariableFramesInPacket;
956 }
957 } else {
958 return kAudioFileUnsupportedPropertyError;
959 }
960 }
961
962 if (numFrames == 0 || (sampleRate == 0.)) {
963 *outBitRate = 0;
964 return noErr;
965 }
966 Float64 duration = (Float64)numFrames / sampleRate;
967 *outBitRate = (UInt32)(bitsPerByte * (Float64)numBytes / duration);
968 }
969
970 return noErr;
971 }
972
973 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
974
GetMagicCookieDataSize(UInt32 * outDataSize,UInt32 * isWritable)975 OSStatus AudioFileObject::GetMagicCookieDataSize(
976 UInt32 *outDataSize,
977 UInt32 *isWritable)
978 {
979 if (outDataSize) *outDataSize = 0;
980 if (isWritable) *isWritable = 0;
981 return kAudioFileUnsupportedPropertyError;
982 }
983
984 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
985
GetMagicCookieData(UInt32 * ioDataSize,void * ioPropertyData)986 OSStatus AudioFileObject::GetMagicCookieData(
987 UInt32 *ioDataSize,
988 void *ioPropertyData)
989 {
990 *ioDataSize = 0;
991 return kAudioFileUnsupportedPropertyError;
992 }
993
994 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
995
SetMagicCookieData(UInt32,const void * inPropertyData)996 OSStatus AudioFileObject::SetMagicCookieData( UInt32 /*inDataSize*/,
997 const void *inPropertyData)
998 {
999 return kAudioFileInvalidChunkError;
1000 }
1001
1002 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1003
GetMarkerListSize(UInt32 * outDataSize,UInt32 * isWritable)1004 OSStatus AudioFileObject::GetMarkerListSize(
1005 UInt32 *outDataSize,
1006 UInt32 *isWritable)
1007 {
1008 if (outDataSize) *outDataSize = 0;
1009 if (isWritable) *isWritable = 0;
1010 return kAudioFileUnsupportedPropertyError;
1011 }
1012
1013 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1014
GetMarkerList(UInt32 * ioDataSize,AudioFileMarkerList *)1015 OSStatus AudioFileObject::GetMarkerList(
1016 UInt32 *ioDataSize,
1017 AudioFileMarkerList* /*ioPropertyData*/)
1018 {
1019 *ioDataSize = 0;
1020 return kAudioFileUnsupportedPropertyError;
1021 }
1022
1023 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1024
SetMarkerList(UInt32,const AudioFileMarkerList *)1025 OSStatus AudioFileObject::SetMarkerList( UInt32 /*inDataSize*/,
1026 const AudioFileMarkerList* /*inPropertyData*/)
1027 {
1028 return kAudioFileUnsupportedPropertyError;
1029 }
1030
1031
1032 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1033
GetRegionListSize(UInt32 * outDataSize,UInt32 * isWritable)1034 OSStatus AudioFileObject::GetRegionListSize(
1035 UInt32 *outDataSize,
1036 UInt32 *isWritable)
1037 {
1038 if (outDataSize) *outDataSize = 0;
1039 if (isWritable) *isWritable = 0;
1040 return kAudioFileUnsupportedPropertyError;
1041 }
1042
1043 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1044
GetRegionList(UInt32 * ioDataSize,AudioFileRegionList * ioPropertyData)1045 OSStatus AudioFileObject::GetRegionList(
1046 UInt32 *ioDataSize,
1047 AudioFileRegionList *ioPropertyData)
1048 {
1049 *ioDataSize = 0;
1050 return kAudioFileUnsupportedPropertyError;
1051 }
1052
1053 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1054
SetRegionList(UInt32,const AudioFileRegionList *)1055 OSStatus AudioFileObject::SetRegionList( UInt32 /*inDataSize*/,
1056 const AudioFileRegionList* /*inPropertyData*/)
1057 {
1058 return kAudioFileUnsupportedPropertyError;
1059 }
1060
1061 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1062
GetChannelLayoutSize(UInt32 * outDataSize,UInt32 * isWritable)1063 OSStatus AudioFileObject::GetChannelLayoutSize(
1064 UInt32 *outDataSize,
1065 UInt32 *isWritable)
1066 {
1067 if (outDataSize) *outDataSize = 0;
1068 if (isWritable) *isWritable = 0;
1069 return kAudioFileUnsupportedPropertyError;
1070 }
1071
1072 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1073
GetChannelLayout(UInt32 * ioDataSize,AudioChannelLayout *)1074 OSStatus AudioFileObject::GetChannelLayout(
1075 UInt32 *ioDataSize,
1076 AudioChannelLayout* /*ioPropertyData*/)
1077 {
1078 *ioDataSize = 0;
1079 return kAudioFileUnsupportedPropertyError;
1080 }
1081
1082 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1083
SetChannelLayout(UInt32,const AudioChannelLayout *)1084 OSStatus AudioFileObject::SetChannelLayout( UInt32 /*inDataSize*/,
1085 const AudioChannelLayout* /*inPropertyData*/)
1086 {
1087 return kAudioFileUnsupportedPropertyError;
1088 }
1089
1090 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1091
GetInfoDictionarySize(UInt32 * outDataSize,UInt32 * isWritable)1092 OSStatus AudioFileObject::GetInfoDictionarySize( UInt32 *outDataSize,
1093 UInt32 *isWritable)
1094 {
1095 if (outDataSize) *outDataSize = sizeof(CFDictionaryRef);
1096 if (isWritable) *isWritable = 0;
1097 return noErr;
1098 }
1099
1100 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1101
GetInfoDictionary(CACFDictionary * infoDict)1102 OSStatus AudioFileObject::GetInfoDictionary(CACFDictionary *infoDict)
1103 {
1104 Float64 fl;
1105 if (GetEstimatedDuration(&fl) == noErr)
1106 return AddDurationToInfoDictionary(infoDict, fl);
1107
1108 return kAudioFileUnsupportedPropertyError;
1109 }
1110
1111 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1112
SetInfoDictionary(CACFDictionary * infoDict)1113 OSStatus AudioFileObject::SetInfoDictionary(CACFDictionary *infoDict)
1114 {
1115 return kAudioFileUnsupportedPropertyError;
1116 }
1117
1118 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
GetEstimatedDuration(Float64 * duration)1119 OSStatus AudioFileObject::GetEstimatedDuration(Float64* duration)
1120 {
1121 // calculate duration
1122 AudioStreamBasicDescription ASBD = GetDataFormat();
1123
1124 *duration = (ASBD.mFramesPerPacket != 0) ? (GetNumPackets() * ASBD.mFramesPerPacket) / ASBD.mSampleRate : 0.0;
1125
1126 /*
1127 For now, assume that any ASBD that has zero in the frames per packet field has been subclassed for this
1128 method. i.e. A CAF file has a frame count in one of it's chunks.
1129
1130 MP3 has been subclassed because it guesstimates a duration so the entire file does not
1131 need to be parsed in order to calculate the total frames.
1132 */
1133
1134 return noErr;
1135
1136 }
1137
1138 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1139
GetPropertyInfo(AudioFilePropertyID inPropertyID,UInt32 * outDataSize,UInt32 * isWritable)1140 OSStatus AudioFileObject::GetPropertyInfo (
1141 AudioFilePropertyID inPropertyID,
1142 UInt32 *outDataSize,
1143 UInt32 *isWritable)
1144 {
1145 OSStatus err = noErr;
1146 UInt32 writable = 0;
1147
1148 switch (inPropertyID)
1149 {
1150 case kAudioFilePropertyDeferSizeUpdates :
1151 if (outDataSize) *outDataSize = sizeof(UInt32);
1152 writable = 1;
1153 break;
1154
1155 case kAudioFilePropertyFileFormat:
1156 if (outDataSize) *outDataSize = sizeof(UInt32);
1157 writable = 0;
1158 break;
1159
1160 case kAudioFilePropertyDataFormat:
1161 if (outDataSize) *outDataSize = sizeof(AudioStreamBasicDescription);
1162 writable = 1;
1163 break;
1164
1165 case kAudioFilePropertyFormatList:
1166 err = GetFormatListInfo(*outDataSize, writable);
1167 break;
1168
1169 case kAudioFilePropertyPacketSizeUpperBound:
1170 case kAudioFilePropertyIsOptimized:
1171 case kAudioFilePropertyMaximumPacketSize:
1172 if (outDataSize) *outDataSize = sizeof(UInt32);
1173 writable = 0;
1174 break;
1175
1176 case kAudioFilePropertyAudioDataByteCount:
1177 case kAudioFilePropertyAudioDataPacketCount:
1178 writable = 1;
1179 if (outDataSize) *outDataSize = sizeof(SInt64);
1180 break;
1181
1182 case kAudioFilePropertyDataOffset:
1183 writable = 0;
1184 if (outDataSize) *outDataSize = sizeof(SInt64);
1185 break;
1186
1187 case kAudioFilePropertyBitRate:
1188 writable = 0;
1189 if (outDataSize) *outDataSize = sizeof(UInt32);
1190 break;
1191
1192 case kAudioFilePropertyMagicCookieData:
1193 err = GetMagicCookieDataSize(outDataSize, &writable);
1194 break;
1195
1196 case kAudioFilePropertyMarkerList :
1197 err = GetMarkerListSize(outDataSize, &writable);
1198 break;
1199
1200 case kAudioFilePropertyRegionList :
1201 err = GetRegionListSize(outDataSize, &writable);
1202 break;
1203
1204 case kAudioFilePropertyChannelLayout :
1205 err = GetChannelLayoutSize(outDataSize, &writable);
1206 break;
1207
1208 case kAudioFilePropertyPacketToFrame :
1209 case kAudioFilePropertyFrameToPacket :
1210 if (outDataSize) *outDataSize = sizeof(AudioFramePacketTranslation);
1211 writable = 0;
1212 break;
1213
1214 case kAudioFilePropertyPacketToByte :
1215 case kAudioFilePropertyByteToPacket :
1216 if (outDataSize) *outDataSize = sizeof(AudioBytePacketTranslation);
1217 writable = 0;
1218 break;
1219
1220 case kAudioFilePropertyInfoDictionary :
1221 err = GetInfoDictionarySize(outDataSize, &writable);
1222 break;
1223
1224 case kTEMPAudioFilePropertySoundCheckDictionary :
1225 err = GetSoundCheckDictionarySize(outDataSize, &writable);
1226 break;
1227
1228 case kTEMPAudioFilePropertyGenerateLoudnessInfo :
1229 err = GetLoudnessInfoSize(outDataSize, &writable);
1230 writable = 0;
1231 break;
1232
1233 case kTEMPAudioFilePropertyLoudnessInfo :
1234 err = GetLoudnessInfoSize(outDataSize, &writable);
1235 break;
1236
1237 case kAudioFilePropertyEstimatedDuration :
1238 if (outDataSize) *outDataSize = sizeof(Float64);
1239 writable = 0;
1240 break;
1241
1242 case 'LYRC':
1243 if (outDataSize) *outDataSize = sizeof(CFStringRef);
1244 if (isWritable) *isWritable = 0;
1245 break;
1246
1247 case 'eof?':
1248 if (outDataSize) *outDataSize = sizeof(UInt32);
1249 if (isWritable) *isWritable = 0;
1250 break;
1251
1252 case 'sbtd' /*kAudioFilePropertySourceBitDepth*/ :
1253 if (outDataSize) *outDataSize = sizeof(SInt32);
1254 if (isWritable) *isWritable = CanWrite();
1255 break;
1256
1257 default:
1258 writable = 0;
1259 err = kAudioFileUnsupportedPropertyError;
1260 break;
1261 }
1262
1263 if (isWritable)
1264 *isWritable = writable;
1265 return (err);
1266 }
1267
1268 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1269
GetProperty(AudioFilePropertyID inPropertyID,UInt32 * ioDataSize,void * ioPropertyData)1270 OSStatus AudioFileObject::GetProperty(
1271 AudioFilePropertyID inPropertyID,
1272 UInt32 *ioDataSize,
1273 void *ioPropertyData)
1274 {
1275 OSStatus err = noErr;
1276 UInt32 neededSize;
1277 UInt32 writable;
1278
1279 switch (inPropertyID)
1280 {
1281 case kAudioFilePropertyFileFormat:
1282 FailWithAction(*ioDataSize != sizeof(UInt32),
1283 err = kAudioFileBadPropertySizeError, Bail, "inDataSize is wrong");
1284
1285 *(UInt32 *) ioPropertyData = GetFileType();
1286 break;
1287
1288 case kAudioFilePropertyFormatList:
1289 err = GetFormatList(*ioDataSize, (AudioFormatListItem*)ioPropertyData);
1290 break;
1291
1292 case kAudioFilePropertyDataFormat:
1293 FailWithAction(*ioDataSize != sizeof(AudioStreamBasicDescription),
1294 err = kAudioFileBadPropertySizeError, Bail, "inDataSize is wrong");
1295
1296 memcpy(ioPropertyData, &mDataFormat, sizeof(AudioStreamBasicDescription));
1297 break;
1298 case kAudioFilePropertyDataOffset:
1299 FailWithAction(*ioDataSize != sizeof(SInt64),
1300 err = kAudioFileBadPropertySizeError, Bail, "inDataSize is wrong");
1301 *(SInt64 *) ioPropertyData = mDataOffset;
1302 break;
1303 case kAudioFilePropertyIsOptimized:
1304 FailWithAction(*ioDataSize != sizeof(UInt32),
1305 err = kAudioFileBadPropertySizeError, Bail, "inDataSize is wrong");
1306 *(UInt32 *) ioPropertyData = mIsOptimized;
1307 break;
1308
1309 case kAudioFilePropertyAudioDataByteCount:
1310 FailWithAction(*ioDataSize != sizeof(SInt64),
1311 err = kAudioFileBadPropertySizeError, Bail, "inDataSize is wrong");
1312 *(SInt64 *)ioPropertyData = GetNumBytes();
1313 break;
1314
1315 case kAudioFilePropertyAudioDataPacketCount:
1316 FailWithAction(*ioDataSize != sizeof(SInt64),
1317 err = kAudioFileBadPropertySizeError, Bail, "inDataSize is wrong");
1318 *(SInt64 *)ioPropertyData = GetNumPackets();
1319 break;
1320
1321 case kAudioFilePropertyPacketSizeUpperBound:
1322 FailWithAction(*ioDataSize != sizeof(UInt32),
1323 err = kAudioFileBadPropertySizeError, Bail, "inDataSize is wrong");
1324 *(UInt32 *)ioPropertyData = GetPacketSizeUpperBound();
1325 break;
1326
1327 case kAudioFilePropertyMaximumPacketSize:
1328 FailWithAction(*ioDataSize != sizeof(UInt32),
1329 err = kAudioFileBadPropertySizeError, Bail, "inDataSize is wrong");
1330 *(UInt32 *)ioPropertyData = FindMaximumPacketSize();
1331 break;
1332
1333
1334 case kAudioFilePropertyBitRate:
1335 FailWithAction(*ioDataSize != sizeof(UInt32),
1336 err = kAudioFileBadPropertySizeError, Bail, "inDataSize is wrong");
1337 err = GetBitRate((UInt32*)ioPropertyData);
1338 break;
1339
1340 case kAudioFilePropertyMagicCookieData:
1341
1342 err = GetMagicCookieData(ioDataSize, ioPropertyData);
1343 break;
1344
1345 case kAudioFilePropertyMarkerList :
1346 err = GetMarkerList(ioDataSize, static_cast<AudioFileMarkerList*>(ioPropertyData));
1347 break;
1348
1349 case kAudioFilePropertyRegionList :
1350 memset(ioPropertyData, 0, *ioDataSize);
1351 err = GetRegionList(ioDataSize, static_cast<AudioFileRegionList*>(ioPropertyData));
1352 break;
1353
1354 case kAudioFilePropertyChannelLayout :
1355 err = GetChannelLayoutSize(&neededSize, &writable);
1356 FailIf(err, Bail, "GetChannelLayoutSize failed");
1357 FailWithAction(*ioDataSize != neededSize, err = kAudioFileBadPropertySizeError, Bail, "inDataSize is wrong");
1358
1359 err = GetChannelLayout(ioDataSize, static_cast<AudioChannelLayout*>(ioPropertyData));
1360 break;
1361
1362 case kAudioFilePropertyDeferSizeUpdates :
1363 FailWithAction(*ioDataSize != sizeof(UInt32),
1364 err = kAudioFileBadPropertySizeError, Bail, "inDataSize is wrong");
1365
1366 *(UInt32 *) ioPropertyData = DeferSizeUpdates();
1367 break;
1368
1369 case kAudioFilePropertyPacketToFrame :
1370 {
1371 FailWithAction(*ioDataSize != sizeof(AudioFramePacketTranslation),
1372 err = kAudioFileBadPropertySizeError, Bail, "inDataSize is wrong");
1373
1374 AudioFramePacketTranslation* afpt = (AudioFramePacketTranslation*)ioPropertyData;
1375 err = PacketToFrame(afpt->mPacket, afpt->mFrame);
1376 break;
1377 }
1378 case kAudioFilePropertyFrameToPacket :
1379 {
1380 FailWithAction(*ioDataSize != sizeof(AudioFramePacketTranslation),
1381 err = kAudioFileBadPropertySizeError, Bail, "inDataSize is wrong");
1382
1383 AudioFramePacketTranslation* afpt = (AudioFramePacketTranslation*)ioPropertyData;
1384 err = FrameToPacket(afpt->mFrame, afpt->mPacket, afpt->mFrameOffsetInPacket);
1385 break;
1386 }
1387
1388 case kAudioFilePropertyPacketToByte :
1389 {
1390 FailWithAction(*ioDataSize != sizeof(AudioBytePacketTranslation),
1391 err = kAudioFileBadPropertySizeError, Bail, "inDataSize is wrong");
1392
1393 AudioBytePacketTranslation* abpt = (AudioBytePacketTranslation*)ioPropertyData;
1394 err = PacketToByte(abpt);
1395 break;
1396 }
1397 case kAudioFilePropertyByteToPacket :
1398 {
1399 FailWithAction(*ioDataSize != sizeof(AudioBytePacketTranslation),
1400 err = kAudioFileBadPropertySizeError, Bail, "inDataSize is wrong");
1401
1402 AudioBytePacketTranslation* abpt = (AudioBytePacketTranslation*)ioPropertyData;
1403 err = ByteToPacket(abpt);
1404 break;
1405 }
1406
1407 case kAudioFilePropertyInfoDictionary :
1408 {
1409 FailWithAction(*ioDataSize != sizeof(CFDictionaryRef),
1410 err = kAudioFileBadPropertySizeError, Bail, "inDataSize is wrong");
1411
1412 CACFDictionary afInfoDictionary(true);
1413
1414 err = GetInfoDictionary(&afInfoDictionary);
1415
1416 if (!err)
1417 {
1418 *(CFMutableDictionaryRef *)ioPropertyData = afInfoDictionary.CopyCFMutableDictionary();
1419 }
1420 break;
1421 }
1422
1423 case kTEMPAudioFilePropertySoundCheckDictionary :
1424 {
1425 FailWithAction(*ioDataSize != sizeof(CFDictionaryRef),
1426 err = kAudioFileBadPropertySizeError, Bail, "inDataSize is wrong");
1427
1428 CACFDictionary afInfoDictionary(true);
1429
1430 err = GetSoundCheckDictionary(&afInfoDictionary);
1431 if (err) {
1432 OSStatus err2 = GetSoundCheckDictionaryFromLoudnessInfo(&afInfoDictionary);
1433 if (err2 == noErr) err = noErr; // else report original error from GetSoundCheckDictionary.
1434 }
1435
1436 if (!err)
1437 {
1438 *(CFMutableDictionaryRef *)ioPropertyData = afInfoDictionary.CopyCFMutableDictionary();
1439 }
1440 break;
1441 }
1442
1443 case kTEMPAudioFilePropertyLoudnessInfo :
1444 {
1445 FailWithAction(*ioDataSize != sizeof(CFDictionaryRef),
1446 err = kAudioFileBadPropertySizeError, Bail, "inDataSize is wrong");
1447
1448 CACFDictionary afInfoDictionary(true);
1449
1450 err = GetLoudnessInfo(&afInfoDictionary);
1451 if (err) {
1452 OSStatus err2 = GetLoudnessInfoFromSoundCheckDictionary(&afInfoDictionary);
1453 if (err2 == noErr) err = noErr; // else report original error from GetLoudnessInfo.
1454 }
1455
1456 if (!err)
1457 {
1458 *(CFMutableDictionaryRef *)ioPropertyData = afInfoDictionary.CopyCFMutableDictionary();
1459 }
1460 break;
1461 }
1462
1463 case kTEMPAudioFilePropertyGenerateLoudnessInfo :
1464 {
1465 FailWithAction(*ioDataSize != sizeof(CFDictionaryRef),
1466 err = kAudioFileBadPropertySizeError, Bail, "inDataSize is wrong");
1467
1468 CACFDictionary afInfoDictionary(true);
1469
1470 err = GenerateLoudnessInfo(&afInfoDictionary);
1471
1472 if (!err)
1473 {
1474 *(CFMutableDictionaryRef *)ioPropertyData = afInfoDictionary.CopyCFMutableDictionary();
1475 }
1476 break;
1477 }
1478
1479 case kAudioFilePropertyEstimatedDuration :
1480 {
1481 FailWithAction(*ioDataSize != sizeof(Float64),
1482 err = kAudioFileBadPropertySizeError, Bail, "inDataSize is wrong");
1483
1484 err = GetEstimatedDuration((Float64*)ioPropertyData);
1485 break;
1486 }
1487
1488 case 'LYRC' :
1489 if (*ioDataSize < sizeof(CFStringRef))
1490 return kAudioFileBadPropertySizeError;
1491
1492 *ioDataSize = sizeof(CFStringRef);
1493 err = GetLyrics((CFStringRef*) ioPropertyData);
1494 break;
1495
1496 case 'eof?' :
1497 {
1498 if (*ioDataSize != sizeof(UInt32))
1499 return kAudioFileBadPropertySizeError;
1500
1501 SInt64 pos;
1502 err = GetDataSource()->GetPos(pos);
1503 if (err) break;
1504
1505 SInt64 endOfData = GetDataOffset() + GetNumBytes();
1506 *(UInt32*)ioPropertyData = pos >= endOfData;
1507
1508 break;
1509 }
1510 case 'sbtd' /*kAudioFilePropertySourceBitDepth*/ :
1511 {
1512 if (*ioDataSize != sizeof(SInt32))
1513 return kAudioFileBadPropertySizeError;
1514
1515 SInt32 outValue = 0;
1516 err = GetSourceBitDepth(outValue);
1517 if ((err || outValue == 0) && GetDataFormat().mFormatID == kAudioFormatLinearPCM) {
1518 // if there was no stored source bit depth, and this file is LPCM, then report this file's bit depth.
1519 err = noErr;
1520 outValue = GetDataFormat().mBitsPerChannel;
1521 if (GetDataFormat().mFormatFlags & kAudioFormatFlagIsFloat)
1522 outValue = -outValue;
1523 } else if (err)
1524 break;
1525
1526 *(SInt32 *) ioPropertyData = outValue;
1527
1528 break;
1529 }
1530 default:
1531 err = kAudioFileUnsupportedPropertyError;
1532 break;
1533 }
1534
1535 Bail:
1536 return err;
1537 }
1538
1539 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1540
SetProperty(AudioFilePropertyID inPropertyID,UInt32 inDataSize,const void * inPropertyData)1541 OSStatus AudioFileObject::SetProperty(
1542 AudioFilePropertyID inPropertyID,
1543 UInt32 inDataSize,
1544 const void *inPropertyData)
1545 {
1546 OSStatus err = noErr;
1547
1548 switch (inPropertyID)
1549 {
1550 case kAudioFilePropertyDataFormat:
1551 FailWithAction(inDataSize != sizeof(AudioStreamBasicDescription),
1552 err = kAudioFileBadPropertySizeError, Bail, "Incorrect data size");
1553 err = UpdateDataFormat((AudioStreamBasicDescription *) inPropertyData);
1554 break;
1555 case kAudioFilePropertyFormatList:
1556 err = SetFormatList(inDataSize, (AudioFormatListItem*)inPropertyData);
1557 break;
1558
1559 case kAudioFilePropertyAudioDataByteCount: {
1560 FailWithAction(inDataSize != sizeof(SInt64), err = kAudioFileBadPropertySizeError, Bail, "Incorrect data size");
1561 SInt64 numBytes = *(SInt64 *) inPropertyData;
1562 if (numBytes > GetNumBytes()) {
1563 // can't use this to increase data size.
1564 return kAudioFileOperationNotSupportedError;
1565 }
1566 UInt32 saveDefer = DeferSizeUpdates();
1567 SetDeferSizeUpdates(0); // force an update.
1568 err = UpdateNumBytes(numBytes);
1569 SetDeferSizeUpdates(saveDefer);
1570 } break;
1571
1572 case kAudioFilePropertyAudioDataPacketCount: {
1573 SInt64 numPackets = *(SInt64 *) inPropertyData;
1574 if (numPackets > GetNumPackets()) {
1575 // can't use this to increase data size.
1576 return kAudioFileOperationNotSupportedError;
1577 }
1578 err = UpdateNumPackets(numPackets);
1579 } break;
1580
1581 case kAudioFilePropertyMagicCookieData:
1582 err = SetMagicCookieData(inDataSize, inPropertyData);
1583 break;
1584
1585
1586 case kAudioFilePropertyMarkerList :
1587 err = SetMarkerList(inDataSize, static_cast<const AudioFileMarkerList*>(inPropertyData));
1588 break;
1589
1590 case kAudioFilePropertyRegionList :
1591 err = SetRegionList(inDataSize, static_cast<const AudioFileRegionList*>(inPropertyData));
1592 break;
1593
1594 case kAudioFilePropertyChannelLayout :
1595 err = SetChannelLayout(inDataSize, static_cast<const AudioChannelLayout*>(inPropertyData));
1596 break;
1597
1598 case kAudioFilePropertyDeferSizeUpdates :
1599 FailWithAction(inDataSize != sizeof(UInt32),
1600 err = kAudioFileBadPropertySizeError, Bail, "inDataSize is wrong");
1601 SetDeferSizeUpdates(*(UInt32 *) inPropertyData);
1602 break;
1603
1604 case kAudioFilePropertyInfoDictionary :
1605 {
1606 FailWithAction(inDataSize != sizeof(CFDictionaryRef),
1607 err = kAudioFileBadPropertySizeError, Bail, "inDataSize is wrong");
1608
1609 // pass the SetInfoDictionary a CACFDictionary object made with the provided CFDictionaryRef
1610 // Let the caller release their own CFObject so pass false for th erelease parameter
1611 CACFDictionary afInfoDictionary(*(CFDictionaryRef *)inPropertyData, false);
1612 err = SetInfoDictionary(&afInfoDictionary);
1613
1614 break;
1615 }
1616
1617 case kTEMPAudioFilePropertySoundCheckDictionary :
1618 {
1619 FailWithAction(inDataSize != sizeof(CFDictionaryRef),
1620 err = kAudioFileBadPropertySizeError, Bail, "inDataSize is wrong");
1621
1622 // pass the SetInfoDictionary a CACFDictionary object made with the provided CFDictionaryRef
1623 // Let the caller release their own CFObject so pass false for the release parameter
1624 CACFDictionary afInfoDictionary(*(CFDictionaryRef *)inPropertyData, false);
1625 err = SetSoundCheckDictionary(&afInfoDictionary);
1626
1627 break;
1628 }
1629
1630 case kTEMPAudioFilePropertyLoudnessInfo :
1631 {
1632 FailWithAction(inDataSize != sizeof(CFDictionaryRef),
1633 err = kAudioFileBadPropertySizeError, Bail, "inDataSize is wrong");
1634
1635 // pass the SetInfoDictionary a CACFDictionary object made with the provided CFDictionaryRef
1636 // Let the caller release their own CFObject so pass false for the release parameter
1637 CACFDictionary afInfoDictionary(*(CFDictionaryRef *)inPropertyData, false);
1638 err = SetLoudnessInfo(&afInfoDictionary);
1639
1640 break;
1641 }
1642
1643 case 'sbtd' /*kAudioFilePropertySourceBitDepth*/ :
1644 {
1645 FailWithAction(inDataSize != sizeof(SInt32),
1646 err = kAudioFileBadPropertySizeError, Bail, "inDataSize is wrong");
1647
1648 SInt32 inValue = *(SInt32 *)inPropertyData;
1649 err = SetSourceBitDepth(inValue);
1650
1651 break;
1652 }
1653
1654 default:
1655 err = kAudioFileUnsupportedPropertyError;
1656 break;
1657 }
1658
1659 Bail:
1660 return err;
1661 }
1662
1663
1664 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1665
SetDataFormat(const AudioStreamBasicDescription * inStreamFormat)1666 OSStatus AudioFileObject::SetDataFormat(const AudioStreamBasicDescription* inStreamFormat)
1667 {
1668 OSStatus err = noErr;
1669
1670 if (!IsDataFormatValid(inStreamFormat))
1671 return kAudioFileUnsupportedDataFormatError;
1672
1673 if (!IsDataFormatSupported(inStreamFormat))
1674 return kAudioFileUnsupportedDataFormatError;
1675
1676 UInt32 prevBytesPerPacket = mDataFormat.mBytesPerPacket;
1677
1678 mDataFormat = *inStreamFormat;
1679
1680 // if CBR and bytes per packet changes, we need to change the number of packets we think we have.
1681 if (mDataFormat.mBytesPerPacket && mDataFormat.mBytesPerPacket != prevBytesPerPacket)
1682 {
1683 SInt64 numPackets = GetNumBytes() / mDataFormat.mBytesPerPacket;
1684 SetNumPackets(numPackets);
1685 SetMaximumPacketSize(mDataFormat.mBytesPerPacket);
1686
1687 if (!mFirstSetFormat)
1688 SizeChanged();
1689 }
1690
1691 mFirstSetFormat = false;
1692
1693 return err;
1694 }
1695
1696 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1697
GetFormatListInfo(UInt32 & outDataSize,UInt32 & outWritable)1698 OSStatus AudioFileObject::GetFormatListInfo( UInt32 &outDataSize,
1699 UInt32 &outWritable)
1700 {
1701 // default implementation is to just return the data format
1702 outDataSize = sizeof(AudioFormatListItem);
1703 outWritable = false;
1704 return noErr;
1705 }
1706
1707 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1708
GetFormatList(UInt32 & ioDataSize,AudioFormatListItem * ioPropertyData)1709 OSStatus AudioFileObject::GetFormatList( UInt32 &ioDataSize,
1710 AudioFormatListItem *ioPropertyData)
1711 {
1712 // default implementation is to just return the data format
1713 if (ioDataSize < sizeof(AudioFormatListItem))
1714 return kAudioFileBadPropertySizeError;
1715
1716 AudioFormatListItem afli;
1717 afli.mASBD = mDataFormat;
1718 AudioChannelLayoutTag layoutTag = /*kAudioChannelLayoutTag_Unknown*/ 0xFFFF0000 | mDataFormat.mChannelsPerFrame;
1719 UInt32 layoutSize, isWritable;
1720 OSStatus err = GetChannelLayoutSize(&layoutSize, &isWritable);
1721 if (err == noErr)
1722 {
1723 CAAutoFree<AudioChannelLayout> layout;
1724 layout.allocBytes(layoutSize);
1725 err = GetChannelLayout(&layoutSize, layout());
1726 if (err == noErr) {
1727 layoutTag = layout->mChannelLayoutTag;
1728 }
1729 }
1730 afli.mChannelLayoutTag = layoutTag;
1731
1732 memcpy(ioPropertyData, &afli, sizeof(AudioFormatListItem));
1733
1734 ioDataSize = sizeof(AudioFormatListItem);
1735 return noErr;
1736 }
1737
1738 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1739
SetFormatList(UInt32 inDataSize,const AudioFormatListItem * inPropertyData)1740 OSStatus AudioFileObject::SetFormatList( UInt32 inDataSize,
1741 const AudioFormatListItem *inPropertyData)
1742 {
1743 return kAudioFileOperationNotSupportedError;
1744 }
1745
1746 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1747
UpdateDataFormat(const AudioStreamBasicDescription * inStreamFormat)1748 OSStatus AudioFileObject::UpdateDataFormat(const AudioStreamBasicDescription* inStreamFormat)
1749 {
1750 return SetDataFormat(inStreamFormat);
1751 }
1752
1753
1754 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1755
IsDataFormatValid(AudioStreamBasicDescription const * inDesc)1756 Boolean AudioFileObject::IsDataFormatValid(AudioStreamBasicDescription const* inDesc)
1757 {
1758 if (inDesc->mSampleRate < 0.)
1759 return false;
1760
1761 if (inDesc->mSampleRate > 3e6)
1762 return false;
1763
1764 if (inDesc->mChannelsPerFrame < 1 || inDesc->mChannelsPerFrame > 0x000FFFFF)
1765 return false;
1766
1767 if (inDesc->mFormatID == kAudioFormatLinearPCM)
1768 {
1769 if (inDesc->mBitsPerChannel < 1 || inDesc->mBitsPerChannel > 64)
1770 return false;
1771
1772 if (inDesc->mFramesPerPacket != 1)
1773 return false;
1774
1775 if (inDesc->mBytesPerPacket == 0)
1776 return false;
1777
1778 if (inDesc->mBytesPerFrame != inDesc->mBytesPerPacket)
1779 return false;
1780
1781 // [3605260] we assume here that a packet is an integer number of frames.
1782 UInt32 minimumBytesPerPacket = (inDesc->mBitsPerChannel * inDesc->mChannelsPerFrame + 7) / 8;
1783 if (inDesc->mBytesPerPacket < minimumBytesPerPacket)
1784 return false;
1785 }
1786 return true;
1787 }
1788
1789 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1790
SetDataSource(DataSource * inDataSource)1791 void AudioFileObject::SetDataSource(DataSource* inDataSource)
1792 {
1793 if (mDataSource != inDataSource) {
1794 delete mDataSource;
1795 mDataSource = inDataSource;
1796 }
1797 }
1798
1799 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1800
SetURL(CFURLRef inURL)1801 void AudioFileObject::SetURL (CFURLRef inURL)
1802 {
1803 if (mFileRef == inURL) return;
1804 if (inURL) CFRetain (inURL);
1805 if (mFileRef) CFRelease(mFileRef);
1806 mFileRef = inURL;
1807 }
1808
OpenFile(SInt8 inPermissions,int inFD)1809 OSStatus AudioFileObject::OpenFile(SInt8 inPermissions, int inFD)
1810 {
1811 OSStatus err = noErr;
1812
1813 SetDataSource(new Cached_DataSource(new UnixFile_DataSource(inFD, inPermissions, true)));
1814
1815 mFileD = inFD;
1816 SetPermissions (inPermissions);
1817
1818 return err;
1819 }
1820
CreateDataFile(CFURLRef inFileRef,int & outFileD)1821 OSStatus AudioFileObject::CreateDataFile (CFURLRef inFileRef, int &outFileD)
1822 {
1823 UInt8 fPath[FILENAME_MAX];
1824 if (!CFURLGetFileSystemRepresentation (inFileRef, true, fPath, FILENAME_MAX))
1825 return kAudio_FileNotFoundError;
1826
1827 struct stat stbuf;
1828 if (stat ((const char*)fPath, &stbuf) == 0)
1829 return kAudioFilePermissionsError;
1830
1831 #if TARGET_OS_WIN32
1832 int filePerms = S_IREAD | S_IWRITE;
1833 int flags = O_CREAT | O_EXCL | O_RDWR | O_BINARY;
1834 #else
1835 mode_t filePerms = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
1836 int flags = O_CREAT | O_EXCL | O_RDWR;
1837 #endif
1838 outFileD = open((const char*)fPath, flags, filePerms);
1839 if (outFileD < 0)
1840 return AudioFileTranslateErrno(errno);
1841
1842 return noErr;
1843 }
1844
AddDurationToInfoDictionary(CACFDictionary * infoDict,Float64 & inDuration)1845 OSStatus AudioFileObject::AddDurationToInfoDictionary(CACFDictionary *infoDict, Float64 &inDuration)
1846 {
1847 #if !TARGET_OS_WIN32
1848 CFLocaleRef currentLocale = CFLocaleGetSystem();
1849 CFNumberFormatterRef numberFormatter = NULL;
1850 numberFormatter = CFNumberFormatterCreate(kCFAllocatorDefault, currentLocale, kCFNumberFormatterDecimalStyle);
1851 CFStringRef cfStr = CFNumberFormatterCreateStringWithValue( kCFAllocatorDefault, numberFormatter, kCFNumberFloat64Type, &inDuration);
1852 if (cfStr)
1853 {
1854 if (CFStringGetLength(cfStr) != 0)
1855 infoDict->AddString(CFSTR(kAFInfoDictionary_ApproximateDurationInSeconds), cfStr);
1856 CFRelease(cfStr);
1857 }
1858 CFRelease(numberFormatter);
1859 #endif
1860 return noErr;
1861 }
1862
SizeChanged()1863 OSStatus AudioFileObject::SizeChanged()
1864 {
1865 OSStatus err = noErr;
1866 if (mPermissions & kAudioFileWritePermission)
1867 {
1868 if (DeferSizeUpdates())
1869 SetNeedsSizeUpdate(true);
1870 else
1871 err = UpdateSize();
1872 }
1873 return err;
1874 }
1875
UpdateSizeIfNeeded()1876 OSStatus AudioFileObject::UpdateSizeIfNeeded()
1877 {
1878 if (GetNeedsSizeUpdate())
1879 {
1880 OSStatus err = UpdateSize();
1881 if (err) return err;
1882 SetNeedsSizeUpdate(false);
1883 }
1884 return noErr;
1885 }
1886
CountUserData(UInt32,UInt32 *)1887 OSStatus AudioFileObject::CountUserData( UInt32 /*inUserDataID*/,
1888 UInt32* /*outNumberItems*/)
1889 {
1890 return kAudioFileOperationNotSupportedError;
1891 }
1892
GetUserDataSize(UInt32,UInt32,UInt32 *)1893 OSStatus AudioFileObject::GetUserDataSize( UInt32 /*inUserDataID*/,
1894 UInt32 /*inIndex*/,
1895 UInt32* /*outDataSize*/)
1896 {
1897 return kAudioFileOperationNotSupportedError;
1898 }
1899
GetUserData(UInt32,UInt32,UInt32 *,void *)1900 OSStatus AudioFileObject::GetUserData( UInt32 /*inUserDataID*/,
1901 UInt32 /*inIndex*/,
1902 UInt32* /*ioDataSize*/,
1903 void* /*ioUserData*/)
1904 {
1905 return kAudioFileOperationNotSupportedError;
1906 }
1907
SetUserData(UInt32,UInt32,UInt32,const void *)1908 OSStatus AudioFileObject::SetUserData( UInt32 /*inUserDataID*/,
1909 UInt32 /*inIndex*/,
1910 UInt32 /*inDataSize*/,
1911 const void* /*inUserData*/)
1912 {
1913 return kAudioFileOperationNotSupportedError;
1914 }
1915
RemoveUserData(UInt32,UInt32)1916 OSStatus AudioFileObject::RemoveUserData( UInt32 /*inUserDataID*/,
1917 UInt32 /*inIndex*/)
1918 {
1919 return kAudioFileOperationNotSupportedError;
1920 }
1921
MoveData(SInt64 fromPos,SInt64 toPos,SInt64 size)1922 OSStatus AudioFileObject::MoveData(SInt64 fromPos, SInt64 toPos, SInt64 size)
1923 {
1924 if (fromPos == toPos)
1925 return noErr;
1926
1927 OSStatus err = noErr;
1928 CAAutoFree<char> audioData(kCopySoundDataBufferSize, true);
1929
1930 SInt64 bytesRemaining = size;
1931 if (fromPos < toPos) {
1932 while (bytesRemaining > 0)
1933 {
1934 // read from old file
1935 UInt32 byteCount;
1936 SInt64 count = (bytesRemaining < kCopySoundDataBufferSize) ? bytesRemaining : kCopySoundDataBufferSize;
1937 err = GetDataSource()->ReadBytes(SEEK_SET, fromPos+(bytesRemaining-count), (UInt32)count, audioData(), &byteCount);
1938 FailIf (err != noErr, Bail, "MoveData ReadBytes failed");
1939
1940 err = GetDataSource()->WriteBytes(SEEK_SET, toPos+(bytesRemaining-count), (UInt32)count, audioData(), &byteCount);
1941 FailIf (err != noErr, Bail, "WriteBytes failed");
1942
1943 bytesRemaining -= count;
1944 }
1945 } else {
1946 while (bytesRemaining > 0)
1947 {
1948 // read from old file
1949 UInt32 byteCount;
1950 SInt64 count = (bytesRemaining < kCopySoundDataBufferSize) ? bytesRemaining : kCopySoundDataBufferSize;
1951 err = GetDataSource()->ReadBytes(SEEK_SET, fromPos+(size - bytesRemaining), (UInt32)count, audioData(), &byteCount);
1952 FailIf (err != noErr, Bail, "MoveData ReadBytes failed");
1953
1954 err = GetDataSource()->WriteBytes(SEEK_SET, toPos+(size - bytesRemaining), (UInt32)count, audioData(), &byteCount);
1955 FailIf (err != noErr, Bail, "WriteBytes failed");
1956
1957 bytesRemaining -= count;
1958 }
1959 }
1960
1961 Bail:
1962 return err;
1963 }
1964
1965 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1966
1967