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

📄 hxaudstr.cpp

📁 著名的 helix realplayer 基于手机 symbian 系统的 播放器全套源代码
💻 CPP
📖 第 1 页 / 共 5 页
字号:
                    pDryNotification = (IHXDryNotification*) (*lIter);
                    pDryNotification->OnDryNotification(ulLastWriteTime, ulNumMsRequired);
                }

                if (m_Owner->GetState() != E_PLAYING)
                {
                    return HXR_OK;
                }
            }
        }
    }

    m_Owner->DataInAudioDevice(TRUE);
    // /////////////////////////////////////////////////////////////
    // There may be no buffers in the list. No packets? Play silence.
    // Still need to increment time.
    if ( m_pDataList->IsEmpty() && m_pInstantaneousList->IsEmpty() )
    {
        m_llLastWriteTime += CAST_TO_INT64 m_ulGranularity;
//{FILE* f1 = ::fopen("e:\\MixIntoBuffer.txt", "a+"); ::fprintf(f1, "%lu\t%p\t%lu\n", HX_GET_BETTERTICKCOUNT(), this, (UINT32)m_llLastWriteTime);::fclose(f1);}
        return HXR_NO_DATA;
    }

    UCHAR*      pSourceBuffer = 0;
    ULONG32     ulMaxBytes = 0;
    ULONG32     ulMaxFramesIn = 0;
    ULONG32     ulMaxFramesOut = 0;
    ULONG32     ulNumBytesMixed = 0;
    BOOL        bMonoToStereoMayBeConverted = TRUE;
    BOOL        bResampleBufferDirty        = FALSE;


    // /////////////////////////////////////////////////////////////
    // If no  resampling, mix stream data directly into the player
    // buffer.
    if ( !m_pResampler)
    {
        pSourceBuffer   = pPlayerBuf;
        ulMaxBytes      = m_ulInputBytesPerGran;

        /* For only those sound cards which do not
         * support stereo - a RARE (non-existent) case 
         */
        if (m_AudioFmt.uChannels == 2 && m_DeviceFmt.uChannels == 1)
        {
            /* We should never reach here since this case
             * should be handled by the Resampler
             * Temporary ASSERT... 
             */
            HX_ASSERT(FALSE);
        }
        /* Mono->Stereo conversion*/
        else if (m_bChannelConvert)
        {
            HX_ASSERT(ulMaxBytes <= ulBufSize/2);
            
            /* Avoid GPF in retail builds! */
            if (ulMaxBytes > ulBufSize/2)
            {
                ulMaxBytes = ulBufSize/2;
            }
        }
        else
        {
            HX_ASSERT(ulMaxBytes <= ulBufSize);
            
            /* Avoid GPF in retail builds! */
            if (ulMaxBytes > ulBufSize)
            {
                ulMaxBytes = ulBufSize;
            }
        }
    }
#if defined(HELIX_FEATURE_RESAMPLER)
    // /////////////////////////////////////////////////////////////
    // If resampling, mix stream data into a tmp buffer. Then
    // resample this buffer and mix the final resampled buffer into
    // the player buffer.
    else
    {
        bMonoToStereoMayBeConverted = FALSE;

//      memset(m_pTmpResBuf, 0, HX_SAFESIZE_T(m_ulMaxBlockSize));
        pSourceBuffer = m_pTmpResBuf;

        /* 
         * Audio Session will always ask for m_ulOutputBytesPerGran bytes to be mixed
         * in MixIntoBuffer() call. So we need to produce these many number of bytes.
         * If there is any mono-stereo conversion that happens in the mixing, number
         * of output bytes required from the resampler are half the number of 
         * m_ulOutputBytesPerGran bytes.
         */

        if (m_pResampler)
        {
            ulMaxFramesOut = m_ulOutputBytesPerGran/(m_DeviceFmt.uBitsPerSample==8 ? 1 : 2);

            if (m_DeviceFmt.uChannels == 2)
            {
                ulMaxFramesOut /= 2;
            }

            ulMaxFramesIn = m_pResampler->Requires(ulMaxFramesOut);

            ulMaxBytes = ulMaxFramesIn *  ((m_AudioFmt.uBitsPerSample==8)? 1 : 2)
                                            * m_AudioFmt.uChannels;
        }
        else
        {
            ulMaxBytes = m_ulInputBytesPerGran;
        }

        HX_ASSERT(ulMaxBytes <= m_ulMaxBlockSize);
    }
