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

📄 pa_win_wmme.c

📁 一个开源SIP协议栈
💻 C
📖 第 1 页 / 共 5 页
字号:
            
            if( inputChannelCount > 0 ) /* full duplex */
            {
                if( *framesPerHostInputBuffer != *framesPerHostOutputBuffer )
                {
                    if( inputStreamInfo
                            && ( inputStreamInfo->flags & paWinMmeUseLowLevelLatencyParameters ) )
                    { 
                        /* a custom StreamInfo was used for specifying both input
                            and output buffer sizes, the larger buffer size
                            must be a multiple of the smaller buffer size */

                        if( *framesPerHostInputBuffer < *framesPerHostOutputBuffer )
                        {
                            if( *framesPerHostOutputBuffer % *framesPerHostInputBuffer != 0 )
                            {
                                result = paIncompatibleHostApiSpecificStreamInfo;
                                goto error;
                            }
                        }
                        else
                        {
                            assert( *framesPerHostInputBuffer > *framesPerHostOutputBuffer );
                            if( *framesPerHostInputBuffer % *framesPerHostOutputBuffer != 0 )
                            {
                                result = paIncompatibleHostApiSpecificStreamInfo;
                                goto error;
                            }
                        }                        
                    }
                    else
                    {
                        /* a custom StreamInfo was not used for specifying the input buffer size,
                            so use the output buffer size, and approximately the same latency. */

                        *framesPerHostInputBuffer = *framesPerHostOutputBuffer;
                        *hostInputBufferCount = (((unsigned long)(suggestedInputLatency * sampleRate)) / *framesPerHostInputBuffer) + 1;

                        if( *hostInputBufferCount < PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_FULL_DUPLEX_ )
                            *hostInputBufferCount = PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_FULL_DUPLEX_;
                    }
                }
            }
        }
        else
        {
            unsigned long hostBufferSizeBytes, hostBufferCount;
            unsigned long minimumBufferCount = PA_MME_MIN_HOST_OUTPUT_BUFFER_COUNT_;
            unsigned long maximumBufferSize;
            int hostOutputFrameSize;
            int hostOutputSampleSize;

            hostOutputSampleSize = Pa_GetSampleSize( hostOutputSampleFormat );
            if( hostOutputSampleSize < 0 )
            {
                result = hostOutputSampleSize;
                goto error;
            }

            if( outputStreamInfo
                && ( outputStreamInfo->flags & paWinMmeUseMultipleDevices ) )
            {
                /* set effectiveOutputChannelCount to the largest number of
                    channels on any one device.
                */
                effectiveOutputChannelCount = 0;
                for( i=0; i< outputStreamInfo->deviceCount; ++i )
                {
                    if( outputStreamInfo->devices[i].channelCount > effectiveOutputChannelCount )
                        effectiveOutputChannelCount = outputStreamInfo->devices[i].channelCount;
                }
            }
            else
            {
                effectiveOutputChannelCount = outputChannelCount;
            }

            hostOutputFrameSize = hostOutputSampleSize * effectiveOutputChannelCount;
            
            maximumBufferSize = (long) ((PA_MME_MAX_HOST_BUFFER_SECS_ * sampleRate) * hostOutputFrameSize);
            if( maximumBufferSize > PA_MME_MAX_HOST_BUFFER_BYTES_ )
                maximumBufferSize = PA_MME_MAX_HOST_BUFFER_BYTES_;


            /* compute the following in bytes, then convert back to frames */

            SelectBufferSizeAndCount(
                ((framesPerBuffer == paFramesPerBufferUnspecified)
                    ? PA_MME_MIN_HOST_BUFFER_FRAMES_WHEN_UNSPECIFIED_
                    : framesPerBuffer ) * hostOutputFrameSize, /* baseBufferSize */
                ((unsigned long)(suggestedOutputLatency * sampleRate)) * hostOutputFrameSize, /* suggestedLatency */
                4, /* baseBufferCount */
                minimumBufferCount,
                maximumBufferSize,
                &hostBufferSizeBytes, &hostBufferCount );

            *framesPerHostOutputBuffer = hostBufferSizeBytes / hostOutputFrameSize;
            *hostOutputBufferCount = hostBufferCount;


            if( inputChannelCount > 0 )
            {
                /* ensure that both input and output buffer sizes are the same.
                    if they don't match at this stage, choose the smallest one
                    and use that for input and output
                */

                if( *framesPerHostOutputBuffer != *framesPerHostInputBuffer )
                {
                    if( framesPerHostInputBuffer < framesPerHostOutputBuffer )
                    {
                        unsigned long framesPerHostBuffer = *framesPerHostInputBuffer;
                        
                        minimumBufferCount = PA_MME_MIN_HOST_OUTPUT_BUFFER_COUNT_;
                        ReselectBufferCount(
                            framesPerHostBuffer * hostOutputFrameSize, /* bufferSize */
                            ((unsigned long)(suggestedOutputLatency * sampleRate)) * hostOutputFrameSize, /* suggestedLatency */
                            4, /* baseBufferCount */
                            minimumBufferCount,
                            &hostBufferCount );

                        *framesPerHostOutputBuffer = framesPerHostBuffer;
                        *hostOutputBufferCount = hostBufferCount;
                    }
                    else
                    {
                        unsigned long framesPerHostBuffer = *framesPerHostOutputBuffer;
                        
                        minimumBufferCount = PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_FULL_DUPLEX_;
                        ReselectBufferCount(
                            framesPerHostBuffer * hostInputFrameSize, /* bufferSize */
                            ((unsigned long)(suggestedInputLatency * sampleRate)) * hostInputFrameSize, /* suggestedLatency */
                            4, /* baseBufferCount */
                            minimumBufferCount,
                            &hostBufferCount );

                        *framesPerHostInputBuffer = framesPerHostBuffer;
                        *hostInputBufferCount = hostBufferCount;
                    }
                }   
            }
        }
    }
    else
    {
        *framesPerHostOutputBuffer = 0;
        *hostOutputBufferCount = 0;
    }

