symbian-qemu-0.9.1-12/libsdl-trunk/src/cdrom/macosx/AudioFileReaderThread.c
changeset 1 2fb8b9db1c86
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/symbian-qemu-0.9.1-12/libsdl-trunk/src/cdrom/macosx/AudioFileReaderThread.c	Fri Jul 31 15:01:17 2009 +0100
@@ -0,0 +1,605 @@
+/*
+    SDL - Simple DirectMedia Layer
+    Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002  Sam Lantinga
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public
+    License along with this library; if not, write to the Free
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+    Sam Lantinga
+    slouken@libsdl.org
+
+    This file based on Apple sample code. We haven't changed the file name, 
+    so if you want to see the original search for it on apple.com/developer
+*/
+#include "SDL_config.h"
+
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+   AudioFileManager.cpp
+*/
+#include "AudioFilePlayer.h"
+#include <mach/mach.h> /* used for setting policy of thread */
+#include "SDLOSXCAGuard.h"
+#include <pthread.h>
+
+/*#include <list>*/
+
+/*typedef void *FileData;*/
+typedef struct S_FileData
+{
+    AudioFileManager *obj;
+    struct S_FileData *next;
+} FileData;
+
+
+typedef struct S_FileReaderThread {
+/*public:*/
+    SDLOSXCAGuard*                    (*GetGuard)(struct S_FileReaderThread *frt);
+    void                        (*AddReader)(struct S_FileReaderThread *frt);
+    void                        (*RemoveReader)(struct S_FileReaderThread *frt, AudioFileManager* inItem);
+    int                         (*TryNextRead)(struct S_FileReaderThread *frt, AudioFileManager* inItem);
+
+    int     mThreadShouldDie;
+    
+/*private:*/
+    /*typedef std::list<AudioFileManager*> FileData;*/
+
+    SDLOSXCAGuard             *mGuard;
+    UInt32              mThreadPriority;
+    
+    int                 mNumReaders;    
+    FileData            *mFileData;
+
+
+    void                        (*ReadNextChunk)(struct S_FileReaderThread *frt);
+    int                         (*StartFixedPriorityThread)(struct S_FileReaderThread *frt);
+    /*static*/
+    UInt32               (*GetThreadBasePriority)(pthread_t inThread);
+    /*static*/
+    void*                (*DiskReaderEntry)(void *inRefCon);
+} FileReaderThread;
+
+
+static SDLOSXCAGuard* FileReaderThread_GetGuard(FileReaderThread *frt)
+{
+    return frt->mGuard;
+}
+
+/* returns 1 if succeeded */
+static int FileReaderThread_TryNextRead (FileReaderThread *frt, AudioFileManager* inItem)
+{
+    int didLock = 0;
+    int succeeded = 0;
+    if (frt->mGuard->Try(frt->mGuard, &didLock))
+    {
+        /*frt->mFileData.push_back (inItem);*/
+        /* !!! FIXME: this could be faster with a "tail" member. --ryan. */
+        FileData *i = frt->mFileData;
+        FileData *prev = NULL;
+
+        FileData *newfd = (FileData *) SDL_malloc(sizeof (FileData));
+        newfd->obj = inItem;
+        newfd->next = NULL;
+
+        while (i != NULL) { prev = i; i = i->next; }
+        if (prev == NULL)
+            frt->mFileData = newfd;
+        else
+            prev->next = newfd;
+
+        frt->mGuard->Notify(frt->mGuard);
+        succeeded = 1;
+
+        if (didLock)
+            frt->mGuard->Unlock(frt->mGuard);
+    }
+                
+    return succeeded;
+}
+
+static void    FileReaderThread_AddReader(FileReaderThread *frt)
+{
+    if (frt->mNumReaders == 0)
+    {
+        frt->mThreadShouldDie = 0;
+        frt->StartFixedPriorityThread (frt);
+    }
+    frt->mNumReaders++;
+}
+
+static void    FileReaderThread_RemoveReader (FileReaderThread *frt, AudioFileManager* inItem)
+{
+    if (frt->mNumReaders > 0)
+    {
+        int bNeedsRelease = frt->mGuard->Lock(frt->mGuard);
+        
+        /*frt->mFileData.remove (inItem);*/
+        FileData *i = frt->mFileData;
+        FileData *prev = NULL;
+        while (i != NULL)
+        {
+            FileData *next = i->next;
+            if (i->obj != inItem)
+                prev = i;
+            else
+            {
+                if (prev == NULL)
+                    frt->mFileData = next;
+                else
+                    prev->next = next;
+                SDL_free(i);
+            }
+            i = next;
+        }
+
+        if (--frt->mNumReaders == 0) {
+            frt->mThreadShouldDie = 1;
+            frt->mGuard->Notify(frt->mGuard); /* wake up thread so it will quit */
+            frt->mGuard->Wait(frt->mGuard);   /* wait for thread to die */
+        }
+
+        if (bNeedsRelease) frt->mGuard->Unlock(frt->mGuard);
+    }   
+}
+
+static int    FileReaderThread_StartFixedPriorityThread (FileReaderThread *frt)
+{
+    pthread_attr_t      theThreadAttrs;
+    pthread_t           pThread;
+
+    OSStatus result = pthread_attr_init(&theThreadAttrs);
+        if (result) return 0; /*THROW_RESULT("pthread_attr_init - Thread attributes could not be created.")*/
+    
+    result = pthread_attr_setdetachstate(&theThreadAttrs, PTHREAD_CREATE_DETACHED);
+        if (result) return 0; /*THROW_RESULT("pthread_attr_setdetachstate - Thread attributes could not be detached.")*/
+    
+    result = pthread_create (&pThread, &theThreadAttrs, frt->DiskReaderEntry, frt);
+        if (result) return 0; /*THROW_RESULT("pthread_create - Create and start the thread.")*/
+    
+    pthread_attr_destroy(&theThreadAttrs);
+    
+    /* we've now created the thread and started it
+       we'll now set the priority of the thread to the nominated priority
+       and we'll also make the thread fixed */
+    thread_extended_policy_data_t       theFixedPolicy;
+    thread_precedence_policy_data_t     thePrecedencePolicy;
+    SInt32                              relativePriority;
+    
+    /* make thread fixed */
+    theFixedPolicy.timeshare = 0;   /* set to 1 for a non-fixed thread */
+    result = thread_policy_set (pthread_mach_thread_np(pThread), THREAD_EXTENDED_POLICY, (thread_policy_t)&theFixedPolicy, THREAD_EXTENDED_POLICY_COUNT);
+        if (result) return 0; /*THROW_RESULT("thread_policy - Couldn't set thread as fixed priority.")*/
+    /* set priority */
+    /* precedency policy's "importance" value is relative to spawning thread's priority */
+    relativePriority = frt->mThreadPriority - frt->GetThreadBasePriority(pthread_self());
+        
+    thePrecedencePolicy.importance = relativePriority;
+    result = thread_policy_set (pthread_mach_thread_np(pThread), THREAD_PRECEDENCE_POLICY, (thread_policy_t)&thePrecedencePolicy, THREAD_PRECEDENCE_POLICY_COUNT);
+        if (result) return 0; /*THROW_RESULT("thread_policy - Couldn't set thread priority.")*/
+
+    return 1;
+}
+
+static UInt32  FileReaderThread_GetThreadBasePriority (pthread_t inThread)
+{
+    thread_basic_info_data_t            threadInfo;
+    policy_info_data_t                  thePolicyInfo;
+    unsigned int                        count;
+    
+    /* get basic info */
+    count = THREAD_BASIC_INFO_COUNT;
+    thread_info (pthread_mach_thread_np (inThread), THREAD_BASIC_INFO, (integer_t*)&threadInfo, &count);
+    
+    switch (threadInfo.policy) {
+        case POLICY_TIMESHARE:
+            count = POLICY_TIMESHARE_INFO_COUNT;
+            thread_info(pthread_mach_thread_np (inThread), THREAD_SCHED_TIMESHARE_INFO, (integer_t*)&(thePolicyInfo.ts), &count);
+            return thePolicyInfo.ts.base_priority;
+            break;
+            
+        case POLICY_FIFO:
+            count = POLICY_FIFO_INFO_COUNT;
+            thread_info(pthread_mach_thread_np (inThread), THREAD_SCHED_FIFO_INFO, (integer_t*)&(thePolicyInfo.fifo), &count);
+            if (thePolicyInfo.fifo.depressed) {
+                return thePolicyInfo.fifo.depress_priority;
+            } else {
+                return thePolicyInfo.fifo.base_priority;
+            }
+            break;
+            
+        case POLICY_RR:
+            count = POLICY_RR_INFO_COUNT;
+            thread_info(pthread_mach_thread_np (inThread), THREAD_SCHED_RR_INFO, (integer_t*)&(thePolicyInfo.rr), &count);
+            if (thePolicyInfo.rr.depressed) {
+                return thePolicyInfo.rr.depress_priority;
+            } else {
+                return thePolicyInfo.rr.base_priority;
+            }
+            break;
+    }
+    
+    return 0;
+}
+
+static void    *FileReaderThread_DiskReaderEntry (void *inRefCon)
+{
+    FileReaderThread *frt = (FileReaderThread *)inRefCon;
+    frt->ReadNextChunk(frt);
+    #if DEBUG
+    printf ("finished with reading file\n");
+    #endif
+    
+    return 0;
+}
+
+static void    FileReaderThread_ReadNextChunk (FileReaderThread *frt)
+{
+    OSStatus result;
+    UInt32  dataChunkSize;
+    AudioFileManager* theItem = 0;
+
+    for (;;) 
+    {
+        { /* this is a scoped based lock */
+            int bNeedsRelease = frt->mGuard->Lock(frt->mGuard);
+            
+            if (frt->mThreadShouldDie) {
+                frt->mGuard->Notify(frt->mGuard);
+                if (bNeedsRelease) frt->mGuard->Unlock(frt->mGuard);
+                return;
+            }
+            
+            /*if (frt->mFileData.empty())*/
+            if (frt->mFileData == NULL)
+            {
+                frt->mGuard->Wait(frt->mGuard);
+            }
+                        
+            /* kill thread */
+            if (frt->mThreadShouldDie) {
+            
+                frt->mGuard->Notify(frt->mGuard);
+                if (bNeedsRelease) frt->mGuard->Unlock(frt->mGuard);
+                return;
+            }
+
+            /*theItem = frt->mFileData.front();*/
+            /*frt->mFileData.pop_front();*/
+            theItem = NULL;
+            if (frt->mFileData != NULL)
+            {
+                FileData *next = frt->mFileData->next;
+                theItem = frt->mFileData->obj;
+                SDL_free(frt->mFileData);
+                frt->mFileData = next;
+            }
+
+            if (bNeedsRelease) frt->mGuard->Unlock(frt->mGuard);
+        }
+    
+        if ((theItem->mFileLength - theItem->mReadFilePosition) < theItem->mChunkSize)
+            dataChunkSize = theItem->mFileLength - theItem->mReadFilePosition;
+        else
+            dataChunkSize = theItem->mChunkSize;
+        
+            /* this is the exit condition for the thread */
+        if (dataChunkSize <= 0) {
+            theItem->mFinishedReadingData = 1;
+            continue;
+        }
+            /* construct pointer */
+        char* writePtr = (char *) (theItem->GetFileBuffer(theItem) +
+                                (theItem->mWriteToFirstBuffer ? 0 : theItem->mChunkSize));
+    
+            /* read data */
+        result = theItem->Read(theItem, writePtr, &dataChunkSize);
+        if (result != noErr && result != eofErr) {
+            AudioFilePlayer *afp = (AudioFilePlayer *) theItem->GetParent(theItem);
+            afp->DoNotification(afp, result);
+            continue;
+        }
+        
+        if (dataChunkSize != theItem->mChunkSize)
+        {
+            writePtr += dataChunkSize;
+
+            /* can't exit yet.. we still have to pass the partial buffer back */
+            SDL_memset(writePtr, 0, (theItem->mChunkSize - dataChunkSize));
+        }
+        
+        theItem->mWriteToFirstBuffer = !theItem->mWriteToFirstBuffer;   /* switch buffers */
+        
+        if (result == eofErr)
+            theItem->mReadFilePosition = theItem->mFileLength;
+        else
+            theItem->mReadFilePosition += dataChunkSize;        /* increment count */
+    }
+}
+
+void delete_FileReaderThread(FileReaderThread *frt)
+{
+    if (frt != NULL)
+    {
+        delete_SDLOSXCAGuard(frt->mGuard);
+        SDL_free(frt);
+    }
+}
+
+FileReaderThread *new_FileReaderThread ()
+{
+    FileReaderThread *frt = (FileReaderThread *) SDL_malloc(sizeof (FileReaderThread));
+    if (frt == NULL)
+        return NULL;
+    SDL_memset(frt, '\0', sizeof (*frt));
+
+    frt->mGuard = new_SDLOSXCAGuard();
+    if (frt->mGuard == NULL)
+    {
+        SDL_free(frt);
+        return NULL;
+    }
+
+    #define SET_FILEREADERTHREAD_METHOD(m) frt->m = FileReaderThread_##m
+    SET_FILEREADERTHREAD_METHOD(GetGuard);
+    SET_FILEREADERTHREAD_METHOD(AddReader);
+    SET_FILEREADERTHREAD_METHOD(RemoveReader);
+    SET_FILEREADERTHREAD_METHOD(TryNextRead);
+    SET_FILEREADERTHREAD_METHOD(ReadNextChunk);
+    SET_FILEREADERTHREAD_METHOD(StartFixedPriorityThread);
+    SET_FILEREADERTHREAD_METHOD(GetThreadBasePriority);
+    SET_FILEREADERTHREAD_METHOD(DiskReaderEntry);
+    #undef SET_FILEREADERTHREAD_METHOD
+
+    frt->mThreadPriority = 62;
+    return frt;
+}
+
+
+static FileReaderThread *sReaderThread;
+
+
+static int    AudioFileManager_DoConnect (AudioFileManager *afm)
+{
+    if (!afm->mIsEngaged)
+    {
+        OSStatus result;
+
+        /*afm->mReadFilePosition = 0;*/
+        afm->mFinishedReadingData = 0;
+
+        afm->mNumTimesAskedSinceFinished = 0;
+        afm->mLockUnsuccessful = 0;
+        
+        UInt32 dataChunkSize;
+        
+        if ((afm->mFileLength - afm->mReadFilePosition) < afm->mChunkSize)
+            dataChunkSize = afm->mFileLength - afm->mReadFilePosition;
+        else
+            dataChunkSize = afm->mChunkSize;
+        
+        result = afm->Read(afm, afm->mFileBuffer, &dataChunkSize);
+           if (result) return 0; /*THROW_RESULT("AudioFileManager::DoConnect(): Read")*/
+
+        afm->mReadFilePosition += dataChunkSize;
+                
+        afm->mWriteToFirstBuffer = 0;
+        afm->mReadFromFirstBuffer = 1;
+
+        sReaderThread->AddReader(sReaderThread);
+        
+        afm->mIsEngaged = 1;
+    }
+    /*
+    else
+        throw static_cast<OSStatus>(-1); */ /* thread has already been started */
+
+    return 1;
+}
+
+static void    AudioFileManager_Disconnect (AudioFileManager *afm)
+{
+    if (afm->mIsEngaged)
+    {
+        sReaderThread->RemoveReader (sReaderThread, afm);
+        afm->mIsEngaged = 0;
+    }
+}
+
+static OSStatus AudioFileManager_Read(AudioFileManager *afm, char *buffer, UInt32 *len)
+{
+    return FSReadFork (afm->mForkRefNum,
+                       fsFromStart,
+                       afm->mReadFilePosition + afm->mAudioDataOffset,
+                       *len,
+                       buffer,
+                       len);
+}
+
+static OSStatus AudioFileManager_GetFileData (AudioFileManager *afm, void** inOutData, UInt32 *inOutDataSize)
+{
+    if (afm->mFinishedReadingData)
+    {
+        ++afm->mNumTimesAskedSinceFinished;
+        *inOutDataSize = 0;
+        *inOutData = 0;
+        return noErr;
+    }
+    
+    if (afm->mReadFromFirstBuffer == afm->mWriteToFirstBuffer) {
+        #if DEBUG
+        printf ("* * * * * * * Can't keep up with reading file\n");
+        #endif
+        
+        afm->mParent->DoNotification (afm->mParent, kAudioFilePlayErr_FilePlayUnderrun);
+        *inOutDataSize = 0;
+        *inOutData = 0;
+    } else {
+        *inOutDataSize = afm->mChunkSize;
+        *inOutData = afm->mReadFromFirstBuffer ? afm->mFileBuffer : (afm->mFileBuffer + afm->mChunkSize);
+    }
+
+    afm->mLockUnsuccessful = !sReaderThread->TryNextRead (sReaderThread, afm);
+    
+    afm->mReadFromFirstBuffer = !afm->mReadFromFirstBuffer;
+
+    return noErr;
+}
+
+static void    AudioFileManager_AfterRender (AudioFileManager *afm)
+{
+    if (afm->mNumTimesAskedSinceFinished > 0)
+    {
+        int didLock = 0;
+        SDLOSXCAGuard *guard = sReaderThread->GetGuard(sReaderThread);
+        if (guard->Try(guard, &didLock)) {
+            afm->mParent->DoNotification (afm->mParent, kAudioFilePlay_FileIsFinished);
+            if (didLock)
+                guard->Unlock(guard);
+        }
+    }
+
+    if (afm->mLockUnsuccessful)
+        afm->mLockUnsuccessful = !sReaderThread->TryNextRead (sReaderThread, afm);
+}
+
+static void    AudioFileManager_SetPosition (AudioFileManager *afm, SInt64 pos)
+{
+    if (pos < 0 || pos >= afm->mFileLength) {
+        SDL_SetError ("AudioFileManager::SetPosition - position invalid: %d filelen=%d\n", 
+            (unsigned int)pos, (unsigned int)afm->mFileLength);
+        pos = 0;
+    }
+        
+    afm->mReadFilePosition = pos;
+}
+    
+static void    AudioFileManager_SetEndOfFile (AudioFileManager *afm, SInt64 pos)
+{
+    if (pos <= 0 || pos > afm->mFileLength) {
+        SDL_SetError ("AudioFileManager::SetEndOfFile - position beyond actual eof\n");
+        pos = afm->mFileLength;
+    }
+    
+    afm->mFileLength = pos;
+}
+
+static const char *AudioFileManager_GetFileBuffer(AudioFileManager *afm)
+{
+    return afm->mFileBuffer;
+}
+
+const AudioFilePlayer *AudioFileManager_GetParent(AudioFileManager *afm)
+{
+    return afm->mParent;
+}
+
+static int AudioFileManager_GetByteCounter(AudioFileManager *afm)
+{
+    return afm->mByteCounter;
+}
+
+
+static OSStatus    AudioFileManager_FileInputProc (void                       *inRefCon,
+                                             AudioUnitRenderActionFlags inActionFlags,
+                                             const AudioTimeStamp       *inTimeStamp, 
+                                             UInt32                     inBusNumber, 
+                                             AudioBuffer                *ioData)
+{
+    AudioFileManager* afm = (AudioFileManager*)inRefCon;
+    return afm->Render(afm, ioData);
+}
+
+static OSStatus    AudioFileManager_Render (AudioFileManager *afm, AudioBuffer *ioData)
+{
+    OSStatus result = noErr;
+    
+	if (afm->mBufferOffset >= afm->mBufferSize) {
+		result = afm->GetFileData(afm, &afm->mTmpBuffer, &afm->mBufferSize);
+		if (result) {
+			SDL_SetError ("AudioConverterFillBuffer:%ld\n", result);
+			afm->mParent->DoNotification(afm->mParent, result);
+			return result;
+		}
+
+		afm->mBufferOffset = 0;
+	}
+    	
+    if (ioData->mDataByteSize > afm->mBufferSize - afm->mBufferOffset)
+    	ioData->mDataByteSize = afm->mBufferSize - afm->mBufferOffset;
+    ioData->mData = (char *)afm->mTmpBuffer + afm->mBufferOffset;
+    afm->mBufferOffset += ioData->mDataByteSize;
+    
+	afm->mByteCounter += ioData->mDataByteSize;
+	afm->AfterRender(afm);
+    return result;
+}
+
+
+void delete_AudioFileManager (AudioFileManager *afm)
+{
+    if (afm != NULL) {
+        if (afm->mFileBuffer) {
+            free(afm->mFileBuffer);
+        }
+
+        SDL_free(afm);
+    }
+}
+
+
+AudioFileManager *new_AudioFileManager(AudioFilePlayer *inParent,
+                                       SInt16          inForkRefNum,
+                                       SInt64          inFileLength,
+                                       UInt32          inChunkSize)
+{
+    AudioFileManager *afm;
+
+    if (sReaderThread == NULL)
+    {
+        sReaderThread = new_FileReaderThread();
+        if (sReaderThread == NULL)
+            return NULL;
+    }
+
+    afm = (AudioFileManager *) SDL_malloc(sizeof (AudioFileManager));
+    if (afm == NULL)
+        return NULL;
+    SDL_memset(afm, '\0', sizeof (*afm));
+
+    #define SET_AUDIOFILEMANAGER_METHOD(m) afm->m = AudioFileManager_##m
+    SET_AUDIOFILEMANAGER_METHOD(Disconnect);
+    SET_AUDIOFILEMANAGER_METHOD(DoConnect);
+    SET_AUDIOFILEMANAGER_METHOD(Read);
+    SET_AUDIOFILEMANAGER_METHOD(GetFileBuffer);
+    SET_AUDIOFILEMANAGER_METHOD(GetParent);
+    SET_AUDIOFILEMANAGER_METHOD(SetPosition);
+    SET_AUDIOFILEMANAGER_METHOD(GetByteCounter);
+    SET_AUDIOFILEMANAGER_METHOD(SetEndOfFile);
+    SET_AUDIOFILEMANAGER_METHOD(Render);
+    SET_AUDIOFILEMANAGER_METHOD(GetFileData);
+    SET_AUDIOFILEMANAGER_METHOD(AfterRender);
+    SET_AUDIOFILEMANAGER_METHOD(FileInputProc);
+    #undef SET_AUDIOFILEMANAGER_METHOD
+
+    afm->mParent = inParent;
+    afm->mForkRefNum = inForkRefNum;
+    afm->mBufferSize = inChunkSize;
+    afm->mBufferOffset = inChunkSize;
+    afm->mChunkSize = inChunkSize;
+    afm->mFileLength = inFileLength;
+    afm->mFileBuffer = (char*) SDL_malloc(afm->mChunkSize * 2);
+    FSGetForkPosition(afm->mForkRefNum, &afm->mAudioDataOffset);
+    assert (afm->mFileBuffer != NULL);
+    return afm;
+}
+