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

📄 pa_mac_core.c

📁 一个开源SIP协议栈
💻 C
📖 第 1 页 / 共 5 页
字号:
        * If input and output devs are different or we are doing SR conversion,
        * we also need a
        * ring buffer to store inpt data while waiting for output
        * data.
        */
       if( (stream->outputUnit && stream->inputUnit != stream->outputUnit)
           || stream->inputSRConverter )
       {
          /* May want the ringSize ot initial position in
             ring buffer to depend somewhat on sample rate change */

          void *data;
          long ringSize;

          ringSize = computeRingBufferSize( inputParameters,
                                            outputParameters,
                                            stream->inputFramesPerBuffer,
                                            stream->outputFramesPerBuffer,
                                            sampleRate );
          /*ringSize <<= 4; *//*16x bigger, for testing */


          /*now, we need to allocate memory for the ring buffer*/
          data = calloc( ringSize, szfl );
          if( !data )
          {
             result = paInsufficientMemory;
             goto error;
          }

          /* now we can initialize the ring buffer */
          /*assert( 0 ==*/
            RingBuffer_Init( &stream->inputRingBuffer,
                             ringSize*szfl, data ) /*)*/;
          /* advance the read point a little, so we are reading from the
             middle of the buffer */
          if( stream->outputUnit )
             RingBuffer_AdvanceWriteIndex( &stream->inputRingBuffer, ringSize*szfl / RING_BUFFER_ADVANCE_DENOMINATOR );
       }
    }

    /* -- initialize Blio Buffer Processors -- */
    if( !streamCallback )
    {
       long ringSize;

       ringSize = computeRingBufferSize( inputParameters,
                                         outputParameters,
                                         stream->inputFramesPerBuffer,
                                         stream->outputFramesPerBuffer,
                                         sampleRate );
       result = initializeBlioRingBuffers( &stream->blio,
              inputParameters?inputParameters->sampleFormat:0 ,
              outputParameters?outputParameters->sampleFormat:0 ,
              MAX(stream->inputFramesPerBuffer,stream->outputFramesPerBuffer),
              ringSize,
              inputParameters?inputChannelCount:0 ,
              outputParameters?outputChannelCount:0 ) ;
       if( result != paNoError )
          goto error;
    }

    /* -- initialize Buffer Processor -- */
    {
       unsigned long maxHostFrames = stream->inputFramesPerBuffer;
       if( stream->outputFramesPerBuffer > maxHostFrames )
          maxHostFrames = stream->outputFramesPerBuffer;
       result = PaUtil_InitializeBufferProcessor( &stream->bufferProcessor,
                 inputChannelCount, inputSampleFormat,
                 hostInputSampleFormat,
                 outputChannelCount, outputSampleFormat,
                 hostOutputSampleFormat,
                 sampleRate,
                 streamFlags,
                 framesPerBuffer,
                 /* If sample rate conversion takes place, the buffer size
                    will not be known. */
                 maxHostFrames,
                 stream->inputSRConverter
                              ? paUtilUnknownHostBufferSize
                              : paUtilBoundedHostBufferSize,
                 streamCallback ? streamCallback : BlioCallback,
                 streamCallback ? userData : &stream->blio );
       if( result != paNoError )
           goto error;
    }
    stream->bufferProcessorIsInitialized = TRUE;

    /*
        IMPLEMENT ME: initialise the following fields with estimated or actual
        values.
        I think this is okay the way it is br 12/1/05
        maybe need to change input latency estimate if IO devs differ
    */
    stream->streamRepresentation.streamInfo.inputLatency =
            PaUtil_GetBufferProcessorInputLatency(&stream->bufferProcessor)/sampleRate;
    stream->streamRepresentation.streamInfo.outputLatency =
            PaUtil_GetBufferProcessorOutputLatency(&stream->bufferProcessor)/sampleRate;
    stream->streamRepresentation.streamInfo.sampleRate = sampleRate;

    stream->sampleRate  = sampleRate;
    stream->outDeviceSampleRate = 0;
    if( stream->outputUnit ) {
       Float64 rate;
       UInt32 size = sizeof( rate );
       result = ERR( AudioDeviceGetProperty( stream->outputDevice,
                                    0,
                                    FALSE,
                                    kAudioDevicePropertyNominalSampleRate,
                                    &size, &rate ) );
       if( result )
          goto error;
       stream->outDeviceSampleRate = rate;
    }
    stream->inDeviceSampleRate = 0;
    if( stream->inputUnit ) {
       Float64 rate;
       UInt32 size = sizeof( rate );
       result = ERR( AudioDeviceGetProperty( stream->inputDevice,
                                    0,
                                    TRUE,
                                    kAudioDevicePropertyNominalSampleRate,
                                    &size, &rate ) );
       if( result )
          goto error;
       stream->inDeviceSampleRate = rate;
    }
    stream->userInChan  = inputChannelCount;
    stream->userOutChan = outputChannelCount;

    stream->isTimeSet   = FALSE;
    stream->state = STOPPED;
    stream->xrunFlags = 0;

    *s = (PaStream*)stream;

    return result;