error:
    return result;
}


typedef struct
{
    HANDLE bufferEvent;
    void *waveHandles;
    unsigned int deviceCount;
    /* unsigned int channelCount; */
    WAVEHDR **waveHeaders;                  /* waveHeaders[device][buffer] */
    unsigned int bufferCount;
    unsigned int currentBufferIndex;
    unsigned int framesPerBuffer;
    unsigned int framesUsedInCurrentBuffer;
}PaWinMmeSingleDirectionHandlesAndBuffers;

/* prototypes for functions operating on PaWinMmeSingleDirectionHandlesAndBuffers */

static void InitializeSingleDirectionHandlesAndBuffers( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers );
static PaError InitializeWaveHandles( PaWinMmeHostApiRepresentation *winMmeHostApi,
        PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers,
        unsigned long bytesPerHostSample,
        double sampleRate, PaWinMmeDeviceAndChannelCount *devices,
        unsigned int deviceCount, int isInput );
static PaError TerminateWaveHandles( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers, int isInput, int currentlyProcessingAnError );
static PaError InitializeWaveHeaders( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers,
        unsigned long hostBufferCount,
        PaSampleFormat hostSampleFormat,
        unsigned long framesPerHostBuffer,
        PaWinMmeDeviceAndChannelCount *devices,
        int isInput );
static void TerminateWaveHeaders( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers, int isInput );


static void InitializeSingleDirectionHandlesAndBuffers( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers )
{
    handlesAndBuffers->bufferEvent = 0;
    handlesAndBuffers->waveHandles = 0;
    handlesAndBuffers->deviceCount = 0;
    handlesAndBuffers->waveHeaders = 0;
    handlesAndBuffers->bufferCount = 0;
}    

