src/cdrom/macosx/AudioFileReaderThread.c
author Sam Lantinga <slouken@libsdl.org>
Thu, 09 Mar 2006 06:33:21 +0000
changeset 1487 dc6b59e925a2
parent 1402 d910939febfa
child 1662 782fd950bd46
child 1895 c121d94672cb
child 4159 a1b03ba2fcd0
permissions -rw-r--r--
Cleaning up warnings on MacOS X
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002  Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Library General Public
     7     License as published by the Free Software Foundation; either
     8     version 2 of the License, or (at your option) any later version.
     9 
    10     This library is distributed in the hope that it will be useful,
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13     Library General Public License for more details.
    14 
    15     You should have received a copy of the GNU Library General Public
    16     License along with this library; if not, write to the Free
    17     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 
    22     This file based on Apple sample code. We haven't changed the file name, 
    23     so if you want to see the original search for it on apple.com/developer
    24 */
    25 #include "SDL_config.h"
    26 
    27 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    28    AudioFileManager.cpp
    29 */
    30 #include "AudioFilePlayer.h"
    31 #include <mach/mach.h> /* used for setting policy of thread */
    32 #include "SDLOSXCAGuard.h"
    33 #include <pthread.h>
    34 
    35 /*#include <list>*/
    36 
    37 /*typedef void *FileData;*/
    38 typedef struct S_FileData
    39 {
    40     AudioFileManager *obj;
    41     struct S_FileData *next;
    42 } FileData;
    43 
    44 
    45 typedef struct S_FileReaderThread {
    46 /*public:*/
    47     SDLOSXCAGuard*                    (*GetGuard)(struct S_FileReaderThread *frt);
    48     void                        (*AddReader)(struct S_FileReaderThread *frt);
    49     void                        (*RemoveReader)(struct S_FileReaderThread *frt, AudioFileManager* inItem);
    50     int                         (*TryNextRead)(struct S_FileReaderThread *frt, AudioFileManager* inItem);
    51 
    52     int     mThreadShouldDie;
    53     
    54 /*private:*/
    55     /*typedef std::list<AudioFileManager*> FileData;*/
    56 
    57     SDLOSXCAGuard             *mGuard;
    58     UInt32              mThreadPriority;
    59     
    60     int                 mNumReaders;    
    61     FileData            *mFileData;
    62 
    63 
    64     void                        (*ReadNextChunk)(struct S_FileReaderThread *frt);
    65     int                         (*StartFixedPriorityThread)(struct S_FileReaderThread *frt);
    66     /*static*/
    67     UInt32               (*GetThreadBasePriority)(pthread_t inThread);
    68     /*static*/
    69     void*                (*DiskReaderEntry)(void *inRefCon);
    70 } FileReaderThread;
    71 
    72 
    73 static SDLOSXCAGuard* FileReaderThread_GetGuard(FileReaderThread *frt)
    74 {
    75     return frt->mGuard;
    76 }
    77 
    78 /* returns 1 if succeeded */
    79 static int FileReaderThread_TryNextRead (FileReaderThread *frt, AudioFileManager* inItem)
    80 {
    81     int didLock = 0;
    82     int succeeded = 0;
    83     if (frt->mGuard->Try(frt->mGuard, &didLock))
    84     {
    85         /*frt->mFileData.push_back (inItem);*/
    86         /* !!! FIXME: this could be faster with a "tail" member. --ryan. */
    87         FileData *i = frt->mFileData;
    88         FileData *prev = NULL;
    89 
    90         FileData *newfd = (FileData *) SDL_malloc(sizeof (FileData));
    91         newfd->obj = inItem;
    92         newfd->next = NULL;
    93 
    94         while (i != NULL) { prev = i; i = i->next; }
    95         if (prev == NULL)
    96             frt->mFileData = newfd;
    97         else
    98             prev->next = newfd;
    99 
   100         frt->mGuard->Notify(frt->mGuard);
   101         succeeded = 1;
   102 
   103         if (didLock)
   104             frt->mGuard->Unlock(frt->mGuard);
   105     }
   106                 
   107     return succeeded;
   108 }
   109 
   110 static void    FileReaderThread_AddReader(FileReaderThread *frt)
   111 {
   112     if (frt->mNumReaders == 0)
   113     {
   114         frt->mThreadShouldDie = 0;
   115         frt->StartFixedPriorityThread (frt);
   116     }
   117     frt->mNumReaders++;
   118 }
   119 
   120 static void    FileReaderThread_RemoveReader (FileReaderThread *frt, AudioFileManager* inItem)
   121 {
   122     if (frt->mNumReaders > 0)
   123     {
   124         int bNeedsRelease = frt->mGuard->Lock(frt->mGuard);
   125         
   126         /*frt->mFileData.remove (inItem);*/
   127         FileData *i = frt->mFileData;
   128         FileData *prev = NULL;
   129         while (i != NULL)
   130         {
   131             FileData *next = i->next;
   132             if (i->obj != inItem)
   133                 prev = i;
   134             else
   135             {
   136                 if (prev == NULL)
   137                     frt->mFileData = next;
   138                 else
   139                     prev->next = next;
   140                 SDL_free(i);
   141             }
   142             i = next;
   143         }
   144 
   145         if (--frt->mNumReaders == 0) {
   146             frt->mThreadShouldDie = 1;
   147             frt->mGuard->Notify(frt->mGuard); /* wake up thread so it will quit */
   148             frt->mGuard->Wait(frt->mGuard);   /* wait for thread to die */
   149         }
   150 
   151         if (bNeedsRelease) frt->mGuard->Unlock(frt->mGuard);
   152     }   
   153 }
   154 
   155 static int    FileReaderThread_StartFixedPriorityThread (FileReaderThread *frt)
   156 {
   157     pthread_attr_t      theThreadAttrs;
   158     pthread_t           pThread;
   159 
   160     OSStatus result = pthread_attr_init(&theThreadAttrs);
   161         if (result) return 0; /*THROW_RESULT("pthread_attr_init - Thread attributes could not be created.")*/
   162     
   163     result = pthread_attr_setdetachstate(&theThreadAttrs, PTHREAD_CREATE_DETACHED);
   164         if (result) return 0; /*THROW_RESULT("pthread_attr_setdetachstate - Thread attributes could not be detached.")*/
   165     
   166     result = pthread_create (&pThread, &theThreadAttrs, frt->DiskReaderEntry, frt);
   167         if (result) return 0; /*THROW_RESULT("pthread_create - Create and start the thread.")*/
   168     
   169     pthread_attr_destroy(&theThreadAttrs);
   170     
   171     /* we've now created the thread and started it
   172        we'll now set the priority of the thread to the nominated priority
   173        and we'll also make the thread fixed */
   174     thread_extended_policy_data_t       theFixedPolicy;
   175     thread_precedence_policy_data_t     thePrecedencePolicy;
   176     SInt32                              relativePriority;
   177     
   178     /* make thread fixed */
   179     theFixedPolicy.timeshare = 0;   /* set to 1 for a non-fixed thread */
   180     result = thread_policy_set (pthread_mach_thread_np(pThread), THREAD_EXTENDED_POLICY, (thread_policy_t)&theFixedPolicy, THREAD_EXTENDED_POLICY_COUNT);
   181         if (result) return 0; /*THROW_RESULT("thread_policy - Couldn't set thread as fixed priority.")*/
   182     /* set priority */
   183     /* precedency policy's "importance" value is relative to spawning thread's priority */
   184     relativePriority = frt->mThreadPriority - frt->GetThreadBasePriority(pthread_self());
   185         
   186     thePrecedencePolicy.importance = relativePriority;
   187     result = thread_policy_set (pthread_mach_thread_np(pThread), THREAD_PRECEDENCE_POLICY, (thread_policy_t)&thePrecedencePolicy, THREAD_PRECEDENCE_POLICY_COUNT);
   188         if (result) return 0; /*THROW_RESULT("thread_policy - Couldn't set thread priority.")*/
   189 
   190     return 1;
   191 }
   192 
   193 static UInt32  FileReaderThread_GetThreadBasePriority (pthread_t inThread)
   194 {
   195     thread_basic_info_data_t            threadInfo;
   196     policy_info_data_t                  thePolicyInfo;
   197     unsigned int                        count;
   198     
   199     /* get basic info */
   200     count = THREAD_BASIC_INFO_COUNT;
   201     thread_info (pthread_mach_thread_np (inThread), THREAD_BASIC_INFO, (integer_t*)&threadInfo, &count);
   202     
   203     switch (threadInfo.policy) {
   204         case POLICY_TIMESHARE:
   205             count = POLICY_TIMESHARE_INFO_COUNT;
   206             thread_info(pthread_mach_thread_np (inThread), THREAD_SCHED_TIMESHARE_INFO, (integer_t*)&(thePolicyInfo.ts), &count);
   207             return thePolicyInfo.ts.base_priority;
   208             break;
   209             
   210         case POLICY_FIFO:
   211             count = POLICY_FIFO_INFO_COUNT;
   212             thread_info(pthread_mach_thread_np (inThread), THREAD_SCHED_FIFO_INFO, (integer_t*)&(thePolicyInfo.fifo), &count);
   213             if (thePolicyInfo.fifo.depressed) {
   214                 return thePolicyInfo.fifo.depress_priority;
   215             } else {
   216                 return thePolicyInfo.fifo.base_priority;
   217             }
   218             break;
   219             
   220         case POLICY_RR:
   221             count = POLICY_RR_INFO_COUNT;
   222             thread_info(pthread_mach_thread_np (inThread), THREAD_SCHED_RR_INFO, (integer_t*)&(thePolicyInfo.rr), &count);
   223             if (thePolicyInfo.rr.depressed) {
   224                 return thePolicyInfo.rr.depress_priority;
   225             } else {
   226                 return thePolicyInfo.rr.base_priority;
   227             }
   228             break;
   229     }
   230     
   231     return 0;
   232 }
   233 
   234 static void    *FileReaderThread_DiskReaderEntry (void *inRefCon)
   235 {
   236     FileReaderThread *frt = (FileReaderThread *)inRefCon;
   237     frt->ReadNextChunk(frt);
   238     #if DEBUG
   239     printf ("finished with reading file\n");
   240     #endif
   241     
   242     return 0;
   243 }
   244 
   245 static void    FileReaderThread_ReadNextChunk (FileReaderThread *frt)
   246 {
   247     OSStatus result;
   248     UInt32  dataChunkSize;
   249     AudioFileManager* theItem = 0;
   250 
   251     for (;;) 
   252     {
   253         { /* this is a scoped based lock */
   254             int bNeedsRelease = frt->mGuard->Lock(frt->mGuard);
   255             
   256             if (frt->mThreadShouldDie) {
   257                 frt->mGuard->Notify(frt->mGuard);
   258                 if (bNeedsRelease) frt->mGuard->Unlock(frt->mGuard);
   259                 return;
   260             }
   261             
   262             /*if (frt->mFileData.empty())*/
   263             if (frt->mFileData == NULL)
   264             {
   265                 frt->mGuard->Wait(frt->mGuard);
   266             }
   267                         
   268             /* kill thread */
   269             if (frt->mThreadShouldDie) {
   270             
   271                 frt->mGuard->Notify(frt->mGuard);
   272                 if (bNeedsRelease) frt->mGuard->Unlock(frt->mGuard);
   273                 return;
   274             }
   275 
   276             /*theItem = frt->mFileData.front();*/
   277             /*frt->mFileData.pop_front();*/
   278             theItem = NULL;
   279             if (frt->mFileData != NULL)
   280             {
   281                 FileData *next = frt->mFileData->next;
   282                 theItem = frt->mFileData->obj;
   283                 SDL_free(frt->mFileData);
   284                 frt->mFileData = next;
   285             }
   286 
   287             if (bNeedsRelease) frt->mGuard->Unlock(frt->mGuard);
   288         }
   289     
   290         if ((theItem->mFileLength - theItem->mReadFilePosition) < theItem->mChunkSize)
   291             dataChunkSize = theItem->mFileLength - theItem->mReadFilePosition;
   292         else
   293             dataChunkSize = theItem->mChunkSize;
   294         
   295             /* this is the exit condition for the thread */
   296         if (dataChunkSize <= 0) {
   297             theItem->mFinishedReadingData = 1;
   298             continue;
   299         }
   300             /* construct pointer */
   301         char* writePtr = (char *) (theItem->GetFileBuffer(theItem) +
   302                                 (theItem->mWriteToFirstBuffer ? 0 : theItem->mChunkSize));
   303     
   304             /* read data */
   305         result = theItem->Read(theItem, writePtr, &dataChunkSize);
   306         if (result != noErr && result != eofErr) {
   307             AudioFilePlayer *afp = (AudioFilePlayer *) theItem->GetParent(theItem);
   308             afp->DoNotification(afp, result);
   309             continue;
   310         }
   311         
   312         if (dataChunkSize != theItem->mChunkSize)
   313         {
   314             writePtr += dataChunkSize;
   315 
   316             /* can't exit yet.. we still have to pass the partial buffer back */
   317             SDL_memset(writePtr, 0, (theItem->mChunkSize - dataChunkSize));
   318         }
   319         
   320         theItem->mWriteToFirstBuffer = !theItem->mWriteToFirstBuffer;   /* switch buffers */
   321         
   322         if (result == eofErr)
   323             theItem->mReadFilePosition = theItem->mFileLength;
   324         else
   325             theItem->mReadFilePosition += dataChunkSize;        /* increment count */
   326     }
   327 }
   328 
   329 void delete_FileReaderThread(FileReaderThread *frt)
   330 {
   331     if (frt != NULL)
   332     {
   333         delete_SDLOSXCAGuard(frt->mGuard);
   334         SDL_free(frt);
   335     }
   336 }
   337 
   338 FileReaderThread *new_FileReaderThread ()
   339 {
   340     FileReaderThread *frt = (FileReaderThread *) SDL_malloc(sizeof (FileReaderThread));
   341     if (frt == NULL)
   342         return NULL;
   343     SDL_memset(frt, '\0', sizeof (*frt));
   344 
   345     frt->mGuard = new_SDLOSXCAGuard();
   346     if (frt->mGuard == NULL)
   347     {
   348         SDL_free(frt);
   349         return NULL;
   350     }
   351 
   352     #define SET_FILEREADERTHREAD_METHOD(m) frt->m = FileReaderThread_##m
   353     SET_FILEREADERTHREAD_METHOD(GetGuard);
   354     SET_FILEREADERTHREAD_METHOD(AddReader);
   355     SET_FILEREADERTHREAD_METHOD(RemoveReader);
   356     SET_FILEREADERTHREAD_METHOD(TryNextRead);
   357     SET_FILEREADERTHREAD_METHOD(ReadNextChunk);
   358     SET_FILEREADERTHREAD_METHOD(StartFixedPriorityThread);
   359     SET_FILEREADERTHREAD_METHOD(GetThreadBasePriority);
   360     SET_FILEREADERTHREAD_METHOD(DiskReaderEntry);
   361     #undef SET_FILEREADERTHREAD_METHOD
   362 
   363     frt->mThreadPriority = 62;
   364     return frt;
   365 }
   366 
   367 
   368 static FileReaderThread *sReaderThread;
   369 
   370 
   371 static int    AudioFileManager_DoConnect (AudioFileManager *afm)
   372 {
   373     if (!afm->mIsEngaged)
   374     {
   375         OSStatus result;
   376 
   377         /*afm->mReadFilePosition = 0;*/
   378         afm->mFinishedReadingData = 0;
   379 
   380         afm->mNumTimesAskedSinceFinished = 0;
   381         afm->mLockUnsuccessful = 0;
   382         
   383         UInt32 dataChunkSize;
   384         
   385         if ((afm->mFileLength - afm->mReadFilePosition) < afm->mChunkSize)
   386             dataChunkSize = afm->mFileLength - afm->mReadFilePosition;
   387         else
   388             dataChunkSize = afm->mChunkSize;
   389         
   390         result = afm->Read(afm, afm->mFileBuffer, &dataChunkSize);
   391            if (result) return 0; /*THROW_RESULT("AudioFileManager::DoConnect(): Read")*/
   392 
   393         afm->mReadFilePosition += dataChunkSize;
   394                 
   395         afm->mWriteToFirstBuffer = 0;
   396         afm->mReadFromFirstBuffer = 1;
   397 
   398         sReaderThread->AddReader(sReaderThread);
   399         
   400         afm->mIsEngaged = 1;
   401     }
   402     /*
   403     else
   404         throw static_cast<OSStatus>(-1); */ /* thread has already been started */
   405 
   406     return 1;
   407 }
   408 
   409 static void    AudioFileManager_Disconnect (AudioFileManager *afm)
   410 {
   411     if (afm->mIsEngaged)
   412     {
   413         sReaderThread->RemoveReader (sReaderThread, afm);
   414         afm->mIsEngaged = 0;
   415     }
   416 }
   417 
   418 static OSStatus AudioFileManager_Read(AudioFileManager *afm, char *buffer, UInt32 *len)
   419 {
   420     return FSReadFork (afm->mForkRefNum,
   421                        fsFromStart,
   422                        afm->mReadFilePosition + afm->mAudioDataOffset,
   423                        *len,
   424                        buffer,
   425                        len);
   426 }
   427 
   428 static OSStatus AudioFileManager_GetFileData (AudioFileManager *afm, void** inOutData, UInt32 *inOutDataSize)
   429 {
   430     if (afm->mFinishedReadingData)
   431     {
   432         ++afm->mNumTimesAskedSinceFinished;
   433         *inOutDataSize = 0;
   434         *inOutData = 0;
   435         return noErr;
   436     }
   437     
   438     if (afm->mReadFromFirstBuffer == afm->mWriteToFirstBuffer) {
   439         #if DEBUG
   440         printf ("* * * * * * * Can't keep up with reading file\n");
   441         #endif
   442         
   443         afm->mParent->DoNotification (afm->mParent, kAudioFilePlayErr_FilePlayUnderrun);
   444         *inOutDataSize = 0;
   445         *inOutData = 0;
   446     } else {
   447         *inOutDataSize = afm->mChunkSize;
   448         *inOutData = afm->mReadFromFirstBuffer ? afm->mFileBuffer : (afm->mFileBuffer + afm->mChunkSize);
   449     }
   450 
   451     afm->mLockUnsuccessful = !sReaderThread->TryNextRead (sReaderThread, afm);
   452     
   453     afm->mReadFromFirstBuffer = !afm->mReadFromFirstBuffer;
   454 
   455     return noErr;
   456 }
   457 
   458 static void    AudioFileManager_AfterRender (AudioFileManager *afm)
   459 {
   460     if (afm->mNumTimesAskedSinceFinished > 0)
   461     {
   462         int didLock = 0;
   463         SDLOSXCAGuard *guard = sReaderThread->GetGuard(sReaderThread);
   464         if (guard->Try(guard, &didLock)) {
   465             afm->mParent->DoNotification (afm->mParent, kAudioFilePlay_FileIsFinished);
   466             if (didLock)
   467                 guard->Unlock(guard);
   468         }
   469     }
   470 
   471     if (afm->mLockUnsuccessful)
   472         afm->mLockUnsuccessful = !sReaderThread->TryNextRead (sReaderThread, afm);
   473 }
   474 
   475 static void    AudioFileManager_SetPosition (AudioFileManager *afm, SInt64 pos)
   476 {
   477     if (pos < 0 || pos >= afm->mFileLength) {
   478         SDL_SetError ("AudioFileManager::SetPosition - position invalid: %d filelen=%d\n", 
   479             (unsigned int)pos, (unsigned int)afm->mFileLength);
   480         pos = 0;
   481     }
   482         
   483     afm->mReadFilePosition = pos;
   484 }
   485     
   486 static void    AudioFileManager_SetEndOfFile (AudioFileManager *afm, SInt64 pos)
   487 {
   488     if (pos <= 0 || pos > afm->mFileLength) {
   489         SDL_SetError ("AudioFileManager::SetEndOfFile - position beyond actual eof\n");
   490         pos = afm->mFileLength;
   491     }
   492     
   493     afm->mFileLength = pos;
   494 }
   495 
   496 static const char *AudioFileManager_GetFileBuffer(AudioFileManager *afm)
   497 {
   498     return afm->mFileBuffer;
   499 }
   500 
   501 const AudioFilePlayer *AudioFileManager_GetParent(AudioFileManager *afm)
   502 {
   503     return afm->mParent;
   504 }
   505 
   506 static int AudioFileManager_GetByteCounter(AudioFileManager *afm)
   507 {
   508     return afm->mByteCounter;
   509 }
   510 
   511 
   512 static OSStatus    AudioFileManager_FileInputProc (void                       *inRefCon,
   513                                              AudioUnitRenderActionFlags inActionFlags,
   514                                              const AudioTimeStamp       *inTimeStamp, 
   515                                              UInt32                     inBusNumber, 
   516                                              AudioBuffer                *ioData)
   517 {
   518     AudioFileManager* afm = (AudioFileManager*)inRefCon;
   519     return afm->Render(afm, ioData);
   520 }
   521 
   522 static OSStatus    AudioFileManager_Render (AudioFileManager *afm, AudioBuffer *ioData)
   523 {
   524     OSStatus result = noErr;
   525     
   526 	if (afm->mBufferOffset >= afm->mBufferSize) {
   527 		result = afm->GetFileData(afm, &afm->mTmpBuffer, &afm->mBufferSize);
   528 		if (result) {
   529 			SDL_SetError ("AudioConverterFillBuffer:%ld\n", result);
   530 			afm->mParent->DoNotification(afm->mParent, result);
   531 			return result;
   532 		}
   533 
   534 		afm->mBufferOffset = 0;
   535 	}
   536     	
   537     if (ioData->mDataByteSize > afm->mBufferSize - afm->mBufferOffset)
   538     	ioData->mDataByteSize = afm->mBufferSize - afm->mBufferOffset;
   539     ioData->mData = (char *)afm->mTmpBuffer + afm->mBufferOffset;
   540     afm->mBufferOffset += ioData->mDataByteSize;
   541     
   542 	afm->mByteCounter += ioData->mDataByteSize;
   543 	afm->AfterRender(afm);
   544     return result;
   545 }
   546 
   547 
   548 void delete_AudioFileManager (AudioFileManager *afm)
   549 {
   550     if (afm != NULL) {
   551         if (afm->mFileBuffer) {
   552             free(afm->mFileBuffer);
   553         }
   554 
   555         SDL_free(afm);
   556     }
   557 }
   558 
   559 
   560 AudioFileManager *new_AudioFileManager(AudioFilePlayer *inParent,
   561                                        SInt16          inForkRefNum,
   562                                        SInt64          inFileLength,
   563                                        UInt32          inChunkSize)
   564 {
   565     AudioFileManager *afm;
   566 
   567     if (sReaderThread == NULL)
   568     {
   569         sReaderThread = new_FileReaderThread();
   570         if (sReaderThread == NULL)
   571             return NULL;
   572     }
   573 
   574     afm = (AudioFileManager *) SDL_malloc(sizeof (AudioFileManager));
   575     if (afm == NULL)
   576         return NULL;
   577     SDL_memset(afm, '\0', sizeof (*afm));
   578 
   579     #define SET_AUDIOFILEMANAGER_METHOD(m) afm->m = AudioFileManager_##m
   580     SET_AUDIOFILEMANAGER_METHOD(Disconnect);
   581     SET_AUDIOFILEMANAGER_METHOD(DoConnect);
   582     SET_AUDIOFILEMANAGER_METHOD(Read);
   583     SET_AUDIOFILEMANAGER_METHOD(GetFileBuffer);
   584     SET_AUDIOFILEMANAGER_METHOD(GetParent);
   585     SET_AUDIOFILEMANAGER_METHOD(SetPosition);
   586     SET_AUDIOFILEMANAGER_METHOD(GetByteCounter);
   587     SET_AUDIOFILEMANAGER_METHOD(SetEndOfFile);
   588     SET_AUDIOFILEMANAGER_METHOD(Render);
   589     SET_AUDIOFILEMANAGER_METHOD(GetFileData);
   590     SET_AUDIOFILEMANAGER_METHOD(AfterRender);
   591     SET_AUDIOFILEMANAGER_METHOD(FileInputProc);
   592     #undef SET_AUDIOFILEMANAGER_METHOD
   593 
   594     afm->mParent = inParent;
   595     afm->mForkRefNum = inForkRefNum;
   596     afm->mBufferSize = inChunkSize;
   597     afm->mBufferOffset = inChunkSize;
   598     afm->mChunkSize = inChunkSize;
   599     afm->mFileLength = inFileLength;
   600     afm->mFileBuffer = (char*) SDL_malloc(afm->mChunkSize * 2);
   601     FSGetForkPosition(afm->mForkRefNum, &afm->mAudioDataOffset);
   602     assert (afm->mFileBuffer != NULL);
   603     return afm;
   604 }
   605