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

📄 pa_mac.c

📁 ppciaxclient softphone
💻 C
📖 第 1 页 / 共 5 页
字号:
    int32  framesPerHostBuffer;
    int32  numHostBuffers;
    
    minFramesPerHostBuffer = pahsc->pahsc_MinFramesPerHostBuffer;
    minFramesPerHostBuffer = (minFramesPerHostBuffer + 7) & ~7;
    DBUG(("PaHost_CalcNumHostBuffers: minFramesPerHostBuffer = %d\n", minFramesPerHostBuffer ));
    
    /* Determine number of user buffers based on minimum latency. */
	/* PLB20020417 I used to call Pa_GetMinNumBuffers() which doesn't take into account the
	**    variable minFramesPerHostBuffer. Now I call PaMac_GetMinNumBuffers() which will
	**    gove lower latency when virtual memory is turned off. */
    /* minNumBuffers = Pa_GetMinNumBuffers( past->past_FramesPerUserBuffer, past->past_SampleRate ); WRONG */
    minNumBuffers = PaMac_GetMinNumBuffers( minFramesPerHostBuffer, past->past_FramesPerUserBuffer, past->past_SampleRate );
    
    past->past_NumUserBuffers = ( minNumBuffers > past->past_NumUserBuffers ) ? minNumBuffers : past->past_NumUserBuffers;
    DBUG(("PaHost_CalcNumHostBuffers: min past_NumUserBuffers = %d\n", past->past_NumUserBuffers ));
    minTotalFrames = past->past_NumUserBuffers * past->past_FramesPerUserBuffer;
    
    /* We cannot make the buffers too small because they may not get serviced quickly enough. */
    if( (int32) past->past_FramesPerUserBuffer < minFramesPerHostBuffer )
    {
        userBuffersPerHostBuffer =
            (minFramesPerHostBuffer + past->past_FramesPerUserBuffer - 1) /
            past->past_FramesPerUserBuffer;
    }
    else
    {
        userBuffersPerHostBuffer = 1;
    }
    framesPerHostBuffer = past->past_FramesPerUserBuffer * userBuffersPerHostBuffer;
    
    /* Calculate number of host buffers needed. Round up to cover minTotalFrames. */
    numHostBuffers = (minTotalFrames + framesPerHostBuffer - 1) / framesPerHostBuffer;
    /* Make sure we have enough host buffers. */
    if( numHostBuffers < PA_MIN_NUM_HOST_BUFFERS)
    {
        numHostBuffers = PA_MIN_NUM_HOST_BUFFERS;
    }
    else
    {
        /* If we have too many host buffers, try to put more user buffers in a host buffer. */
        while(numHostBuffers > PA_MAX_NUM_HOST_BUFFERS)
        {
            userBuffersPerHostBuffer += 1;
            framesPerHostBuffer = past->past_FramesPerUserBuffer * userBuffersPerHostBuffer;
            numHostBuffers = (minTotalFrames + framesPerHostBuffer - 1) / framesPerHostBuffer;
        }
    }

    pahsc->pahsc_UserBuffersPerHostBuffer = userBuffersPerHostBuffer;
    pahsc->pahsc_FramesPerHostBuffer = framesPerHostBuffer;
    pahsc->pahsc_NumHostBuffers = numHostBuffers;
    DBUG(("PaHost_CalcNumHostBuffers: pahsc_UserBuffersPerHostBuffer = %d\n", pahsc->pahsc_UserBuffersPerHostBuffer ));
    DBUG(("PaHost_CalcNumHostBuffers: pahsc_NumHostBuffers = %d\n", pahsc->pahsc_NumHostBuffers ));
    DBUG(("PaHost_CalcNumHostBuffers: pahsc_FramesPerHostBuffer = %d\n", pahsc->pahsc_FramesPerHostBuffer ));
    DBUG(("PaHost_CalcNumHostBuffers: past_NumUserBuffers = %d\n", past->past_NumUserBuffers ));
}