static PaError InitializeWaveHandles( PaWinMmeHostApiRepresentation *winMmeHostApi,
        PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers,
        unsigned long bytesPerHostSample,
        double sampleRate, PaWinMmeDeviceAndChannelCount *devices,
        unsigned int deviceCount, int isInput )
{
    PaError result;
    MMRESULT mmresult;
    unsigned long bytesPerFrame;
    WAVEFORMATEX wfx;
    signed int i;

    /* for error cleanup we expect that InitializeSingleDirectionHandlesAndBuffers()
        has already been called to zero some fields */       

    result = CreateEventWithPaError( &handlesAndBuffers->bufferEvent, NULL, FALSE, FALSE, NULL );
    if( result != paNoError ) goto error;

    if( isInput )
        handlesAndBuffers->waveHandles = (void*)PaUtil_AllocateMemory( sizeof(HWAVEIN) * deviceCount );
    else
        handlesAndBuffers->waveHandles = (void*)PaUtil_AllocateMemory( sizeof(HWAVEOUT) * deviceCount );
    if( !handlesAndBuffers->waveHandles )
    {
        result = paInsufficientMemory;
        goto error;
    }

    handlesAndBuffers->deviceCount = deviceCount;

    for( i = 0; i < (signed int)deviceCount; ++i )
    {
        if( isInput )
            ((HWAVEIN*)handlesAndBuffers->waveHandles)[i] = 0;
        else
            ((HWAVEOUT*)handlesAndBuffers->waveHandles)[i] = 0;
    }

    wfx.wFormatTag = WAVE_FORMAT_PCM;
    wfx.nSamplesPerSec = (DWORD) sampleRate;
    wfx.cbSize = 0;
    
    for( i = 0; i < (signed int)deviceCount; ++i )
    {
        UINT winMmeDeviceId;

        winMmeDeviceId = LocalDeviceIndexToWinMmeDeviceId( winMmeHostApi, devices[i].device );
        wfx.nChannels = (WORD)devices[i].channelCount;

        bytesPerFrame = wfx.nChannels * bytesPerHostSample;

        wfx.nAvgBytesPerSec = (DWORD)(bytesPerFrame * sampleRate);
        wfx.nBlockAlign = (WORD)bytesPerFrame;
        wfx.wBitsPerSample = (WORD)((bytesPerFrame/wfx.nChannels) * 8);

        /* REVIEW: consider not firing an event for input when a full duplex
            stream is being used. this would probably depend on the
            neverDropInput flag. */

        if( isInput )
            mmresult = waveInOpen( &((HWAVEIN*)handlesAndBuffers->waveHandles)[i], winMmeDeviceId, &wfx,
                               (DWORD)handlesAndBuffers->bufferEvent, (DWORD)0, CALLBACK_EVENT );
        else
            mmresult = waveOutOpen( &((HWAVEOUT*)handlesAndBuffers->waveHandles)[i], winMmeDeviceId, &wfx,
                                (DWORD)handlesAndBuffers->bufferEvent, (DWORD)0, CALLBACK_EVENT );

        if( mmresult != MMSYSERR_NOERROR )
        {
            switch( mmresult )
            {
                case MMSYSERR_ALLOCATED:    /* Specified resource is already allocated. */
                    result = paDeviceUnavailable;
                    break;
                case MMSYSERR_NODRIVER:	    /* No device driver is present. */
                    result = paDeviceUnavailable;
                    break;
                case MMSYSERR_NOMEM:	    /* Unable to allocate or lock memory. */
                    result = paInsufficientMemory;
                    break;

                case MMSYSERR_BADDEVICEID:	/* Specified device identifier is out of range. */
                    /* falls through */
                case WAVERR_BADFORMAT:      /* Attempted to open with an unsupported waveform-audio format. */
                    /* falls through */
                default:
                    result = paUnanticipatedHostError;
                    if( isInput )
                    {
                        PA_MME_SET_LAST_WAVEIN_ERROR( mmresult );
                    }
                    else
                    {
                        PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult );
                    }
            }
            goto error;
        }
    }

    return result;

error:
    TerminateWaveHandles( handlesAndBuffers, isInput, 1 /* currentlyProcessingAnError */ );

    return result;
}


static PaError TerminateWaveHandles( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers, int isInput, int currentlyProcessingAnError )
{
    PaError result = paNoError;
    MMRESULT mmresult = 0;
    signed int i;
    
    if( handlesAndBuffers->waveHandles )
    {
        for( i = handlesAndBuffers->deviceCount-1; i >= 0; --i )
        {
            if( isInput )
            {
                if( ((HWAVEIN*)handlesAndBuffers->waveHandles)[i] )
                    mmresult = waveInClose( ((HWAVEIN*)handlesAndBuffers->waveHandles)[i] );
            }
            else
            {
                if( ((HWAVEOUT*)handlesAndBuffers->waveHandles)[i] )
                    mmresult = waveOutClose( ((HWAVEOUT*)handlesAndBuffers->waveHandles)[i] );
            }

            if( mmresult != MMSYSERR_NOERROR &&
                

⌨️ 快捷键说明

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