error:
    CloseStream( stream );
    return result;
}

PaTime GetStreamTime( PaStream *s )
{
   /* FIXME: I am not at all sure this timing info stuff is right.
             patest_sine_time reports negative latencies, which is wierd.*/
    PaMacCoreStream *stream = (PaMacCoreStream*)s;
    AudioTimeStamp timeStamp;

    VVDBUG(("GetStreamTime()\n"));

    if ( !stream->isTimeSet )
        return (PaTime)0;

    if ( stream->outputDevice ) {
        AudioDeviceGetCurrentTime( stream->outputDevice, &timeStamp);
        return (PaTime)(timeStamp.mSampleTime - stream->startTime.mSampleTime)/stream->outDeviceSampleRate;
    } else if ( stream->inputDevice ) {
        AudioDeviceGetCurrentTime( stream->inputDevice, &timeStamp);
    return (PaTime)(timeStamp.mSampleTime - stream->startTime.mSampleTime)/stream->inDeviceSampleRate;
    } else {
        return (PaTime)0;
    }
}

static void setStreamStartTime( PaStream *stream )
{
   /* FIXME: I am not at all sure this timing info stuff is right.
             patest_sine_time reports negative latencies, which is wierd.*/
   PaMacCoreStream *s = (PaMacCoreStream *) stream;
   VVDBUG(("setStreamStartTime()\n"));
   if( s->outputDevice )
      AudioDeviceGetCurrentTime( s->outputDevice, &s->startTime);
   else if( s->inputDevice )
      AudioDeviceGetCurrentTime( s->inputDevice, &s->startTime);
   else
      bzero( &s->startTime, sizeof( s->startTime ) );

   //FIXME: we need a memory barier here

   s->isTimeSet = TRUE;
}


static PaTime TimeStampToSecs(PaMacCoreStream *stream, const AudioTimeStamp* timeStamp)
{
    VVDBUG(("TimeStampToSecs()\n"));
    //printf( "ATS: %lu, %g, %g\n", timeStamp->mFlags, timeStamp->mSampleTime, timeStamp->mRateScalar );
    if (timeStamp->mFlags & kAudioTimeStampSampleTimeValid)
        return (timeStamp->mSampleTime / stream->sampleRate);
    else
        return 0;
}

#define RING_BUFFER_EMPTY (1000)

static OSStatus ringBufferIOProc( AudioConverterRef inAudioConverter, 
                             UInt32*ioDataSize, 
                             void** outData, 
                             void*inUserData )
{
   void *dummyData;
   long dummySize;
   RingBuffer *rb = (RingBuffer *) inUserData;

   VVDBUG(("ringBufferIOProc()\n"));

   assert( sizeof( UInt32 ) == sizeof( long ) );
   if( RingBuffer_GetReadAvailable( rb ) == 0 ) {
      *outData = NULL;
      *ioDataSize = 0;
      return RING_BUFFER_EMPTY;
   }
   RingBuffer_GetReadRegions( rb, *ioDataSize,
                              outData, (long *)ioDataSize, 
                              &dummyData, &dummySize );
      
   assert( *ioDataSize );
   RingBuffer_AdvanceReadIndex( rb, *ioDataSize );

   return noErr;
}

/*
 * Called by the AudioUnit API to process audio from the sound card.
 * This is where the magic happens.
 */
/* FEEDBACK: there is a lot of redundant code here because of how all the cases differ. This makes it hard to maintain, so if there are suggestinos for cleaning it up, I'm all ears. */
static OSStatus AudioIOProc( void *inRefCon,
                               AudioUnitRenderActionFlags *ioActionFlags,
                               const AudioTimeStamp *inTimeStamp,
                               UInt32 inBusNumber,
                               UInt32 inNumberFrames,
                               AudioBufferList *ioData )
{
   unsigned long framesProcessed     = 0;
   PaStreamCallbackTimeInfo timeInfo = {0,0,0};
   PaMacCoreStream *stream           = (PaMacCoreStream*)inRefCon;
   const bool isRender               = inBusNumber == OUTPUT_ELEMENT;
   int callbackResult                = paContinue ;

   VVDBUG(("AudioIOProc()\n"));

   PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer );

   /* -----------------------------------------------------------------*\
      This output may be useful for debugging,
      But printing durring the callback is a bad enough idea that
      this is not enabled by enableing the usual debugging calls.
   \* -----------------------------------------------------------------*/
   /*
   static int renderCount = 0;
   static int inputCount = 0;
   printf( "-------------------  starting reder/input\n" );
   if( isRender )
      printf("Render callback (%d):\t", ++renderCount);
   else
      printf("Input callback  (%d):\t", ++inputCount);
   printf( "Call totals: %d (input), %d (render)\n", inputCount, renderCount );

   printf( "--- inBusNumber: %lu\n", inBusNumber );
   printf( "--- inNumberFrames: %lu\n", inNumberFrames );
   printf( "--- %x ioData\n", (unsigned) ioData );
   if( ioData )
   {
      int i=0;
      printf( "--- ioData.mNumBuffers %lu: \n", ioData->mNumberBuffers );
      for( i=0; i<ioData->mNumberBuffers; ++i )
         printf( "--- ioData buffer %d size: %lu.\n", i, ioData->mBuffers[i].mDataByteSize );
   }
      ----------------------------------------------------------------- */

   if( !stream->isTimeSet )
      setStreamStartTime( stream );

   if( isRender ) {
      AudioTimeStamp currentTime;
      timeInfo.outputBufferDacTime = TimeStampToSecs(stream, inTimeStamp);
      AudioDeviceGetCurrentTime(stream->outputDevice, &currentTime);
      timeInfo.currentTime = TimeStampToSecs(stream, &currentTime);
   }
   if( isRender && stream->inputUnit == stream->outputUnit )
      timeInfo.inputBufferAdcTime = TimeStampToSecs(stream, inTimeStamp);
   if( !isRender ) {
      AudioTimeStamp currentTime;
      timeInfo.inputBufferAdcTime = TimeStampToSecs(stream, inTimeStamp);
      AudioDeviceGetCurrentTime(stream->inputDevice, &currentTime);
      timeInfo.currentTime = TimeStampToSecs(stream, &currentTime);
   }

   //printf( "---%g, %g, %g\n", timeInfo.inputBufferAdcTime, timeInfo.currentTime, timeInfo.outputBufferDacTime );

   if( isRender && stream->inputUnit == stream->outputUnit
                && !stream->inputSRConverter )
   {
      /* --------- Full Duplex, One Device, no SR Conversion -------
       *
       * This is the lowest latency case, and also the simplest.
       * Input data and output data are available at the same time.
       * we do not use the input SR converter or the input ring buffer.
       *
       */
      OSErr err = 0;
      unsigned long frames;

      /* -- start processing -- */
      PaUtil_BeginBufferProcessing( &(stream->bufferProcessor),

⌨️ 快捷键说明

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