macaudio.cp
上传用户:zhongxx05
上传日期:2007-06-06
资源大小:33641k
文件大小:36k
源码类别:

Symbian

开发平台:

C/C++

  1. /* ***** BEGIN LICENSE BLOCK ***** 
  2.  * Version: RCSL 1.0/RPSL 1.0 
  3.  *  
  4.  * Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved. 
  5.  *      
  6.  * The contents of this file, and the files included with this file, are 
  7.  * subject to the current version of the RealNetworks Public Source License 
  8.  * Version 1.0 (the "RPSL") available at 
  9.  * http://www.helixcommunity.org/content/rpsl unless you have licensed 
  10.  * the file under the RealNetworks Community Source License Version 1.0 
  11.  * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl, 
  12.  * in which case the RCSL will apply. You may also obtain the license terms 
  13.  * directly from RealNetworks.  You may not use this file except in 
  14.  * compliance with the RPSL or, if you have a valid RCSL with RealNetworks 
  15.  * applicable to this file, the RCSL.  Please see the applicable RPSL or 
  16.  * RCSL for the rights, obligations and limitations governing use of the 
  17.  * contents of the file.  
  18.  *  
  19.  * This file is part of the Helix DNA Technology. RealNetworks is the 
  20.  * developer of the Original Code and owns the copyrights in the portions 
  21.  * it created. 
  22.  *  
  23.  * This file, and the files included with this file, is distributed and made 
  24.  * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
  25.  * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
  26.  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS 
  27.  * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
  28.  * 
  29.  * Technology Compatibility Kit Test Suite(s) Location: 
  30.  *    http://www.helixcommunity.org/content/tck 
  31.  * 
  32.  * Contributor(s): 
  33.  *  
  34.  * ***** END LICENSE BLOCK ***** */ 
  35. //
  36. // macaudio.cp
  37. // 
  38. #include <stdio.h>
  39. #include "macaudio.h"
  40. #include "USound.h"
  41. #ifndef _MAC_MACHO
  42. #include <AIFF.h>
  43. #include <fixmath.h>
  44. #endif
  45. #include "hxtypes.h"
  46. #include "hxerrors.h"
  47. #include "hxcom.h"
  48. #include "hxausvc.h"
  49. #include "auderrs.h"
  50. #include "hxaudev.h"
  51. #include "hxslist.h"
  52. #include "hxtick.h"
  53. #include "chxpckts.h"
  54. #ifdef THREADS_SUPPORTED
  55. #include "hxthread.h"
  56. #endif
  57. #include "hxmm.h"
  58. //#define LOG_MULTIPLE_DEFERRED_TASKS 1
  59. BOOL  gSoundCallbackTime = FALSE;
  60. #if defined( _CARBON ) || defined( _MAC_UNIX )
  61. DeferredTaskUPP CAudioOutMac::gDeferredTask = NewDeferredTaskUPP(CAudioOutMac::DeferredTaskCallback);
  62. #else
  63. DeferredTaskUPP CAudioOutMac::gDeferredTask = NewDeferredTaskProc(CAudioOutMac::DeferredTaskCallback);
  64. #endif
  65. #ifdef THREADS_SUPPORTED
  66. HXMutex* CAudioOutMac::zm_pMutex = NULL;
  67. #endif
  68. CAudioOutMac*       gActiveAudioDevice = NULL;     
  69. #if defined( _CARBON ) || defined( _MAC_UNIX )
  70. typedef pascal Handle (*MacAudioNewHandleSysProcPtr)(Size);
  71. CFragConnectionID gAudioInterfaceLibConnID = kInvalidID;
  72. MacAudioNewHandleSysProcPtr gMacAudioNewHandleSysProc = nil;
  73. bool gMacAudioTriedToInitialize = false;
  74. void MacAudioInitInterfaceLibProcPtrs()
  75. {
  76. if (gMacAudioTriedToInitialize) return;
  77. gMacAudioTriedToInitialize = true;
  78. if (gAudioInterfaceLibConnID == kInvalidID)
  79. {
  80. GetSharedLibrary("pInterfaceLib", kCompiledCFragArch, kReferenceCFrag,
  81. &gAudioInterfaceLibConnID, nil, nil);
  82. }
  83. if (gAudioInterfaceLibConnID != kInvalidID)
  84. {
  85. OSErr err = noErr;
  86. err = FindSymbol(gAudioInterfaceLibConnID, "pNewHandleSys", (Ptr*)&gMacAudioNewHandleSysProc, nil);
  87. }
  88. }
  89. #endif
  90. /*--------------------------------------------------------------------------
  91. | CMacWaveFormat
  92. |
  93. | Default ctor.
  94. --------------------------------------------------------------------------*/
  95. CMacWaveFormat::CMacWaveFormat (void)
  96. { /* begin CMacWaveFormat */
  97. SetFormatDflt ();
  98. } /* end CMacWaveFormat */
  99. /*--------------------------------------------------------------------------
  100. | ~CMacWaveFormat
  101. |
  102. | dtor.
  103. --------------------------------------------------------------------------*/
  104. CMacWaveFormat::~CMacWaveFormat (void)
  105. { /* begin ~CMacWaveFormat */
  106. } /* end ~CMacWaveFormat */
  107. /*--------------------------------------------------------------------------
  108. | SetUpSound
  109. |
  110. | Formats a sound handle.
  111. --------------------------------------------------------------------------*/
  112. OSErr CMacWaveFormat::SetUpSound (
  113. SndListHandle sndHandle,
  114. long numBytes,
  115. short *headerLen,
  116. long *headerOffset)
  117. { /* begin SetUpSound */
  118. OSErr e = noErr;
  119. long response;
  120. if (sampleSize > 8) {
  121. if (USound::CheckSMVersion () < 3) {
  122.     if ((::Gestalt(gestaltSoundAttr, &response) == noErr)
  123.      && ((response & (1L << gestalt16BitSoundIO)) == 0))
  124. return (noHardwareErr);
  125. } /* if */
  126. else {
  127.     if ((::Gestalt(gestaltSoundAttr, &response) == noErr)
  128.      && ((response & (1L << gestalt16BitAudioSupport)) == 0))
  129. return (noHardwareErr);
  130. } /* else */
  131. } /* if */
  132. if (noErr != (e = ::SetupSndHeader (sndHandle,
  133.    numChannels,
  134.    sampleRate,
  135.    sampleSize,
  136.    compressionType,
  137.    baseFrequency,
  138.    numBytes,
  139.    headerLen)))
  140. goto CleanUp;
  141.    
  142. if (noErr != (e = USound::GetSoundHeaderOffset (sndHandle, headerOffset)))
  143. goto CleanUp;
  144. CleanUp:
  145. return (e);
  146. } /* end SetUpSound */
  147. /*--------------------------------------------------------------------------
  148. | SetHeaderLength [static]
  149. |
  150. | Formats a sound header for a given byte count.
  151. --------------------------------------------------------------------------*/
  152. OSErr CMacWaveFormat::SetHeaderLength (
  153. SoundHeaderPtr pSoundHeader,
  154. long numBytes)
  155. { /* begin SetHeaderLength */
  156. switch (pSoundHeader->encode) {
  157. case stdSH:  /*standard sound header*/
  158. pSoundHeader->length = numBytes;
  159. break;
  160. case extSH:  /*extended sound header*/
  161. {
  162.                                 ExtSoundHeaderPtr eh = (ExtSoundHeaderPtr) pSoundHeader;
  163. eh->numFrames = numBytes / (eh->numChannels * (eh->sampleSize / 8));
  164.                                 }
  165. break;
  166. case cmpSH: /*compressed sound header*/
  167. {
  168.                                 CmpSoundHeaderPtr ch = (CmpSoundHeaderPtr) pSoundHeader;
  169. ch->numFrames = numBytes / (ch->numChannels * (ch->sampleSize / 8));
  170.                                 }
  171. break;
  172. default:
  173. return badFormat;
  174. } /* switch */
  175. return noErr;
  176. } /* SetHeaderLength */
  177. /*--------------------------------------------------------------------------
  178. | SetFormatDflt
  179. |
  180. | Sets up the default Sound header information.
  181. --------------------------------------------------------------------------*/
  182. void CMacWaveFormat::SetFormatDflt (void)
  183. { /* begin SetFormatDflt */
  184. //mwf.wf.nAvgBytesPerSec = 22050;
  185. //mwf.wf.nBlockAlign = 2;
  186. numChannels = 1; //mwf.wf.nChannels = 1;
  187. sampleRate = Long2Fix (8000); //mwf.wf.nSamplesPerSec = 8000;
  188. //sampleRate = rate11025hz; //mwf.wf.nSamplesPerSec = 11025;
  189. sampleSize = 16; //mwf.wBitsPerSample = 16;
  190. compressionType = NoneType; //mwf.wf.wFormatTag = WAVE_FORMAT_PCM;
  191. baseFrequency = kMiddleC;
  192. } /* end SetFormatDflt */
  193. /*--------------------------------------------------------------------------
  194. | SetFormatDflt
  195. |
  196. | Sets up the default Sound header information.
  197. --------------------------------------------------------------------------*/
  198. void CMacWaveFormat::SetFormat (
  199. ULONG32 inSampleRate,
  200. UINT16  channels,
  201. UINT16  bitsPerSample)
  202. numChannels = channels;
  203. sampleRate = inSampleRate << 16L;
  204. sampleSize = bitsPerSample;
  205. compressionType = NoneType;
  206. baseFrequency = kMiddleC;
  207. }
  208. /*--------------------------------------------------------------------------
  209. | CWaveHeader
  210. --------------------------------------------------------------------------*/
  211. CWaveHeader::CWaveHeader (void)
  212. : soundA5 (0)
  213. , state (kFreeState)
  214. , waveOut (NULL)
  215. , mMaxPlay (0)
  216. , sndHandle (nil)
  217. , mHeaderLen (0)
  218. , mSoundHeader (nil)
  219. { /* begin CWaveHeader */
  220. soundA5 = SetCurrentA5 ();
  221. } /* end CWaveHeader */
  222. /*--------------------------------------------------------------------------
  223. | ~CWaveHeader
  224. --------------------------------------------------------------------------*/
  225. CWaveHeader::~CWaveHeader (void)
  226. { /* begin ~CWaveHeader */
  227. if (sndHandle) ::DisposeHandle ((Handle) sndHandle);
  228. sndHandle = nil;
  229. } /* end ~CWaveHeader */
  230. /*--------------------------------------------------------------------------
  231. | CWaveHeader
  232. --------------------------------------------------------------------------*/
  233. const Size CWaveHeader::kSndHeaderSize = 512;
  234. UINT16 CWaveHeader::WAVE_BLOCKSIZE = 4096;
  235. OSErr CWaveHeader::Allocate (
  236. UINT16 inMaxPlay,
  237. float   sampleRate,
  238. UINT16  channels,
  239. UINT16  bitsPerSample)
  240. { /* begin Allocate */
  241. OSErr e = badFormat;
  242. long offset;
  243. if (!waveOut)
  244. goto CleanUp;
  245. OSErr theError;
  246. sndHandle = (SndListHandle) ::TempNewHandle (kSndHeaderSize + inMaxPlay, &theError);
  247. if (!sndHandle)
  248. goto CleanUp;
  249.         check_noerr (theError);
  250. waveOut->wf.SetFormat ((long)sampleRate,channels,bitsPerSample);
  251. if (noErr != (e = waveOut->wf.SetUpSound (sndHandle, inMaxPlay, &mHeaderLen, &offset)))
  252. goto CleanUp;
  253. ::SetHandleSize ((Handle) sndHandle, mHeaderLen + inMaxPlay);
  254. if (noErr != (e = MemError ()))
  255. goto CleanUp;
  256. mMaxPlay = inMaxPlay;
  257. ::MoveHHi ((Handle) sndHandle);
  258. ::HLock ((Handle) sndHandle);
  259. mSoundHeader = (SoundHeaderPtr) ((*(Handle) sndHandle) + offset);
  260. CleanUp:
  261. return (e);
  262. } /* end Allocate */
  263. /*--------------------------------------------------------------------------
  264. | Release
  265. --------------------------------------------------------------------------*/
  266. void CWaveHeader::Release (short releaseCode, BOOL bSendTimeSync /*= TRUE*/)
  267. { /* begin Release */
  268.     if (kFreeState != state) 
  269.     {
  270. state = kFreeState;
  271. if ((CWaveHeader::kResetRelease != releaseCode) &&
  272. (CWaveHeader::kAbortRelease != releaseCode)) //cz 5/7/96
  273. if (waveOut) waveOut->DonePlaying (cbPlaying, timeEnd,releaseCode == kCallBackRelease, bSendTimeSync);
  274.     } /* if */
  275.     if (kAbortRelease == releaseCode) 
  276.     {
  277.         
  278. if (sndHandle) 
  279. {
  280.     ::DisposeHandle ((Handle) sndHandle);
  281.     sndHandle=NULL;
  282. }
  283. sndHandle = nil;
  284. mMaxPlay = 0;
  285. mSoundHeader = nil;
  286.     } /* if */
  287. } /* end Release */
  288. /*--------------------------------------------------------------------------
  289. | PlayBuffer
  290. --------------------------------------------------------------------------*/
  291. OSErr CWaveHeader::PlayBuffer (
  292. char *pData,
  293. UINT16 cbPlayingArg,
  294. ULONG32 timeEndArg)
  295. { /* begin PlayBuffer */
  296. OSErr e = noErr;
  297. SndCommand cmd;
  298. if (!waveOut)
  299. return (badFormat);
  300. if (kFreeState != state)
  301. return (badFormat);
  302. if (!sndHandle) 
  303. return (nilHandleErr);
  304. if (cbPlayingArg > mMaxPlay)
  305. return (memFullErr);
  306. if (noErr != (e = waveOut->wf.SetHeaderLength (mSoundHeader, cbPlayingArg)))
  307. goto CleanUp;
  308. if(pData != NULL)
  309. ::BlockMove (pData, (*(Handle) sndHandle) + mHeaderLen, cbPlayingArg);
  310. cmd.cmd = bufferCmd;
  311. cmd.param1 = 0;
  312. cmd.param2 = (long) mSoundHeader;
  313. if (noErr != (e = ::SndDoCommand (waveOut->chan, &cmd, TRUE))) goto CleanUp;
  314. state = kQueuedState;
  315. cbPlaying = cbPlayingArg;
  316. timeEnd = timeEndArg;
  317. waveOut->StartedPlaying (cbPlaying);
  318. cmd.cmd = callBackCmd;
  319. cmd.param1 = kCallBackRelease;
  320. cmd.param2 = (long) this;
  321. if (noErr != (e = ::SndDoCommand (waveOut->chan, &cmd, TRUE))) goto CleanUp;
  322. waveOut->m_bAudioCallbacksAreAlive = TRUE;
  323. CleanUp:
  324. return (e);
  325. } /* end PlayBuffer */
  326. /*--------------------------------------------------------------------------
  327. | NewChannel
  328. --------------------------------------------------------------------------*/
  329. SndChannelPtr CWaveHeader::NewChannel (void)
  330. { /* begin NewChannel */
  331. SndChannelPtr chan = nil;
  332. #if defined( _CARBON ) || defined( _MAC_UNIX )
  333. SndCallBackUPP userProc = NewSndCallBackUPP (Callback);
  334. #else
  335. SndCallBackUPP userProc = NewSndCallBackProc (Callback);
  336. #endif
  337. // if (noErr != ::SndNewChannel (&chan, sampledSynth, initStereo + initNoDrop + initNoInterp, userProc))
  338. if (noErr != ::SndNewChannel (&chan, sampledSynth, initStereo, userProc))
  339. chan = nil;
  340. return chan;
  341. } /* end NewChannel */
  342. /*--------------------------------------------------------------------------
  343. | DisposeChannel
  344. --------------------------------------------------------------------------*/
  345. OSErr CWaveHeader::DisposeChannel (
  346. SndChannelPtr chan)
  347. { /* begin DisposeChannel */
  348. OSErr e;
  349. if(chan)
  350. {
  351. SndCallBackUPP userProc = chan->callBack;
  352. #if defined( _CARBON ) || defined( _MAC_UNIX )
  353. if (userProc) DisposeSndCallBackUPP (userProc);
  354. #else
  355. if (userProc) DisposeRoutineDescriptor (userProc);
  356. #endif
  357. e = ::SndDisposeChannel (chan, TRUE);
  358. }
  359. return e;
  360. } /* end DisposeChannel */
  361. /*--------------------------------------------------------------------------
  362. | Callback
  363. --------------------------------------------------------------------------*/
  364. pascal void CWaveHeader::Callback (
  365. SndChannelPtr chan,
  366. SndCommand *cmd)
  367. { /* begin Callback */
  368. #ifndef _MAC_UNIX
  369. HXMM_INTERRUPTON();
  370. #endif
  371. //    if (HXMM_RAHUL_CHECK())
  372. //    {
  373. //        DebugStr("pCWaveHeader Deferred Task ENTER;g");
  374. //    }
  375.     
  376. DeferredTask* dtrec = NULL;
  377. CWaveHeader*    wh    = NULL;
  378.                 SndCommand*   newCommand;
  379.                 
  380. if (cmd)
  381. {
  382. wh = (CWaveHeader *) cmd->param2;
  383. if ( wh )
  384. {
  385.     CAudioOutMac* theWaveOut = wh->waveOut;
  386.     
  387.     if ( theWaveOut )
  388.     {
  389. CMacWaveFormat wf = theWaveOut->wf;
  390. UINT32 ulBytesPerSecond = 
  391. wf.numChannels *
  392. ( (ULONG32)wf.sampleRate >> 16 ) *
  393. ( wf.sampleSize / 8 );
  394. theWaveOut->m_millisecondsIntoClip +=
  395. (double)wh->cbPlaying * 1000.0 / (double)ulBytesPerSecond;
  396.     }
  397. }
  398. dtrec=wh->waveOut->mDeferredTaskRec;
  399. }
  400. if (!dtrec)
  401. {
  402. goto CleanUp;
  403. }
  404. newCommand=new SndCommand;
  405. HX_ASSERT(newCommand);
  406. if (!newCommand)
  407. {
  408. delete dtrec;
  409. goto CleanUp;
  410. }
  411. if (cmd)
  412. {
  413. *newCommand=*cmd;
  414. }
  415. else
  416. {
  417. delete newCommand;
  418. delete dtrec;
  419. goto CleanUp;
  420. }
  421. wh->waveOut->AddToThePendingList(newCommand);
  422. if (!wh->waveOut->m_bDeferredTaskPending)
  423. {
  424.     wh->waveOut->m_bDeferredTaskPending = TRUE;
  425.     
  426.     short err = 0;
  427.     
  428.     if ( wh->waveOut->m_bIsQuitting )
  429.     {
  430. err = -1; // just so it's nonzero
  431.     }
  432.     else
  433.     {
  434. err = DTInstall(dtrec);
  435.     }
  436.     if ( err != noErr )
  437.     {
  438. wh->waveOut->m_bDeferredTaskPending = FALSE;
  439. wh->waveOut->m_bAudioCallbacksAreAlive = FALSE;
  440. delete dtrec;
  441. delete newCommand;
  442. goto CleanUp;
  443.     }
  444. }
  445. /*
  446. if (wh) {
  447. long saveA5 = SetA5 (wh->soundA5);
  448. wh->Release (cmd->param1);
  449. SetA5 (saveA5);
  450. */
  451. CleanUp:
  452. #ifndef _MAC_UNIX
  453. HXMM_INTERRUPTOFF();
  454. #endif
  455. //    if (HXMM_RAHUL_CHECK())
  456. //    {
  457. //        DebugStr("pCWaveHeader Deferred Task LEAVE;g");
  458. //    }
  459. return;
  460. } /* end Callback */
  461. pascal void CAudioOutMac::DeferredTaskCallback(long param)
  462. {
  463.     if (!param)
  464.     {
  465.         return;
  466.     }
  467.     
  468. #ifndef _MAC_UNIX
  469. HXMM_INTERRUPTON();
  470. #endif
  471. CAudioOutMac* pAudioOut = (CAudioOutMac*) param;
  472. pAudioOut->m_bAudioCallbacksAreAlive = FALSE;
  473. #ifdef THREADS_SUPPORTED
  474. if (zm_pMutex)
  475. {
  476.     zm_pMutex->Lock();
  477. }
  478. #endif
  479. #if defined(_DEBUG) && defined(LOG_MULTIPLE_DEFERRED_TASKS)
  480.     if ( !pAudioOut->m_bAudioCallbacksAreAlive )
  481.     {
  482. DebugStr( "pDeferredTaskCallback -- m_bAudioCallbacksAreAlive not true!;g" );
  483.     }
  484. #endif
  485. while (gActiveAudioDevice &&
  486.        pAudioOut->m_pPendingCallbackList && 
  487.       !pAudioOut->m_pPendingCallbackList->IsEmpty())
  488. {
  489. SndCommand* cmd = (SndCommand*) pAudioOut->m_pPendingCallbackList->RemoveHead();
  490. BOOL bIsEmpty = pAudioOut->m_pPendingCallbackList->IsEmpty();
  491. #ifdef THREADS_SUPPORTED
  492. // we used to deadlock here; we'd grab the audio mutex before the core mutex,
  493. // which is not how the rest of this class operates
  494. if (zm_pMutex)
  495. {
  496.     zm_pMutex->Unlock();
  497. }
  498. #endif
  499. /* Send time sync for ONLY the last pending audio callback */
  500. pAudioOut->ProcessCmd(cmd, bIsEmpty);
  501.       delete cmd;
  502. #ifdef THREADS_SUPPORTED
  503. if (zm_pMutex)
  504. {
  505.     zm_pMutex->Lock();
  506. }
  507. #endif
  508. }
  509. /* It is possible that on a timesync, a renderer may issue a hyper navigate request.
  510.  * This may result in leaving the currently active page (thereby unloading 
  511.  * the embedded player and the core. We would have destructed the CMacAudio class
  512.  * in this case.
  513.  */ 
  514. if (!gActiveAudioDevice)
  515. {
  516.     goto cleanup;
  517. }
  518. pAudioOut->m_bDeferredTaskPending = FALSE;
  519. cleanup:
  520. #ifdef THREADS_SUPPORTED
  521. if (zm_pMutex)
  522. {
  523.     zm_pMutex->Unlock();
  524. }
  525. #endif
  526. #ifndef _MAC_UNIX
  527. HXMM_INTERRUPTOFF();
  528. #endif
  529. }
  530. void
  531. CAudioOutMac::ProcessCmd(SndCommand* cmd, BOOL bSendTimeSync /*= TRUE*/)
  532. {
  533. CWaveHeader *wh = (CWaveHeader *) cmd->param2;
  534. if (wh)
  535. {
  536. wh->Release(cmd->param1, bSendTimeSync);
  537. }
  538. }
  539. /*--------------------------------------------------------------------------
  540. | CAudioOutMac
  541. --------------------------------------------------------------------------*/
  542. UINT16 CAudioOutMac::NUM_WAVEHDRS = 12; // was 30
  543. CAudioOutMac::CAudioOutMac ()
  544. : chan (nil)
  545. , mlpWaveHdrs (NULL)
  546. , mcbPlaying (0)
  547. , mPaused (TRUE)
  548. , m_uNumBlocksInDevice(0)
  549. , m_bFirstPacket(TRUE)
  550. , m_ulTimeOfFirstPacket(0L)
  551. , m_pPendingCallbackList(NULL)
  552. , m_bDeferredTaskPending(FALSE)
  553. , m_bAudioCallbacksAreAlive(FALSE)
  554. , m_bIsQuitting(FALSE)
  555. , m_millisecondsIntoClip(0.0)
  556. , m_pCallback(NULL)
  557. , m_pInterruptState(NULL)
  558. { /* begin CAudioOutMac */
  559. mDeferredTaskRec=(DeferredTask*)NewPtrClear(sizeof(DeferredTask));
  560. mDeferredTaskRec->qType=dtQType;
  561. mDeferredTaskRec->dtAddr=CAudioOutMac::gDeferredTask;
  562.     mDeferredTaskRec->dtParam= (long) this;
  563.     
  564. // Gestalt-based code that remembers potential deferred tasks for emergency removal
  565. #ifndef _MAC_UNIX
  566. Handle dtGestaltHandle = nil;
  567. OSErr err = Gestalt( kLetInterruptsFinishBeforeQuittingGestalt, (long*)&dtGestaltHandle );
  568. if ( err != noErr )
  569. {
  570. #if defined( _CARBON )
  571.     MacAudioInitInterfaceLibProcPtrs();
  572.     if (gMacAudioNewHandleSysProc)
  573.     {
  574. dtGestaltHandle = (*gMacAudioNewHandleSysProc)( 0 );
  575.     }
  576.     if (!dtGestaltHandle)
  577.     {
  578. dtGestaltHandle = NewHandle( 0 );
  579.     }
  580. #else
  581.     dtGestaltHandle = NewHandleSys( 0 );
  582. #endif
  583.     if ( dtGestaltHandle )
  584.     {
  585. NewGestaltValue( kLetInterruptsFinishBeforeQuittingGestalt, (long)dtGestaltHandle );
  586.     }
  587. }
  588. if ( dtGestaltHandle )
  589. {
  590.     GestaltDeferredStruct gds;
  591.     gds.quitting = &m_bIsQuitting;
  592.     gds.pending = &m_bAudioCallbacksAreAlive;
  593.     GetCurrentProcess(&(gds.psn));
  594.     PtrAndHand( &gds, dtGestaltHandle, sizeof(gds) );
  595. }
  596. #endif
  597. #ifdef THREADS_SUPPORTED
  598. if (!zm_pMutex)
  599. {
  600.     HXMutex::MakeMutex(zm_pMutex);
  601. }
  602. #endif
  603.     gActiveAudioDevice = this;
  604. } /* end CAudioOutMac */
  605. /*--------------------------------------------------------------------------
  606. | ~CAudioOutMac
  607. --------------------------------------------------------------------------*/
  608. CAudioOutMac::~CAudioOutMac ()
  609. { /* begin ~CAudioOutMac */ 
  610. Abort ();
  611. #if defined(_DEBUG) && defined(LOG_MULTIPLE_DEFERRED_TASKS)
  612. BOOL bWaitedForPending = FALSE;
  613. if ( m_bAudioCallbacksAreAlive )
  614. {
  615.     DebugStr( "pCAudioOutMac dtor -- m_bAudioCallbacksAreAlive still true!;g" );
  616.     bWaitedForPending = TRUE;
  617. }
  618. #endif
  619.     
  620.     m_bIsQuitting = TRUE;
  621.     // sit-n-spin awaiting interrupts to finish.
  622.     for ( int i = 0; i < 10; i++ )
  623.     {
  624. unsigned long dummyTix;
  625. Delay( 6, &dummyTix );
  626. if ( !m_bAudioCallbacksAreAlive )
  627. {
  628.     i = 10;
  629. }
  630.     }
  631.     
  632. #if defined(_DEBUG) && defined(LOG_MULTIPLE_DEFERRED_TASKS)
  633. if ( bWaitedForPending )
  634. {
  635.     if ( m_bAudioCallbacksAreAlive )
  636.     {
  637. DebugStr( "ptasks STILL pending! This is gonna hurt...;g" );
  638.     }
  639.     else
  640.     {
  641. DebugStr( "pSuccessfully purged pending callbacks;g" );
  642.     }
  643. }
  644. #endif
  645. if (mDeferredTaskRec)
  646. {
  647. // first ensure that the Gestalt handle doesn't think it's
  648. // here any more.
  649. #ifndef _MAC_UNIX
  650. Handle dtGestaltHandle = nil;
  651. Gestalt( kLetInterruptsFinishBeforeQuittingGestalt, (long*)&dtGestaltHandle );
  652. if ( dtGestaltHandle )
  653. {
  654.     // XXXNH: only look at tasks for this process
  655.     ProcessSerialNumber psn;
  656.     GetCurrentProcess(&psn);
  657.     // zip through and if an entry equals this deferred task,
  658.     // simply zero it out. We won't worry about shuffling
  659.     // the handle size at this juncture.
  660.     long hSize = GetHandleSize( dtGestaltHandle );
  661.     GestaltDeferredStruct* currentPtr = (GestaltDeferredStruct*)*dtGestaltHandle;
  662.     for ( int i = 0; i < hSize / sizeof(GestaltDeferredStruct); i++ )
  663.     {
  664.         unsigned char bSameProcess = FALSE;
  665.         SameProcess(&(currentPtr[i].psn), &psn, &bSameProcess);
  666.         
  667. if (bSameProcess && 
  668.     currentPtr[i].quitting == &m_bIsQuitting && 
  669.     currentPtr[i].pending == &m_bAudioCallbacksAreAlive )
  670. {
  671.     currentPtr[i].quitting = NULL;
  672.     currentPtr[i].pending = NULL;
  673. }
  674.     }    
  675. }
  676. #endif
  677. ::DisposePtr ((Ptr)mDeferredTaskRec);
  678. }    
  679. CleanupPendingLists();
  680. HX_DELETE(m_pPendingCallbackList);
  681. gActiveAudioDevice = NULL;
  682. HX_RELEASE(m_pScheduler);
  683. HX_RELEASE(m_pInterruptState);
  684. } /* end ~CAudioOutMac */
  685. UINT16 CAudioOutMac::m_uzVolume = 50;
  686. HX_RESULT   
  687. CAudioOutMac::_Imp_Open( const HXAudioFormat* pFormat )
  688. {
  689.     /*
  690.     ** Open the sound channel.
  691.     */
  692.     NUM_WAVEHDRS = 45; //params->numBufs;
  693.     CWaveHeader::WAVE_BLOCKSIZE = pFormat->uMaxBlockSize;
  694.     if (chan) CWaveHeader::DisposeChannel (chan);
  695.     m_bAudioCallbacksAreAlive = FALSE;
  696.     chan = CWaveHeader::NewChannel ();
  697.     if (!chan) 
  698. return (HX_AUDIO_DRIVER_ERROR);
  699. if (!m_pPendingCallbackList)
  700. {
  701.     m_pPendingCallbackList = new CHXSimpleList;
  702. }
  703.     ULONG32 nSampleRate = pFormat->ulSamplesPerSec;
  704.     ULONG32 nBlockSize = pFormat->uMaxBlockSize;
  705. #if powerc && FORCE_RATE_CONVERSION
  706. // if we are on a PowerPC we will do our own sample rate conversion
  707. // since the Apple version gives us a lot of pops and aliasing
  708.     ULONG32 sysSampleRate = ::USound::GetSystemSampleRate(chan);
  709. // Note: we currently have to HACK 11227 and 22254 sample rates on
  710. // old macs to 11025 and 22050
  711.     switch(sysSampleRate)
  712.     {
  713. case 11227:
  714.     sysSampleRate = 11025;
  715.     break;
  716. case 22254:
  717.     sysSampleRate = 22050;
  718.     break;
  719.     }
  720. // we only have a problem if the sample rate is <= 32000 Hz. (sigh!)
  721.     if(nSampleRate <= 32000)
  722.     {
  723. if(sysSampleRate > 0 && nSampleRate != sysSampleRate)
  724. {
  725.     UINT16 bytesPerSample = pFormat->wBitsPerSample > 8 ? 2 : 1;
  726.     UINT16 frameSize = bytesPerSample * pFormat->wChannels;
  727.     ULONG32 bytesPerSecond = (ULONG32) (nSampleRate * frameSize);
  728.     float bufDuration = (float)pFormat->uMaxBlockSize/(float)bytesPerSecond;
  729.     // calculate the bytesPerSecond of the system sample rate
  730.     bytesPerSecond = (ULONG32) (sysSampleRate * frameSize);
  731.     // update the buffer size to handle the new sample rate
  732.     nBlockSize = bytesPerSecond * bufDuration;
  733.     // round the buffersize to a framesize
  734.     nBlockSize = ((nBlockSize/frameSize) * frameSize) + frameSize;
  735.     nSampleRate = sysSampleRate;
  736.     //pFormat->ulSamplesPerSec = sysSampleRate;
  737. }
  738.     }
  739. #ifndef MAC_RELEASE
  740. #if 0
  741. char s[256];
  742. ::sprintf(s,"sample rate %ld",sysSampleRate);
  743. ::c2pstr(s);
  744. DebugStr((UCHAR *)s);
  745. #endif
  746. #endif // MAC_RELEASE
  747. #endif // powerc && FORCE_RATE_CONVERSION
  748. //    SetVolume(pFormat->volume);
  749.     _Imp_SetVolume(m_uzVolume);
  750.     
  751. /*
  752. ** Allocate memory for wave block headers and for wave data.
  753. */
  754.     if (NULL == mlpWaveHdrs) 
  755.     {
  756. if (NULL == (mlpWaveHdrs = new CWaveHeader [NUM_WAVEHDRS])) 
  757.     return (HX_MEMORY_ERROR);
  758. for (short iwh = 0; iwh < NUM_WAVEHDRS; iwh++) 
  759. {
  760.     CWaveHeader *pwh = GetWaveHeader (iwh);
  761.     if (pwh) 
  762.     {
  763. pwh->SetOutput (this);
  764. switch (pwh->Allocate (nBlockSize, nSampleRate,
  765. pFormat->uChannels,pFormat->uBitsPerSample)) 
  766. {
  767.     case noErr:
  768. break;
  769.     case memFullErr:
  770. return (HX_MEMORY_ERROR);
  771.     default:
  772. return (HX_AUDIO_DRIVER_ERROR);
  773.     } 
  774.     } 
  775. /*
  776. ** Indicate that no audio blocks are currently playing.
  777. */
  778.     mcbPlaying = 0;
  779.     mPaused = FALSE;
  780.     
  781.     if (!m_pScheduler && m_pContext)
  782.     {
  783. m_pContext->QueryInterface(IID_IHXScheduler, (void**) &m_pScheduler);
  784. m_pContext->QueryInterface(IID_IHXInterruptState, (void**) &m_pInterruptState);
  785.     }
  786.     
  787.     return (HX_NO_ERROR);
  788. }
  789. HX_RESULT   
  790. CAudioOutMac::_Imp_Close( void )
  791. {
  792.     Abort();
  793.     return HXR_OK;
  794. }
  795. HX_RESULT   
  796. CAudioOutMac::_Imp_Pause( void )
  797. {
  798.     mPaused = TRUE;
  799.     
  800.     if (OkToPauseResume(FALSE))
  801.     {
  802. // Stop playback
  803. if (chan != NULL) 
  804. DoImmediate (pauseCmd);
  805.     }
  806.     
  807.     return HXR_OK;
  808. }
  809. HX_RESULT   
  810. CAudioOutMac::_Imp_Resume( void )
  811. {
  812.     mPaused = FALSE;
  813.     if (OkToPauseResume(TRUE))
  814.     {
  815. if (chan != NULL) 
  816. {
  817. DoImmediate (resumeCmd);
  818. }
  819. this->OnTimeSync();
  820.     }
  821.     
  822.     return HXR_OK;    
  823. }
  824. HX_RESULT   
  825. CAudioOutMac::_Imp_Write( const HXAudioData* pAudioOutHdr )
  826. {
  827.     HX_RESULT err = HX_NO_ERROR;
  828.         
  829. //    CWaveHeader *pwh = GetWaveHeader(0);;
  830.     CWaveHeader *pwh=NULL;
  831.     Boolean found = FALSE;
  832.     void* pBuffer = NULL;
  833.     for (short iwh = 0; iwh < NUM_WAVEHDRS && !found; iwh++) 
  834.     {
  835. pwh = GetWaveHeader(iwh);
  836. found = pwh && pwh->Available ();
  837.     }
  838.     if (found)
  839.     {
  840. pBuffer = pwh->get_buffer();
  841.     }
  842.     else
  843.     {
  844. return playError;
  845.     }
  846.     if(pwh == 0)
  847.     {
  848. return (playError);
  849.     }
  850.     char* pData = 0;
  851.     pData = (char*)pAudioOutHdr->pData->GetBuffer();
  852.     ULONG32 nLen = pAudioOutHdr->pData->GetSize();
  853.     if (pBuffer)
  854.     {
  855.      memcpy(pBuffer, pData, nLen);
  856.     
  857. if (noErr != pwh->PlayBuffer ((char*)pBuffer, nLen, pAudioOutHdr->ulAudioTime))
  858.     err = (playError);
  859.     }
  860. if (!err)
  861. {
  862. m_uNumBlocksInDevice++;
  863. if(m_bFirstPacket)
  864. {
  865. m_bFirstPacket = FALSE;
  866. m_ulTimeOfFirstPacket = pAudioOutHdr->ulAudioTime;
  867. }
  868. }
  869.     return err;
  870. }
  871. HX_RESULT   
  872. CAudioOutMac::_Imp_Reset( void )
  873. {
  874.     // Stop playback
  875.     if (chan != NULL) {
  876. DoImmediate (pauseCmd);
  877. DoImmediate (flushCmd);
  878. DoImmediate (quietCmd);
  879.     } /* if */
  880.     m_ulCurrentTime = 0;
  881.     m_bFirstPacket = TRUE;
  882.     
  883.     // Mark blocks as available.
  884.     ReleaseBlocks (CWaveHeader::kResetRelease);
  885.     m_uNumBlocksInDevice = 0;
  886.     
  887.     CleanupPendingLists();
  888.     return HX_NO_ERROR;
  889. }
  890. HX_RESULT  
  891. CAudioOutMac::_Imp_Drain( void )
  892. {
  893.     return HX_NO_ERROR;
  894. }
  895. BOOL 
  896. CAudioOutMac::_Imp_SupportsVolume( void )
  897. {
  898.     return TRUE;
  899. }
  900. UINT16   
  901. CAudioOutMac::_Imp_GetVolume()
  902. {
  903. #if 0
  904.     unsigned long volume=0;
  905.     SndCommand theCmd;
  906.     theCmd.cmd = getVolumeCmd;
  907.     theCmd.param1 = 0;
  908.     theCmd.param2 = volume;
  909. // queue volume command in channel
  910.     ::SndDoImmediate(chan,&theCmd);
  911.     return  (UINT16) volume;
  912. #endif
  913.     return m_uzVolume;
  914. }
  915. HX_RESULT   
  916. CAudioOutMac::_Imp_SetVolume( const UINT16 uVolume )
  917. {
  918.     SndCommand theCmd;
  919.     unsigned long volume;
  920.     unsigned long leftVolume, rightVolume;
  921. //    if(uVolume < 0) uVolume = 0;
  922.     
  923.     if(chan)
  924.     {
  925. #if defined( _CARBON ) || defined( _MAC_UNIX )
  926. leftVolume = rightVolume = (long) uVolume * 5; //uVolume is between 0 and 100
  927. volume = (rightVolume << 16) + leftVolume;
  928. theCmd.cmd = volumeCmd;
  929. theCmd.param1 = 0;
  930. theCmd.param2 = volume;
  931. // queue volume command in channel
  932. ::SndDoImmediate(chan,&theCmd);
  933. #else
  934. #if OLDROUTINENAMES && !GENERATINGCFM
  935. if (USound::CheckSMVersion () < 3)
  936. ::SetSoundVol (uVolume);
  937. #else
  938. leftVolume = rightVolume = (long) uVolume * 5; //uVolume is between 0 and 100
  939. volume = (rightVolume << 16) + leftVolume;
  940. theCmd.cmd = volumeCmd;
  941. theCmd.param1 = 0;
  942. theCmd.param2 = volume;
  943. // queue volume command in channel
  944. ::SndDoImmediate(chan,&theCmd);
  945. #endif
  946. #endif
  947.     }
  948.     
  949.     m_uzVolume = uVolume;
  950.     return HXR_OK;
  951. }
  952. HX_RESULT   
  953. CAudioOutMac::_Imp_CheckFormat( const HXAudioFormat* pFormat)
  954. {
  955.     return HX_NO_ERROR;
  956. }
  957. HX_RESULT 
  958. CAudioOutMac::_Imp_Seek(ULONG32 ulSeekTime)
  959. {
  960.     m_ulCurrentTime = 0;
  961.     return HX_NO_ERROR;
  962. }
  963. /*---------------------------------------------------------------------------
  964. | ReleaseBlocks
  965. |
  966. | Frees the blocks manually
  967. --------------------------------------------------------------------------*/
  968. void CAudioOutMac::ReleaseBlocks (
  969. short releaseCode)
  970. { /* begin ReleaseBlocks */
  971. // Mark blocks as available.
  972. for (short iwh = 0; iwh < NUM_WAVEHDRS; iwh++) {
  973. CWaveHeader *pwh = GetWaveHeader (iwh);
  974. // if (pwh && !pwh->Available ())
  975. if (pwh)
  976. pwh->Release (releaseCode);
  977. } /* for */
  978. m_millisecondsIntoClip = 0.0;
  979. } /* end ReleaseBlocks */
  980. /*---------------------------------------------------------------------------
  981. | DoImmediate
  982. |
  983. | Executes a sound command
  984. --------------------------------------------------------------------------*/
  985. OSErr CAudioOutMac::DoImmediate (
  986. short cmd,
  987. short param1/*= 0*/,
  988. long param2/*= 0L*/)
  989. { /* begin DoImmediate */
  990. SndCommand sndCmd;
  991. sndCmd.cmd = cmd;
  992. sndCmd.param1 = param1;
  993. sndCmd.param2 = param2;
  994. return ::SndDoImmediate (chan, &sndCmd);
  995. } /* end DoImmediate */
  996. /*---------------------------------------------------------------------------
  997. | Abort
  998. |
  999. | Halts playback and shuts down
  1000. --------------------------------------------------------------------------*/
  1001. void CAudioOutMac::Abort (void)
  1002. { /* begin Abort */
  1003. // Stop playback
  1004. if (chan != NULL) {
  1005. // Kludge around usual SM unreliability