macaudio.cp
上传用户:dangjiwu
上传日期:2013-07-19
资源大小:42019k
文件大小:37k
源码类别:

Symbian

开发平台:

Visual C++

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