#endif /* HELIX_FEATURE_RESAMPLER */

    // /////////////////////////////////////////////////////////////
    // Mix n bytes of data into buffer
    ulNumBytesMixed = MixData(pSourceBuffer, ulMaxBytes, bMonoToStereoMayBeConverted, 
        (!m_pResampler) ? bIsMixBufferDirty : bResampleBufferDirty);

/*
    if (ulNumBytesMixed > 0)
    {
        ::fwrite(pSourceBuffer, ulNumBytesMixed, 1, fdbefore);
    }
*/

#if defined(HELIX_FEATURE_RESAMPLER)
    // /////////////////////////////////////////////////////////////
    // If we need to resample , then do this and then mix data into
    // the player buffer.
    // Only resample and mix if volume is *not* zero and there 
    // are some bytes to mix.
    if (m_pResampler && ulNumBytesMixed > 0 && m_uVolume > 0 && !m_bMute)
    {
        if(ulNumBytesMixed < ulMaxBytes  &&  8==m_AudioFmt.uBitsPerSample)
        {
            //fill remainder with 128's (-1), silence:
            UCHAR* pTmp = &pSourceBuffer[ulNumBytesMixed];
            ULONG32 ulNumBytesLeftToSilence = ulMaxBytes-ulNumBytesMixed;
            do
            {
                *pTmp = 128;
                pTmp++;
            } while(--ulNumBytesLeftToSilence);
        }

        ULONG32 ulOutBytes      = 0;
        if (m_pResampler)
        {
            ulOutBytes = m_pResampler->Resample((UINT16*)pSourceBuffer,
                                                ulMaxBytes,
                                                (UINT16*)m_pResampleBuf);

/*
            FILE* fp = fopen("c:\\temp\\audio.txt", "w+");
            ::fwrite(m_pResampleBuf, ulOutBytes, 1, fp);
            fclose(fp);
*/
            /* Resampler will do stereo to mono conversion for us.*/
            HX_ASSERT(ulMaxFramesOut == (ulOutBytes / 2 / 
                      (m_AudioFmt.uChannels == 2 && m_DeviceFmt.uChannels == 1 ? 1 : m_AudioFmt.uChannels))) ;
        }

        if (m_bChannelConvert)
        {
            HX_ASSERT(ulOutBytes*2 <= ulBufSize);
            if ( ulOutBytes > ulBufSize/2 )
            {           
                ulOutBytes = ulBufSize/2;
            }
        }
        else
        {
            HX_ASSERT(ulOutBytes <= ulBufSize);
            ulOutBytes = ulBufSize;
        }

        BOOL bBeforeMixBufferDirty = bIsMixBufferDirty;
        UINT32 ulMixedNumBytes = 0;

#if defined(HELIX_FEATURE_MIXER)
        ulMixedNumBytes = CHXMixer::MixBuffer( m_pResampleBuf, pPlayerBuf, 
                             ulOutBytes, m_bChannelConvert,
                             m_uVolume, m_DeviceFmt.uBitsPerSample, bIsMixBufferDirty);
#else
        ::memcpy(pPlayerBuf, m_pResampleBuf, ulOutBytes); /* Flawfinder: ignore */
        bIsMixBufferDirty = TRUE;
        ulMixedNumBytes = ulOutBytes;
#endif /* HELIX_FEATURE_MIXER */

        // If we mixed only a partial buffer, make the remaining buffer silent
        if (!bBeforeMixBufferDirty && ulMixedNumBytes < ulBufSize)
        {
            ::memset(pPlayerBuf+ulMixedNumBytes, 0, ulBufSize-ulMixedNumBytes);
        }
    }

