⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 audunix.cpp

📁 著名的 helix realplayer 基于手机 symbian 系统的 播放器全套源代码
💻 CPP
📖 第 1 页 / 共 3 页
字号:
    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 + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -