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