audunix.cpp
来自「linux下的一款播放器」· C++ 代码 · 共 1,081 行 · 第 1/3 页
CPP
1,081 行
}HX_RESULT CAudioOutUNIX::_Resume(){ return RA_AOE_NOTSUPPORTED;}BOOL CAudioOutUNIX::_IsSelectable() const{ return TRUE;}BOOL CAudioOutUNIX::_HardwarePauseSupported() const{ return FALSE;}#if defined(_THREADED_AUDIO) && defined(_UNIX_THREADS_SUPPORTED)void* CAudioOutUNIX::AudioThread(void *thisPointer ){ BOOL bReadyToExit=FALSE; CAudioOutUNIX* that = (CAudioOutUNIX*)thisPointer; while(!bReadyToExit) { //If you want to destroy frame rate just sit on this lock for //a while. If you don't, make sure this is a *very* fast loop. that->m_mtxWriteListPlayStateLock->Lock(); that->m_mtxDeviceStateLock->Lock(); if(that->m_wState!=RA_AOS_CLOSED && that->m_wState!=RA_AOS_CLOSING) { if( that->m_pWriteList->GetCount() > 0 && that->m_wState == RA_AOS_OPEN_PLAYING ) { that->_PushBits(); } } else { bReadyToExit=TRUE; } that->m_mtxDeviceStateLock->Unlock(); that->m_mtxWriteListPlayStateLock->Unlock(); //OK, sleep the amount of time it takes to play 1/4 of the device's buffer. microsleep(that->m_ulSleepTime/4); } //Signal the parent thread that we are done. that->m_audioThread->Exit(0); return (void*)0;}#endif// Don't protect anything in this method with mutexes. It has // already been done from where it is called from. But mostly// because we aren't using recursive mutexes yet.ULONG32 CAudioOutUNIX::_PushBits(){ IHXBuffer* pBuffer = NULL; UCHAR* pData = 0; ULONG32 ulBufLen = 0; LONG32 lCount = 0; //We are going to try and write. Grab the head and do it. pBuffer = (IHXBuffer*)m_pWriteList->RemoveHead(); pData = pBuffer->GetBuffer(); ulBufLen = pBuffer->GetSize(); // // Now, in case there is no mixer present, do the volume manually. // UCHAR* pNoVolumeData = NULL; if ( !m_bMixerPresent ) { //Save a copy of the non-volume mutated sound data. If we don't, our //rewind buffer will fill up with volume modified data and it will get //run through the manual sound code again. if( !_HardwarePauseSupported() ) { pNoVolumeData = new UCHAR[ ulBufLen ]; memcpy( pNoVolumeData, pData, ulBufLen ); /* Flawfinder: ignore */ } int i, j = ulBufLen / sizeof(short); short *s = (short *)pData; for (i = 0 ; i < j ; i++) { s[i] = ((int)s[i]) * (m_uCurVolume) / MAX_VOLUME; } } UNLOCK(m_mtxWriteListPlayStateLock); _WriteBytes(pData, ulBufLen, lCount); LOCK(m_mtxWriteListPlayStateLock); //Make sure we wrote the whole buffer like we wanted to. if( lCount!=-1 && lCount != ulBufLen) { //In release we can ignore this...I guess. But why didn't we? HX_ASSERT( "We ALWAYS write full buffers!" == NULL ); } // Check for bad write...then check errno; write could be interrupted // by setitimer and sigalarm. If so, loop and try writing again. if ( lCount == -1 ) { //EAGAIN should *never* happen as we are checking to make sure we don't //block on this call.... if ( errno == EAGAIN) { HX_ASSERT( "We shouldn't be blocking here..."==NULL); } } if( lCount > 0 ) { m_ulTotalWritten += lCount; //We only need to do this if the hardware doesn't support pause. if( !_HardwarePauseSupported() ) { // If we wrote to the device we need to keep a copy of the // data our device buffer. We use this to 'rewind' the data // in case we get paused. //If we could write lCount without blocking then there was at //least that much room in the device and since m_pRollbackBuffer //is as large as the devices buffer, we can safely shift and copy. //Add the new stuff to the end pushing the rest of the data forward. //We need this sanity check to prevent a very hard bug to find. //Don't get rid of it! If this asserts it *really* means something. //The first thing to check is the __powerpc defines that determine //buffer size. HX_ASSERT( lCount <= m_ulDeviceBufferSize ); // Ok, now that we've asserted to catch the // bug, let's prevent the crash. if (lCount > m_ulDeviceBufferSize) lCount = m_ulDeviceBufferSize; memmove( m_pRollbackBuffer, m_pRollbackBuffer+lCount, m_ulDeviceBufferSize-lCount); /* Flawfinder: ignore */ //Now copy in the new data at the end of the buffer. if( NULL != pNoVolumeData ) memcpy( m_pRollbackBuffer+m_ulDeviceBufferSize-lCount, pNoVolumeData, lCount ); /* Flawfinder: ignore */ else memcpy( m_pRollbackBuffer+m_ulDeviceBufferSize-lCount, pData, lCount ); /* Flawfinder: ignore */ } } HX_VECTOR_DELETE(pNoVolumeData); HX_RELEASE( pBuffer ); return lCount;}HX_RESULT CAudioOutUNIX::_Imp_Write( const HXAudioData* pAudioOutHdr ){ IHXBuffer* pBuffer = NULL; ULONG32 ulCount = 0; //_Imp_Write won't be called if the device couldn't be opened. But, //Just in case. if( !IsOpen() ) { return RA_AOE_DEVNOTOPEN; } //Schedule callbacks. if( m_bFirstWrite && pAudioOutHdr ) { m_bFirstWrite = FALSE; // Initialize the playback callback time. HXTimeval lTime = m_pScheduler->GetCurrentSchedulerTime(); m_pPlaybackCountCBTime->tv_sec = lTime.tv_sec; m_pPlaybackCountCBTime->tv_usec = lTime.tv_usec; // Scheduler playback callback. ReschedPlaybackCheck(); } //Blindly add the incoming data to the tail of the writelist. //Some audio devices have very small device buffers. If this //buffer is smaller than our incoming block size we must break //up the incoming buffer into smaller chuncks. We want to be //able to fix *at least* two(1.5?) chunks into the buffer so we don't //block all the time. if( pAudioOutHdr != NULL ) { LOCK(m_mtxWriteListPlayStateLock); int nBuffSize = pAudioOutHdr->pData->GetSize(); // In heap-optimized mode, this is where we set the value of // m_ulDeviceBufferSize, and malloc the buffer.#ifdef HELIX_CONFIG_MIN_ROLLBACK_BUFFER if( m_ulDeviceBufferSize != nBuffSize ) { m_ulDeviceBufferSize = nBuffSize; HX_VECTOR_DELETE(m_pRollbackBuffer); m_pRollbackBuffer = new UCHAR[m_ulDeviceBufferSize]; }#endif // HELIX_CONFIG_MIN_ROLLBACK_BUFFER // Shouldn't this be ">=" and not ">"? if( m_ulDeviceBufferSize >= nBuffSize ) { //No need to break it up. IHXBuffer* pTmpBuff = pAudioOutHdr->pData; m_pWriteList->AddTail(pTmpBuff); pTmpBuff->AddRef(); } else { //Break it up. First find the correct size. while( nBuffSize >= m_ulDeviceBufferSize ) nBuffSize = nBuffSize>>1; //Now make sure we never break a buffer apart in the //middle of a Frame. int nRem = nBuffSize%(m_uSampFrameSize*m_unNumChannels); nBuffSize = nBuffSize>nRem ? nBuffSize-nRem : nBuffSize ; //March through the buffer, breaking it up. UCHAR* pData = pAudioOutHdr->pData->GetBuffer(); int nLimit = pAudioOutHdr->pData->GetSize(); int nPtr = 0; while( nPtr < nLimit ) { IHXBuffer* pNewBuffer = new CHXBuffer(); if( nPtr+nBuffSize <= nLimit ) { pNewBuffer->Set( pData+nPtr, nBuffSize ); } else { pNewBuffer->Set( pData+nPtr, (nLimit-nPtr) ); } m_pWriteList->AddTail( pNewBuffer ); pNewBuffer->AddRef(); nPtr += nBuffSize; } } UNLOCK(m_mtxWriteListPlayStateLock); }#if defined(_THREADED_AUDIO) && defined(_UNIX_THREADS_SUPPORTED) //If we are using threaded audio just return and let the audio thread //grab the data and write it to the device. if( m_bUserWantsThreads ) { return RA_AOE_NOERR; }#endif // ----------- Threaded audio note: // // We don't need to protect anything below here with the mutex // because we will never get here if we are running with threaded // audio. // //XXXgfw This doesn't seem to be doing any good anymore. So I am taking it // out// //Check for underflow here and do what? Pause it?// if( m_wState!=RA_AOS_OPEN_PAUSED && m_pWriteList->GetCount() <= 0 )// { // ULONG32 ulTmp = 0; // _GetRoomOnDevice(ulTmp);// //there better be stuff in the device because we wouldn't get this// //far if we were not in an OPEN/Playing state.// if( ulTmp >= m_ulDeviceBufferSize )// {// //XXXgfw, read below...// //We aren't writting anything and there is no // //data in the device buffer. Lions, tigers and bears..// //Maybe we should just do a _Pause here to keep// //the byte count from the audio device correct?// HX_ASSERT( "UNDERFLOW in AUDIO DEVICE" == NULL );// }// } //Just return if there is nothing to do if( m_pWriteList->GetCount() <= 0 || m_wState==RA_AOS_OPEN_PAUSED ) { return RA_AOE_NOERR; } // // We only want to write to the device if we can send the // whole buffer. If there isn't that much room then just // put the buffer back in the front of the que. // ULONG32 ulBytesAvailable = 0; HX_RESULT code = RA_AOE_NOERR; code = _GetRoomOnDevice(ulBytesAvailable); if( RA_AOE_NOERR != code ) { //What? Can't get the room on the device for some reason. m_wLastError = code; return m_wLastError; } //Peek at the head. pBuffer = (IHXBuffer*)m_pWriteList->GetHead(); if( NULL==pBuffer || ulBytesAvailable < pBuffer->GetSize()) { m_wLastError = RA_AOE_NOERR; return m_wLastError; } ulCount = _PushBits(); if ( m_bFirstWrite ) { m_bFirstWrite = FALSE; /* Initialize the playback callback time. */ HXTimeval lTime = m_pScheduler->GetCurrentSchedulerTime(); m_pPlaybackCountCBTime->tv_sec = lTime.tv_sec; m_pPlaybackCountCBTime->tv_usec = lTime.tv_usec; /* Scheduler playback callback. */ ReschedPlaybackCheck(); } //make sure the device is kept full. if( m_pWriteList->GetCount()>0 && ulCount>0 ) _Imp_Write(NULL); return m_wLastError; }HX_RESULT CAudioOutUNIX::_CheckFormat( const HXAudioFormat* pFormat ){ return RA_AOE_NOERR;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?