afterMixing:
#endif /* HELIX_FEATURE_RESAMPLER */

#ifdef _TESTING
    if ( g_log > 0 )
    {
        write( g_log, pPlayerBuf, ulNumBytesMixed);
    }

#endif

    /* This is for *FROM* stream */
    if (bGetCrossFadeData)
    {
        m_bFadeAlreadyDone = TRUE;
    }
    /* If we are cross-fading, we have data from this stream in pPlayerBuf
     * Now get data to be  cross-faded from *From* stream in 
     * m_pCrossFadeBuffer
     */
#if defined(HELIX_FEATURE_CROSSFADE) && defined(HELIX_FEATURE_MIXER)
    else if (bCrossFadeThisTime)
    {
        /* Allocate CrossFade Buffer */
        if (!m_pCrossFadeBuffer)
        {
            m_ulCrossFadeBufferSize = ulBufSize;
            m_pCrossFadeBuffer = new UCHAR[m_ulCrossFadeBufferSize];
        }

        memset(m_pCrossFadeBuffer, 0, HX_SAFESIZE_T(m_ulCrossFadeBufferSize));

        UINT32 ulCrossFadeLen = m_ulCrossFadeBufferSize;
        UINT32 ulTmpBufTime   = 0;
        BOOL bIsDrity = FALSE;
        m_pCrossFadeStream->MixIntoBuffer(m_pCrossFadeBuffer,
                                         ulCrossFadeLen, ulTmpBufTime, bIsDrity, TRUE);
        /* Now it is time to perform cross-fading between
         * pPlayerBuf and m_pCrossFadeBuffer
         */
        
        UINT32 ulStartByteToFade            = 0;
        UINT32 ulNumMsInThisBuffer          = CalcDeviceMs(ulBufSize);
        UINT32 ulNumBytesToBeCrossFaded = ulBufSize;
        UINT32 ulSampleSize = ((m_DeviceFmt.uBitsPerSample==8)? 1 : 2)
                            * m_DeviceFmt.uChannels;

        /* Make sure we have integral number of samples */
        HX_ASSERT(ulBufSize == (ulBufSize/ulSampleSize) * ulSampleSize);


        /* Only partial buffer needs to be cross-faded.
         *   -------------
         * ~~_____________|
         *
         *       -----------
         *      |___________~~
         *
         *      
         *     -----
         *    |_____|  <-- Granularity size block that is mixed.
         *
         *       <--> Only partial block needs to be faded
         */
        
        if (ulTimeActuallyFaded < ulNumMsInThisBuffer)
        {
            ulNumBytesToBeCrossFaded = (UINT32) (ulBufSize * 
                (ulTimeActuallyFaded*1./ulNumMsInThisBuffer)) ;

            UINT32 ulOutOfPhase = ulNumBytesToBeCrossFaded % ulSampleSize;
            if (ulOutOfPhase > 0)
            {
                ulNumBytesToBeCrossFaded = 
                    ulNumBytesToBeCrossFaded - ulOutOfPhase;
            }

            ulStartByteToFade = ulBufSize - ulNumBytesToBeCrossFaded;
        }

        if (ulTimeActuallyFaded > m_ulCrossFadeDuration)
        {
            ulNumBytesToBeCrossFaded = (UINT32) (ulBufSize * 
                (m_ulCrossFadeDuration*1./ulNumMsInThisBuffer)) ;

            UINT32 ulOutOfPhase = ulNumBytesToBeCrossFaded % ulSampleSize;
            if (ulOutOfPhase > 0)
            {
                ulNumBytesToBeCrossFaded = 
                    ulNumBytesToBeCrossFaded - ulOutOfPhase;
            }
        }

        UINT16 uNumSamples = (UINT16) (ulNumBytesToBeCrossFaded/
                                       ulSampleSize);

        BOOL bWasDirty = bIsMixBufferDirty;
        /* Mix the initial bytes that are not cross-faded*/
        if (ulStartByteToFade > 0)
        {
            CHXMixer::MixBuffer( m_pCrossFadeBuffer, pPlayerBuf, 
                        ulStartByteToFade, FALSE, 100, 8, bWasDirty);
        }

        m_pCrossFader->CrossFade((INT16*) (m_pCrossFadeBuffer+ulStartByteToFade), 
                                 (INT16*) (pPlayerBuf+ulStartByteToFade), 
                                 uNumSamples);

        /* make sure we have silence in bytes that were not touched */
        if (!bIsMixBufferDirty &&
            (ulStartByteToFade + (uNumSamples*ulSampleSize)) < ulBufSize)
        {
            ::memset(pPlayerBuf+ulStartByteToFade + (uNumSamples*ulSampleSize), 0, 
                ulBufSize - (ulStartByteToFade + (uNumSamples*ulSampleSize)));
        }

        bIsMixBufferDirty = TRUE;
    }

    if (bGetCrossFadeData || bCrossFadeThisTime)
    {
        if (bGetCrossFadeData)
        {
            HX_ASSERT(m_llLastWriteTime >= m_llCrossFadeStartTime);
            if (m_llLastWriteTime >= m_llCrossFadeStartTime)
            {
                HX_ASSERT(m_llLastWriteTime - m_llCrossFadeStartTime < MAX_TIMESTAMP_GAP);
                ulTimeActuallyFaded = INT64_TO_UINT32(m_llLastWriteTime - m_llCrossFadeStartTime);
            }
        }

        if (ulTimeActuallyFaded >= m_ulCrossFadeDuration)
        {
            m_bCrossFadingToBeDone = FALSE;
            HX_RELEASE(m_pCrossFadeStream);

            /* We should release any extra buffers if it is a
             * *from* stream
             */
            if (!m_bFadeToThisStream)
            {
                /* Do not remove any instantaenous buffers */
                FlushBuffers(FALSE);
            }
        }
        else
        {
            m_ulCrossFadeDuration   -= ulTimeActuallyFaded;
            m_llCrossFadeStartTime  += CAST_TO_INT64 ulTimeActuallyFaded;
        }
    }
    else if (m_bCrossFadingToBeDone && !m_bFadeToThisStream)
    {
        m_pCrossFadeStream->SyncStream(m_llLastWriteTime);
    }