/*******************************************************************/
PaError PaHost_OpenStream( internalPortAudioStream   *past )
{
    OSErr             err;
    PaError             result = paHostError;
    PaHostSoundControl *pahsc;
    int                 i;
    /* Allocate and initialize host data. */
    pahsc = (PaHostSoundControl *) PaHost_AllocateFastMemory(sizeof(PaHostSoundControl));
    if( pahsc == NULL )
    {
        return paInsufficientMemory;
    }
    past->past_DeviceData = (void *) pahsc;

    /* If recording, and virtual memory is turned on, then use bigger buffers to prevent glitches. */
    if( (past->past_NumInputChannels > 0)  && Mac_IsVirtualMemoryOn() )
    {
        pahsc->pahsc_MinFramesPerHostBuffer = MAC_VIRTUAL_FRAMES_PER_BUFFER;
    }
    else
    {
        pahsc->pahsc_MinFramesPerHostBuffer = MAC_PHYSICAL_FRAMES_PER_BUFFER;
    }

    PaHost_CalcNumHostBuffers( past );
    
    /* Setup constants for CPU load measurement. */
    pahsc->pahsc_InverseMicrosPerHostBuffer = past->past_SampleRate / (1000000.0 * 	pahsc->pahsc_FramesPerHostBuffer);

    /* ------------------ OUTPUT */
    if( past->past_NumOutputChannels > 0 )
    {
        /* Create sound channel to which we can send commands. */
        pahsc->pahsc_Channel = 0L;
        err = SndNewChannel(&pahsc->pahsc_Channel, sampledSynth, 0, nil); /* FIXME - use kUseOptionalOutputDevice if not default. */
        if(err != 0)
        {
            ERR_RPT(("Error in PaHost_OpenStream: SndNewChannel returned 0x%x\n", err ));
            goto error;
        }

        /* Install our callback function pointer straight into the sound channel structure */
        /* Use new CARBON name for callback procedure. */
#if TARGET_API_MAC_CARBON
        pahsc->pahsc_OutputCompletionProc = NewSndCallBackUPP(PaMac_OutputCompletionProc);
#else
        pahsc->pahsc_OutputCompletionProc = NewSndCallBackProc(PaMac_OutputCompletionProc);
#endif

        pahsc->pahsc_Channel->callBack = pahsc->pahsc_OutputCompletionProc;

        pahsc->pahsc_BytesPerOutputHostBuffer = pahsc->pahsc_FramesPerHostBuffer * past->past_NumOutputChannels * sizeof(int16);
        for (i = 0; i<pahsc->pahsc_NumHostBuffers; i++)
        {
            char *buf = (char *)PaHost_AllocateFastMemory(pahsc->pahsc_BytesPerOutputHostBuffer);
            if (buf == NULL)
            {
                ERR_RPT(("Error in PaHost_OpenStream: could not allocate output buffer. Size = \n", pahsc->pahsc_BytesPerOutputHostBuffer ));
                goto memerror;
            }

            PaMac_InitSoundHeader( past, &pahsc->pahsc_SoundHeaders[i] );
            pahsc->pahsc_SoundHeaders[i].samplePtr = buf;
            pahsc->pahsc_SoundHeaders[i].numFrames = (unsigned long) pahsc->pahsc_FramesPerHostBuffer;

        }
    }
#ifdef SUPPORT_AUDIO_CAPTURE
    /* ------------------ INPUT */
    /* Use double buffer scheme that matches output. */
    if( past->past_NumInputChannels > 0 )
    {
        int16   tempS;
        long    tempL;
        Fixed   tempF;
        long    mRefNum;
        Str255 namePString;
#if TARGET_API_MAC_CARBON
        pahsc->pahsc_InputCompletionProc = NewSICompletionUPP((SICompletionProcPtr)PaMac_InputCompletionProc);
#else
        pahsc->pahsc_InputCompletionProc = NewSICompletionProc((ProcPtr)PaMac_InputCompletionProc);
#endif
        pahsc->pahsc_BytesPerInputHostBuffer = pahsc->pahsc_FramesPerHostBuffer * past->past_NumInputChannels * sizeof(int16);
        for (i = 0; i<pahsc->pahsc_NumHostBuffers; i++)
        {
            char *buf = (char *) PaHost_AllocateFastMemory(pahsc->pahsc_BytesPerInputHostBuffer);
            if ( buf == NULL )
            {
                ERR_RPT(("PaHost_OpenStream: could not allocate input  buffer. Size = \n", pahsc->pahsc_BytesPerInputHostBuffer ));
                goto memerror;
            }
            pahsc->pahsc_InputMultiBuffer.buffers[i] = buf;
        }
        pahsc->pahsc_InputMultiBuffer.numBuffers = pahsc->pahsc_NumHostBuffers;

        // err = SPBOpenDevice( (const unsigned char *) &noname, siWritePermission, &mRefNum);
        CToPString((char *)sDevices[past->past_InputDeviceID].pad_Info.name, namePString);
        err = SPBOpenDevice(namePString, siWritePermission, &mRefNum);

        if (err) goto error;
        pahsc->pahsc_InputRefNum = mRefNum;
        DBUG(("PaHost_OpenStream: mRefNum = %d\n", mRefNum ));

        /* Set input device characteristics. */
        tempS = 1;
        err = SPBSetDeviceInfo(mRefNum, siContinuous, (Ptr) &tempS);
        if (err)
        {
            ERR_RPT(("Error in PaHost_OpenStream: SPBSetDeviceInfo siContinuous returned %d\n", err ));
            goto error;
        }

        tempL = 0x03;
        err = SPBSetDeviceInfo(mRefNum, siActiveChannels, (Ptr) &tempL);
        if (err)
        {
            DBUG(("PaHost_OpenStream: setting siActiveChannels returned 0x%x. Error ignored.\n", err ));
        }

        /* PLB20010908 - Use requested number of input channels. Thanks Dominic Mazzoni. */
        tempS = past->past_NumInputChannels;
        err = SPBSetDeviceInfo(mRefNum, siNumberChannels, (Ptr) &tempS);
        if (err)
        {
            ERR_RPT(("Error in PaHost_OpenStream: SPBSetDeviceInfo siNumberChannels returned %d\n", err ));
            goto error;
        }

        tempF = ((unsigned long)past->past_SampleRate) << 16;
        err = SPBSetDeviceInfo(mRefNum, siSampleRate, (Ptr) &tempF);
        if (err)
        {
            ERR_RPT(("Error in PaHost_OpenStream: SPBSetDeviceInfo siSampleRate returned %d\n", err ));
            goto error;
        }

        /* Setup record-parameter block */
        pahsc->pahsc_InputParams.inRefNum          = mRefNum;
        pahsc->pahsc_InputParams.milliseconds      = 0;   // not used
        pahsc->pahsc_InputParams.completionRoutine = pahsc->pahsc_InputCompletionProc;
        pahsc->pahsc_InputParams.interruptRoutine  = 0;
        pahsc->pahsc_InputParams.userLong          = (long) past;
        pahsc->pahsc_InputParams.unused1           = 0;
    }
#endif /* SUPPORT_AUDIO_CAPTURE */
    DBUG(("PaHost_OpenStream: complete.\n"));
    return paNoError;

error:
    PaHost_CloseStream( past );
    ERR_RPT(("PaHost_OpenStream: sPaHostError =  0x%x.\n", err ));
    sPaHostError = err;
    return paHostError;

memerror:
    PaHost_CloseStream( past );
    return paInsufficientMemory;
}

/***********************************************************************
** Called by Pa_CloseStream().
** May be called during error recovery or cleanup code
** so protect against NULL pointers.
*/
PaError PaHost_CloseStream( internalPortAudioStream   *past )
{
    PaError result = paNoError;
    OSErr   err = 0;
    int     i;
    PaHostSoundControl *pahsc;

    DBUG(("PaHost_CloseStream( 0x%x )\n", past ));

    if( past == NULL ) return paBadStreamPtr;

    pahsc = (PaHostSoundControl *) past->past_DeviceData;
    if( pahsc == NULL ) return paNoError;

    if( past->past_NumOutputChannels > 0 )
    {
        /* TRUE means flush now instead of waiting for quietCmd to be processed. */
        if( pahsc->pahsc_Channel != NULL ) SndDisposeChannel(pahsc->pahsc_Channel, TRUE);
        {
            for (i = 0; i<pahsc->pahsc_NumHostBuffers; i++)
            {
                Ptr p = (Ptr) pahsc->pahsc_SoundHeaders[i].samplePtr;
                if( p != NULL ) PaHost_FreeFastMemory( p, pahsc->pahsc_BytesPerOutputHostBuffer );
            }
        }
    }

    if( past->past_NumInputChannels > 0 )
    {
        if( pahsc->pahsc_InputRefNum )
        {
            err = SPBCloseDevice(pahsc->pahsc_InputRefNum);
            pahsc->pahsc_InputRefNum = 0;
            if( err )
            {
                sPaHostError = err;
                result = paHostError;
            }
        }
        {
            for (i = 0; i<pahsc->pahsc_InputMultiBuffer.numBuffers; i++)
            {
                Ptr p = (Ptr) pahsc->pahsc_InputMultiBuffer.buffers[i];
                if( p != NULL ) PaHost_FreeFastMemory( p, pahsc->pahsc_BytesPerInputHostBuffer );
            }
        }
    }

    past->past_DeviceData = NULL;
    PaHost_FreeFastMemory( pahsc, sizeof(PaHostSoundControl) );

    DBUG(("PaHost_CloseStream: complete.\n", past ));
    return result;
}
/*************************************************************************/
int Pa_GetMinNumBuffers( int framesPerUserBuffer, double sampleRate )
{
/* We use the MAC_VIRTUAL_FRAMES_PER_BUFFER because we might be recording.
** This routine doesn't have enough information to determine the best value
** and is being depracated. */
    return PaMac_GetMinNumBuffers( MAC_VIRTUAL_FRAMES_PER_BUFFER, framesPerUserBuffer, sampleRate );
}
/*************************************************************************/
static int PaMac_GetMinNumBuffers( int minFramesPerHostBuffer, int framesPerUserBuffer, double sampleRate )
{
    int minUserPerHost = ( minFramesPerHostBuffer + framesPerUserBuffer - 1) / framesPerUserBuffer;
    int numBufs = PA_MIN_NUM_HOST_BUFFERS * minUserPerHost;
    if( numBufs < PA_MIN_NUM_HOST_BUFFERS ) numBufs = PA_MIN_NUM_HOST_BUFFERS;
    (void) sampleRate;
    return numBufs;
}

/*************************************************************************/
void Pa_Sleep( int32 msec )
{
    EventRecord   event;
    int32 sleepTime, endTime;
    /* Convert to ticks. Round up so we sleep a MINIMUM of msec time. */
    sleepTime = ((msec * 60) + 999) / 1000;
    if( sleepTime < 1 ) sleepTime = 1;
    endTime = TickCount() + sleepTime;
    do
    {
        DBUGX(("Sleep for %d ticks.\n", sleepTime ));
        /* Use WaitNextEvent() to sleep without getting events. */
        /* PLB20010907 - Pass unused event to WaitNextEvent instead of NULL to prevent
         * Mac OSX crash. Thanks Dominic Mazzoni. */
        WaitNextEvent( 0, &event, sleepTime, NULL );
        sleepTime = endTime - TickCount();
    }
    while( sleepTime > 0 );
}
/*************************************************************************/
int32 Pa_GetHostError( void )
{
    int32 err = sPaHostError;
    sPaHostError = 0;
    return err;
}

/*************************************************************************
 * Allocate memory that can be accessed in real-time.
 * This may need to be held in physical memory so that it is not
 * paged to virtual memory.
 * This call MUST be balanced with a call to PaHost_FreeFastMemory().
 */
void *PaHost_AllocateFastMemory( long numBytes )
{
    void *addr = NewPtrClear( numBytes );
    if( (addr == NULL) || (MemError () != 0) ) return NULL;

#if (TARGET_API_MAC_CARBON == 0)
    if( HoldMemory( addr, numBytes ) != noErr )
    {
        DisposePtr( (Ptr) addr );

⌨️ 快捷键说明

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