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

📄 pa_unix.c

📁 Audacity是一款用於錄音和編輯聲音的、免費的開放源碼軟體。它可以執行於Mac OS X、Microsoft Windows、GNU/Linux和其它作業系統
💻 C
📖 第 1 页 / 共 3 页
字号:
 * and the watchdog will detect it. */#define SCHEDULER_POLICY         SCHED_RR#define WATCHDOG_MAX_SECONDS    (3)#define WATCHDOG_INTERVAL_USEC  (1000000)static int PaHost_CanaryProc( PaHostSoundControl   *pahsc ){    int   result = 0;#ifdef GNUSTEP    GSRegisterCurrentThread(); /* SB20010904 */#endif    while( pahsc->pahsc_CanaryRun) {      usleep( WATCHDOG_INTERVAL_USEC );      gettimeofday( &pahsc->pahsc_CanaryTime, NULL );    }    DBUG(("PaHost_CanaryProc: exiting.\n"));#ifdef GNUSTEP    GSUnregisterCurrentThread();  /* SB20010904 */#endif    return result;}/******************************************************************************************* * Monitor audio thread and lower its it if it hogs the CPU. * To prevent getting killed, the audio thread must update a * variable with a timer value. * If the value is not recent enough, then the * thread will get killed. */static PaError PaHost_WatchDogProc( PaHostSoundControl   *pahsc ){    struct sched_param    schp = { 0 };    int                   maxPri;#ifdef GNUSTEP    GSRegisterCurrentThread(); /* SB20010904 */#endif/* Run at a priority level above audio thread so we can still run if it hangs. *//* Rise more than 1 because of rumored off-by-one scheduler bugs. */    schp.sched_priority = pahsc->pahsc_AudioPriority + 4;    maxPri = sched_get_priority_max(SCHEDULER_POLICY);    if( schp.sched_priority > maxPri ) schp.sched_priority = maxPri;    if (sched_setscheduler(0, SCHEDULER_POLICY, &schp) != 0)    {        ERR_RPT(("PaHost_WatchDogProc: cannot set watch dog priority!\n"));        goto killAudio;    }    /* Compare watchdog time with audio and canary thread times. */    /* Sleep for a while or until thread cancelled. */    while( pahsc->pahsc_WatchDogRun )    {        int              delta;        struct timeval   currentTime;        usleep( WATCHDOG_INTERVAL_USEC );        gettimeofday( &currentTime, NULL );        /* If audio thread is not advancing, then it must be hung so kill it. */        delta = currentTime.tv_sec - pahsc->pahsc_EntryTime.tv_sec;        DBUG(("PaHost_WatchDogProc: audio delta = %d\n", delta ));        if( delta > WATCHDOG_MAX_SECONDS )        {            goto killAudio;        }        /* If canary died, then lower audio priority and halt canary. */        delta = currentTime.tv_sec - pahsc->pahsc_CanaryTime.tv_sec;        if( delta > WATCHDOG_MAX_SECONDS )        {            ERR_RPT(("PaHost_WatchDogProc: canary died!\n"));            goto lowerAudio;        }    }    DBUG(("PaHost_WatchDogProc: exiting.\n"));#ifdef GNUSTEP    GSUnregisterCurrentThread();  /* SB20010904 */#endif    return 0;lowerAudio:    {        struct sched_param    schat = { 0 };        if( sched_setscheduler(pahsc->pahsc_AudioThreadPID, SCHED_OTHER, &schat) != 0)        {            ERR_RPT(("PaHost_WatchDogProc: failed to lower audio priority. errno = %d\n", errno ));            /* Fall through into killing audio thread. */        }        else        {            ERR_RPT(("PaHost_WatchDogProc: lowered audio priority to prevent hogging of CPU.\n"));            goto cleanup;        }    }killAudio:    ERR_RPT(("PaHost_WatchDogProc: killing hung audio thread!\n"));    pthread_kill( pahsc->pahsc_AudioThread, SIGKILL );cleanup:    pahsc->pahsc_CanaryRun = 0;    DBUG(("PaHost_WatchDogProc: cancel Canary\n"));    pthread_cancel( pahsc->pahsc_CanaryThread );    DBUG(("PaHost_WatchDogProc: join Canary\n"));    pthread_join( pahsc->pahsc_CanaryThread, NULL );    DBUG(("PaHost_WatchDogProc: forget Canary\n"));    pahsc->pahsc_IsCanaryThreadValid = 0;#ifdef GNUSTEP    GSUnregisterCurrentThread();  /* SB20010904 */#endif    return 0;}/*******************************************************************************************/static void PaHost_StopWatchDog( PaHostSoundControl   *pahsc ){/* Cancel WatchDog thread if there is one. */    if( pahsc->pahsc_IsWatchDogThreadValid )    {        pahsc->pahsc_WatchDogRun = 0;        DBUG(("PaHost_StopWatchDog: cancel WatchDog\n"));        pthread_cancel( pahsc->pahsc_WatchDogThread );        pthread_join( pahsc->pahsc_WatchDogThread, NULL );        pahsc->pahsc_IsWatchDogThreadValid = 0;    }/* Cancel Canary thread if there is one. */    if( pahsc->pahsc_IsCanaryThreadValid )    {        pahsc->pahsc_CanaryRun = 0;        DBUG(("PaHost_StopWatchDog: cancel Canary\n"));        pthread_cancel( pahsc->pahsc_CanaryThread );        DBUG(("PaHost_StopWatchDog: join Canary\n"));        pthread_join( pahsc->pahsc_CanaryThread, NULL );        pahsc->pahsc_IsCanaryThreadValid = 0;    }}/*******************************************************************************************/static PaError PaHost_StartWatchDog( PaHostSoundControl   *pahsc ){    int      hres;    PaError  result = 0;    /* The watch dog watches for these timer updates */    gettimeofday( &pahsc->pahsc_EntryTime, NULL );    gettimeofday( &pahsc->pahsc_CanaryTime, NULL );    /* Launch a canary thread to detect priority abuse. */    pahsc->pahsc_CanaryRun = 1;    hres = pthread_create(&(pahsc->pahsc_CanaryThread),                      NULL /*pthread_attr_t * attr*/,                      (pthread_function_t)PaHost_CanaryProc, pahsc);    if( hres != 0 )    {        pahsc->pahsc_IsCanaryThreadValid = 0;        result = paHostError;        sPaHostError = hres;        goto error;    }    pahsc->pahsc_IsCanaryThreadValid = 1;    /* Launch a watchdog thread to prevent runaway audio thread. */    pahsc->pahsc_WatchDogRun = 1;    hres = pthread_create(&(pahsc->pahsc_WatchDogThread),                      NULL /*pthread_attr_t * attr*/,                      (pthread_function_t)PaHost_WatchDogProc, pahsc);    if( hres != 0 )    {        pahsc->pahsc_IsWatchDogThreadValid = 0;        result = paHostError;        sPaHostError = hres;        goto error;    }    pahsc->pahsc_IsWatchDogThreadValid = 1;    return result;error:    PaHost_StopWatchDog( pahsc );    return result;}/******************************************************************************************* * Bump priority of audio thread if running with superuser priveledges. * if priority bumped then launch a watchdog. */static PaError PaHost_BoostPriority( internalPortAudioStream *past ){    PaHostSoundControl  *pahsc;    PaError              result = paNoError;    struct sched_param   schp = { 0 };    pahsc = (PaHostSoundControl *) past->past_DeviceData;    if( pahsc == NULL ) return paInternalError;    pahsc->pahsc_AudioThreadPID = getpid();    DBUG(("PaHost_BoostPriority: audio PID = %d\n", pahsc->pahsc_AudioThreadPID ));    /* Choose a priority in the middle of the range. */    pahsc->pahsc_AudioPriority = (sched_get_priority_max(SCHEDULER_POLICY) -                                  sched_get_priority_min(SCHEDULER_POLICY)) / 2;    schp.sched_priority = pahsc->pahsc_AudioPriority;    if (sched_setscheduler(0, SCHEDULER_POLICY, &schp) != 0)    {        DBUG(("PortAudio: only superuser can use real-time priority.\n"));    }    else    {        DBUG(("PortAudio: audio callback priority set to level %d!\n", schp.sched_priority));        /* We are running at high priority so we should have a watchdog in case audio goes wild. */        result = PaHost_StartWatchDog( pahsc );    }    return result;}/*******************************************************************************************/static PaError Pa_AudioThreadProc( internalPortAudioStream   *past ){    PaError      result;    PaHostSoundControl             *pahsc;    ssize_t      bytes_read, bytes_written;    pahsc = (PaHostSoundControl *) past->past_DeviceData;    if( pahsc == NULL ) return paInternalError;#ifdef GNUSTEP    GSRegisterCurrentThread(); /* SB20010904 */#endif    result = PaHost_BoostPriority( past );    if( result < 0 ) goto error;    past->past_IsActive = 1;    DBUG(("entering thread.\n"));    while( (past->past_StopNow == 0) && (past->past_StopSoon == 0) )    {        /* Read data from device */        if(pahsc->pahsc_NativeInputBuffer)        {            unsigned int totalread = 0;            DBUG(("Pa_AudioThreadProc: attempt to read %d bytes\n", pahsc->pahsc_BytesPerInputBuffer));            do            {                bytes_read = read(pahsc->pahsc_InputHandle,                    (char *)pahsc->pahsc_NativeInputBuffer + totalread,                    pahsc->pahsc_BytesPerInputBuffer - totalread);                if (bytes_read < 0)                {                    ERR_RPT(("PortAudio: read interrupted!\n"));                    break;                }                totalread += bytes_read;            } while( totalread < pahsc->pahsc_BytesPerInputBuffer);        }        /* Convert 16 bit native data to user data and call user routine. */        DBUG(("converting...\n"));        Pa_StartUsageCalculation( past );        result = Pa_CallConvertInt16( past,                                      pahsc->pahsc_NativeInputBuffer,                                      pahsc->pahsc_NativeOutputBuffer );        Pa_EndUsageCalculation( past );        if( result != 0)        {            DBUG(("hmm, Pa_CallConvertInt16() says: %d. i'm bailing.\n",                  result));            break;        }        /* Write data to device. */        if( pahsc->pahsc_NativeOutputBuffer )        {            unsigned int totalwritten = 0;            do            {                bytes_written = write(pahsc->pahsc_OutputHandle,                    (void *)pahsc->pahsc_NativeOutputBuffer,                    pahsc->pahsc_BytesPerOutputBuffer);                if( bytes_written < 0 )                {                    ERR_RPT(("PortAudio: write interrupted!"));                    break;                }                totalwritten += bytes_written;            } while( totalwritten < pahsc->pahsc_BytesPerOutputBuffer);        }        Pa_UpdateStreamTime(pahsc);    }    DBUG(("Pa_AudioThreadProc: left audio loop.\n"));    past->past_IsActive = 0;    PaHost_StopWatchDog( pahsc );error:    DBUG(("leaving audio thread.\n"));#ifdef GNUSTEP    GSUnregisterCurrentThread();  /* SB20010904 */#endif    return result;}/*************************************************************************** Determine minimum number of buffers required for this host based** on minimum latency. Latency can be optionally set by user by setting** an environment variable. For example, to set latency to 200 msec, put:****    set PA_MIN_LATENCY_MSEC=200**** in the cshrc file.*/#define PA_LATENCY_ENV_NAME  ("PA_MIN_LATENCY_MSEC")int Pa_GetMinNumBuffers( int framesPerBuffer, double framesPerSecond ){    int minBuffers;    int minLatencyMsec = MIN_LATENCY_MSEC;    char *minLatencyText = getenv(PA_LATENCY_ENV_NAME);    if( minLatencyText != NULL )    {        PRINT(("PA_MIN_LATENCY_MSEC = %s\n", minLatencyText ));        minLatencyMsec = atoi( minLatencyText );        if( minLatencyMsec < 1 ) minLatencyMsec = 1;        else if( minLatencyMsec > 5000 ) minLatencyMsec = 5000;    }    minBuffers = (int) ((minLatencyMsec * framesPerSecond) / ( 1000.0 * framesPerBuffer ));    if( minBuffers < 2 ) minBuffers = 2;    return minBuffers;}/*******************************************************************/PaError PaHost_OpenStream( internalPortAudioStream   *past ){    PaError          result = paNoError;    PaHostSoundControl *pahsc;    unsigned int     minNumBuffers;    internalPortAudioDevice *pad;    DBUG(("PaHost_OpenStream() called.\n" ));    /* Allocate and initialize host data. */    pahsc = (PaHostSoundControl *) malloc(sizeof(PaHostSoundControl));    if( pahsc == NULL )    {        result = paInsufficientMemory;        goto error;    }    memset( pahsc, 0, sizeof(PaHostSoundControl) );    past->past_DeviceData = (void *) pahsc;    pahsc->pahsc_OutputHandle = BAD_DEVICE_ID; /* No device currently opened. */    pahsc->pahsc_InputHandle = BAD_DEVICE_ID;    pahsc->pahsc_IsAudioThreadValid = 0;    pahsc->pahsc_IsWatchDogThreadValid = 0;

⌨️ 快捷键说明

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