📄 macaudio.cp
字号:
if (zm_pMutex) { zm_pMutex->Lock(); }#endif#if defined(_DEBUG) && defined(LOG_MULTIPLE_DEFERRED_TASKS) if ( !pAudioOut->m_bAudioCallbacksAreAlive ) { DebugStr( "\pDeferredTaskCallback -- m_bAudioCallbacksAreAlive not true!;g" ); }#endif while (gActiveAudioDevice && pAudioOut->m_pPendingCallbackList && !pAudioOut->m_pPendingCallbackList->IsEmpty()) { SndCommand* cmd = (SndCommand*) pAudioOut->m_pPendingCallbackList->RemoveHead(); BOOL bIsEmpty = pAudioOut->m_pPendingCallbackList->IsEmpty(); #ifdef THREADS_SUPPORTED // we used to deadlock here; we'd grab the audio mutex before the core mutex, // which is not how the rest of this class operates if (zm_pMutex) { zm_pMutex->Unlock(); }#endif /* Send time sync for ONLY the last pending audio callback */ pAudioOut->ProcessCmd(cmd, bIsEmpty); delete cmd;#ifdef THREADS_SUPPORTED if (zm_pMutex) { zm_pMutex->Lock(); }#endif } /* It is possible that on a timesync, a renderer may issue a hyper navigate request. * This may result in leaving the currently active page (thereby unloading * the embedded player and the core. We would have destructed the CMacAudio class * in this case. */ if (!gActiveAudioDevice) { goto cleanup; } pAudioOut->m_bDeferredTaskPending = FALSE; cleanup: #ifdef THREADS_SUPPORTED if (zm_pMutex) { zm_pMutex->Unlock(); }#endif#ifndef _MAC_UNIX HXMM_INTERRUPTOFF();#endif}voidCAudioOutMac::ProcessCmd(SndCommand* cmd, BOOL bSendTimeSync /*= TRUE*/){ CWaveHeader *wh = (CWaveHeader *) cmd->param2; if (wh) { wh->Release(cmd->param1, bSendTimeSync); }} /*--------------------------------------------------------------------------| CAudioOutMac--------------------------------------------------------------------------*/UINT16 CAudioOutMac::NUM_WAVEHDRS = 12; // was 30CAudioOutMac::CAudioOutMac () : chan (nil) , mlpWaveHdrs (NULL) , mcbPlaying (0) , mPaused (TRUE) , m_uNumBlocksInDevice(0) , m_bFirstPacket(TRUE) , m_ulTimeOfFirstPacket(0L) , m_pPendingCallbackList(NULL) , m_bDeferredTaskPending(FALSE) , m_bAudioCallbacksAreAlive(FALSE) , m_bIsQuitting(FALSE) , m_millisecondsIntoClip(0.0) , m_pCallback(NULL) , m_pInterruptState(NULL){ /* begin CAudioOutMac */ mDeferredTaskRec=(DeferredTask*)NewPtrClear(sizeof(DeferredTask)); mDeferredTaskRec->qType=dtQType; mDeferredTaskRec->dtAddr=CAudioOutMac::gDeferredTask; mDeferredTaskRec->dtParam= (long) this; // Gestalt-based code that remembers potential deferred tasks for emergency removal #ifndef _MAC_UNIX Handle dtGestaltHandle = nil; OSErr err = Gestalt( kLetInterruptsFinishBeforeQuittingGestalt, (long*)&dtGestaltHandle ); if ( err != noErr ) {#if defined( _CARBON ) MacAudioInitInterfaceLibProcPtrs(); if (gMacAudioNewHandleSysProc) { dtGestaltHandle = (*gMacAudioNewHandleSysProc)( 0 ); } if (!dtGestaltHandle) { dtGestaltHandle = NewHandle( 0 ); }#else dtGestaltHandle = NewHandleSys( 0 );#endif if ( dtGestaltHandle ) { NewGestaltValue( kLetInterruptsFinishBeforeQuittingGestalt, (long)dtGestaltHandle ); } } if ( dtGestaltHandle ) { GestaltDeferredStruct gds; gds.quitting = &m_bIsQuitting; gds.pending = &m_bAudioCallbacksAreAlive; GetCurrentProcess(&(gds.psn)); PtrAndHand( &gds, dtGestaltHandle, sizeof(gds) ); }#endif #ifdef THREADS_SUPPORTED if (!zm_pMutex) { HXMutex::MakeMutex(zm_pMutex); }#endif gActiveAudioDevice = this;} /* end CAudioOutMac *//*--------------------------------------------------------------------------| ~CAudioOutMac--------------------------------------------------------------------------*/CAudioOutMac::~CAudioOutMac (){ /* begin ~CAudioOutMac */ Abort ();#if defined(_DEBUG) && defined(LOG_MULTIPLE_DEFERRED_TASKS) BOOL bWaitedForPending = FALSE; if ( m_bAudioCallbacksAreAlive ) { DebugStr( "\pCAudioOutMac dtor -- m_bAudioCallbacksAreAlive still true!;g" ); bWaitedForPending = TRUE; }#endif m_bIsQuitting = TRUE; // sit-n-spin awaiting interrupts to finish. for ( int i = 0; i < 10; i++ ) { unsigned long dummyTix; Delay( 6, &dummyTix ); if ( !m_bAudioCallbacksAreAlive ) { i = 10; } } #if defined(_DEBUG) && defined(LOG_MULTIPLE_DEFERRED_TASKS) if ( bWaitedForPending ) { if ( m_bAudioCallbacksAreAlive ) { DebugStr( "\ptasks STILL pending! This is gonna hurt...;g" ); } else { DebugStr( "\pSuccessfully purged pending callbacks;g" ); } }#endif if (mDeferredTaskRec) { // first ensure that the Gestalt handle doesn't think it's // here any more. #ifndef _MAC_UNIX Handle dtGestaltHandle = nil; Gestalt( kLetInterruptsFinishBeforeQuittingGestalt, (long*)&dtGestaltHandle ); if ( dtGestaltHandle ) { // XXXNH: only look at tasks for this process ProcessSerialNumber psn; GetCurrentProcess(&psn); // zip through and if an entry equals this deferred task, // simply zero it out. We won't worry about shuffling // the handle size at this juncture. long hSize = GetHandleSize( dtGestaltHandle ); GestaltDeferredStruct* currentPtr = (GestaltDeferredStruct*)*dtGestaltHandle; for ( int i = 0; i < hSize / sizeof(GestaltDeferredStruct); i++ ) { unsigned char bSameProcess = FALSE; SameProcess(&(currentPtr[i].psn), &psn, &bSameProcess); if (bSameProcess && currentPtr[i].quitting == &m_bIsQuitting && currentPtr[i].pending == &m_bAudioCallbacksAreAlive ) { currentPtr[i].quitting = NULL; currentPtr[i].pending = NULL; } } }#endif ::DisposePtr ((Ptr)mDeferredTaskRec); } CleanupPendingLists(); HX_DELETE(m_pPendingCallbackList); gActiveAudioDevice = NULL; HX_RELEASE(m_pScheduler); HX_RELEASE(m_pInterruptState);} /* end ~CAudioOutMac */UINT16 CAudioOutMac::m_uzVolume = 50;HX_RESULT CAudioOutMac::_Imp_Open( const HXAudioFormat* pFormat ){ /* ** Open the sound channel. */ NUM_WAVEHDRS = 45; //params->numBufs; CWaveHeader::WAVE_BLOCKSIZE = pFormat->uMaxBlockSize; if (chan) CWaveHeader::DisposeChannel (chan); m_bAudioCallbacksAreAlive = FALSE; chan = CWaveHeader::NewChannel (); if (!chan) return (HX_AUDIO_DRIVER_ERROR); if (!m_pPendingCallbackList) { m_pPendingCallbackList = new CHXSimpleList; } ULONG32 nSampleRate = pFormat->ulSamplesPerSec; ULONG32 nBlockSize = pFormat->uMaxBlockSize;#if powerc && FORCE_RATE_CONVERSION // if we are on a PowerPC we will do our own sample rate conversion // since the Apple version gives us a lot of pops and aliasing ULONG32 sysSampleRate = ::USound::GetSystemSampleRate(chan); // Note: we currently have to HACK 11227 and 22254 sample rates on // old macs to 11025 and 22050 switch(sysSampleRate) { case 11227: sysSampleRate = 11025; break; case 22254: sysSampleRate = 22050; break; } // we only have a problem if the sample rate is <= 32000 Hz. (sigh!) if(nSampleRate <= 32000) { if(sysSampleRate > 0 && nSampleRate != sysSampleRate) { UINT16 bytesPerSample = pFormat->wBitsPerSample > 8 ? 2 : 1; UINT16 frameSize = bytesPerSample * pFormat->wChannels; ULONG32 bytesPerSecond = (ULONG32) (nSampleRate * frameSize); float bufDuration = (float)pFormat->uMaxBlockSize/(float)bytesPerSecond; // calculate the bytesPerSecond of the system sample rate bytesPerSecond = (ULONG32) (sysSampleRate * frameSize); // update the buffer size to handle the new sample rate nBlockSize = bytesPerSecond * bufDuration; // round the buffersize to a framesize nBlockSize = ((nBlockSize/frameSize) * frameSize) + frameSize; nSampleRate = sysSampleRate; //pFormat->ulSamplesPerSec = sysSampleRate; } }#ifndef MAC_RELEASE#if 0 char s[256]; ::sprintf(s,"sample rate %ld",sysSampleRate); ::c2pstr(s); DebugStr((UCHAR *)s);#endif#endif // MAC_RELEASE#endif // powerc && FORCE_RATE_CONVERSION// SetVolume(pFormat->volume); _Imp_SetVolume(m_uzVolume); /* ** Allocate memory for wave block headers and for wave data. */ if (NULL == mlpWaveHdrs) { if (NULL == (mlpWaveHdrs = new CWaveHeader [NUM_WAVEHDRS])) return (HX_MEMORY_ERROR); for (short iwh = 0; iwh < NUM_WAVEHDRS; iwh++) { CWaveHeader *pwh = GetWaveHeader (iwh); if (pwh) { pwh->SetOutput (this); switch (pwh->Allocate (nBlockSize, nSampleRate, pFormat->uChannels,pFormat->uBitsPerSample)) { case noErr: break; case memFullErr: return (HX_MEMORY_ERROR); default: return (HX_AUDIO_DRIVER_ERROR); } } } } /* ** Indicate that no audio blocks are currently playing. */ mcbPlaying = 0; mPaused = FALSE; if (!m_pScheduler && m_pContext) { m_pContext->QueryInterface(IID_IHXScheduler, (void**) &m_pScheduler); m_pContext->QueryInterface(IID_IHXInterruptState, (void**) &m_pInterruptState); } return (HX_NO_ERROR);}HX_RESULT CAudioOutMac::_Imp_Close( void ){ Abort(); return HXR_OK;}HX_RESULT CAudioOutMac::_Imp_Pause( void ){ mPaused = TRUE; if (OkToPauseResume(FALSE)) { // Stop playback if (chan != NULL) DoImmediate (pauseCmd); } return HXR_OK;}HX_RESULT CAudioOutMac::_Imp_Resume( void ){ mPaused = FALSE; if (OkToPauseResume(TRUE)) { if (chan != NULL) { DoImmediate (resumeCmd); } this->OnTimeSync(); } return HXR_OK; }HX_RESULT CAudioOutMac::_Imp_Write( const HXAudioData* pAudioOutHdr ){ HX_RESULT err = HX_NO_ERROR; // CWaveHeader *pwh = GetWaveHeader(0);; CWaveHeader *pwh=NULL; Boolean found = FALSE; void* pBuffer = NULL; for (short iwh = 0; iwh < NUM_WAVEHDRS && !found; iwh++) { pwh = GetWaveHeader(iwh); found = pwh && pwh->Available (); } if (found) { pBuffer = pwh->get_buffer(); } else { return playError; } if(pwh == 0) { return (playError); } char* pData = 0; pData = (char*)pAudioOutHdr->pData->GetBuffer(); ULONG32 nLen = pAudioOutHdr->pData->GetSize(); if (pBuffer) { memcpy(pBuffer, pData, nLen); if (noErr != pwh->PlayBuffer ((char*)pBuffer, nLen, pAudioOutHdr->ulAudioTime)) err = (playError); } if (!err) { m_uNumBlocksInDevice++; if(m_bFirstPacket) { m_bFirstPacket = FALSE; m_ulTimeOfFirstPacket = pAudioOutHdr->ulAudioTime; } } return err;}HX_RESULT CAudioOutMac::_Imp_Reset( void ){ // Stop playback if (chan != NULL) { DoImmediate (pauseCmd); DoImmediate (flushCmd); DoImmediate (quietCmd); } /* if */ m_ulCurrentTime = 0; m_bFirstPacket = TRUE; // Mark blocks as available. ReleaseBlocks (CWaveHeader::kResetRelease); m_uNumBlocksInDevice = 0; CleanupPendingLists(); return HX_NO_ERROR;}HX_RESULT CAudioOutMac::_Imp_Drain( void ){ return HX_NO_ERROR;}BOOL CAudioOutMac::_Imp_SupportsVolume( void ){ return TRUE;}UINT16 CAudioOutMac::_Imp_GetVolume(){#if 0 unsigned long volume=0; SndCommand theCmd; theCmd.cmd = getVolumeCmd; theCmd.param1 = 0; theCmd.param2 = volume; // queue volume command in channel ::SndDoImmediate(chan,&theCmd); return (UINT16) volume;#endif return m_uzVolume;}HX_RESULT CAudioOutMac::_Imp_SetVolume( const UINT16 uVolume ){ SndCommand theCmd; unsigned long volume; unsigned long leftVolume, rightVolume; // if(uVolume < 0) uVolume = 0; if(chan) {#if defined( _CARBON ) || defined( _MAC_UNIX ) leftVolume = rightVolume = (long) uVolume * 5; //uVolume is between 0 and 100 volume = (rightVolume << 16) + leftVolume; theCmd.cmd = volumeCmd; theCmd.param1 = 0; theCmd.param2 = volume; // queue volume command in channel ::SndDoImmediate(chan,&theCmd);#else#if OLDROUTINENAMES && !GENERATINGCFM if (USound::CheckSMVersion () < 3) ::SetSoundVol (uVolume);#else leftVolume = rightVolume = (long) uVolume * 5; //uVolume is between 0 and 100 volume = (rightVolume << 16) + leftVolume; theCmd.cmd = volumeCmd; theCmd.param1 = 0; theCmd.param2 = volume; // queue volume command in channel ::SndDoImmediate(chan,&theCmd);#endif#endif } m_uzVolume = uVolume; return HXR_OK; }HX_RESULT CAudioOutMac::_Imp_CheckFormat( const HXAudioFormat* pFormat){ return HX_NO_ERROR;}HX_RESULT CAudioOutMac::_Imp_Seek(ULONG32 ulSeekTime){ m_ulCurrentTime = 0; return HX_NO_ERROR;}/*---------------------------------------------------------------------------| ReleaseBlocks|| Frees the blocks manually--------------------------------------------------------------------------*/void CAudioOutMac::ReleaseBlocks ( short releaseCode) { /* begin ReleaseBlocks */ // Mark blocks as available. for (short iwh = 0; iwh < NUM_WAVEHDRS; iwh++) { CWaveHeader *pwh = GetWaveHeader (iwh); // if (pwh && !pwh->Available ()) if (pwh) pwh->Release (releaseCode); } /* for */ m_millisecondsIntoClip = 0.0; } /* end ReleaseBlocks *//*---------------------------------------------------------------------------| DoImmediate|| Executes a sound command--------------------------------------------------------------------------*/OSErr CAudioOutMac::DoImmediate ( short cmd, short param1/*= 0*/, long param2/*= 0L*/) { /* begin DoImmediate */ SndCommand sndCmd; sndCmd.cmd = cmd; sndCmd.param1 = param1; sndCmd.param2 = param2; return ::SndDoImmediate (chan, &sndCmd); } /* end DoImmediate *//*---------------------------------------------------------------------------| Abort|| Halts playback and shuts down--------------------------------------------------------------------------*/void CAudioOutMac::Abort (void) { /* begin Abort */ // Stop playback if (chan != NULL) { // Kludge around usual SM unreliability
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -