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 + -
显示快捷键?