#endif /* HELIX_FEATURE_CROSSFADE && HELIX_FEATURE_MIXER */

//{FILE* f1 = ::fopen("e:\\MixIntoBuffer.txt", "a+"); ::fprintf(f1, "%lu\t%p\t%lu\n", HX_GET_BETTERTICKCOUNT(), this, (UINT32)m_llLastWriteTime);::fclose(f1);}
    return HXR_OK;
}


/************************************************************************
 *  Method:
 *      CHXAudioStream::MixData
 *  Purpose:
 *      Mix all valid data in my auxilliary list into the buffer.
 *
 *  Thoughts:
 *      while there are buffers available
 *          if (buffertime is more than endtime) break;
 *          if (any part of buffer is >startime and < endtime)
 *              we are in business. 
 *              mix that part of the buffer, update offset, 
 *              update max of num bytes written in this round.
     * Looks like we need to keep LastWrite time and offsets for all buffers
     * that get written in one pass.
     * Consider this scenario:
     *  
     *
        ----------------- -----------------
       |________________| |_______________|  -> Skew  1
          ________ __________   
         |_______| |_________|              ->Skew    2  5
          ____________________________________
         |__________________|_|_______________| Skew in opposite direction 3
               _______
              |_______|                               4

         ____________
        |____________|      <- Buffer to be mixed currently
               
        
          Order of buffer processing will be in the order of numbers on the right.
          Since all the theree buffers have fudge within fudge limit, they need to 
          be written one after the other. This is possible only if we keep last
          write times and last written offsets in mixer buffer for each one of them.

        Is this extra processsing on every write worthed OR do we place limitations
        on the data that can be written.

     *  Hmmm... We are now going with STREAMED/INSTANTANEOUS/TIMED model since the
     *  above case is shows that users can really screw things up and it would be
     *  very difficult to handle this case. So instead, we do not support over-lapped
     *  buffers any more. i.e

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -