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

📄 pa_mac.c

📁 ppciaxclient softphone
💻 C
📖 第 1 页 / 共 5 页
字号:
        return NULL;
    }
#endif
    return addr;
}

/*************************************************************************
 * Free memory that could be accessed in real-time.
 * This call MUST be balanced with a call to PaHost_AllocateFastMemory().
 */
void PaHost_FreeFastMemory( void *addr, long numBytes )
{
    if( addr == NULL ) return;
#if TARGET_API_MAC_CARBON
    (void) numBytes;
#else
    UnholdMemory( addr, numBytes );
#endif
    DisposePtr( (Ptr) addr );
}

/*************************************************************************/
PaTimestamp Pa_StreamTime( PortAudioStream *stream )
{
	PaTimestamp   framesDone1;
	PaTimestamp   framesDone2;
	UInt64        whenIncremented;
	UnsignedWide  now;
	UInt64        now64;
	long          microsElapsed;
	long          framesElapsed;
	
    PaHostSoundControl *pahsc;
    internalPortAudioStream   *past = (internalPortAudioStream *) stream;
    if( past == NULL ) return paBadStreamPtr;
    pahsc = (PaHostSoundControl *) past->past_DeviceData;
    
/* Capture information from audio thread.
 * We have to be careful that we don't get interrupted in the middle.
 * So we grab the pahsc_NumFramesDone twice and make sure it didn't change.
 */
 	do
 	{
 		framesDone1 = pahsc->pahsc_NumFramesDone;
 		whenIncremented = pahsc->pahsc_WhenFramesDoneIncremented;
 		framesDone2 = pahsc->pahsc_NumFramesDone;
 	} while( framesDone1 != framesDone2 );
 	
 /* Calculate how many microseconds have elapsed and convert to frames. */
 	Microseconds( &now );
 	now64 = UnsignedWideToUInt64( now );
 	microsElapsed = U64Subtract( now64, whenIncremented );
 	framesElapsed = microsElapsed * past->past_SampleRate * 0.000001;
 	
	return framesDone1 + framesElapsed;
}

/**************************************************************************
** Callback for Input, SPBRecord()
*/
int gRecordCounter = 0;
int gPlayCounter = 0;
pascal void PaMac_InputCompletionProc(SPBPtr recParams)
{
    PaError                    result = paNoError;
    int                        finished = 1;
    internalPortAudioStream   *past;
    PaHostSoundControl        *pahsc;

    gRecordCounter += 1; /* debug hack to see if engine running */

    /* Get our PA data from Mac structure. */
    past = (internalPortAudioStream *) recParams->userLong;
    if( past == NULL ) return;

    if( past->past_Magic != PA_MAGIC )
    {
        AddTraceMessage("PaMac_InputCompletionProc: bad MAGIC, past", (long) past );
        AddTraceMessage("PaMac_InputCompletionProc: bad MAGIC, magic", (long) past->past_Magic );
        goto error;
    }
    pahsc = (PaHostSoundControl *) past->past_DeviceData;
    past->past_NumCallbacks += 1;

    /* Have we been asked to stop recording? */
    if( (recParams->error == abortErr) || pahsc->pahsc_StopRecording ) goto error;

    /* If there are no output channels, then we need to call the user callback function from here.
     * Otherwise we will call the user code during the output completion routine.
     */
    if(past->past_NumOutputChannels == 0)
    {
		SetFramesDone( pahsc,
			pahsc->pahsc_NumFramesDone + pahsc->pahsc_FramesPerHostBuffer );
        result = PaMac_CallUserLoop( past, NULL );
    }

    /* Did user code ask us to stop? If not, issue another recording request. */
    if( (result == paNoError) && (pahsc->pahsc_StopRecording == 0) )
    {
        result = PaMac_RecordNext( past );
        if( result != paNoError ) pahsc->pahsc_IsRecording = 0;
    }
    else goto error;

    return;

error:
    pahsc->pahsc_IsRecording = 0;
    pahsc->pahsc_StopRecording = 0;
    return;
}

/***********************************************************************
** Called by either input or output completion proc.
** Grabs input data if any present, and calls PA conversion code,
** that in turn calls user code.
*/
static PaError PaMac_CallUserLoop( internalPortAudioStream   *past, int16 *outPtr )
{
    PaError             result = paNoError;
    PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
    int16              *inPtr = NULL;
    int                 i;
    

    /* Advance read index for sound input FIFO here, independantly of record/write process. */
    if(past->past_NumInputChannels > 0)
    {
        if( MultiBuffer_IsReadable( &pahsc->pahsc_InputMultiBuffer ) )
        {
            inPtr = (int16 *)  MultiBuffer_GetNextReadBuffer( &pahsc->pahsc_InputMultiBuffer );
            MultiBuffer_AdvanceReadIndex( &pahsc->pahsc_InputMultiBuffer );
        }
    }

    /* Call user code enough times to fill buffer. */
    if( (inPtr != NULL) || (outPtr != NULL) )
    {
        PaMac_StartLoadCalculation( past ); /* CPU usage */

#ifdef PA_MAX_USAGE_ALLOWED
	/* If CPU usage exceeds limit, skip user callback to prevent hanging CPU. */
		if( past->past_Usage > PA_MAX_USAGE_ALLOWED )
	    {
	    	past->past_FrameCount += (PaTimestamp) pahsc->pahsc_FramesPerHostBuffer;
		}
		else
#endif
		{
		
	        for( i=0; i<pahsc->pahsc_UserBuffersPerHostBuffer; i++ )
	        {
	            result = (PaError) Pa_CallConvertInt16( past, inPtr, outPtr );
	            if( result != 0)
	            {
	                /* Recording might be in another process, so tell it to stop with a flag. */
	                pahsc->pahsc_StopRecording = pahsc->pahsc_IsRecording;
	                break;
	            }
	            /* Advance sample pointers. */
	            if(inPtr != NULL) inPtr += past->past_FramesPerUserBuffer * past->past_NumInputChannels;
	            if(outPtr != NULL) outPtr += past->past_FramesPerUserBuffer * past->past_NumOutputChannels;
	        }
	    }
		
        PaMac_EndLoadCalculation( past );
    }
    return result;
}

/***********************************************************************
** Setup next recording buffer in FIFO and issue recording request to Snd Input Manager.
*/
static PaError PaMac_RecordNext( internalPortAudioStream   *past )
{
    PaError  result = paNoError;
    OSErr     err;
    PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
    /* Get pointer to next buffer to record into. */
    pahsc->pahsc_InputParams.bufferPtr  = MultiBuffer_GetNextWriteBuffer( &pahsc->pahsc_InputMultiBuffer );

    /* Advance write index if there is room. Otherwise keep writing same buffer. */
    if( MultiBuffer_IsWriteable( &pahsc->pahsc_InputMultiBuffer ) )
    {
        MultiBuffer_AdvanceWriteIndex( &pahsc->pahsc_InputMultiBuffer );
    }

    AddTraceMessage("PaMac_RecordNext: bufferPtr", (long) pahsc->pahsc_InputParams.bufferPtr );
    AddTraceMessage("PaMac_RecordNext: nextWrite", pahsc->pahsc_InputMultiBuffer.nextWrite );

    /* Setup parameters and issue an asynchronous recording request. */
    pahsc->pahsc_InputParams.bufferLength      = pahsc->pahsc_BytesPerInputHostBuffer;
    pahsc->pahsc_InputParams.count             = pahsc->pahsc_BytesPerInputHostBuffer;
    err = SPBRecord(&pahsc->pahsc_InputParams, true);
    if( err )
    {
        AddTraceMessage("PaMac_RecordNext: SPBRecord error ", err );
        sPaHostError = err;
        result = paHostError;
    }
    else
    {
        pahsc->pahsc_IsRecording = 1;
    }
    return result;
}

/**************************************************************************
** Callback for Output Playback()
** Return negative error, 0 to continue, 1 to stop.
*/
long    PaMac_FillNextOutputBuffer( internalPortAudioStream   *past, int index )
{
    PaHostSoundControl  *pahsc;
    long                 result = 0;
    int                  finished = 1;
    char                *outPtr;

    gPlayCounter += 1; /* debug hack */

    past->past_NumCallbacks += 1;
    pahsc = (PaHostSoundControl *) past->past_DeviceData;
    if( pahsc == NULL ) return -1;
    /* Are we nested?! */
    if( pahsc->pahsc_IfInsideCallback ) return 0;
    pahsc->pahsc_IfInsideCallback = 1;
    /* Get pointer to buffer to fill. */
    outPtr = pahsc->pahsc_SoundHeaders[index].samplePtr;
    /* Combine with any sound input, and call user callback. */
    result = PaMac_CallUserLoop( past, (int16 *) outPtr );

    pahsc->pahsc_IfInsideCallback = 0;
    return result;
}

/*************************************************************************************
** Called by SoundManager when ready for another buffer.
*/
static pascal void PaMac_OutputCompletionProc (SndChannelPtr theChannel, SndCommand * theCallBackCmd)
{
    internalPortAudioStream *past;
    PaHostSoundControl      *pahsc;
    (void) theChannel;
    (void) theCallBackCmd;

    /* Get our data from Mac structure. */
    past = (internalPortAudioStream *) theCallBackCmd->param2;
    if( past == NULL ) return;

    pahsc = (PaHostSoundControl *) past->past_DeviceData;
    pahsc->pahsc_NumOutsPlayed += 1;

	SetFramesDone( pahsc,
			pahsc->pahsc_NumFramesDone + pahsc->pahsc_FramesPerHostBuffer );
			
    PaMac_BackgroundManager( past, theCallBackCmd->param1 );
}

/*******************************************************************/
static PaError PaMac_BackgroundManager( internalPortAudioStream   *past, int index )
{
    PaError      result = paNoError;
    PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
    /* Has someone asked us to abort by calling Pa_AbortStream()? */
    if( past->past_StopNow )
    {
        SndCommand  command;
        /* Clear the queue of any pending commands. */
        command.cmd = flushCmd;
        command.param1 = command.param2 = 0;
        SndDoImmediate( pahsc->pahsc_Channel, &command );
        /* Then stop currently playing buffer, if any. */
        command.cmd = quietCmd;
        SndDoImmediate( pahsc->pahsc_Channel, &command );
        past->past_IsActive = 0;
    }
    /* Has someone asked us to stop by calling Pa_StopStream()
     * OR has a user callback returned '1' to indicate finished.
     */
    else if( past->past_StopSoon )
    {
        if( (pahsc->pahsc_NumOutsQueued - pahsc->pahsc_NumOutsPlayed) <= 0 )
        {
            past->past_IsActive = 0; /* We're finally done. */
        }
    }
    else
    {
        PaMac_PlayNext( past, index );
    }
    return result;
}

/*************************************************************************************
** Fill next buffer with sound and queue it for playback.
*/
static void PaMac_PlayNext ( internalPortAudioStream *past, int index )
{
    OSErr                  error;
    long                     result;
    SndCommand               playCmd;
    SndCommand           callbackCmd;
    PaHostSoundControl      *pahsc = (PaHostSoundControl *) past->past_DeviceData;

    /* If this was the last buffer, or abort requested, then just be done. */
    if ( past->past_StopSoon ) goto done;
    
    /* Load buffer with sound. */
    result = PaMac_FillNextOutputBuffer ( past, index );
    if( result > 0 ) past->past_StopSoon = 1; /* Stop generating audio but wait until buffers play. */
    else if( result < 0 ) goto done;
    
    /* Play the next buffer. */
    playCmd.cmd = bufferCmd;
    playCmd.param1 = 0;
    playCmd.param2 = (long) &pahsc->pahsc_SoundHeaders[ index ];
    error = SndDoCommand (pahsc->pahsc_Channel, &playCmd, true );
    if( error != noErr ) goto gotError;
    
    /* Ask for a callback when it is done. */
    callbackCmd.cmd = callBackCmd;
    callbackCmd.param1 = index;
    callbackCmd.param2 = (long)past;
    error = SndDoCommand (pahsc->pahsc_Channel, &callbackCmd, true );
    if( error != noErr ) goto gotError;
    pahsc->pahsc_NumOutsQueued += 1;

    return;

gotError:
    sPaHostError = error;
done:
    return;
}

⌨️ 快捷键说明

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